پایتونیک - ساخت پکیج توی پایتون 1

مقدمه

سلام به همه‌ی دوستان عزیز! تصور کنید یه برنامه پایتون خیلی خیلی باحال نوشتید و کلی اشتیاق دارید که اون رو به همه بدید تا اونا‌ هم از این برنامه شما استفاده کنند. اما خب دقیقاً چیکار باید کرد؟‌ باید فایل پایتون برنامه رو بفرستید برای دوستتون؟ یا شاید راه بهتری هست؟

حتما راه بهتری هست و این راه، چیزی نیست جز ساختن پکیج برای اون برنامه‌ خیلی باحال. اما مساله اینه که ساخت پکیج توی پایتون یکم گیج‌کننده‌اس و هدف من از نوشتن این پست‌ روشن کردن خیلی از بخش‌های تاریک توی این حوزه‌اس.

اما قبل از اینکه شروع کنیم بریم سراغ کد زدن‌ها باید مطمئن بشیم تعریف هممون از مفاهیم زیر یکیه.

پکیج در توزیع‌های مختلف لینوکس(یا گنو/لینوکس؟)

پکیج چیه،‌ بهرام؟ اساساً میشه پکیج رو یک فایل آرشیو شده تعریف کرد (منظورِ من از آرشیو شده اینه که تمام فایل‌ها در قالب یک فایل نوشته شدن) که پکیج‌منیجر میدونه دقیقاً هر فایل باید بره کجا کپی بشه تا همه‌چی درست اجرا بشه.

وقتی شما توی سیستمتون میزنید:

apt-get install vim
yum install vim # or any other package manager

کاری که اون پشت داره صورت میگیره اینِ که پکیج‌منیجر شما میره فایل آرشیو شده اون برنامه رو می‌گیره و نصب‌اش میکنه(فایلهای مختلف اجرایی و کانفیگ در مسیر درست توی سیستم شما کپی می‌کنه).

ماژول توی پایتون

ماژول چیه توی پایتون؟ هر برنامه‌ای که به زبان پایتون نوشته باشه رو بهش ‌میگیم ماژول. یعنی هر فایلی که پسوند py. داشته باشه. اما خب به چه دردی می‌خوره؟
مثلا تصویر پایین رو ببینید. من توی دایرکتوریی هستم به اسم funproject که توی اون دایرکتوری یک فایل وجود داره به اسم core.py. این فایل یک ماژول هست طبق تعریف فوق.

محتویاتش رو با هم ببنیم چون جلوتر می‌خوام ازش استفاده کنم:

همونطور که می‌بینید اینجا دو تا فانکشن تعریف شده که اولی یک متن احوالپرسی غیررسمی به زبان انگلیسی برمی‌گردونه دومی رسمی. ماژول این امکان رو میده که بتونیم توی برنامه‌های دیگه‌ بتونیم کدی که نوشتیم رو import کنیم. چیزی شبیه زیر امکان پذیره:

توی کد بالا، من سعی کردم همه حالت‌هایی که میشه از کد‌های یک ماژول استفاده کرد،‌ استفاده کنم. توی اولین حالت گفتیم از ماژول core، تابع format_greeting رو وارد کن. توی حالت دوم، می‌خواستم بگم که میشه به ماژول ها به صورت relative هم دسترسی داشت. یعنی نسبت به مسیری که کد داره اجرا میشه بقیه رو آدرس دهی کنیم. مثلا من گفتم توی همین دایرکتوری که هستی از ماژول core. بعضی مواقع حتی ممکنه توی کدها ببینید از یک دایرکتوری بالاتر هم از کد یک ماژول استفاده بشه، مثلا اینجوری:

from ..core import *

در حقیقت ماژول‌ها باعث میشن بخش‌های مختلف برناممون رو جدا از هم تعریف ‌کنیم و اونارو بهم بچسبونیم(ماژولار).

پکیج توی پایتون

پکیج‌ها توی پایتون با تعریف پکیجی که تا الان گفتیم(توی سیستم های گنو/لینوکسی) متفاوته! تصور کنید یه برنامه خیلی بزرگ نوشتیم که خیلی بخش‌های مختلفی داره. چون توی بخش‌ بالا یاد گرفتیم ماژولار کد بزنیم میاییم چیکار میکنیم کد‌های که مربتط به هم‌ هستن روی توی یک دایرکتوری با یک اسم قابل‌فهم (بامسمی) می‌ذاریم. این میشه تعریف پکیج توی پایتون! فقط برای اینکه پایتون بفهمه اون دایرکتوری یک دایرکتوری معمولی نیست بلکه یک پکیج‌ِه باید یک فایل با یک اسم خاص بسازیم. اون اسم خاص هست:

__init__.py

این فایل اسمش اینجوری خونده میشه: داندر اینیت (dunder init)

دایرکتوری funproject رو یادتونه، این شکلیه:

الان میتونیم یه برنامه بنویسیم که مجاور دایرکتوری funproject باشه و اینجوری از funproject استفاده کنیم:

خب این‌فایلی که ساختیم (init__.py__) همیشه قرار نیست همینجوری خالی بذاریمش. می‌تونیم یه فایل‌های که می‌خوایم مسیر‌ دسترسی بهشون کوتاه تر باشه اونجا importشون کنیم. مثلا ممکنه برنامه ما اینجوری اجرا بشه:

برای اینکار لازم نیست بریم ماژول‌ها رو تغییر بدیم بلکه تنها کاری که می‌کنیم اینه توی فایل init__.py__ اون توابع و کلاس‌هایی که می‌خوایم به صورت مستقیم قابل دسترسی باشند رو import می‌کنیم، من برای funproject اینجوری نوشتم:

در حقیقت اینجا گفتیم که توی همین دایرکتوریج جاری از ماژول core اون دو تا فانکشن رو وارد کن. بهمین راحتی.

جمع‌بندی پکیج

پس میشه گفت پکیج توی پایتون یه جورایی به ما اجازه میده که کدمون رو خیلی تمیز و مرتب کنیم. برای ساخت یک پکیج گفتیم کافیه یک دایرکتوری با اسم دلخواه بسازیم و یک فایل init__.py__ داخل اون دایرکتوری ایجاد کنیم.

اما خب نوبتی‌ هم باشه باید بریم بفهمیم پس چه‌جوری میتونیم کدمون رو با دیگران توی پایتون به راحتی اشتراک بذاریم!

اهمم Distribution


اما خب اون تعریفی که اولِ پُست در رابطه با پکیج توی سیستم‌های گنو/لینوکسی گفتم رو یادتونه؟ این عمل که فایل‌ها رو آرشیو می‌کنیم به صورتی که یک پکیج‌منجر میفهمه هر فایل باید بره کجا کپی شه تا تموم برنامه به درستی کار کنه. توی پایتون به این معنا میشه که کد‌های شما به لایبرری‌های پایتون اضافه میشه و اگه اسکریپتی هم هست که قابلیت اجرایی داره بره جایی نصب شده که به PATH سیستم شما اضافه بشه. این عملیات توی پایتون Distributeکردن برنامه‌تون گفته میشه که البته واقعا خیلی از جاها با همون اسم پکیج‌ کردن پایتون میشناسَنش.

اولین قدم

اما خب برای اینکه ادامه‌ی کار به مشکل نخوریم من یک پروژه کوچیک نوشتم که نیاز‌های آینده این اموزش چند قسمتی رو برآورده کنه. این پروژه همون funproject هست و روی گیت‌هاب گذاشتمش که همه بهش براحتی دسترسی داشته باشیم. این پروژه از طریق این لینک قابل دسترسیه.

ساختار پروژه funproject

خب اول به تصویر پایین یه نگاه بندازین

این پروژه دوتا دایرکتوری داره، اولین دایرکتوری طبق تعاریف بالا یک پکیج حساب میشه. چرا؟ چون داخل اون یک init__.py__ ایجاد کردیم. در حقیقت فرض می‌کنیم این کل برنامه باحالیه که شما می‌خواستید بدین به دوستاتون! این برنامه در حقیقت دو تا فانکشن داره که گفتیم یک احوالپرسی رسمی و غیررسمی رو به صورت تصادفی بر میگردونن؛

اما دایرکتوری دوم چیه؟ دایرکتوری دوم یک خط‌فرمان برای پروژه‌مون حساب میشه. پیشنهاد من اینه که قبل از اینکه بقیه متن رو بخونید برید ببینید داخل این فایل چی نوشته شده:‌ فایل

همون‌طور که دیدید، توی این فایل فرض شده پکیج funproject توی سیستم نصب شده و ما فقط قراره از اون استفاده کنیم. پس یعنی هیچ وابستگی بین پروژه خودمون (funproject) و این اسکریپت نیست. یعنی ما این دایرکتوری scripts رو واسه این اضافه کردیم که موقعی رفتیم جلوتر و ساخت پکیج‌ِمون کامل شده کاربر بتونه توی کامندلاین بنویسه funproject و برنامه اجرا بشه!

نکته‌ی شاید کم‌ربط
اگه یک فایل‌پایتون دارید که می‌خواید مفسر رو توی اون مشخص کنید(Shebang line) همیشه مشابه دستور پایین رو بنویسید خیلی مهمه که از طریق برنامه env برید python رو صدا بزنید، بعدا ممکنه خیلی اتفاقای بدی رخ بده اگه خودتون آدرس کامل پایتون رو بهش بدید.
#!/usr/bin/env python3

پس شما اولین کاری که باید انجام بدید تا بتونید این مجموعه آموزشی رو دنبال کنید،‌ اینه که اول اون کد رو توی سیستم خودتون Clone کنید تا بعدش بریم سراغ بقیه مراحل بعدی‌ کار:

git clone https://github.com/GreatBahram/Python_Packaging_Tutorial

معرفی PyPI

پروژه PyPI(بخونید پای پی‌ آی نه پای پای) هدفش فراهم اوردن مخزنی برای برنامه‌های پایتون هست که شما در حقیقت وقتی سعی می‌کنید با پکیج منیجر پایتون Pip چیزی رو نصب کنید، پیپ میره از اونجا برنامه رو می‌گیره و میاد روی سیستم شما نصب می‌کنه.

دوستان PyPA

یک گروه‌ خیلی باحالی هم هستند که وظیفشون نگه‌داری و تولید ابزار‌های مختلفی برای ساخت پکیج و آپلود اون، ساخت برای پلتفرم‌های مختلف و ... هست که اسم این گروه PyPA(Python Packaging Authority) هست.

این PyPUG دیگه چیه!

پروژه PyPUG (Python Packaging User Guide) در حقیقت وظیفه‌شون ساخت یک سری مستندات هست که توسعه‌دهنده‌ها بتونن با کمک این مستندات به راحتی برای پروژه‌شون پکیج بسازن و آپلود کنن روی PyPI و ... .

جمع‌بندی

خُب، به نظر من که برای امروز کافیه. تا اینجای کار چیز‌های زیادی رو معرفی کردیم. یاد گرفتیم ماژول، پکیج چیه توی پایتون و با دوستای خوبمون PyPA و پروژه‌های باحالی مثل PyPI و PyPUG آشنا شدیم.

توصیه من به شما جوانان عزیز این هست که حتما یک نگاه به پروژه‌ funproject بندازید،‌ چون جلوتر که بریم کل آموزش‌ها وابسته به این پروژه میشه.