সাইথন কোড সহ পাইথন প্যাকেজটি কীভাবে গঠন করব


122

আমি কিছু সিথন কোডযুক্ত পাইথন প্যাকেজ তৈরি করতে চাই । আমি সাইথন কোডটি সুন্দরভাবে কাজ করতে পেয়েছি। তবে, এখন এটি কীভাবে প্যাকেজ করা যায় তা আমি জানতে চাই।

বেশিরভাগ লোকের জন্য যারা কেবল প্যাকেজটি ইনস্টল করতে চান, আমি .cসাইথনের তৈরি ফাইলটি অন্তর্ভুক্ত করতে চাই setup.pyএবং মডিউলটি তৈরি করার জন্য এটি সংকলনের ব্যবস্থা করতে চাই। তারপরে প্যাকেজটি ইনস্টল করার জন্য ব্যবহারকারীর সিথন ইনস্টল করার প্রয়োজন নেই।

কিন্তু যারা প্যাকেজ পরিবর্তন করতে চান পারে আমিও মত Cython প্রদান চাই .pyxফাইল, এবং একরকম এছাড়াও জন্য অনুমতি setup.pyCython ব্যবহার (তাই ঐ ব্যবহারকারীদের তাদের গড়ে তুলবার হবে Cython ইনস্টল প্রয়োজন)।

এই উভয় পরিস্থিতিতে মেটাতে প্যাকেজের ফাইলগুলি কীভাবে গঠন করব?

Cython ডকুমেন্টেশন একটু নির্দেশিকা দেয় । তবে এটি কোনও একক কীভাবে তৈরি করবেন তা setup.pyসিথনের ক্ষেত্রে / ছাড়াই উভয়কে পরিচালনা করে।


1
আমি দেখতে পাচ্ছি যে প্রশ্নের উত্তরগুলির চেয়ে বেশি ভোট পাচ্ছে। আমি কেন জানতে আগ্রহী যে লোকেরা উত্তরগুলি কেন সন্তোষজনক নয়?
ক্রেগ ম্যাককুইন

4
আমি নথির এই বিভাগটি পেয়েছি , যা ঠিক উত্তর দেয় exactly
উইল

উত্তর:


72

পাইথন প্যাকেজে আমি নিজেই এখন এটি করেছি simplerandom( বিটবকেট রেপো - এডিআইটি: এখন গিথুব ) (আমি এটি একটি জনপ্রিয় প্যাকেজ হওয়ার আশা করি না, তবে সাইথন শিখার জন্য এটি একটি ভাল সুযোগ ছিল)।

এই পদ্ধতি যে একটি বিল্ডিং উপর নির্ভর .pyxসাহায্যে ফাইল Cython.Distutils.build_ext(অন্তত Cython সংস্করণ 0.14 সহ) সবসময় একটি তৈরি বলে মনে হয় .cউৎস হিসেবে একই ডিরেক্টরির মধ্যে ফাইল .pyxফাইল।

এখানে একটি কাট ডাউন সংস্করণ রয়েছে setup.pyযার আমি আশা করি প্রয়োজনীয়গুলি দেখায়:

from distutils.core import setup
from distutils.extension import Extension

try:
    from Cython.Distutils import build_ext
except ImportError:
    use_cython = False
else:
    use_cython = True

cmdclass = {}
ext_modules = []

if use_cython:
    ext_modules += [
        Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.pyx"]),
    ]
    cmdclass.update({'build_ext': build_ext})
else:
    ext_modules += [
        Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.c"]),
    ]

setup(
    name='mypackage',
    ...
    cmdclass=cmdclass,
    ext_modules=ext_modules,
    ...
)

উত্স বিতরণে অন্তর্ভুক্ত রয়েছে MANIFEST.inতা নিশ্চিত করার জন্য আমি সম্পাদনা করেছি (এর সাথে উত্সযুক্ত mycythonmodule.cউত্স বিতরণ python setup.py sdist):

...
recursive-include cython *
...

আমি mycythonmodule.cসংস্করণ নিয়ন্ত্রণ 'ট্রাঙ্ক' (বা মার্চুরিয়ালের জন্য 'ডিফল্ট') প্রতিশ্রুতিবদ্ধ না। আমি যখন প্রকাশ করি তখন উত্স কোড বিতরণের জন্য তা উপস্থিত এবং যুগোপযোগী python setup.py build_extতা নিশ্চিত করার জন্য আমাকে প্রথমে কিছু করতে হবে remember mycythonmodule.cআমি একটি রিলিজ শাখাও করি, এবং সি ফাইলটি শাখায় প্রতিশ্রুতিবদ্ধ করি। সেভাবে আমার কাছে সি ফাইলের একটি historicalতিহাসিক রেকর্ড রয়েছে যা সেই রিলিজের সাথে বিতরণ করা হয়েছিল।


ধন্যবাদ, আমি পাইয়ারেক্স প্রকল্পের জন্য এটি খোলার দরকার ছিল ঠিক তাই! MANIFEST.in আমাকে এক সেকেন্ডের জন্য ছড়িয়ে দিয়েছে, তবে আমার কেবল সেই এক লাইনের দরকার ছিল। আমি আগ্রহের বাইরে উত্স নিয়ন্ত্রণে সি ফাইল অন্তর্ভুক্ত করছি তবে আমি আপনার পয়েন্টটি এটি অপ্রয়োজনীয় দেখছি।
chmullig

সি ফাইলটি কীভাবে ট্রাঙ্ক / ডিফল্ট নয়, তা বোঝাতে আমি আমার উত্তর সম্পাদনা করেছি, তবে একটি রিলিজ শাখায় যুক্ত করা হয়েছে।
ক্রেগ ম্যাককুইন

1
@ ক্রেইগম্যাক কিউইন দুর্দান্ত উত্তরের জন্য ধন্যবাদ, এটি আমাকে অনেক সাহায্য করেছে! তবে আমি ভাবছি, সিথন যখন পাওয়া যায় তখন কী ব্যবহার করা পছন্দসই হয়? আমার কাছে মনে হয় ডিফল্টরূপে প্রাক-উত্পাদিত সি ফাইলগুলি ব্যবহার করা ভাল user এটি ইনস্টলেশনটিকে আরও স্থিতিশীল / শক্তিশালী করে তুলবে, কারণ ব্যবহারকারী সিথনের কোন সংস্করণটি ইনস্টল করেছেন তার উপর ভিত্তি করে বিভিন্ন ফলাফল পেতে পারে - এমনকি তিনি সচেতন হতে পারেন না যে তিনি এটি ইনস্টল করেছেন এবং এটি প্যাকেজ তৈরিতে প্রভাব ফেলছে।
মার্টিনসোস

20

ক্রেগ ম্যাকউউইনের উত্তরে যুক্ত করা: sdistউত্স বন্টন তৈরির আগে সাইথন স্বয়ংক্রিয়ভাবে আপনার উত্স ফাইলগুলি সংকলন করতে কমান্ডটি ওভাররাইড করার জন্য নীচে দেখুন ।

এই পথে আপনার দুর্ঘটনাক্রমে পুরানো Cউত্স বিতরণ করার ঝুঁকি নেই । এটি এমন ক্ষেত্রেও সহায়তা করে যেখানে আপনার বিতরণ প্রক্রিয়ার উপর সীমিত নিয়ন্ত্রণ থাকে যেমন স্বয়ংক্রিয়ভাবে অবিচ্ছিন্ন ইন্টিগ্রেশন থেকে বিতরণ তৈরি করার সময় ইত্যাদি helps

from distutils.command.sdist import sdist as _sdist

...

class sdist(_sdist):
    def run(self):
        # Make sure the compiled Cython files in the distribution are up-to-date
        from Cython.Build import cythonize
        cythonize(['cython/mycythonmodule.pyx'])
        _sdist.run(self)
cmdclass['sdist'] = sdist

19

http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html#distributing-cython-modules

আপনি উত্পন্ন .c ফাইলগুলির পাশাপাশি আপনার সিথন উত্সগুলি বিতরণ করার জন্য দৃ strongly়ভাবে সুপারিশ করা হয়, যাতে ব্যবহারকারীরা সিথন উপলব্ধ না করে আপনার মডিউলটি ইনস্টল করতে পারেন।

আপনার বিতরণ করা সংস্করণে সিথন সংকলন ডিফল্টরূপে সক্ষম না হওয়ার প্রস্তাব দেওয়া হয়। এমনকি ব্যবহারকারী সিথন ইনস্টল করা থাকলেও, তিনি সম্ভবত এটি কেবল আপনার মডিউলটি ইনস্টল করতে ব্যবহার করতে চান না। এছাড়াও, তাঁর কাছে থাকা সংস্করণটি আপনি ব্যবহার করেছেন এমন একই নাও হতে পারে এবং আপনার উত্সগুলি সঠিকভাবে সংকলন করতে পারে না।

এর সহজ অর্থ হ'ল যে সেটআপ.পি ফাইলটি আপনি প্রেরণ করেছেন সেগুলি উত্পন্ন .c ফাইলগুলিতে একটি সাধারণ ডিস্টিল ফাইল হবে, তার পরিবর্তে আমাদের কাছে বেসিক উদাহরণটি থাকবে:

from distutils.core import setup
from distutils.extension import Extension
 
setup(
    ext_modules = [Extension("example", ["example.c"])]
)

7

উভয়কে অন্তর্ভুক্ত করা সহজ তবে কেবল সি-ফাইল ব্যবহার করবেন? .Pyx ফাইলটি অন্তর্ভুক্ত করা দুর্দান্ত, তবে একবারে আপনার কাছে .c ফাইল থাকলে এটির প্রয়োজন হয় না। লোকেরা .px পুনরায় সংকলন করতে চাইলে তারা পাইরেক্স ইনস্টল করতে পারে এবং ম্যানুয়ালি এটি করতে পারে।

অন্যথায় আপনার কাছে প্রথমে সি ফাইলটি তৈরি করে এমন ডিসটুইটেলের জন্য কাস্টম বিল্ড_েক্সট কমান্ড থাকা দরকার। সিথন ইতিমধ্যে একটি অন্তর্ভুক্ত। http://docs.cython.org/src/userguide/source_files_and_compilation.html

এই ডকুমেন্টেশনটি যা করে না তা হ'ল কীভাবে এই শর্তযুক্ত করা যায় তা বলা হয়, তবে

try:
     from Cython.distutils import build_ext
except ImportError:
     from distutils.command import build_ext

এটি পরিচালনা করা উচিত।


1
আপনার উত্তরের জন্য ধন্যবাদ. এটি যুক্তিযুক্ত, যদিও আমি পছন্দ করি যদি সিথন ইনস্টল হওয়ার setup.pyপরে .pyxফাইলটি সরাসরি তৈরি করতে পারে । আমার উত্তর সেটিও কার্যকর করেছে।
ক্রেগ ম্যাককুইন 21

ঠিক আছে, এটা আমার উত্তর পুরো পয়েন্ট। এটি একটি সম্পূর্ণ সেটআপ.পি ছিল না।
লেনার্ট রেজেব্রো

4

(সিথন) উত্পাদিত .c ফাইলগুলি সহ বেশ বিচিত্র। বিশেষত যখন আমরা গিটকে অন্তর্ভুক্ত করি। আমি সেটআপটুল_সাইথন ব্যবহার করতে পছন্দ করব । যখন সিথন উপলভ্য নয়, এটি একটি ডিম তৈরি করবে যা অন্তর্নির্মিত সিথন পরিবেশ তৈরি করেছে এবং তারপরে ডিমটি ব্যবহার করে আপনার কোড তৈরি করবে।

একটি সম্ভাব্য উদাহরণ: https://github.com/douban/greenify/blob/master/setup.py


আপডেট (2017-01-05):

যেহেতু setuptools 18.0, ব্যবহার করার দরকার নেই setuptools_cython। স্ক্র্যাচ ছাড়াই সিথন প্রকল্পটি তৈরির উদাহরণ এখানেsetuptools_cython


আপনি সেটআপ_ প্রয়োজনীয়গুলিতে নির্দিষ্ট করে নিলেও সাইথন ইস্যু করা হচ্ছে না তা এই সমস্যার সমাধান করে?
কামিল সিন্ধি

এছাড়াও 'setuptools>=18.0'পদ্ধতিটি তৈরির পরিবর্তে সেটআপ_ প্রয়োজনীয়গুলি রাখা সম্ভব নয় is_installed?
কামিল সিন্ধি

1
@capitalistpug প্রথমে নিশ্চিত করা প্রয়োজন setuptools>=18.0তারপর আপনি শুধুমাত্র করা প্রয়োজন, ইনস্টল করা হয়েছে 'Cython >= 0.18'setup_requires, এবং Cython উন্নতি ইনস্টল করার সময় ইনস্টল করা হবে। তবে আপনি যদি সেটআপলুলস <18.0 ব্যবহার করে থাকেন, এমনকি আপনি সেটআপ_রেকায়ারগুলিতে নির্দিষ্ট সিথনও ব্যবহার করেন তবে এটি ইনস্টল হবে না, এক্ষেত্রে আপনার ব্যবহার বিবেচনা করা উচিত setuptools_cython
ম্যাককেলভিন

ধন্যবাদ @ এমসি কেলভিন, এটি দুর্দান্ত সমাধান হিসাবে মনে হচ্ছে! এরপরে, উত্স ফাইলগুলি আগে থেকে সিথোনাইজ করে অন্য পদ্ধতিকে ব্যবহার করার কেন আমাদের কোনও কারণ আছে? আমি আপনার পদ্ধতির চেষ্টা করেছি এবং ইনস্টল করার সময় এটি কিছুটা ধীর বলে মনে হচ্ছে (ইনস্টল করতে এক মিনিট সময় লাগে তবে একটি সেকেন্ডে বিল্ড হয়)।
মার্টিনসোস

1
@Martinsos pip install wheel। তারপরে এটি অবশ্যই কারণ হতে হবে। দয়া করে প্রথমে চাকা ইনস্টল করুন এবং আবার চেষ্টা করুন।
ম্যাককেলভিন

2

এটি আমি একটি সেটআপ স্ক্রিপ্ট লিখেছি যা বিল্ডের ভিতরে নেস্টেড ডিরেক্টরিগুলি অন্তর্ভুক্ত করা সহজ করে তোলে। এটি একটি প্যাকেজের মধ্যে ফোল্ডার থেকে চালানো প্রয়োজন।

জিভিগ কাঠামো এর মতো:

__init__.py
setup.py
test.py
subdir/
      __init__.py
      anothertest.py

setup.py

from setuptools import setup, Extension
from Cython.Distutils import build_ext
# from os import path
ext_names = (
    'test',
    'subdir.anothertest',       
) 

cmdclass = {'build_ext': build_ext}
# for modules in main dir      
ext_modules = [
    Extension(
        ext,
        [ext + ".py"],            
    ) 
    for ext in ext_names if ext.find('.') < 0] 
# for modules in subdir ONLY ONE LEVEL DOWN!! 
# modify it if you need more !!!
ext_modules += [
    Extension(
        ext,
        ["/".join(ext.split('.')) + ".py"],     
    )
    for ext in ext_names if ext.find('.') > 0]

setup(
    name='name',
    ext_modules=ext_modules,
    cmdclass=cmdclass,
    packages=["base", "base.subdir"],
)
#  Build --------------------------
#  python setup.py build_ext --inplace

শুভ সংকলন;)


2

আমি নিয়ে এসেছি সহজ হ্যাক:

from distutils.core import setup

try:
    from Cython.Build import cythonize
except ImportError:
    from pip import pip

    pip.main(['install', 'cython'])

    from Cython.Build import cythonize


setup(…)

সাইথন যদি এটি আমদানি করা না যায় তবে ইনস্টল করুন। একটি সম্ভবত এই কোডটি ভাগ করা উচিত নয়, তবে আমার নিজের নির্ভরতার জন্য এটি যথেষ্ট ভাল।


2

অন্য সমস্ত উত্তর হয় হয় নির্ভর করে

  • distutils
  • আমদানি করা হয় Cython.Build, যা সিথনের মাধ্যমে setup_requiresএটি আমদানির মাধ্যমে মুরগি এবং ডিমের সমস্যা তৈরি করে।

পরিবর্তে একটি আধুনিক সমাধান হ'ল সেটআপলগুলি ব্যবহার করা, এই উত্তরটি দেখুন (সাইথন এক্সটেনশানগুলির স্বয়ংক্রিয়ভাবে পরিচালনা করার জন্য সেটআপটোলগুলি 18.0 এর প্রয়োজন, অর্থাত এটি এটি বহু বছর ধরে উপলভ্য)। setup.pyপ্রয়োজনীয় হ্যান্ডলিং, একটি এন্ট্রি পয়েন্ট এবং একটি সিথন মডিউল সহ একটি আধুনিক স্ট্যান্ডার্ড এটি দেখতে পারে:

from setuptools import setup, Extension

with open('requirements.txt') as f:
    requirements = f.read().splitlines()

setup(
    name='MyPackage',
    install_requires=requirements,
    setup_requires=[
        'setuptools>=18.0',  # automatically handles Cython extensions
        'cython>=0.28.4',
    ],
    entry_points={
        'console_scripts': [
            'mymain = mypackage.main:main',
        ],
    },
    ext_modules=[
        Extension(
            'mypackage.my_cython_module',
            sources=['mypackage/my_cython_module.pyx'],
        ),
    ],
)

Cython.Buildসেটআপের সময় থেকে আমদানি করা আমার জন্য আমদানির কারণ হয়ে থাকে। পাইক্স সংকলনের জন্য সেটআপলগুলি রাখা এটির সর্বোত্তম উপায়।
কারসন ইপ

1

বৈশিষ্ট্যটির সীমাবদ্ধ ডিস্টুটিসগুলির পরিবর্তে কেবলমাত্র সেটআপলগুলি ব্যবহার করে আমি সবচেয়ে সহজ উপায়

from setuptools import setup
from setuptools.extension import Extension
try:
    from Cython.Build import cythonize
except ImportError:
    use_cython = False
else:
    use_cython = True

ext_modules = []
if use_cython:
    ext_modules += cythonize('package/cython_module.pyx')
else:
    ext_modules += [Extension('package.cython_module',
                              ['package/cython_modules.c'])]

setup(name='package_name', ext_modules=ext_modules)

আসলে, সেটআপলগুলির সাথে সুস্পষ্ট চেষ্টা / ক্যাচ আমদানির কোনও প্রয়োজন নেই Cython.Build, আমার উত্তর দেখুন।
bluenote10

0

আমি মনে করি একটি কাস্টম build_extকমান্ড সরবরাহ করে আমি এটি করার একটি দুর্দান্ত উপায় খুঁজে পেয়েছি । ধারণা নিম্নোক্ত:

  1. আমি ফাংশনটির মুখ্য অংশগুলিকে ওভাররাইড করে finalize_options()এবং নিমপি শিরোনামগুলি যুক্ত করি import numpy, যা setup()ইনস্টল করার আগে নিম্পের উপস্থিতি না থাকার সমস্যাটি সুন্দরভাবে এড়িয়ে চলে ।

  2. যদি সিস্টেমে সিথন উপলব্ধ থাকে তবে এটি কমান্ডের check_extensions_list()পদ্ধতিটি সন্ধান করে এবং সিথোনাইজ করে সমস্ত অতিক্রান্ত সাইথন মডিউলগুলিকে সি এক্সটেনশন দিয়ে প্রতিস্থাপন করে যা পরে build_extension() পদ্ধতি দ্বারা পরিচালনা করতে পারে । আমরা কেবলমাত্র আমাদের মডিউলটিতে কার্যকারিতার পরবর্তী অংশটি সরবরাহ করি: এর অর্থ এটি যদি সিথন উপলব্ধ না হয় তবে আমাদের কাছে সি এক্সটেনশন উপস্থিত থাকে, এটি এখনও কাজ করে, যা আপনাকে উত্স বিতরণ করতে দেয়।

কোডটি এখানে:

import re, sys, os.path
from distutils import dep_util, log
from setuptools.command.build_ext import build_ext

try:
    import Cython.Build
    HAVE_CYTHON = True
except ImportError:
    HAVE_CYTHON = False

class BuildExtWithNumpy(build_ext):
    def check_cython(self, ext):
        c_sources = []
        for fname in ext.sources:
            cname, matches = re.subn(r"(?i)\.pyx$", ".c", fname, 1)
            c_sources.append(cname)
            if matches and dep_util.newer(fname, cname):
                if HAVE_CYTHON:
                    return ext
                raise RuntimeError("Cython and C module unavailable")
        ext.sources = c_sources
        return ext

    def check_extensions_list(self, extensions):
        extensions = [self.check_cython(ext) for ext in extensions]
        return build_ext.check_extensions_list(self, extensions)

    def finalize_options(self):
        import numpy as np
        build_ext.finalize_options(self)
        self.include_dirs.append(np.get_include())

এটি একজনকে কেবল setup()আমদানি সম্পর্কে চিন্তাভাবনা না করে এবং কারও কাছে সিথন উপলব্ধ রয়েছে তা ছাড়াই যুক্তিগুলি লেখার অনুমতি দেয় :

setup(
    # ...
    ext_modules=[Extension("_my_fast_thing", ["src/_my_fast_thing.pyx"])],
    setup_requires=['numpy'],
    cmdclass={'build_ext': BuildExtWithNumpy}
    )
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.