Bagaimana saya bisa mendapatkan versi yang didefinisikan di setup.py (setuptools) dalam paket saya?

153

Bagaimana saya bisa mendapatkan versi yang didefinisikan setup.pydari paket saya (untuk --version, atau tujuan lain)?

elmarco
sumber
3
Saya kira ini kira-kira pertanyaan yang sama dengan stackoverflow.com/questions/458550/… .
Zooko

Jawaban:

246

Menginterogasi string versi dari distribusi yang sudah diinstal

Untuk mengambil versi dari dalam paket Anda pada saat runtime (apa yang sebenarnya ditanyakan oleh pertanyaan Anda), Anda dapat menggunakan:

import pkg_resources  # part of setuptools
version = pkg_resources.require("MyProject")[0].version

Simpan string versi untuk digunakan selama instalasi

Jika Anda ingin melakukan hal sebaliknya (yang tampaknya merupakan jawaban yang oleh penulis lain tampaknya Anda tanyakan), letakkan string versi di file terpisah dan baca isi file itu setup.py.

Anda bisa membuat version.py dalam paket Anda dengan sebuah __version__baris, lalu membacanya dari setup.py menggunakan execfile('mypackage/version.py'), sehingga ia menetapkan __version__di namespace setup.py.

Jika Anda menginginkan cara yang lebih sederhana yang akan bekerja dengan semua versi Python dan bahkan bahasa non-Python yang mungkin memerlukan akses ke string versi:

Simpan string versi sebagai satu-satunya konten file teks biasa, beri nama eg VERSION, dan baca file itu selama setup.py.

version_file = open(os.path.join(mypackage_root_dir, 'VERSION'))
version = version_file.read().strip()

File yang sama VERSIONkemudian akan berfungsi sama baiknya di program lain, bahkan yang non-Python, dan Anda hanya perlu mengubah string versi di satu tempat untuk semua program.

Peringatan tentang kondisi lomba saat pemasangan

Ngomong-ngomong, JANGAN mengimpor paket Anda dari setup.py Anda seperti yang disarankan dalam jawaban lain di sini: tampaknya akan bekerja untuk Anda (karena Anda sudah memiliki dependensi paket Anda diinstal), tetapi itu akan mendatangkan malapetaka pada pengguna baru paket Anda. , karena mereka tidak akan dapat menginstal paket Anda tanpa menginstal dependensi secara manual terlebih dahulu.

PJ Eby
sumber
1
Ini hanyalah jawaban terbaik di sini: cara terbaik adalah menggunakan execfile jika Anda memerlukan setup.py untuk mendapatkan versi dari paket Anda.
trinth
2
execfileberfungsi dengan sangat baik ... tetapi (sayangnya) tidak bekerja dengan Python 3.
medmunds
9
... OK, untuk Python 2 dan 3 digunakan with open('mypackage/version.py') as f: exec(f.read())sebagai pengganti execfile('mypackage/version.py'). (Dari stackoverflow.com/a/437857/647002 )
medmunds
5
Bagian malapetaka belum tentu benar ... itu hanya akan mendatangkan malapetaka jika file init .py Anda dalam paket memiliki ketergantungan impor kode (langsung atau tidak langsung).
Pykler
2
Tampaknya layak disebutkan bahwa Django melakukan panggilan __import__ di setup.py mereka . Apakah '__import__' vs 'impor' membuat ini aman? Tampaknya tidak menimbulkan masalah bagi mereka.
user1978019
33

contoh studi: mymodule

Bayangkan konfigurasi ini:

setup.py
mymodule/
        / __init__.py
        / version.py
        / myclasses.py

Kemudian bayangkan beberapa skenario biasa di mana Anda memiliki dependensi dan setup.pyterlihat seperti:

setup(...
    install_requires=['dep1','dep2', ...]
    ...)

Dan sebuah contoh __init__.py:

from mymodule.myclasses import *
from mymodule.version import __version__

Dan misalnya myclasses.py:

# these are not installed on your system.
# importing mymodule.myclasses would give ImportError
import dep1
import dep2

masalah # 1: mengimpor mymoduleselama pengaturan

Jika setup.pyimpor Anda mymodulemaka selama setup Anda kemungkinan besar akan mendapatkan ImportError. Ini adalah kesalahan yang sangat umum ketika paket Anda memiliki dependensi. Jika paket Anda tidak memiliki dependensi lain selain bawaan, Anda mungkin aman; Namun ini bukan praktik yang baik. Alasan untuk itu adalah bahwa itu bukan bukti masa depan; katakan besok kode Anda perlu mengkonsumsi beberapa ketergantungan lainnya.

masalah # 2: dimana saya __version__?

Jika Anda memasukkan hardcode ke __version__dalam, setup.pymaka itu mungkin tidak cocok dengan versi yang akan Anda kirimkan dalam modul Anda. Agar konsisten, Anda akan meletakkannya di satu tempat dan membacanya dari tempat yang sama saat Anda membutuhkannya. Menggunakan importAnda mungkin mendapatkan masalah # 1.

solusi: à la setuptools

Anda akan menggunakan kombinasi dari open, execdan memberikan perintah untuk execmenambahkan variabel:

# setup.py
from setuptools import setup, find_packages
from distutils.util import convert_path

main_ns = {}
ver_path = convert_path('mymodule/version.py')
with open(ver_path) as ver_file:
    exec(ver_file.read(), main_ns)

setup(...,
    version=main_ns['__version__'],
    ...)

Dan dalam mymodule/version.pymengekspos versi:

__version__ = 'some.semantic.version'

Dengan cara ini, versi dikirimkan bersama modul, dan Anda tidak memiliki masalah selama pengaturan mencoba mengimpor modul yang tidak memiliki dependensi (belum diinstal).

tidak tahu
sumber
2
Ini sepertinya solusi yang paling masuk akal karena hanya bergantung pada dependensi yang diizinkan.
Dogweather
Apakah konsep versi paket didefinisikan dalam file setup.py berbeda dari versi ?
variabel
16

Teknik terbaik adalah mendefinisikan __version__kode produk Anda, lalu mengimpornya ke setup.py dari sana. Ini memberi Anda nilai yang dapat Anda baca di modul yang sedang berjalan, dan hanya memiliki satu tempat untuk mendefinisikannya.

Nilai-nilai di setup.py tidak diinstal, dan setup.py tidak bertahan setelah instalasi.

Apa yang saya lakukan (misalnya) di coverage.py:

# coverage/__init__.py
__version__ = "3.2"


# setup.py
from coverage import __version__

setup(
    name = 'coverage',
    version = __version__,
    ...
    )

UPDATE (2017): coverage.py tidak lagi mengimpor sendiri untuk mendapatkan versi. Mengimpor kode Anda sendiri dapat membuatnya tidak bisa dihapus, karena kode produk Anda akan mencoba mengimpor dependensi, yang belum diinstal, karena setup.py adalah yang menginstalnya.

Ned Batchelder
sumber
4
@ Evan: Saya tidak yakin apa yang Anda maksudkan "hanya tarik nilai itu dari sumbernya". Jika file dengan __version__itu rusak dalam beberapa cara, maka impor Anda juga akan rusak. Python tidak tahu bagaimana hanya menafsirkan pernyataan yang Anda inginkan. @pjeby benar: jika modul Anda perlu mengimpor modul lain, mereka mungkin belum diinstal, dan itu akan kacau. Teknik ini berfungsi jika Anda berhati-hati bahwa impor tidak menyebabkan rantai panjang impor lainnya.
Ned Batchelder
1
@Ned Batchelder Saya cukup yakin bahwa, jika Anda meletakkan versi sebelum setiap impor dalam file sumber dan hanya ke 'dari versi modul impor' itu tidak akan lex lagi dari file sumber daripada yang dibutuhkan. Selain itu, siapa yang akan merilis kode yang rusak? Jika paket membutuhkan dependensi, gunakan setuptools atau tunggu rilis distutils2 nanti di tahun tersebut.
Evan Plaice
15
@Van, saya minta maaf, tetapi Anda salah tentang mengimpor sebagian file. Coba letakkan pernyataan cetak di akhir modul panjang, dan impor variabel pertama yang ditentukan dalam file. Pernyataan cetak akan dieksekusi.
Ned Batchelder
23
Saya setuju dengan ini, tetapi @pjeby sepenuhnya benar: "Omong-omong, JANGAN mengimpor paket Anda dari setup.py Anda seperti yang disarankan dalam jawaban lain di sini: tampaknya akan berfungsi untuk Anda (karena Anda sudah memiliki dependensi paket Anda yang diinstal ), tetapi itu akan mendatangkan malapetaka pada pengguna baru paket Anda, karena mereka tidak akan dapat menginstal paket Anda tanpa menginstal dependensi secara manual terlebih dahulu. " Ned, maukah Anda menambahkan peringatan pada jawaban Anda?
Dr. Jan-Philip Gehrcke
1
Seperti @ Jan-PhilipGehrcke ketika saya upload file setup.py seperti ini untuk PyPI dan kemudian pip install <packagename>, saya mendapatkan error berikut: ImportError: No module named <packagename>. PERINGATAN pembaca Anda bahwa Anda tidak dapat menjalankan file setup.py seperti ini di lingkungan di mana paket belum diinstal!
Hobs
14

Pertanyaan Anda agak kabur, tetapi saya pikir apa yang Anda tanyakan adalah bagaimana menentukannya.

Anda perlu mendefinisikan __version__seperti:

__version__ = '1.4.4'

Dan kemudian Anda dapat mengonfirmasi bahwa setup.py tahu tentang versi yang baru saja Anda tentukan:

% ./setup.py --version
1.4.4
jathanisme
sumber
9

Saya tidak senang dengan jawaban ini ... tidak ingin memerlukan setuptools, atau membuat modul terpisah untuk variabel tunggal, jadi saya datang dengan ini.

Karena ketika Anda yakin modul utama dalam gaya pep8 dan akan tetap seperti itu:

version = '0.30.unknown'
with file('mypkg/mymod.py') as f:
    for line in f:
        if line.startswith('__version__'):
            _, _, version = line.replace("'", '').split()
            break

Jika Anda ingin ekstra hati-hati dan menggunakan pengurai nyata:

import ast
version = '0.30.unknown2'
with file('mypkg/mymod.py') as f:
    for line in f:
        if line.startswith('__version__'):
            version = ast.parse(line).body[0].value.s
            break

setup.py agak modul sekali pakai jadi tidak masalah jika itu agak jelek.


Pembaruan: cukup lucu Saya sudah pindah dari ini dalam beberapa tahun terakhir dan mulai menggunakan file terpisah dalam paket yang disebut meta.py. Saya memasukkan banyak data meta ke sana yang mungkin ingin saya ubah sesering mungkin. Jadi, bukan hanya untuk satu nilai.

Gringo Suave
sumber
+1. Ini relatif sederhana, menyimpan nomor versi di satu tempat, tidak memerlukan file terpisah untuk memuatnya, dan tidak memaksakan dependensi impor modul python pada setup.py. Saya bahkan tidak akan repot-repot dengan manajer konteks dalam program yang berumur pendek sebagai setup.py.
ʇsәɹoɈ
Jauh lebih bagus daripada menggunakan regex, terima kasih. Anda juga dapat menggunakan ast.get_docstring()beberapa .split('\n')[0].strip()dll untuk secara otomatis mengisi descriptiondari sumbernya. Satu hal lagi yang perlu disinkronkan
hilang
4

Buat file di pohon sumber Anda, misalnya di yourbasedir / yourpackage / _version.py. Biarkan file itu hanya berisi satu baris kode, seperti ini:

__version__ = "1.1.0-r4704"

Kemudian di setup.py Anda, buka file itu dan uraikan nomor versi seperti ini:

verstr = "tidak diketahui"
mencoba:
    verstrline = terbuka ('paket Anda / _version.py', "rt"). read ()
kecuali EnvironmentError:
    lulus # Oke, tidak ada file versi.
lain:
    VSRE = r "^ __ version__ = ['\"] ([^' \ "] *) ['\"] "
    mo = penelitian ulang (VSRE, verstrline, re.M)
    jika mo:
        verstr = mo.group (1)
    lain:
        meningkatkan RuntimeError ("tidak dapat menemukan versi di paket Anda / _version.py")

Akhirnya, dalam yourbasedir/yourpackage/__init__.pyimpor _versi seperti ini:

__version__ = "tidak diketahui"
mencoba:
    dari _version import __version__
kecuali ImportError:
    # Kami berjalan di pohon yang tidak memiliki _version.py, jadi kami tidak tahu apa versi kami.
    lulus

Contoh kode yang melakukan ini adalah paket "pyutil" yang saya pelihara. (Lihat pencarian PyPI atau google - stackoverflow melarang saya untuk memasukkan hyperlink ke dalamnya dalam jawaban ini.)

@pjeby benar bahwa Anda tidak boleh mengimpor paket Anda dari setup.py sendiri. Itu akan bekerja ketika Anda mengujinya dengan membuat juru bahasa Python baru dan menjalankan setup.py di dalamnya hal pertama:, python setup.pytetapi ada beberapa kasus ketika itu tidak akan berfungsi. Itu karena import youpackagetidak berarti membaca direktori kerja saat ini untuk direktori bernama "paket Anda", artinya mencari arus sys.modulesuntuk kunci "paket Anda" dan kemudian melakukan berbagai hal jika tidak ada di sana. Jadi selalu berfungsi ketika Anda melakukannya python setup.pykarena Anda memiliki yang baru, kosong sys.modules, tetapi ini tidak bekerja secara umum.

Misalnya, bagaimana jika py2exe mengeksekusi setup.py Anda sebagai bagian dari proses mengemas aplikasi? Saya telah melihat kasus seperti ini di mana py2exe akan memasukkan nomor versi yang salah pada suatu paket karena paket tersebut mendapatkan nomor versinyaimport myownthingdi setup.py-nya, tetapi versi berbeda dari paket itu sebelumnya telah diimpor selama menjalankan py2exe. Demikian juga, bagaimana jika setuptools, easy_install, distribusikan, atau distutils2 sedang mencoba membangun paket Anda sebagai bagian dari proses menginstal paket berbeda yang tergantung pada Anda? Lalu apakah paket Anda dapat diimpor pada saat setup.py sedang dievaluasi, atau apakah sudah ada versi paket Anda yang telah diimpor selama masa juru bahasa Python ini, atau apakah mengimpor paket Anda memerlukan paket lain yang harus diinstal terlebih dahulu , atau memiliki efek samping, dapat mengubah hasil. Saya mengalami beberapa kesulitan dalam mencoba menggunakan kembali paket Python yang menyebabkan masalah untuk alat seperti py2exe dan setuptools karena setup.py mereka mengimpor paket itu sendiri untuk menemukan nomor versinya.

Omong-omong, teknik ini berfungsi baik dengan alat untuk secara otomatis membuat yourpackage/_version.pyfile untuk Anda, misalnya dengan membaca riwayat kontrol revisi Anda dan menuliskan nomor versi berdasarkan tag terbaru dalam riwayat kontrol revisi. Berikut adalah alat yang melakukan itu untuk darcs: http://tahoe-lafs.org/trac/darcsver/browser/trunk/README.rst dan di sini adalah potongan kode yang melakukan hal yang sama untuk git: http: // github .com / warner / python-ecdsa / blob / 0ed702a9d4057ecf33eea969b8cf280eaccd89a1 / setup.py # L34

Zooko
sumber
3

Ini juga harus berfungsi, menggunakan ekspresi reguler dan bergantung pada bidang metadata untuk memiliki format seperti ini:

__fieldname__ = 'value'

Gunakan yang berikut di awal setup.py Anda:

import re
main_py = open('yourmodule.py').read()
metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", main_py))

Setelah itu, Anda dapat menggunakan metadata dalam skrip Anda seperti ini:

print 'Author is:', metadata['author']
print 'Version is:', metadata['version']
terima kasih
sumber
Seperti yang saya katakan di atas, cukup gunakan str.split :)
Éric Araujo
Ya Tuhan tidak. Anda mengurai Python dengan Python? Paling tidak, gunakan eval (), anak.
slacy
3
Nasihat yang buruk slacy, eval harus dihindari ketika begitu mudah.
Gringo Suave
3

Dengan struktur seperti ini:

setup.py
mymodule/
        / __init__.py
        / version.py
        / myclasses.py

di mana version.py berisi:

__version__ = 'version_string'

Anda dapat melakukan ini di setup.py :

import sys

sys.path[0:0] = ['mymodule']

from version import __version__

Ini tidak akan menimbulkan masalah dengan dependensi apa pun yang Anda miliki di mymodule / __ init__.py

Jahid
sumber
2

Untuk menghindari mengimpor file (dan dengan demikian mengeksekusi kodenya) orang dapat menguraikannya dan memulihkan versionatribut dari pohon sintaks:

# assuming 'path' holds the path to the file

import ast

with open(path, 'rU') as file:
    t = compile(file.read(), path, 'exec', ast.PyCF_ONLY_AST)
    for node in (n for n in t.body if isinstance(n, ast.Assign)):
        if len(node.targets) == 1:
            name = node.targets[0]
            if isinstance(name, ast.Name) and \
                    name.id in ('__version__', '__version_info__', 'VERSION'):
                v = node.value
                if isinstance(v, ast.Str):
                    version = v.s
                    break
                if isinstance(v, ast.Tuple):
                    r = []
                    for e in v.elts:
                        if isinstance(e, ast.Str):
                            r.append(e.s)
                        elif isinstance(e, ast.Num):
                            r.append(str(e.n))
                    version = '.'.join(r)
                    break

Kode ini mencoba untuk menemukan __version__atau VERSIONpenugasan di tingkat atas pengembalian modul adalah nilai string. Sisi kanan bisa berupa string atau tupel.

Mikhail Edoshin
sumber
3
Itu terlihat pintar dan rumit :) Akan lebih mudah untuk hanya memiliki file _version.py yang berisi satu tugas dan uraikan dengan open-read-str.split.
Éric Araujo
Terima kasih telah memposting ini. Saya pikir ini terlalu rumit untuk situasi ini, tetapi sangat membantu untuk memahami bagaimana seseorang dapat mendekati masalah. Saya suka itu menyimpan nomor versi di satu tempat, tidak memerlukan file terpisah untuk memuatnya, dan tidak memaksakan dependensi impor modul python pada skrip pengaturan.
ʇsәɹoɈ
2

Ada seribu cara menguliti kucing - inilah milik saya:

# Copied from (and hacked):
# https://github.com/pypa/virtualenv/blob/develop/setup.py#L42
def get_version(filename):
    import os
    import re

    here = os.path.dirname(os.path.abspath(__file__))
    f = open(os.path.join(here, filename))
    version_file = f.read()
    f.close()
    version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
                              version_file, re.M)
    if version_match:
        return version_match.group(1)
    raise RuntimeError("Unable to find version string.")
Marc Abramowitz
sumber
2

Membersihkan https://stackoverflow.com/a/12413800 dari @ gringo-suave:

from itertools import ifilter
from os import path
from ast import parse

with open(path.join('package_name', '__init__.py')) as f:
    __version__ = parse(next(ifilter(lambda line: line.startswith('__version__'),
                                     f))).body[0].value.s
DI
sumber
2

Sekarang ini kotor dan perlu beberapa pemurnian (bahkan mungkin ada panggilan anggota yang tidak ditemukan di pkg_resources yang saya lewatkan), tetapi saya tidak melihat mengapa ini tidak berhasil, atau mengapa tidak ada yang menyarankan untuk berkencan (Googling sekitar memiliki tidak mengaktifkan ini) ... perhatikan bahwa ini adalah Python 2.x, dan akan membutuhkan pkg_resources (sigh):

import pkg_resources

version_string = None
try:
    if pkg_resources.working_set is not None:
        disto_obj = pkg_resources.working_set.by_key.get('<my pkg name>', None)
        # (I like adding ", None" to gets)
        if disto_obj is not None:
            version_string = disto_obj.version
except Exception:
    # Do something
    pass
Mark Gerolimatos
sumber
2

Kami ingin menempatkan informasi meta tentang paket kami pypackagerydi __init__.py, tapi tidak bisa karena memiliki dependensi pihak ketiga sebagai PJ Eby sudah menunjukkan (lihat jawaban dan peringatan mengenai kondisi lomba).

Kami menyelesaikannya dengan membuat modul terpisah pypackagery_meta.pyyang hanya berisi informasi meta:

"""Define meta information about pypackagery package."""

__title__ = 'pypackagery'
__description__ = ('Package a subset of a monorepo and '
                   'determine the dependent packages.')
__url__ = 'https://github.com/Parquery/pypackagery'
__version__ = '1.0.0'
__author__ = 'Marko Ristin'
__author_email__ = '[email protected]'
__license__ = 'MIT'
__copyright__ = 'Copyright 2018 Parquery AG'

kemudian mengimpor informasi meta di packagery/__init__.py:

# ...

from pypackagery_meta import __title__, __description__, __url__, \
    __version__, __author__, __author_email__, \
    __license__, __copyright__

# ...

dan akhirnya menggunakannya di setup.py:

import pypackagery_meta

setup(
    name=pypackagery_meta.__title__,
    version=pypackagery_meta.__version__,
    description=pypackagery_meta.__description__,
    long_description=long_description,
    url=pypackagery_meta.__url__,
    author=pypackagery_meta.__author__,
    author_email=pypackagery_meta.__author_email__,
    # ...
    py_modules=['packagery', 'pypackagery_meta'],
 )

Anda harus memasukkan pypackagery_metake dalam paket Anda dengan py_modulesargumen pengaturan. Kalau tidak, Anda tidak dapat mengimpornya saat instalasi karena distribusi paket akan kekurangannya.

marko.ristin
sumber
1

Sederhana dan lurus, buat file yang disebut source/package_name/version.pydengan konten berikut:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__version__ = "2.6.9"

Kemudian, pada file source/package_name/__init__.pyAnda, Anda mengimpor versi untuk digunakan orang lain:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
from .version import __version__

Sekarang, Anda bisa memakai ini setup.py

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import re
import sys

try:
    filepath = 'source/package_name/version.py'
    version_file = open( filepath )
    __version__ ,= re.findall( '__version__ = "(.*)"', version_file.read() )

except Exception as error:
    __version__ = "0.0.1"
    sys.stderr.write( "Warning: Could not open '%s' due %s\n" % ( filepath, error ) )

finally:
    version_file.close()

Diuji ini dengan Python 2.7, 3.3, 3.4, 3.5, 3.6dan 3.7di Linux, Windows dan Mac OS. Saya menggunakan paket saya yang memiliki Tes Integrasi dan Unit untuk semua platform tesis. Anda dapat melihat hasil dari .travis.ymldan di appveyor.ymlsini:

  1. https://travis-ci.org/evandrocoan/debugtools/builds/527110800
  2. https://ci.appveyor.com/project/evandrocoan/pythondebugtools/builds/24245446

Versi alternatif menggunakan pengelola konteks:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import re
import sys

try:
    filepath = 'source/package_name/version.py'

    with open( filepath ) as file:
        __version__ ,= re.findall( '__version__ = "(.*)"', file.read() )

except Exception as error:
    __version__ = "0.0.1"
    sys.stderr.write( "Warning: Could not open '%s' due %s\n" % ( filepath, error ) )

Anda juga dapat menggunakan codecsmodul untuk menangani kesalahan unicode baik pada Python 2.7dan3.6

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import re
import sys
import codecs

try:
    filepath = 'source/package_name/version.py'

    with codecs.open( filepath, 'r', errors='ignore' ) as file:
        __version__ ,= re.findall( '__version__ = "(.*)"', file.read() )

except Exception as error:
    __version__ = "0.0.1"
    sys.stderr.write( "Warning: Could not open '%s' due %s\n" % ( filepath, error ) )

Jika Anda menulis modul Python 100% dalam C / C ++ menggunakan Python C Extensions, Anda dapat melakukan hal yang sama, tetapi menggunakan C / C ++ alih-alih Python.

Pada kasus ini, buat yang berikut ini setup.py:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import re
import sys
import codecs
from setuptools import setup, Extension

try:
    filepath = 'source/version.h'

    with codecs.open( filepath, 'r', errors='ignore' ) as file:
        __version__ ,= re.findall( '__version__ = "(.*)"', file.read() )

except Exception as error:
    __version__ = "0.0.1"
    sys.stderr.write( "Warning: Could not open '%s' due %s\n" % ( filepath, error ) )

setup(
        name = 'package_name',
        version = __version__,

        package_data = {
                '': [ '**.txt', '**.md', '**.py', '**.h', '**.hpp', '**.c', '**.cpp' ],
            },

        ext_modules = [
            Extension(
                name = 'package_name',
                sources = [
                    'source/file.cpp',
                ],
                include_dirs = ['source'],
            )
        ],
    )

Yang membaca versi dari file version.h:

const char* __version__ = "1.0.12";

Tapi, jangan lupa untuk membuat MANIFEST.inmenyertakan version.hfile:

include README.md
include LICENSE.txt

recursive-include source *.h

Dan itu terintegrasi ke dalam aplikasi utama dengan:

#include <Python.h>
#include "version.h"

// create the module
PyMODINIT_FUNC PyInit_package_name(void)
{
    PyObject* thismodule;
    ...

    // https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue
    PyObject_SetAttrString( thismodule, "__version__", Py_BuildValue( "s", __version__ ) );

    ...
}

Referensi:

  1. kesalahan buka file python
  2. Tentukan global dalam modul Python dari API C
  3. Bagaimana cara memasukkan paket data dengan setuptools / mendistribusikan?
  4. https://github.com/lark-parser/lark/blob/master/setup.py#L4
  5. Bagaimana cara menggunakan paket setuptools dan ext_modules dengan nama yang sama?
  6. Apakah mungkin untuk memasukkan subdirektori menggunakan dist utils (setup.py) sebagai bagian dari data paket?
pengguna
sumber
1

menyebarkan paket ke server dan konvensi penamaan file untuk paket indeks:

contoh untuk konversi versi dinamis pip:

  • menang:

    • test_pkg-1.0.0-cp36-cp36m-win_amd64.whl
    • test_pkg-1.0.0-py3.6-win-amd64.egg
  • Mac:

    • test_pkg-1.0.0-py3.7-macosx-10.12-x86_64.egg
    • test_pkg-1.0.0-py3.7-macosx-10.12-x86_64.whl
  • linux:
    • test_pkg-1.0.0-cp36-cp36m-linux_x86_64.whl
from setuptools_scm import get_version

def _get_version():

     dev_version = str(".".join(map(str, str(get_version()).split("+")[0]\
            .split('.')[:-1])))

    return dev_version

Temukan contoh setup.py memanggil versi pip dinamis yang cocok dari git commit

setup(
    version=_get_version(),
    name=NAME,
    description=DESCRIPTION,
    long_description=LONG_DESCRIPTION,
    classifiers=CLASSIFIERS,

# add few more for wheel wheel package ...conversion

)
Narayana Reddy
sumber
0

Saya menggunakan variabel lingkungan seperti di bawah ini

VERSION = 0.0.0 python setup.py sdist bdist_wheel

Di setup.py


import os

setup(
    version=os.environ['VERSION'],
    ...
)

Untuk pemeriksaan konsistensi dengan versi pengepak, saya menggunakan skrip di bawah ini.

PKG_VERSION=`python -c "import pkg; print(pkg.__version__)"`
if [ $PKG_VERSION == $VERSION ]; then
    python setup.py sdist bdist_wheel
else
    echo "Package version differs from set env variable"
fi
seongjoo
sumber