۱۰ گام تکمیلی ایجاد پروژه متن باز پایتون — راهنمای کاربردی
در بخش قبلی این راهنما به بررسی روش ساخت پروژههای متنباز پایتون پرداختیم. در این بخش نیز 10 گام تکمیلی ایجاد پروژه پایتون و مواردی مانند روش تست پروژه و یکپارچهسازی آن برای تسریع توسعه و بهبود کیفیت و انسجام کد را مورد بررسی قرار میدهیم. در لینک زیر میتوانید بخش قبلی را مطالعه کنید:
ما در این راهنما از سیستم macOS و پایتون نسخه 3.7 استفاده کردهایم. در زمان نگارش این مقاله در ابتدای سال 1398 همه موارد صحیح و در حال کار بودند؛ اما با توجه به تغییرات سریع دنیای نرمافزار در صورتی که با مشکلی مواجه شدید، ابتدا سازگاری موارد مختلف با هم را مورد بررسی قرار دهید.
گام اول: نصب Black
پکیجی که در بخش قبلی این راهنما ساختیم از قراردادهای سبک متداول کدنویسی پیروی میکند. Black (+) یک بسته پایتون است که به صورت خودکار کد شما را طوری قالببندی میکند که از سبک کدنویسی PEP 8 (+) پیروی کند. Black نسبتاً جدید است و با این حال بیش از یک میلیون بار دانلود شده است. استفاده از آن به سرعت به یک رویه مناسب در کدنویسی پایتون بدل شده است. برای مطالعه بیشتر در مورد آن میتوانید به این لینک (+) مراجعه کنید.
ما از Atom به عنوان ویرایشگر کد استفاده میکنیم و بسته Python-Black را به این ویرایشگر اضافه کردهایم. بدین ترتیب Atom در زمان ذخیره فایل، کد را طوری قالببندی مجدد میکند که از سبک کدنویسی PEP 8 پیروی کند.
در ادامه Black را به عنوان یک محیط توسعه برای همکاران خود نیز اضافه میکنیم. در نهایت هر کسی که روی پروژه کار میکند از سبک کدنویسی یکسانی استفاده خواهد کرد و در غیر این صورت درخواست pull وی پذیرفته نخواهد شد.
عبارت black==18.9b0 را به خط خالی بعد از requirements_dev.txt اضافه کرده و دستور زیر را اجرا کنید:
pip install -r requirements_dev.txt
Black بیشینه طول خط را برابر با 88 کاراکتر قرار میدهد. برخی راهنماها مانند راهنمای سبک کدنویسی Sphinx الزام بیشینه 79 کاراکتر را دارند. در بسته Black Atom شما میتوانید بیشینه طول خط را تعیین کنید.
اینک که طوری تنظیم کردیم که زمان کدنویسیمان صرفهجویی شود میتوانیم در زمان ارسال اپلیکیشن خود به PyPI نیز صرفهجویی کنیم.
گام دوم: ایجاد pypirc.
زمانی که از Twine (+) برای ارسال build-ها به TestPyPI و PyPI استفاده میکنید، باید اطلاعات لاگین خود را به صورت دستی وارد کنید. اگر با Twine آشنا نیستید میتوانید به بخش قبلی این راهنما مراجعه کنید. در ادامه قصد داریم این فرایند را خودکارسازی کنیم.
Twine به دنبال فایلی با نام pypirc. در دایرکتوری home شما میگردد. بدین ترتیب URL ،login و password را هنگام آپلود کرد فایلها به دست میآورد. شما میتوانید فایل pypirc. را با دستور زیر در دایرکتوری home خود ایجاد کنید:
touch ~/.pypirc
محتوای زیر را به این فایل اضافه کنید:
1[distutils]
2index-servers =
3 pypi
4 testpypi
5
6[testpypi]
7repository: https://test.pypi.org/legacy
8username = your_username
9password = your_pypitest_password
10
11[pypi]
12username = your_username
13password = your_pypi_password
نام کاربری و رمز عبور خود را جایگزین کنید. در این مرحله باید مطمئن شوید که فایل را در دایرکتوری home خود ذخیره کردهاید و نه در دایرکتوری کاریتان. اگر میخواهید اطمینان حاصل کنید که کاربران دیگر روی سیستم شما نمیتوانند به این فایل دسترسی داشته باشند، میتوانید مجوزهای آن را از خط فرمان تغییر دهید:
chmod 600 ~/.pypirc
اینک میتوانید بسته خود را با دستور زیر به TestPyPI آپلود کنید:
twine upload -r testpypi dist/*
با استفاده از دستور زیر نیز میتوانید بستهتان را به PyPI آپلود کنید:
twine upload dist/*
دیگر لازم نیست نام کاربری و رمز عبور را وارد کنید. اینک نوبت آن رسیده است که مطمئن شویم پکیجهایی که ساختهایم کار میکنند.
گام سوم: نصب و پیکربندی pytest
Pytest (+) محبوبترین کتابخانه سهلالاستفاده برای تست کردن کد پایتون محسوب میشود. در این مثال، تستهای سادهای را به پروژه خود اضافه خواهیم کرد. در این لینک (+) یک راهنمای مقدماتی خوب برای آشنایی بیشتر با این پکیج ارائه شده است.
Pytest را به فایل requirements_dev.txt خود اضافه کنید:
pytest==4.3.0
دستور زیر را اجرا کنید:
pip install requirements_dev.txt
سپس دستور زیر را اجرا کنید تا pytest بتواند بسته شما را پیدا کند:
pip install -e.
اگر محیط مجازی خود را غیر فعال کردهاید، باید هر دو دستور فوق را مجدداً اجرا کنید تا بتوانید تستها را اجرا کنید.
گام چهارم: ایجاد تستها
یک پوشه test در سطح بالای پروژهتان اضافه کنید. یک فایل درون آن به نام test_your_package_name.py اضافه کنید. فایل ما test_notebookc.py نام دارد. ابتدای نام وقتی با _test آغاز شود به طور خودکار از سوی pytest قابل شناسایی خواهد بود.
در فایل test_notebookc.py تست زیر را اضافه کنید تا بررسی کند آیا نام صحیحی به عنوان بخشی از خروجی تابع نمایش مییابد یا نه. آن را طوری تغییر دهید که نامهای فایل و تابع خود شما را داشته باشد.
1"""Tests for `notebookc` package."""
2import pytest
3from notebookc import notebookc
4
5
6def test_convert(capsys):
7 """Correct my_name argument prints"""
8 notebookc.convert("Jill")
9 captured = capsys.readouterr()
10 assert "Jall" in captured.out
در کد فوق ابتدا ماژول خودمان را ایمپورت کردهایم. سپس یک تابع با نام test_my_function_name ایجاد کردهایم. این قرار داد نامگذاری برای افراد دیگری و پکیج Code Coverage که در ادامه اضافه خواهیم کرد، مفید است.
سپس تابع خود را convert نامگذاری میکنیم و آرگومان آن نیز jill خواهد بود. در ادامه خروجی را دریافت میکنیم. باید یادآوری کنیم که تابع convert کاملاً ابتدایی است و تنها یک پارامتر به نام my_name گرفته و یک خط خروجی میدهد:
print(f”I’ll convert a notebook for you some day, {my_name}.”)
pytest ابتدا بررسی میکند که آیا رشته «Jall» خروجی است یا نه. چنین چیزی نباید باشد چون ما مقدار «Jill» را ارسال کردهایم. برای مشاهده شیوه دریافت خروجی در pytest به این صفحه (+) از مستندات آن مراجعه کنید.
تست خود را با وارد کردن عبارت pytest در خط فرمان اجرا کنید. باید ببینید که تست شما با نمایش متن قرمز شکست میخورد.
این رویه خوبی برای اطمینان یافتن از این است که تستها در مواردی که باید شکست بخورند، واقعاً شکست میخورند. دقت کنید که نباید تستها را صرفاً برای شرایط مساعد و سبز شدن بنویسید. در غیر این صورت ممکن است تستها آن چه را که باید تست بکنند تست نکنند.
پس از این که یک تست شکست خورده داشتیم میتوانیم خروجی مورد انتشار خود را از Jall به Jill تغییر دهیم و تست ما این بار باید موفق بوده و متن سبز رنگ نمایش دهد.
بدین ترتیب اکنون تستی داریم که تضمین میکند وقتی فردی مقدار رشتهای به تابع ارسال کند آن را نمایش میدهد.
در ادامه تستی را اضافه میکنیم که بررسی میکند تنها یک رشته به تابع ما ارسال شده باشد. اگر هر چیزی به جز رشته ارسال شود، در این صورت خطای TypeError ایجاد میشود. اگر میخواهید در مورد استثناها و خطاها در پایتون بیشتر بدانید پیشنهاد میکنیم به این راهنما (+) مراجعه بکنید. هنگامی که تست را قبل از نوشتن کدی که قرار است تست را پاس کند مینویسیم، در واقع اقدام به «توسعه مبتنی بر تست» (test-driven development) یا به اختصار TDD کردهایم. TDD یک روش اثبات شده برای نوشتن کدی با خطاهای کمتر است.
در ادامه مسئله متفاوتی را بررسی میکنیم. به عنوان یک تمرین تست خود را اضافه کنید و کدی بنویسید که تضمین کند تنها یک رشته میتواند به عنوان آرگومان به ()convert ارسال شود.
نکته: integers ،lists و dicts میتوانند به نوع String تبدیل شوند.
پس از این که همه تستها را پاس کردیم، آماده هستیم که پکیج خود را با یک سرویس CI ادغام کنیم.
گام پنجم: راهاندازی Travis CI و پیکربندی آن
Travis CI یک سرویس توزیع یافته پیوسته یکپارچه است که برای ساختن و تست پروژههای نرمافزاری مورد استفاده قرار میگیرد. این سرویس اخیراً از سوی Idera خریداری شده است. گزینههای CI دیگری نیز وجود دارند؛ اما Travis CI محبوب، متنباز و رایگان است و مستندات خوبی دارد.
Travis CI اطمینان یافتن از این نکته را تسهیل کرده است که تنها کدی وارد پروژه شما میشود که تستها و استانداردهای شما را پاس میکند. با مراجعه به این صفحه (+) میتوانید یک حساب کاربری در این سرویس ایجاد کنید. روی لینک Review and add your authorized organizations در صفحه پروفایل خود کلیک کنید. در ادامه از شما خواسته میشود که رمز عبور حساب گیتهاب را وارد کنید. در ادامه با کلیک روی Grant دسترسی به سازمان خود را ارائه کنید.
ما مجبور شدیم حساب خود را برای notebooktoall همگامسازی کنیم تا به عنوان یک سازمان نمایش یابد و ریپازیتوری notebook را نشان دهد. این کار بسته به دادههایی که باید انتقال یابند، غالباً به یک یا چند دقیقه زمان نیاز دارد. در ادامه ریپوی خود را در حالت فعال قرار دهید.
در ادامه روی settings کلیک کنید. میتوانید انتخاب کنید که Travis بر مبنای درخواستهای pull ارسالی ساخته شود و یا از شاخههای ارسال شده استفاده کند.
اینک باید یک فایل را به صورت محلی طوری پیکربندی کنیم که Travis بتواند برای هر درخواست pull ساخته شود.
گام ششم: ایجاد فایل travis.yml.
در سطح فوقانی پوشه پروژه یک فایل به نام travis.yml. با محتوای زیر ایجاد کنید:
1dist: xenial
2language: python
3python: 3.7.2
4install:
5 - pip install -r requirements_dev.txt
6 - pip install -e .
7script:
8 - pytest
dist: xenial برای تعیین این که Travis باید از Ubuntu Xenial 16.04 برای محیط مجازی خود استفاده کند مورد نیاز است. Xenial باید برای تست کردن کد پایتون 3.7 قید شود.
نسخههای مختلف پایتون میتوانند برای تست کردن مورد استفاده قرار گیرند. در این خصوص در سریهای بعدی این مقالات بیشتر توضیح خواهیم داد.
بخش install تضمین میکند که بستههای ما برای توسعه نصب شدهاند. دستور pip install -e. پکیج شما را به صورت یک wheel در محیط مجازی Travis نصب میکند. در ادامه Travis زمانی که pytest را اجرا کند پکیج شما را خواهد یافت.
گام هفتم: تست Travis CI
زمانی که تغییرات خود را کامیت کرده و به گیتهاب پوش و یک PR ایجاد میکنید، Travis CI باید شروع به اجرای خودکار در طی چند ثانیه بکند.
کاری که تراویس انجام میدهد به صورت زیر است:
Travis در صورت ناموفق بودن PR به شما اطلاع میدهد. دقت کنید که اگر درخواست pull ناموفق باشد، میتوانید همان شاخه را push کنید و Travis به صورت خودکار اجرا میشود.
به صفحه ریپوی خود روی Travis بروید و آن را بررسی کنید. اطلاعات زیادی روی Travis در مورد build-های شما وجود دارد. احتمالاً بازدید از این وبسایت در آینده به یکی از منابع خوب شما برای درک علت ناموفق بودن build-هایتان تبدیل خواهد شد. در صورتی که همه چیز سبز باشد، یعنی کار خود را به خوبی انجام دادهاید.
اگر هیچ پیام سبز یا قرمزی را نمیبینید، روی منوی More options کلیک کرده و select Requests را از منوی بازشدنی انتخاب کنید. اگر پیام قرمزی میبینید، پیامهای خطا را بگردید. اگر خطایی به صورت Build config file is required میبینید، در این صورت Travis فایل travis.yml. شما را روی گیتهاب نیافته است. در این حالت مطمئن شوید که این فایل روی ریپوی گیتهاب قرار دارد.
Travis در مواردی که یک Build معیوب اصلاح شود، ایمیلهایی به شما ارسال میکند.
به خاطر داشته باشید که میتوانید کامیت های خود را به یک PR باز ارسال کنید و Travis آنها را به صورت خودکار مجدداً اجرا میکند. در ادامه بررسی میکنیم که چه مقدار از کد ما پوشش تست دارد.
گام هشتم: افزودن پوشش کد
گزارش پوشش کد یا Code Coverage نشان میدهد که چه درصدی از کد شما دستکم مقداری پوشش تست دارد. برای تهیه این گزارش از پکیج pytest-cov استفاده میکنیم. خط زیر را به فایل requirements_dev.txt اضافه میکنیم:
pytest-cov==2.6.1
با دستور زیر آن را اجرا میکنیم:
pytest --cov=my_project_name
خروجی دستور pytest --cov=notebook به صورت زیر است:
همان طور که میبینید همه کد ما دارای پوشش است. البته زمانی که فقط چند خط کد داریم این دستاورد مهمی محسوب نمیشود!
گام نهم: افزودن Coveralls
Coveralls سابقهای از پوشش کد را در معرض دید عموم قرار میدهد.
به آدرس https://coveralls.io بروید و با استفاده از اطلاعات حساب گیتهاب خود یک حساب در این وبسایت باز کنید. نام سازمان خود را اضافه کنید و زمانی که ریپوی شما نمایش یافت به آن مراجعه کنید.
در فایل requirements_dev.txt عبارت coveralls==1.6.0 را اضافه کنید. اینک فایل requirements_dev.txt باید به صورت زیر باشد:
pip==19.0.3 wheel==0.33.0 twine==1.13.0 pytest==4.3.0 pytest-cov==2.6.1 coveralls==1.6.0
فایل travis.yml. را با جایگذاری نام پکیج به صورت زیر تغییر دهید:
1dist: xenial
2language: python
3python: 3.7.2
4install:
5 — pip install -r requirements_dev.txt
6 — pip install -e .
7script:
8 — pytest --cov=my_package_name
9after_success:
10 — coveralls
اینک هنگامی که Travis پروژه شما را build کند، اقدام به نصب پکیجهای ضروری میکند، تستها را اجرا کرده و در ادامه گزارش پوشش کد را تولید میکند. در ادامه گزارش پوشش را به coveralls ارسال میکند.
بنابراین کافی است کدتان را کامیت کرده و به گیتهاب push کنید تا شاهد اجرای همه این موارد باشید. البته ممکن است تولید گزارش شما به چند دقیقه زمان نیاز داشته باشد، بنابراین باید صبور باشید.
اینک coveralls در بررسی PR شما نمایش مییابد. در صفحه وب coveralls ما باید پوشش 100 درصدی را ببینیم.
در ادامه این مقاله با ما همراه باشید تا با ابزارهای بیشتری آشنا شوید.
گام دهم: افزودن PyUP
PyUP.io به شما امکان میدهد که بدانید وابستگیهای پکیج چه زمانی قدیمی شدهاند و یا آسیبپذیریهای امنیتی دارند. این ابزار به طور خودکار درخواست pull ارائه کرده و پکیج را روی گیتهاب بهروزرسانی میکند.
به وبسایت https://pyup.io بروید و از طریق گیتهاب ثبت نام کنید و به سازمان خود اتصال پیدا کنید. زمانی که ریپوی خودتان را اضافه کردید، میتوانید زمانبندی بهروزرسانی را برای هر هفته تعیین کنید. در این حالت در صورتی که وابستگیهای پکیج شما زیاد نباشد، درخواستهای pull زیادی نخواهید داشت.
در ادامه مثالی از یک ریپازیتوری روی PyUP مشاهده میکنید که برخی پکیجهای قدیمی را نمایش میدهد.
اینک میدانیم که چه زمانی باید پکیج را بهروزرسانی کنیم و البته دانستن نیز نیمی از مسیر است. Request pull خودکار نیز نیم دیگر آن است.
جمعبندی
در این مقاله در مورد شیوه افزودن و پیکربندی Black ،ytest ،Travis CI ،Coveralls و PyUp مواردی را یاد گرفتیم. بدین ترتیب امکان نوشتن کدهای امنتر و با سبک منسجمتر فراهم شده است.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی پایتون
- آموزش برنامه نویسی پایتون – مقدماتی
- مجموعه آموزشهای برنامهنویسی
- زبان برنامه نویسی پایتون (Python) — از صفر تا صد
- پنج دلیل برای کاربردی بودن زبان پایتون
==