إنشاء حزم Python: دليل التطوير إلى PyPI

تعلم تعبئة Python من الكود إلى النشر على PyPI

Page content

تغليف Python تطور بشكل كبير، حيث جعل الأدوات الحديثة والمعايير توزيع الكود أسهل من أي وقت مضى.

يوضح هذا الدليل لك كيفية بناء حزم Python المهنية ونشرها على PyPI. إذا كنت مبتدئًا في Python أو تحتاج إلى مرجع سريع، فانظر إلى ورقة Python الخاصة بنا للحصول على معرفة مبدئية بـ Python.

حزم Python

لماذا تغليف كود Python؟

يقدم تغليف مشروع Python عدة فوائد:

  • إعادة الاستخدام: مشاركة الكود عبر مشاريع متعددة دون نسخه ولصقه
  • التوزيع: تمكين الآخرين من تثبيت الكود ببساطة باستخدام pip install
  • إدارة التبعيات: تحديد التبعيات وإدارتها بوضوح
  • الإصدار: تتبع الإصدارات والحفاظ على التوافق الخلفي
  • المعايير المهنية: اتباع أفضل الممارسات في المجتمع Python
  • التوثيق: تشجيع التوثيق المناسب والاختبارات

هيكل حزمة Python الحديثة

تتبع حزمة منظمة هذه الهيكل:

my-package/
├── src/
│   └── mypackage/
│       ├── __init__.py
│       ├── core.py
│       └── utils.py
├── tests/
│   ├── __init__.py
│   └── test_core.py
├── docs/
│   └── index.md
├── .github/
│   └── workflows/
│       └── publish.yml
├── pyproject.toml
├── README.md
├── LICENSE
└── .gitignore

يُفضل الآن استخدام src-layout على الهيكل المسطح لأنه:

  • يمنع استيراد الكود غير المثبت بشكل عرضي أثناء التطوير
  • يجعل الاختبار أكثر موثوقية من خلال إجبار التثبيت
  • يفصل بوضوح الكود المصدر عن ملفات المشروع الأخرى

عند تنظيم هيكل حزمةك الداخلية، تأكد من تطبيق مبادئ الهيكل النظيف لجعل كودك أكثر قابلية للصيانة والاختبار. دليلنا حول أنماط التصميم في Python للهيكل النظيف يغطي مبادئ SOLID، حقن التبعيات، والأنماط المطبق في الهيكل المطبق في Python.

ملف pyproject.toml: التكوين الحديث

pyproject.toml (PEP 518، 621) هو المعيار الحديث لتوزيع مشاريع Python، والذي يحل محل setup.py القديم:

[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "mypackage"
version = "0.1.0"
description = "حزمة رائعة لـ Python"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
    {name = "الاسم", email = "you@example.com"}
]
keywords = ["مثال", "دورة تدريبية", "حزمة"]
classifiers = [
    "الحالة التطويرية :: 4 - بيتا",
    "الجمهور المستهدف :: المطورين",
    "الترخيص :: مُوافقة OSI :: ترخيص MIT",
    "لغة البرمجة :: Python :: 3",
    "لغة البرمجة :: Python :: 3.8",
    "لغة البرمجة :: Python :: 3.9",
    "لغة البرمجة :: Python :: 3.10",
    "لغة البرمجة :: Python :: 3.11",
    "لغة البرمجة :: Python :: 3.12",
]
dependencies = [
    "requests>=2.28.0",
    "click>=8.1.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.4.0",
    "black>=23.0.0",
    "flake8>=6.0.0",
    "mypy>=1.5.0",
]
docs = [
    "sphinx>=7.0.0",
    "sphinx-rtd-theme>=1.3.0",
]

[project.urls]
Homepage = "https://github.com/yourusername/mypackage"
Documentation = "https://mypackage.readthedocs.io"
Repository = "https://github.com/yourusername/mypackage"
Issues = "https://github.com/yourusername/mypackage/issues"

[project.scripts]
mypackage-cli = "mypackage.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

أقسام التكوين الرئيسية

  1. build-system: يحدد وحدة البناء (setuptools، hatchling، poetry-core، flit-core)
  2. project: البيانات الأساسية والتبعيات
  3. project.optional-dependencies: التبعيات الإضافية (التطوير، الوثائق، الاختبار)
  4. project.scripts: نقاط الدخول في سطر الأوامر
  5. tool.*: التكوين الخاص بال أدوات (black، pytest، mypy، إلخ)

اختيار وحدة البناء

setuptools (الخيار القياسي)

الخيار الأكثر استخدامًا والتوافق:

[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

المزايا: توافق عالمي، ميزات واسعة، نظام بيئات كبير العيوب: تكوين أكثر تفصيلًا، أبطأ من الخيارات الحديثة

Hatchling (الخيار الحديث والفعال)

وحدة البناء الخفيفة والفعالة الحديثة:

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

المزايا: بناء سريع، تكوين بسيط، إعدادات افتراضية جيدة العيوب: عدد أقل من المكونات مقارنة بـ setuptools

Poetry (الخيار الشامل)

إدارة التبعيات والبيئات الشاملة:

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "mypackage"
version = "0.1.0"
description = "حزمة رائعة لـ Python"
authors = ["الاسم <you@example.com>"]

[tool.poetry.dependencies]
python = "^3.8"
requests = "^2.28.0"

المزايا: حل تبعيات، ملفات تقييد، سير عمل متكامل العيوب: سير عمل مختلف، سطح أداة أكبر

Flit (الخيار البسيط)

أداة بسيطة لحزم بسيطة:

[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

المزايا: بسيط جدًا، تكوين محدود العيوب: ميزات محدودة للحزم المعقدة

بناء حزمةك

تثبيت أدوات البناء

# تثبيت الأداة الحديثة للبناء
pip install build

# أو لـ Poetry
pip install poetry

# أو لـ Hatchling
pip install hatch

بناء ملفات التوزيع

باستخدام حزمة build (يعمل مع أي وحدة):

# تنظيف البناءات السابقة
rm -rf dist/ build/ *.egg-info

# بناء التوزيع المصدر والوهل
python -m build

# هذا ينشئ:
# dist/mypackage-0.1.0.tar.gz    (توزيع المصدر)
# dist/mypackage-0.1.0-py3-none-any.whl  (وهل)

باستخدام Poetry:

poetry build

باستخدام Hatch:

hatch build

فهم تنسيقات التوزيع

التوزيع المصدر (sdist) - .tar.gz

  • يحتوي على الكود المصدر والتعليمات
  • يقوم pip ببناءه أثناء التثبيت
  • يشمل الاختبارات، الوثائق، وملفات التطوير الأخرى

الوهل - .whl

  • توزيع ثنائي مُبني مسبقًا
  • تثبيت سريع (بدون خطوة بناء)
  • مخصص للمنصات أو بحتة لـ Python
  • التنسيق الموصى به للتوزيع

نشر على PyPI

الطريقة 1: رفع يدوي مع Twine (الطريقة التقليدية)

# تثبيت twine
pip install twine

# تحقق من الحزمة قبل الرفع
twine check dist/*

# رفع إلى TestPyPI أولاً (مُوصى به)
twine upload --repository testpypi dist/*

# اختبار التثبيت من TestPyPI
pip install --index-url https://test.pypi.org/simple/ mypackage

# رفع إلى PyPI الإنتاجي
twine upload dist/*

كوّن بيانات الاعتماد في ~/.pypirc:

[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = pypi-AgEIcHlwaS5vcmc...

[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-AgENdGVzdC5weXBpLm9yZw...

الطريقة 2: النشر الموثوق (مُوصى به لـ CI/CD)

يستخدم النشر الموثوق OpenID Connect (OIDC) للاuthentification من منصات CI/CD دون تخزين الرموز.

إعداد في PyPI:

  1. انتقل إلى إعدادات مشروع PyPI
  2. انتقل إلى قسم “النشر”
  3. أضف “مُنشئ معلق” جديد
  4. اضبط:
    • المالك: اسم مستخدم GitHub/المنظمة
    • ال仓库: اسم الـ Repository
    • العملية: publish.yml
    • البيئة: release (اختياري ولكن مُوصى به)

عملية GitHub Actions (.github/workflows/publish.yml):

name: Publish to PyPI

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install build dependencies
        run: |
          python -m pip install --upgrade pip
          pip install build          
      
      - name: Build package
        run: python -m build
      
      - name: Store distribution packages
        uses: actions/upload-artifact@v3
        with:
          name: python-package-distributions
          path: dist/

  publish:
    needs: build
    runs-on: ubuntu-latest
    environment: release
    permissions:
      id-token: write
    
    steps:
      - name: Download distributions
        uses: actions/download-artifact@v3
        with:
          name: python-package-distributions
          path: dist/
      
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1

المزايا:

  • لا توجد رموز API لإدارة أو أمانها
  • تأكيد تلقائي عبر OIDC
  • أمان محسن من خلال قواعد حماية البيئة
  • سجل مراجعة لجميع النشرات

أفضل الممارسات

1. إدارة الإصدارات

استخدم التصنيف الإصداري (SemVer): MAJOR.MINOR.PATCH

# تثبيت أداة رفع الإصدار
pip install bump2version

# رفع الإصدار
bump2version patch  # 0.1.0 -> 0.1.1
bump2version minor  # 0.1.1 -> 0.2.0
bump2version major  # 0.2.0 -> 1.0.0

كوّن في .bumpversion.cfg:

[bumpversion]
current_version = 0.1.0
commit = True
tag = True

[bumpversion:file:pyproject.toml]
search = version = "{current_version}"
replace = version = "{new_version}"

[bumpversion:file:src/mypackage/__init__.py]
search = __version__ = "{current_version}"
replace = __version__ = "{new_version}"

2. تضمين الملفات الأساسية

README.md: وصف واضح للمشروع، تثبيت، أمثلة الاستخدام LICENSE: اختر ترخيصًا مناسبًا (MIT، Apache 2.0، GPL، إلخ) CHANGELOG.md: وثّق التغييرات بين الإصدارات .gitignore: استبعد الملفات المُنشئة، المخبأة، البيئات الافتراضية

3. الاختبار الشامل

# تثبيت التبعيات الخاصة بالاختبار
pip install pytest pytest-cov

# قم باختبار مع التغطية
pytest --cov=mypackage tests/

# أنشئ تقرير التغطية
pytest --cov=mypackage --cov-report=html tests/

كوّن في pyproject.toml:

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
addopts = "--strict-markers --cov=mypackage"

4. أدوات جودة الكود

# التنسيق
black src/ tests/

# التنقيح
flake8 src/ tests/

# التحقق من النوع
mypy src/

# ترتيب الواردات
isort src/ tests/

دمجها في م-hooks المسبقة (.pre-commit-config.yaml):

repos:
  - repo: https://github.com/psf/black
    rev: 23.9.1
    hooks:
      - id: black
  
  - repo: https://github.com/pycqa/flake8
    rev: 6.1.0
    hooks:
      - id: flake8
  
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.5.1
    hooks:
      - id: mypy

5. الوثائق

استخدم Sphinx للوثائق:

# تثبيت Sphinx
pip install sphinx sphinx-rtd-theme

# تهيئة الوثائق
cd docs
sphinx-quickstart

# بناء الوثائق
make html

أو استخدم MkDocs للوثائق القائمة على Markdown:

pip install mkdocs mkdocs-material
mkdocs new .
mkdocs serve

6. التكامل المستمر

اختبار حزم Python عبر منصات مختلفة وبيئات مختلفة أمر حيوي لضمان الموثوقية. لمعرفة مقارنة أداء Python في سيناريوهات مختلفة، راجع مقالتنا حول أداء AWS Lambda: JavaScript مقابل Python مقابل Golang.

عملية CI/CD كاملة (.github/workflows/ci.yml):

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e ".[dev]"          
      
      - name: Run tests
        run: pytest --cov=mypackage --cov-report=xml
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
  
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install dependencies
        run: |
          pip install black flake8 mypy          
      
      - name: Black formatting check
        run: black --check src/ tests/
      
      - name: Flake8
        run: flake8 src/ tests/
      
      - name: MyPy
        run: mypy src/

المشاكل الشائعة والحلول

المشكلة 1: أخطاء الاستيراد بعد التثبيت

المشكلة: تم تثبيت الحزمة ولكن الاستيراد يفشل

الحل: تأكد من هيكل الحزمة الصحيح مع ملفات __init__.py وتكوين pyproject.toml الصحيح:

[tool.setuptools.packages.find]
where = ["src"]
include = ["mypackage*"]

المشكلة 2: تبعيات مفقودة

المشكلة: تثبيت الحزمة ولكنها تفشل أثناء التشغيل بسبب تبعيات مفقودة

الحل: أعلِن جميع التبعيات في pyproject.toml:

[project]
dependencies = [
    "requests>=2.28.0",
    "click>=8.1.0",
]

المشكلة 3: تعارض الإصدارات

المشكلة: تعمل الحزمة في التطوير ولكنها تفشل في الإنتاج

الحل: استخدم بيئات افتراضية وحدد الإصدارات الدنيا:

# إنشاء بيئة مُفصولة
python -m venv .venv
source .venv/bin/activate  # على Windows: .venv\Scripts\activate

# تثبيت في وضع تطوير قابل للتحرير
pip install -e ".[dev]"

المشكلة 4: حجم الحزمة كبير

المشكلة: تأخذ الحزمة وقتًا طويلاً للتنزيل/التركيب

الحل: استبعد الملفات غير الضرورية باستخدام MANIFEST.in:

include README.md
include LICENSE
include pyproject.toml
recursive-include src *.py
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-exclude tests *
recursive-exclude docs *

المشكلة 5: المشكلات الخاصة بالمنصة

المشكلة: تعمل الحزمة على نظام تشغيل واحد ولكن تفشل على آخر

الحل: اختبر على منصات متعددة باستخدام مصفوفة CI/CD (راجع مثال CI أعلاه)

قائمة مراجعة النشر

قبل نشر حزمتك على PyPI، تحقق من:

  • تمر جميع الاختبارات عبر إصدارات Python
  • تم تنسيق الكود وتنقيحه
  • README.md كامل مع أمثلة
  • تضمن ملف LICENSE
  • تم تحديث رقم الإصدار
  • تم تحديث CHANGELOG.md
  • تم تحديد التبعيات بشكل صحيح
  • تتم بناء الحزمة بدون أخطاء (python -m build)
  • تم اختبار الحزمة على TestPyPI
  • تم تحديث الوثائق
  • تم تأريخ مستودع Git مع الإصدار
  • تم إنشاء إصدار GitHub (للمصادقة الموثوقة)

الموضوعات المتقدمة

نقاط الدخول وأدوات سطر الأوامر

إنشاء واجهات سطر الأوامر:

[project.scripts]
mypackage = "mypackage.cli:main"

التنفيذ في src/mypackage/cli.py:

import click

@click.command()
@click.option('--name', default='World', help='اسم للاستقبال')
def main(name):
    """مثال بسيط لواجهة سطر الأوامر"""
    click.echo(f'مرحبا، {name}!')

if __name__ == '__main__':
    main()

لأمثلة حقيقية حول إنشاء حزم Python تتفاعل مع واجهات برمجة التطبيقات الخارجية، راجع دليلنا حول دمج Ollama مع Python، الذي يوضح إنشاء عميل Python مع كلا من API REST والتكامل مع المكتبة الرسمية.

أنظمة المكونات

تمكين اكتشاف المكونات:

[project.entry-points."mypackage.plugins"]
plugin_a = "mypackage_plugin_a:PluginA"

المكونات C

للأكواد الحاسوبية المهمة:

[tool.setuptools.ext-modules]
name = "mypackage._speedups"
sources = ["src/mypackage/_speedups.c"]

الحزم المسمى

للحزم الموزعة تحت مساحة تسمية مشتركة:

[tool.setuptools.packages.find]
where = ["src"]
include = ["company.*"]

[tool.setuptools.package-data]
"company.mypackage" = ["py.typed"]

أدوات وموارد مفيدة

أدوات تطوير الحزم

  • cookiecutter: قوالب لمشاريع Python
  • tox: تلقائية اختبار عبر إصدارات Python
  • nox: تلقائية اختبار مرنة (بدائل tox)
  • pre-commit: إطار عمل لـ Git لجودة الكود
  • commitizen: استاندارد لرسائل التزام وتحديث الإصدار

منصات الوثائق

  • Read the Docs: مضيف وثائق مجاني
  • GitHub Pages: مضيف MkDocs أو Sphinx
  • pdoc: مولّد وثائق API بسيط

مخازن الحزم

  • PyPI: المخزن الرئيسي لحزم Python (pypi.org)
  • TestPyPI: بيئة اختبار (test.pypi.org)
  • Anaconda.org: توزيع الحزم لـ Conda
  • GitHub Packages: مضيف حزم خاص

المراقبة والتحليلات

  • PyPI Stats: إحصاء تنزيلات الحزم
  • Libraries.io: مراقبة التبعيات وإشعارات
  • Snyk: مسح الثغرات الأمنية
  • Dependabot: تحديثات التبعيات تلقائية

الخاتمة

تطور تغليف Python الحديث أصبح أكثر سهولة للمطورين مع المعايير مثل pyproject.toml، وحدات البناء القوية، ونشر آمن عبر Trusted Publishing. من خلال هذا الدليل، يمكنك إنشاء حزم Python مهنية قابلة للصيانة تخدم مستخدميك بشكل فعّال.

الخلاصة الرئيسية:

  1. استخدم pyproject.toml لكل مشاريع جديدة
  2. اختر الوحدة المناسبة لـ بناء حسب احتياجاتك
  3. تطبيق الاختبارات التلقائية و CI/CD
  4. استخدم النشر الموثوق للنشر الآمن دون رموز
  5. اتبع التصنيف الإصداري وحافظ على سجل التغييرات
  6. قدم وثائق شاملة و أمثلة

生态系统 Python للحزم يواصل التحسن مع أدوات أفضل، معايير، ووظائف أمان. تأكد من تحديث نفسك مع مقترحات تحسين Python (PEPs) وممارسات المجتمع لاستمرار حزمك في التحديث والصيانة.

روابط مفيدة

مقالات مفيدة أخرى على هذا الموقع