إدارة الاعتماديات في مشاريع Python الحديثة باستخدام Poetry وبيئات العمل المعزولة

مقدمة

تُعدّ إدارة الحزم البرمجية من أكثر الجوانب تأثيراً في استقرار تطبيقات بايثون وقابليتها للصيانة. فالمشروع الحديث لا يعتمد عادةً على مكتبة واحدة، بل على عشرات الحزم المباشرة وغير المباشرة، ولكل منها إصدارات ومتطلبات قد تتعارض مع غيرها. هنا تبرز أهمية إدارة الاعتماديات في مشاريع Python الحديثة باستخدام Poetry وبيئات العمل المعزولة بوصفها منهجية تجمع تعريف المشروع، وحل الإصدارات، وإنشاء البيئة الافتراضية، وتثبيت الحزم في سير عمل موحّد.

اعتمد مطورو بايثون طويلاً على pip لتثبيت الحزم، وعلى venv أو virtualenv لعزل بيئات التشغيل، وعلى ملف requirements.txt لتوثيق المتطلبات. هذه الأدوات فعّالة في المشاريع البسيطة، لكنها تترك للمطور مسؤولية ربط خطوات متعددة يدوياً. أما Poetry فيقدّم طبقة تنظيمية حديثة تجعل تعريف الاعتماديات قابلاً للقراءة، وتنتج ملف قفل دقيقاً للإصدارات، وتنشئ بيئات افتراضية تلقائياً، بما يحد من مشكلة «يعمل على جهازي ولا يعمل على جهازك».

لماذا لا تكفي إدارة الاعتماديات التقليدية دائماً؟

تسمح الأوامر التقليدية مثل pip install requests بتثبيت الحزم بسرعة، لكنها لا تضمن وحدها إعادة بناء البيئة نفسها مستقبلاً. قد يكتب الفريق في ملف المتطلبات اسم حزمة دون تحديد إصدارها، مثل requests>=2.0، فيحصل كل مطور أو خادم نشر على إصدار مختلف بحسب وقت التثبيت. كذلك، قد يتغير إصدار حزمة غير مباشرة، فتظهر أخطاء غير متوقعة رغم عدم تعديل الشيفرة المصدرية للمشروع.

تزداد المشكلة تعقيداً عندما تتطلب مكتبتان إصدارين غير متوافقين من المكتبة نفسها. على سبيل المثال، قد يحتاج إطار عمل قديم إلى إصدار محدد من pydantic، بينما تتطلب مكتبة أخرى إصداراً أحدث منه. في بيئة مشتركة على مستوى النظام، يمكن أن يؤدي تثبيت مشروع جديد إلى كسر مشروع قائم. كما أن خلط حزم أدوات التطوير، مثل الاختبارات والتنسيق والتحليل الساكن، مع حزم الإنتاج يجعل بيئة النشر أثقل وأقل أماناً.

لا يعني ذلك أن pip أداة غير مناسبة؛ فهو مدير الحزم الأساسي في بايثون وما زال جزءاً مهماً من المنظومة. لكن Poetry يبني فوق المفاهيم الأساسية طبقة موحدة لإدارة دورة حياة المشروع. فهو يقرأ قيود الإصدارات، ويحل شجرة الاعتماديات كاملة، ثم يسجل النتيجة في ملف قفل يمكن تكراره على أجهزة المطورين وخوادم التكامل المستمر والإنتاج.

مكوّنات Poetry ودورها في المشروع

يعتمد Poetry أساساً على ملفين في جذر المشروع: pyproject.toml وpoetry.lock. الملف الأول هو الوصف المعلن للمشروع؛ يحتوي بياناته الأساسية، مثل الاسم والإصدار ووصف الحزمة وإصدار بايثون المدعوم والاعتماديات المطلوبة. أما الملف الثاني فهو نتيجة الحل الفعلي للاعتماديات، ويضم الإصدارات الدقيقة للحزم المباشرة وغير المباشرة، إضافة إلى معلومات التحقق اللازمة للتثبيت الموثوق.

يستند pyproject.toml إلى معيار واسع الاستخدام في بيئة بايثون، ولذلك لا يرتبط مفهومه بـPoetry وحده. إلا أن Poetry يضيف إليه طريقة عملية لتعريف الحزم ومجموعات الاعتماديات وإعدادات البناء. ويمكن مثلاً تعريف مشروع ويب يعتمد على FastAPI وUvicorn، مع فصل أدوات الاختبار عن متطلبات التشغيل:

[tool.poetry]
name = "inventory-api"
version = "0.1.0"
description = "واجهة برمجية لإدارة المخزون"
authors = ["فريق التطوير <dev@example.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
fastapi = "^0.115.0"
uvicorn = { extras = ["standard"], version = "^0.30.0" }

[tool.poetry.group.dev.dependencies]
pytest = "^8.3.0"
ruff = "^0.6.0"
mypy = "^1.11.0"

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

يشير الرمز ^3.11 في قيد بايثون إلى قبول الإصدارات المتوافقة ضمن النطاق الذي تحدده دلالات الإصدار. أما عند تثبيت الحزم، فلا يعتمد Poetry على هذه القيود وحدها في كل مرة؛ بل يفضّل الإصدارات المحفوظة في poetry.lock. وهذا هو الفارق الجوهري بين وصف ما يقبله المشروع نظرياً وبين توثيق ما ثُبّت فعلاً واختُبر.

تثبيت Poetry وإنشاء مشروع جديد بصورة سليمة

ينبغي تثبيت Poetry كأداة مستقلة عن بيئة المشروع التي سيديرها. لا يُنصح بتثبيته داخل البيئة الافتراضية الخاصة بالتطبيق، لأن Poetry ذاته يعتمد على حزم خارجية قد تتعارض مع حزم المشروع. يمكن استخدام مدير أدوات معزول مثل pipx لتثبيته، ثم إتاحة أمره في سطر الأوامر:

pipx install poetry
poetry --version

بعد التثبيت، يمكن إنشاء مشروع جديد باستخدام الأمر التالي. ينشئ Poetry بنية أولية تتضمن ملف إعدادات المشروع ومجلداً للحزمة وملفات اختبار وفق الخيارات المختارة:

poetry new inventory-api
cd inventory-api

وإذا كان المشروع موجوداً مسبقاً، فإن الأمر poetry init يساعد على إنشاء ملف pyproject.toml تفاعلياً. بعد ذلك تُضاف الحزم بأوامر واضحة بدلاً من تعديل الملفات يدوياً في كل مرة:

poetry add fastapi
poetry add "uvicorn[standard]"
poetry add --group dev pytest ruff mypy

عند تنفيذ poetry add، يحدّث Poetry ملف تعريف المشروع، ويحل الاعتماديات، ويكتب أو يحدّث ملف القفل، ثم يثبت الحزم في البيئة التابعة للمشروع. أما إذا كان الملفان موجودين في مستودع جرى استنساخه، فإن الأمر poetry install يثبت الإصدارات المقفلة دون إعادة اختيار إصدارات جديدة، وهو السلوك المطلوب عادةً عند انضمام مطور جديد إلى الفريق.

حل التعارضات وقفل الإصدارات بموثوقية

عملية حل الاعتماديات ليست مجرد تنزيل أحدث إصدار من كل مكتبة. يفحص Poetry القيود المعلنة للحزم، ثم يستكشف متطلبات الحزم التابعة لها، ويبحث عن مجموعة إصدارات متوافقة. فإذا طلب المشروع fastapi بإصدار حديث يتطلب نطاقاً معيناً من pydantic، بينما طلبت حزمة أخرى نطاقاً لا يتقاطع معه، فسيظهر خطأ واضح بدلاً من إنتاج بيئة غير مستقرة بصمت.

يجب حفظ poetry.lock في نظام التحكم بالإصدارات مثل Git. فالملف ليس ناتجاً مؤقتاً ينبغي تجاهله، بل هو سجل قابل لإعادة الإنتاج للبيئة التي اجتازت الاختبارات. عندما يسحب زميل تغييرات الفرع، سيحصل على النسخ نفسها تقريباً من جميع الحزم، بما فيها الاعتماديات غير المباشرة التي لم يضفها بنفسه.

لإضافة اعتماد جديد دون تثبيت الحزم فوراً يمكن استخدام poetry add --lock في بعض سير العمل، بينما يفيد أمر poetry lock في إعادة توليد ملف القفل بعد تعديل القيود. ويجب التعامل بحذر مع poetry update، لأنه قد يحدّث عدداً كبيراً من الحزم ضمن النطاقات المسموح بها. الأفضل غالباً تحديث حزمة محددة واختبارها:

poetry update fastapi
poetry show --outdated
poetry show --tree

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

بيئات العمل المعزولة وتشغيل الأدوات داخلها

البيئة الافتراضية هي مساحة مستقلة تحتوي مفسر بايثون والحزم الخاصة بالمشروع، من دون تغيير حزم النظام أو التأثير في مشاريع أخرى. ينشئ Poetry بيئة افتراضية تلقائياً عند الحاجة، ويختار مفسر بايثون متوافقاً مع القيد المحدد في pyproject.toml. ويمكن معرفة معلومات البيئة الحالية بالأمر:

poetry env info
poetry env list

لتشغيل أي أمر ضمن البيئة المعزولة، لا يحتاج المطور غالباً إلى تفعيلها يدوياً؛ إذ يكفي استعمال poetry run. وهذا الأسلوب مناسب للتوثيق والبرامج النصية وخطوط التكامل المستمر:

poetry run pytest
poetry run ruff check .
poetry run mypy src
poetry run uvicorn inventory_api.main:app --reload

ويمكن فتح جلسة طرفية داخل البيئة عبر poetry shell في الإصدارات أو الإعدادات التي توفر هذه الإضافة، لكن تشغيل الأوامر مباشرة باستخدام poetry run أوضح في ملفات الأتمتة. وإذا أراد الفريق وضع البيئة داخل مجلد المشروع لتسهيل اكتشافها محلياً، يمكن تفعيل الإعداد التالي:

poetry config virtualenvs.in-project true

عندها تُنشأ البيئة غالباً في المجلد .venv. يجب إضافة هذا المجلد إلى .gitignore، لأن ما يُشارك هو ملفا الإعداد والقفل، لا الملفات الثنائية الخاصة بكل جهاز. وإذا حدث تلف في البيئة أو تبدل مفسر بايثون، يمكن حذف البيئة وإعادة إنشائها عبر poetry env remove ثم poetry install.

تنظيم اعتماديات التطوير والإنتاج والتكامل المستمر

تحتاج المشاريع الاحترافية إلى الفصل بين ما يلزم لتشغيل التطبيق وما يلزم لتطويره فقط. فمكتبات مثل pytest وruff وأدوات التوثيق لا ينبغي أن تكون ضرورية في صورة حاوية الإنتاج. يتيح Poetry تعريف مجموعات اعتماديات منفصلة، ثم اختيار المجموعات المطلوبة أثناء التثبيت.

في جهاز المطور، يكفي عادةً تنفيذ poetry install لتثبيت المجموعة الرئيسية ومجموعة التطوير. أما في بيئة الإنتاج، فيمكن استبعاد مجموعة التطوير:

poetry install --only main

وفي خادم التكامل المستمر، من المهم تثبيت البيئة من ملف القفل، ثم تشغيل الاختبارات والتحليلات ضمن Poetry نفسه. مثال مبسط لأوامر خط أنابيب يمكن وضعها في منصة بناء:

poetry install --with dev
poetry run ruff check .
poetry run mypy src
poetry run pytest --cov=inventory_api

ينبغي أيضاً تحديد إصدارات بايثون المدعومة صراحةً واختبارها في أكثر من نسخة عند الحاجة. فإذا كان التطبيق يدعم بايثون 3.11 و3.12، فيجب أن يعكس ملف الإعداد ذلك، وأن تنفذ منصة التكامل المستمر الاختبارات على النسختين. كما يُستحسن مراجعة التحديثات دورياً، وليس فقط عند ظهور ثغرة؛ فالتراكم الطويل للتحديثات يجعل حل التعارضات لاحقاً أكثر كلفة.

خاتمة

يوفّر Poetry نموذجاً متكاملاً لإدارة مشاريع بايثون الحديثة: تعريف واضح للاعتماديات في pyproject.toml، ونسخ دقيقة قابلة لإعادة الإنتاج في poetry.lock، وبيئات عمل معزولة تمنع تداخل المشاريع، وأوامر موحدة لتشغيل الاختبارات والأدوات والتطبيقات. لا يلغي Poetry دور pip أو مفاهيم البيئات الافتراضية، بل ينظم استخدامها ضمن تجربة أكثر اتساقاً.

لتحقيق أفضل نتيجة، ينبغي تثبيت Poetry خارج بيئات المشاريع، وإيداع ملف القفل في Git، وفصل اعتماديات التطوير عن الإنتاج، وتحديث الحزم بوعي مع تشغيل الاختبارات بعد كل تغيير. بهذه الممارسات تتحول الاعتماديات من مصدر شائع للمفاجآت والأعطال إلى جزء مضبوط وموثوق من هندسة البرمجيات.

تعليقات