من مجلد سكربتات إلى مكتبة قابلة للتثبيت
الشيفرة التي تعيش في مجلد سكربتات تعمل على جهاز واحد لشخص واحد إلى يوم يحتاجها فيه شخص آخر أو تحتاجها أنت في بيئة مختلفة. والتغليف (packaging) يحوّل شيفرتك إلى مكتبة لها اسم وإصدار وتبعيات معلنة يستطيع أي أحد تثبيتها بـ pip install. وبه يتشارك فريق مكتبة تسعير دون نسخ ملفات، ويشغّل دفتر بحث ومهمة إنتاج الشيفرة نفسها بالضبط، ويصل إصلاح خلل إلى الجميع عبر رقم إصدار جديد.
# Versions are numbers, not text: compare them as tuples
def parse_version(text):
parts = [int(part) for part in text.split(".")]
return tuple(parts + [0] * (3 - len(parts)))
print("1.10" > "1.9") # False as text, "1" < "9" decides it: wrong
print(parse_version("1.10") > parse_version("1.9")) # True as numbers (1, 10, 0) is newer than (1, 9, 0)
print(parse_version("2")) # (2, 0, 0)البنية وpyproject.toml والبناء
تضع البنية الشائعة الشيفرة في src/yourlib/ (مع __init__.py) والاختبارات في tests/ وملف pyproject.toml في الجذر. وهذا الملف الوحيد يسمّي أداة البناء (جدول [build-system]) ويصف المشروع: name وversion ووصفًا وإصدارات بايثون المدعومة وdependencies. ويثبّت pip install -e . المجلد بوضع قابل للتحرير أثناء التطوير فتسري التعديلات فورًا؛ وينتج python -m build ملف wheel (.whl جاهزًا للتثبيت) وsdist (أرشيف المصدر) في dist/. وضع الإصدار في مكان واحد فقط واعرضه بـ yourlib.__version__ إن احتاجه المستخدمون.
# A minimal pyproject.toml, generated and then read back with tomllib to prove it is valid
import tomllib
def pyproject_toml(name, version, dependencies):
lines = ["[build-system]", 'requires = ["setuptools>=68"]', 'build-backend = "setuptools.build_meta"', "",
"[project]", f'name = "{name}"', f'version = "{version}"']
if dependencies:
lines += ["dependencies = ["] + [f' "{d}",' for d in dependencies] + ["]"]
else:
lines.append("dependencies = []")
return "\n".join(lines) + "\n"
text = pyproject_toml("qcpricing", "0.3.0", ["numpy>=1.26", "pandas>=2"])
data = tomllib.loads(text)
print(data["project"]["name"], data["project"]["version"]) # qcpricing 0.3.0
print(data["project"]["dependencies"]) # ['numpy>=1.26', 'pandas>=2']الإصدارات ومحددات الإصدار
تتبع معظم المكتبات الإصدار الدلالي: MAJOR.MINOR.PATCH. إصلاح الخلل يزيد الرقم الأخير (1.4.2 إلى 1.4.3) والميزة المتوافقة مع الإصدارات السابقة تزيد الأوسط وتصفّر الأخير (1.5.0) والتغيير الكاسر يزيد الأول (2.0.0). وتُعلن التبعيات بـ محددات: numpy>=1.26,<3 تقبل أي NumPy من 1.26 حتى 3 دون 3. كن مرنًا قدر ما تستطيع بأمانة: حدٌّ أدنى لأقدم إصدار اختبرته وحدٌّ أعلى فقط لإصدار رئيسي تعرف أنه يكسرك. وتثبيت الإصدارات بدقة (==) مكانه ملف القفل في التطبيق لا مكتبة يثبّتها الآخرون.
# Bumping a version and checking a requirement, with versions compared as tuples
import operator
def parse_version(text):
parts = [int(part) for part in text.split(".")]
return tuple(parts + [0] * (3 - len(parts)))
def bump_version(version, part):
major, minor, patch = parse_version(version)
return {"major": f"{major + 1}.0.0", "minor": f"{major}.{minor + 1}.0", "patch": f"{major}.{minor}.{patch + 1}"}[part]
OPS = {">=": operator.ge, "<": operator.lt, "==": operator.eq}
def satisfies(version, specifier):
for clause in specifier.split(","):
symbol = next(op for op in (">=", "==", "<") if clause.startswith(op))
if not OPS[symbol](parse_version(version), parse_version(clause[len(symbol):])):
return False
return True
print(bump_version("1.4.2", "minor")) # 1.5.0
print(satisfies("1.26.4", ">=1.26,<3"), satisfies("3.0.0", ">=1.26,<3")) # True False# One place for the version: read it from the source instead of repeating it in several files
import re
init_py = """__version__ = "0.3.0"
from .pricing import price
"""
match = re.search(r'^__version__ = "([^"]+)"', init_py, re.MULTILINE)
version = match.group(1)
print(version) # 0.3.0
print(tuple(int(part) for part in version.split("."))) # (0, 3, 0)- يمنح التغليف الشيفرة اسمًا وإصدارًا وتبعيات معلنة قابلة للتثبيت بـ
pip install؛ طوّر بـpip install -e .وابنِ بـpython -m build. - يحوي
pyproject.tomlنظام البناء وبيانات[project]؛ قارن الإصدارات كمجموعات أرقام لا كنص أبدًا. - استعمل الإصدار الدلالي (
MAJOR.MINOR.PATCH) ومحددات مرنة (numpy>=1.26,<3)؛ ولا تغيّر إصدارًا منشورًا أبدًا وأبقِ الأسرار خارج الحزمة.
التالي: CI/CD للشيفرة الكمية، تشغيل الفحوص تلقائيًا عند كل تغيير.
المختبر: ما الذي يُقيَّم
- قارن الإصدارات كأرقام باستخدام
parse_version25 نقطة - أصدر الإصدار التالي باستخدام
bump_version25 نقطة - تحقق من متطلب باستخدام
satisfies25 نقطة - صِف الحزمة باستخدام
pyproject_toml25 نقطة