'\" t .\" Man page generated from reStructuredText .\" by the Docutils 0.22.4 manpage writer. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "PECAN" "1" "Mar 20, 2026" "1.8.0" "Pecan" .SH "نام (NAME)" pecan \- مستندات Pecan .sp به Pecan خوش آمدید؛ یک چارچوب وب چابک پایتون که از CherryPy، TurboGears و Pylons الهام گرفته شده است. Pecan در ابتدا توسط توسعه‌دهندگان ShootQ \% در زمان فعالیت در Pictage \%\& ایجاد شد. .sp Pecan برای پر کردن خلأیی در دنیای چارچوب‌های وب Python ساخته شد – یک چارچوب بسیار سبک‌وزن که مسیریابی به سبک object\-dispatch را ارائه می‌دهد. Pecan قصد ندارد یک چارچوب \(dqfull stack\(dq باشد و از این رو به صورت پیش‌فرض شامل مواردی چون نشست‌ها (sessions) یا پایگاه‌های داده نمی‌شود (هرچند آموزش‌هایی برای ادغام این موارد تنها با چند خط کد توسط خودتان فراهم شده است). در عوض، تمرکز Pecan بر خودِ HTTP است. .sp اگرچه این چارچوب سبک است، اما Pecan مجموعه‌ای گسترده از قابلیت‌ها را برای ساخت برنامه‌های کاربردی مبتنی بر HTTP ارائه می‌دهد، از جمله: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 قابلیت Object\-dispatch برای مسیریابی آسان .IP \(bu 2 پشتیبانی کامل از کنترل‌کننده‌های سبک REST .IP \(bu 2 چارچوب امنیتی توسعه‌پذیر .IP \(bu 2 پشتیبانی توسعه‌پذیر از زبان قالب (template language) .IP \(bu 2 پشتیبانی توسعه‌پذیر از JSON .IP \(bu 2 پیکربندی آسان مبتنی بر Python .UNINDENT .UNINDENT .UNINDENT .SH "نصب (INSTALLATION)" .SS "نسخه پایدار (Stable Version)" .sp توصیه می‌کنیم Pecan را با pip \% نصب کنید، اما می‌توانید از \fBeasy_install\fP\& نیز استفاده کنید. ایجاد فضایی در محیط کاری شما که در آن Pecan از سایر بسته‌ها مجزا و ایزوله باشد، بهترین شیوه است. .sp برای شروع کار با یک محیط برای Pecan، توصیه می‌کنیم با استفاده از virtualenv \% یک محیط مجازی جدید \% ایجاد کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ virtualenv pecan\-env $ cd pecan\-env $ source bin/activate .EE .UNINDENT .UNINDENT .sp دستورات بالا یک محیط مجازی ایجاد کرده و آن را \fIفعال\fP می‌کنند. این کار وابستگی‌های نصب‌شدهٔ Pecan را از بسته‌های سیستمی شما ایزوله می‌کند و در صورت نیاز اشکال‌زدایی مشکلات را ساده‌تر می‌سازد. .sp سپس، Pecan را نصب می‌کنیم: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install pecan .EE .UNINDENT .UNINDENT.SS "نسخه توسعه (ناپایدار) (Development (Unstable) Version)" .sp اگر می‌خواهید آخرین نسخه توسعه Pecan را اجرا کنید، باید git را نصب کرده و مخزن را از GitHub کلون نمایید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ git clone https://github.com/pecan/pecan.git .EE .UNINDENT .UNINDENT .sp با فرض اینکه محیط مجازی شما هنوز فعال است، \fBsetup.py\fP را برای نصب نسخه توسعه فراخوانی کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ cd pecan $ python setup.py develop .EE .UNINDENT .UNINDENT .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 شاخه توسعه \fBmaster\fP ناپایدار است و معمولاً برای استفاده در محیط عملیاتی توصیه نمی‌شود. .UNINDENT .UNINDENT .sp همچنین می‌توانید مستقیماً از GitHub با استفاده از \fBpip\fP نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install \-e git://github.com/pecan/pecan.git#egg=pecan .EE .UNINDENT .UNINDENT .SH "ایجاد نخستین برنامه PECAN (CREATING YOUR FIRST PECAN APPLICATION)" .sp بیایید یک پروژه نمونه کوچک با Pecan ایجاد کنیم. .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 این راهنما نحوه نصب Pecan را پوشش نمی‌دهد. در صورت نیاز به دستورالعمل‌های نصب Pecan، به بخش نصب \%<#\:installation>\& مراجعه کنید. .UNINDENT .UNINDENT .SS "قالب پایه برنامه (Base Application Template)" .sp برنامه Pecan شامل یک قالب پایه برای شروع یک پروژه جدید است. در شل خود، دستور زیر را وارد کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan create test_project .EE .UNINDENT .UNINDENT .sp این مثال از \fItest_project\fP به عنوان نام پروژه شما استفاده می‌کند، اما می‌توانید آن را با هر نام بسته معتبر Python که مایلید جایگزین کنید. .sp به دایرکتوری پروژه‌ای که تازه ایجاد کرده‌اید بروید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ cd test_project .EE .UNINDENT .UNINDENT .sp شما باید آن را در \(dqحالت توسعه\(dq (development mode) مستقر کنید، به طوری که در \fBsys.path\fP در دسترس باشد، اما همچنان بتوان آن را مستقیماً از توزیع منبع آن ویرایش کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX $ python setup.py develop .EE .UNINDENT .UNINDENT .sp پروژه جدید شما شامل این فایل‌ها خواهد بود: .INDENT 0.0 .INDENT 3.5 .sp .EX $ ls ├── MANIFEST.in ├── config.py ├── public │\ \ ├── css │\ \ │\ \ └── style.css │\ \ └── images ├── setup.cfg ├── setup.py └── test_project \ \ ├── __init__.py \ \ ├── app.py \ \ ├── controllers \ \ │\ \ ├── __init__.py \ \ │\ \ └── root.py \ \ ├── model \ \ │\ \ └── __init__.py \ \ ├── templates \ \ │\ \ ├── error.html \ \ │\ \ ├── index.html \ \ └── layout.html \ \ └── tests \ \ ├── __init__.py \ \ ├── config.py \ \ ├── test_functional.py \ \ └── test_units.py .EE .UNINDENT .UNINDENT .sp تعداد فایل‌ها و دایرکتوری‌ها ممکن است بر اساس نسخه Pecan متفاوت باشد، اما ساختار بالا باید دید کلی از آنچه انتظار می‌رود را به شما بدهد. .sp بیایید فایل‌های ایجاد شده توسط قالب را بررسی کنیم: .INDENT 0.0 .TP \fBpublic\fP تمام فایل‌های ایستا (مانند CSS، Javascript و تصاویر) در اینجا قرار دارند. Pecan با یک سرویس‌دهنده فایل ساده همراه است که هنگام توسعه، این فایل‌های ایستا را ارائه می‌دهد. .UNINDENT .sp ساختار برنامه Pecan عموماً از الگوی MVC \% پیروی می‌کند. دایرکتوری‌های زیر \fBtest_project\fP شامل مدل‌ها، کنترل‌کننده‌ها و قالب‌های شما هستند. .INDENT 0.0 .TP \fBtest_project/controllers\fP دایرکتوری دربرگیرنده فایل‌های کنترل‌کننده (controller) شما. .TP \fBtest_project/templates\fP تمام قالب‌های (templates) شما در اینجا قرار می‌گیرند. .TP \fBtest_project/model\fP دربرگیرنده فایل‌های مدل (model) شما. .UNINDENT .sp در نهایت، دایرکتوری برای نگهداری آزمون‌های واحد (unit) و یکپارچه‌سازی (integration): .INDENT 0.0 .TP \fBtest_project/tests\fP تمام آزمون‌های مربوط به برنامه شما. .UNINDENT .sp فایل \fBtest_project/app.py\fP چگونگی ایجاد برنامه Pecan را کنترل می‌کند. این فایل باید حاوی یک تابع \fBsetup_app()\fP باشد که شیء برنامه WSGI را برمی‌گرداند. معمولاً نیازی به ویرایش فایل \fBapp.py\fP ارائه شده توسط قالب پایه برنامه نخواهید داشت، مگر اینکه نیاز به سفارشی‌سازی برنامه خود به روشی داشته باشید که با استفاده از پیکربندی امکان‌پذیر نباشد. به بخش پیکربندی مبتنی بر پایتون (Python\-Based Configuration) در ادامه مراجعه کنید. .sp برای جلوگیری از وابستگی‌های غیرضروری و حفظ بیشترین انعطاف‌پذیری ممکن، Pecan هیچ پایگاه داده یا ORM (نگاشت شیء-رابطه‌ای \%) را تحمیل نمی‌کند. اگر پروژه شما با یک پایگاه داده در ارتباط است، می‌توانید کدی به \fBmodel/__init__.py\fP اضافه کنید تا اتصالات پایگاه داده را از فایل پیکربندی شما بارگیری کند و جدول‌ها و تعاریف ORM را مشخص نماید..SS اجرای برنامه .sp قالب پایهٔ پروژه، فایل پیکربندی را با تنظیمات اولیه‌ای که برای اجرای برنامهٔ Pecan خود نیاز دارید در \fBconfig.py\fP\& ایجاد می‌کند. این فایل شامل میزبان و درگاهی است که کارساز باید روی آن اجرا شود، مکانی از دیسک که کنترل‌کننده‌ها و قالب‌های شما در آن ذخیره شده‌اند، و نام دایرکتوری حاوی فایل‌های ایستا (static). .sp اگر تنها دستور \fBpecan serve\fP را با ارسال \fBconfig.py\fP به عنوان فایل پیکربندی اجرا کنید، کارساز توسعه راه‌اندازی شده و برنامه را ارائه می‌دهد: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve config.py Starting server in PID 000. serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 .EE .UNINDENT .UNINDENT .sp محل فایل پیکربندی و خود آرگومان بسیار انعطاف‌پذیر هستند \- می‌توانید یک مسیر مطلق یا نسبی را به فایل ارسال کنید. .SS پیکربندی مبتنی بر پایتون .sp برای سهولت در استفاده، فایل‌های پیکربندی Pecan از نوع پایتون خالص هستند\-\-آن‌ها حتی به عنوان فایل‌های \fB\&.py\fP ذخیره می‌شوند. .sp فایل پیکربندی پیش‌فرض (تولیدشده) شما باید به این صورت باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX # Server Specific Configurations server = { \(aqport\(aq: \(aq8080\(aq, \(aqhost\(aq: \(aq0.0.0.0\(aq } # Pecan Application Configurations app = { \(aqroot\(aq: \(aq${package}.controllers.root.RootController\(aq, \(aqmodules\(aq: [\(aq${package}\(aq], \(aqstatic_root\(aq: \(aq%(confdir)s/public\(aq, \(aqtemplate_path\(aq: \(aq%(confdir)s/${package}/templates\(aq, \(aqdebug\(aq: True, \(aqerrors\(aq: { \(aq404\(aq: \(aq/error/404\(aq, \(aq__force_dict__\(aq: True } } logging = { \(aqloggers\(aq: { \(aqroot\(aq : {\(aqlevel\(aq: \(aqINFO\(aq, \(aqhandlers\(aq: [\(aqconsole\(aq]}, \(aq${package}\(aq: {\(aqlevel\(aq: \(aqDEBUG\(aq, \(aqhandlers\(aq: [\(aqconsole\(aq]} }, \(aqhandlers\(aq: { \(aqconsole\(aq: { \(aqlevel\(aq: \(aqDEBUG\(aq, \(aqclass\(aq: \(aqlogging.StreamHandler\(aq, \(aqformatter\(aq: \(aqsimple\(aq } }, \(aqformatters\(aq: { \(aqsimple\(aq: { \(aqformat\(aq: (\(aq%(asctime)s %(levelname)\-5.5s [%(name)s]\(aq \(aq[%(threadName)s] %(message)s\(aq) } } } # Custom Configurations must be in Python dictionary format:: # # foo = {\(aqbar\(aq:\(aqbaz\(aq} # # All configurations are accessible at:: # pecan.conf .EE .UNINDENT .UNINDENT .sp همچنین می‌توانید پیکربندی‌های سفارشی خود را به صورت دیکشنری‌های پایتون اضافه کنید. .sp موارد زیادی برای پوشش دادن وجود دارد، بنابراین در فصلی دیگر مجدداً به فایل‌های پیکربندی بازخواهیم گشت (Configuring Pecan Applications \%<#\:configuration>)..SS ریشه برنامه (The Application Root) .sp کنترلر ریشه یا \fBRoot Controller\fP نقطه ورود برنامه شما است. می‌توانید آن را مشابه مسیر URL ریشه برنامه خود (در این حالت، \fBhttp://localhost:8080\fP) در نظر بگیرید. .sp این کنترلر در قالب پروژه (\fBtest_project.controllers.root.RootController\fP) به این شکل است: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from webob.exc import status_map class RootController(object): @expose(generic=True, template=\(aqindex.html\(aq) def index(self): return dict() @index.when(method=\(aqPOST\(aq) def index_post(self, q): redirect(\(aqhttps://pecan.readthedocs.io/en/latest/search.html?q=%s\(aq % q) @expose(\(aqerror.html\(aq) def error(self, status): try: status = int(status) except ValueError: status = 0 message = getattr(status_map.get(status), \(aqexplanation\(aq, \(aq\(aq) return dict(status=status, message=message) .EE .UNINDENT .UNINDENT .sp در صورت نیاز می‌توانید کلاس‌ها و متدهای بیشتری را مشخص کنید، اما در حال حاضر بیایید پروژه نمونه را کنترلر به کنترلر بررسی کنیم: .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(generic=True, template=\(aqindex.html\(aq) def index(self): return dict() .EE .UNINDENT .UNINDENT .sp متد \fBindex()\fP از طریق دکوراتور \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> (که به نوبه خود از قالب \fBindex.html\fP استفاده می‌کند) در ریشه برنامه (\%) به عنوان \fIدر دسترس عموم\fP نشانه‌گذاری شده است؛ بنابراین هر درخواست HTTP \fBGET\fP که به ریشه برنامه شما (\fB/\fP) برسد، به این متد هدایت خواهد شد. .sp توجه داشته باشید که متد \fBindex()\fP یک دیکشنری پایتون را برمی‌گرداند. این دیکشنری به عنوان یک فضای نام برای تبدیل قالب مشخص‌شده (\fBindex.html\fP) به HTML استفاده می‌شود و سازوکار اصلی انتقال داده از کنترلر به قالب است. .INDENT 0.0 .INDENT 3.5 .sp .EX @index.when(method=\(aqPOST\(aq) def index_post(self, q): redirect(\(aqhttps://pecan.readthedocs.io/en/latest/search.html?q=%s\(aq % q) .EE .UNINDENT .UNINDENT .sp متد \fBindex_post()\fP یک آرگومان HTTP \fBPOST\fP دریافت می‌کند (\fBq\fP). از آنجا که آرگومان \fBmethod\fP برای \fB@index.when()\fP روی \fB\(aqPOST\(aq\fP تنظیم شده است، هر درخواست HTTP \fBPOST\fP به ریشه برنامه (در پروژه نمونه، ارسال یک فرم) به این متد هدایت خواهد شد. .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(\(aqerror.html\(aq) def error(self, status): try: status = int(status) except ValueError: status = 0 message = getattr(status_map.get(status), \(aqexplanation\(aq, \(aq\(aq) return dict(status=status, message=message) .EE .UNINDENT .UNINDENT .sp در نهایت، متد \fBerror()\fP را داریم که به برنامه امکان می‌دهد صفحه‌های سفارشی را برای برخی از خطاهای HTTP نمایش دهد (\fB404\fP و غیره...)..SS "اجرای آزمون‌ها برای برنامه شما (Running the Tests For Your Application)" .sp برنامه شما شامل چند آزمون نمونه است که می‌توانید آن‌ها را اجرا، جایگزین یا به آن‌ها مواردی اضافه کنید. برای اجرای آن‌ها: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install tox && tox \-e py .EE .UNINDENT .UNINDENT .sp خود آزمون‌ها را می‌توان در ماژول \fBtests\fP در پروژه خود پیدا کرد. .SS "استقرار روی یک وب‌سرور (Deploying to a Web Server)" .sp آماده استقرار برنامه جدید Pecan خود هستید؟ نگاهی به Deploying Pecan in Production \%<#\:deployment>\& بیندازید. .SH "کنترل‌کننده‌ها و مسیریابی (CONTROLLERS AND ROUTING)" .sp ‏Pecan از یک راهبرد مسیریابی موسوم به \fBobject\-dispatch\fP برای نگاشت یک درخواست HTTP به یک کنترل‌کننده، و سپس متدی که باید فراخوانی شود، استفاده می‌کند. ‏\fBobject\-dispatch\fP با تقسیم مسیر به فهرستی از مؤلفه‌ها و سپس پیمایش یک مسیر شیء، با شروع از کنترل‌کننده ریشه آغاز می‌شود. شما می‌توانید کنترل‌کننده‌های برنامه خود را درختی از اشیاء تصور کنید (شاخه‌های درخت اشیاء مستقیماً به مسیرهای URL نگاشت می‌شوند). .sp بیایید به یک برنامه کتاب‌فروشی ساده نگاهی بیندازیم: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class BooksController(object): @expose() def index(self): return \(dqWelcome to book section.\(dq @expose() def bestsellers(self): return \(dqWe have 5 books in the top 10.\(dq class CatalogController(object): @expose() def index(self): return \(dqWelcome to the catalog.\(dq books = BooksController() class RootController(object): @expose() def index(self): return \(dqWelcome to store.example.com!\(dq @expose() def hours(self): return \(dqOpen 24/7 on the web.\(dq catalog = CatalogController() .EE .UNINDENT .UNINDENT .sp یک درخواست برای \fB/catalog/books/bestsellers\fP از فروشگاه برخط، با شکستن درخواست به \fBcatalog\fP، \fBbooks\fP و \fBbestsellers\fP توسط Pecan آغاز می‌شود. سپس، Pecan مقدار \fBcatalog\fP را روی کنترل‌کننده ریشه جستجو می‌کند. با استفاده از شیء \fBcatalog\fP، سپس Pecan مقدار \fBbooks\fP و پس از آن \fBbestsellers\fP را جستجو خواهد کرد. اگر URL با یک اسلش خاتمه یابد چه؟ Pecan وجود متد \fBindex\fP را روی آخرین شیء کنترل‌کننده بررسی خواهد کرد. .sp برای روشن‌تر شدن مطلب، مسیرهای زیر: .INDENT 0.0 .INDENT 3.5 .sp .EX └── / \ \ ├── /hours \ \ └── /catalog \ \ └── /catalog/books \ \ └── /catalog/books/bestsellers .EE .UNINDENT .UNINDENT .sp به متدهای کنترل‌کننده زیر مسیریابی می‌شوند: .INDENT 0.0 .INDENT 3.5 .sp .EX └── RootController.index \ \ ├── RootController.hours \ \ └── CatalogController.index \ \ └── BooksController.index \ \ └── BooksController.bestsellers .EE .UNINDENT .UNINDENT.SS "نمایان‌سازی کنترل‌کننده‌ها (Exposing Controllers)" .sp شما از طریق \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose>\& به Pecan اعلام می‌کنید که کدام متدها در یک کلاس به‌صورت عمومی قابل‌مشاهده هستند. اگر متدی با \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> تزیین \fIنشده باشد\fP، Pecan هرگز درخواستی را به آن هدایت نخواهد کرد. .sp \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> می‌تواند به روش‌های مختلفی استفاده شود. ساده‌ترین حالت شامل ارسال نکردن هیچ آرگومانی است. در این سناریو، کنترل‌کننده رشته‌ای را برمی‌گرداند که نشان‌دهنده بدنه پاسخ HTML است. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose() def hello(self): return \(aqHello World\(aq .EE .UNINDENT .UNINDENT .sp یک مورد استفاده متداول‌تر، مشخص کردن یک قالب و یک فضای نام (namespace) است \%<#\:templates>: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose(\(aqhtml_template.mako\(aq) def hello(self): return {\(aqmsg\(aq: \(aqHello!\(aq} .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX ${msg} .EE .UNINDENT .UNINDENT .sp همچنین Pecan دارای پشتیبانی داخلی از یک رندرکننده ویژه JSON است \%<#\:expose-json>، که فضاهای نام قالب را به متن رندرشده JSON تبدیل می‌کند: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose(\(aqjson\(aq) def hello(self): return {\(aqmsg\(aq: \(aqHello!\(aq} .EE .UNINDENT .UNINDENT .sp فراخوانی‌های \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> همچنین می‌توانند به‌صورت پشته‌ای (روی هم) قرار گیرند، که به شما امکان می‌دهد محتوا را بسته به نحوه درخواست آن، به روش‌های متفاوتی سریال‌سازی کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose(\(aqjson\(aq) @expose(\(aqtext_template.mako\(aq, content_type=\(aqtext/plain\(aq) @expose(\(aqhtml_template.mako\(aq) def hello(self): return {\(aqmsg\(aq: \(aqHello!\(aq} .EE .UNINDENT .UNINDENT .sp متوجه خواهید شد که ما \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> را سه بار با آرگومان‌های متفاوت فراخوانی کردیم. .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(\(aqjson\(aq) .EE .UNINDENT .UNINDENT .sp مورد اول به Pecan می‌گوید زمانی که کلاینت \fB/hello.json\fP را درخواست می‌کند یا اگر یک هدر \fBAccept: application/json\fP وجود داشته باشد، فضای نام پاسخ را با استفاده از سریال‌سازی JSON سریال‌سازی کند. .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(\(aqtext_template.mako\(aq, content_type=\(aqtext/plain\(aq) .EE .UNINDENT .UNINDENT .sp مورد دوم به Pecan می‌گوید زمانی که کلاینت \fB/hello.txt\fP را درخواست می‌کند یا از طریق یک هدر \fBAccept\fP نوع text/plain را درخواست می‌کند، از فایل قالب \fBtext_template.mako\fP استفاده کند. .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(\(aqhtml_template.mako\(aq) .EE .UNINDENT .UNINDENT .sp مورد سوم به Pecan می‌گوید زمانی که کلاینت \fB/hello.html\fP را درخواست می‌کند، از فایل قالب \fBhtml_template.mako\fP استفاده کند\&. اگر کلاینت \fB/hello\fP را درخواست کند، Pecan به‌طور پیش‌فرض از نوع محتوای \fBtext/html\fP استفاده خواهد کرد؛ در غیاب یک نوع محتوای صریح، Pecan فرض می‌کند که کلاینت HTML می‌خواهد. .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 pecan.decorators \-\- تزیین‌کننده‌های Pecan \%<#\:pecan-decorators> .UNINDENT .UNINDENT .UNINDENT.SS مشخص کردن صریح بخش‌های مسیر (Specifying Explicit Path Segments) .sp گاه ممکن است بخواهید در مسیریابی خود از بخشی در مسیر استفاده کنید که به دلیل محدودیت‌های ساختار نحوی Python، با رویکرد اعلانی Pecan در مسیریابی همخوانی ندارد. به عنوان مثال، اگر بخواهید برای مسیری شامل خط تیره مانند \fB/some\-path/\fP مسیریابی انجام دهید، قطعه‌کد زیر در Python معتبر \fIنیست\fP: .INDENT 0.0 .INDENT 3.5 .sp .EX class RootController(object): @pecan.expose() def some\-path(self): return dict() .EE .UNINDENT .UNINDENT .sp برای رفع این مشکل، pecan به شما اجازه می‌دهد تا در دکوراتور \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> یک بخش مسیر را به‌طور صریح مشخص کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX class RootController(object): @pecan.expose(route=\(aqsome\-path\(aq) def some_path(self): return dict() .EE .UNINDENT .UNINDENT .sp در این مثال، برنامه‌ی pecan به درخواست‌های فرستاده‌شده به \fB/some\-path/\fP با پاسخ \fBHTTP 200\fP پاسخ خواهد داد، اما درخواست‌های ارسال‌شده به \fB/some_path/\fP منجر به \fBHTTP 404\fP خواهند شد\&. .sp همچنین می‌توان از \fBroute()\fP \%<#\:pecan\:.routing\:.route> به‌طور صریح به‌عنوان جایگزینی برای آرگومان \fBroute\fP در \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> استفاده کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX class RootController(object): @pecan.expose() def some_path(self): return dict() pecan.route(\(aqsome\-path\(aq, RootController.some_path) .EE .UNINDENT .UNINDENT .sp مسیریابی به کنترلرهای فرزند (child controllers) را نیز می‌توان به روشی مشابه با بهره‌گیری از \fBroute()\fP \%<#\:pecan\:.routing\:.route> مدیریت کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX class ChildController(object): @pecan.expose() def child(self): return dict() class RootController(object): pass pecan.route(RootController, \(aqchild\-path\(aq, ChildController()) .EE .UNINDENT .UNINDENT .sp در این مثال، برنامه‌ی pecan به درخواست‌های فرستاده‌شده به \fB/child\-path/child/\fP با \fBHTTP 200\fP پاسخ خواهد داد\&. .SS مسیریابی بر اساس متد درخواست (Routing Based on Request Method) .sp آرگومان \fBgeneric\fP در \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> امکان چندریختی یا بازتعریف (overloading) نشانی‌های URL را بر اساس متد درخواست فراهم می‌کند. در مثال زیر، یک URL یکسان می‌تواند با استفاده از \fIکنترلرهای عمومی (generic controllers)\fP به دو متد مختلف سرویس‌دهی شود (یکی برای رسیدگی به HTTP \fBGET\fP و دیگری برای HTTP \fBPOST\fP): .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): # HTTP GET / @expose(generic=True, template=\(aqjson\(aq) def index(self): return dict() # HTTP POST / @index.when(method=\(aqPOST\(aq, template=\(aqjson\(aq) def index_POST(self, **kw): uuid = create_something() return dict(uuid=uuid) .EE .UNINDENT .UNINDENT.SS الگوریتم مسیریابی Pecan .sp گاهی اوقات، مسیریابی استاندارد ارجاع به شیء (object\-dispatch) برای هدایت صحیح یک URL به یک کنترلر کافی نیست. Pecan چندین راهکار برای میان‌بُر زدن در سیستم ارجاع به شیء ارائه می‌دهد تا پردازش URLها با کنترل بیشتری انجام پذیرد؛ از جمله متدهای ویژهٔ \fB_lookup()\fP، \fB_default()\fP و \fB_route()\fP. تعریف این متدها روی شیءهای کنترلر شما، انعطاف‌پذیری بیشتری را برای پردازش تمام یا بخشی از یک URL فراهم می‌آورد. .SS مسیریابی به زیرکنترلرها با \fB_lookup\fP .sp متد ویژهٔ \fB_lookup()\fP روشی را برای پردازش بخشی از یک URL و سپس بازگرداندن یک شیء کنترلر جدید جهت هدایت بخش باقی‌مانده فراهم می‌کند. .sp یک متد \fB_lookup()\fP می‌تواند یک یا چند آرگومان را بپذیرد، که بخش‌هایی از مسیر URL هستند که باید پردازش شوند (تفکیک‌شده با \fB/\fP). متد \fB_lookup()\fP همچنین باید آرگومان‌های مکانی متغیر را که نشان‌دهندهٔ ادامهٔ مسیر هستند دریافت کند، و هر بخشی از مسیر را که خود پردازش نمی‌کند در مقدار بازگشتی خود بگنجاند. مثال زیر از یک لیست \fB*remainder\fP استفاده می‌کند که با ادامه یافتن الگوریتم ارجاع به شیء (object\-dispatch)، به کنترلر بازگردانده‌شده ارسال خواهد شد. .sp علاوه بر کاربرد در ساخت پویای کنترلرها، متد \fB_lookup()\fP به عنوان آخرین راه‌حل نیز فراخوانی می‌شود؛ زمانی که هیچ متد کنترلر دیگری با URL همخوانی نداشته باشد و متد \fB_default()\fP نیز تعریف نشده باشد. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, abort from somelib import get_student_by_name class StudentController(object): def __init__(self, student): self.student = student @expose() def name(self): return self.student.name class RootController(object): @expose() def _lookup(self, primary_key, *remainder): student = get_student_by_primary_key(primary_key) if student: return StudentController(student), remainder else: abort(404) .EE .UNINDENT .UNINDENT .sp یک درخواست HTTP GET به \fB/8/name\fP نام دانش‌آموزی را بازمی‌گرداند که در آن \fBprimary_key == 8\fP باشد. .SS بازگشت به متد جایگزین با \fB_default\fP .sp متد \fB_default()\fP به عنوان آخرین راه‌حل، هنگامی که هیچ متد کنترلر دیگری از طریق ارجاع استاندارد به شیء با URL تطابق نداشته باشد، فراخوانی می‌شود. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose() def english(self): return \(aqhello\(aq @expose() def french(self): return \(aqbonjour\(aq @expose() def _default(self): return \(aqI cannot say hello in that language\(aq .EE .UNINDENT .UNINDENT .sp در مثال بالا، درخواستی به \fB/spanish\fP به \fBRootController._default()\fP هدایت خواهد شد..SS تعریف مسیریابی سفارشی با \fB_route\fP .sp متد \fB_route()\fP به کنترل‌کننده اجازه می‌دهد سازوکار مسیریابی Pecan را به‌طور کامل بازنویسی کند. خود Pecan از متد \fB_route()\fP برای پیاده‌سازی \fBRestController\fP \%<#\:pecan\:.rest\:.RestController>\& استفاده می‌کند. اگر می‌خواهید یک سیستم مسیریابی جایگزین بر بستر Pecan طراحی کنید، تعریف یک کلاس کنترل‌کنندهٔ پایه که متد \fB_route()\fP را مشخص کند، به شما امکان کنترل کامل را می‌دهد. .SH "تعامل با شیء درخواست و پاسخ (INTERACTING WITH THE REQUEST AND RESPONSE OBJECT)" .sp برای هر درخواست HTTP، سامانهٔ Pecan یک ارجاع محلی به رشته (thread\-local) \%<#\:contextlocals> به شیء درخواست و پاسخ، \fBpecan.request\fP و \fBpecan.response\fP\&، نگه می‌دارد. این‌ها به ترتیب نمونه‌هایی از \fBpecan.Request\fP و \fBpecan.Response\fP هستند و می‌توان از داخل کد کنترل‌کنندهٔ Pecan با آن‌ها تعامل داشت: .INDENT 0.0 .INDENT 3.5 .sp .EX @pecan.expose() def login(self): assert pecan.request.path == \(aq/login\(aq username = pecan.request.POST.get(\(aqusername\(aq) password = pecan.request.POST.get(\(aqpassword\(aq) pecan.response.status = 403 pecan.response.text = \(aqBad Login!\(aq .EE .UNINDENT .UNINDENT .sp در حالی که Pecan بخش عمده‌ای از نیاز به تعامل مستقیم با این اشیاء را انتزاع می‌کند، موقعیت‌هایی وجود دارد که ممکن است بخواهید به آن‌ها دسترسی داشته باشید، مانند: .INDENT 0.0 .IP \(bu 2 بررسی اجزای URI .IP \(bu 2 تعیین جنبه‌هایی از درخواست، مانند نشانی IP کاربر یا سرآیند referer .IP \(bu 2 تنظیم سرآیندهای خاص پاسخ .IP \(bu 2 رندر کردن دستی بدنهٔ پاسخ .UNINDENT .SS تعیین پاسخ سفارشی .sp با تغییر ویژگی \fBstatus\fP در شیء پاسخ، یک کد وضعیت HTTP مشخص (مانند \fB203 Non\-Authoritative Information\fP) تنظیم کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, response class RootController(object): @expose(\(aqjson\(aq) def hello(self): response.status = 203 return {\(aqfoo\(aq: \(aqbar\(aq} .EE .UNINDENT .UNINDENT .sp برای برانگیختن خطاهای HTTP از تابع کمکی \fBabort()\fP \%<#\:pecan\:.core\:.abort> استفاده کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, abort class RootController(object): @expose(\(aqjson\(aq) def hello(self): abort(404) .EE .UNINDENT .UNINDENT .sp تابع \fBabort()\fP \%<#\:pecan\:.core\:.abort> یک نمونه از \fBWSGIHTTPException\fP را برمی‌انگیزد که توسط Pecan برای رندر کردن بدنه‌های پیش‌فرض پاسخ در خطاهای HTTP استفاده می‌شود. این استثنا در محیط درخواست WSGI (environ) در \fBpecan.original_exception\fP ذخیره می‌شود، جایی که بعداً در چرخهٔ درخواست (برای مثال توسط میان‌افزارهای دیگر یا Custom Error Documents \%<#\:errors>) قابل دسترسی است. .sp اگر می‌خواهید یک پاسخ صریح را بازگردانید، می‌توانید این کار را با استفاده از \fBResponse\fP \%<#\:pecan\:.core\:.Response> انجام دهید: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, Response class RootController(object): @expose() def hello(self): return Response(\(aqHello, World!\(aq, 202) .EE .UNINDENT .UNINDENT.SS گسترش اشیاء Request و Response در Pecan .sp پیاده‌سازی‌های درخواست (request) و پاسخ (response) ارائه‌شده توسط WebOb قدرتمند هستند، اما گاهی اوقات ممکن است گسترش رفتارهای ویژه‌ی برنامه بر روی درخواست و پاسخ شما مفید باشد (مانند تجزیه‌ی سفارشی سرایندهای درخواست یا سریال‌سازی سفارشی بدنه‌ی پاسخ). برای انجام این کار، کلاس‌های سفارشی تعریف کنید که به ترتیب از \fBpecan.Request\fP و \fBpecan.Response\fP ارث‌بری کنند: .INDENT 0.0 .INDENT 3.5 .sp .EX class MyRequest(pecan.Request): pass class MyResponse(pecan.Response): pass .EE .UNINDENT .UNINDENT .sp و پیکربندی برنامه‌ی خود را برای استفاده از آن‌ها تغییر دهید: .INDENT 0.0 .INDENT 3.5 .sp .EX from myproject import MyRequest, MyResponse app = { \(aqroot\(aq : \(aqproject.controllers.root.RootController\(aq, \(aqmodules\(aq : [\(aqproject\(aq], \(aqstatic_root\(aq : \(aq%(confdir)s/public\(aq, \(aqtemplate_path\(aq : \(aq%(confdir)s/project/templates\(aq, \(aqrequest_cls\(aq: MyRequest, \(aqresponse_cls\(aq: MyResponse } .EE .UNINDENT .UNINDENT .SS نگاشت آرگومان‌های کنترل‌کننده (Controller) .sp در Pecan، متغیرهای \fBGET\fP و \fBPOST\fP در پروتکل HTTP که در طول فرآیند مسیریابی (routing) مصرف نمی‌شوند، می‌توانند به عنوان آرگومان به متد کنترل‌کننده منتقل شوند. .sp بسته به امضای (signature) متد، این متغیرها می‌توانند به‌طور صریح به آرگومان‌ها نگاشت شوند: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose() def index(self, arg): return arg @expose() def kwargs(self, **kwargs): return str(kwargs) .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ curl http://localhost:8080/?arg=foo foo $ curl http://localhost:8080/kwargs?a=1&b=2&c=3 {u\(aqa\(aq: u\(aq1\(aq, u\(aqc\(aq: u\(aq3\(aq, u\(aqb\(aq: u\(aq2\(aq} .EE .UNINDENT .UNINDENT .sp یا می‌توانند بر اساس موقعیت (positionally) مصرف شوند: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose() def args(self, *args): return \(aq,\(aq.join(args) .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ curl http://localhost:8080/args/one/two/three one,two,three .EE .UNINDENT .UNINDENT .sp همین نتیجه را می‌توان با متغیرهای بدنه در HTTP \fBPOST\fP نیز به دست آورد: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose() def index(self, arg): return arg .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ curl \-X POST \(dqhttp://localhost:8080/\(dq \-H \(dqContent\-Type: application/x\-www\-form\-urlencoded\(dq \-d \(dqarg=foo\(dq foo .EE .UNINDENT .UNINDENT.SS ارائه فایل‌های ایستا (Static File Serving) .sp از آنجا که Pecan دسترسی مستقیم به \fBRequest\fP زیرین را در اختیارتان می‌گذارد، ارائه یک فایل ایستا برای دانلود به سادگیِ تنظیم \fBapp_iter\fP در WSGI و مشخص کردن نوع محتوا است: .INDENT 0.0 .INDENT 3.5 .sp .EX import os from random import choice from webob.static import FileIter from pecan import expose, response class RootController(object): @expose(content_type=\(aqimage/gif\(aq) def gifs(self): filepath = choice(( \(dq/path/to/funny/gifs/catdance.gif\(dq, \(dq/path/to/funny/gifs/babydance.gif\(dq, \(dq/path/to/funny/gifs/putindance.gif\(dq )) f = open(filepath, \(aqrb\(aq) response.app_iter = FileIter(f) response.headers[ \(aqContent\-Disposition\(aq ] = \(aqattachment; filename=\(dq%s\(dq\(aq % os.path.basename(f.name) .EE .UNINDENT .UNINDENT .sp اگر نوع محتوا را از قبل نمی‌دانید (برای نمونه، اگر فایل‌ها و نوع محتوای آن‌ها را از یک منبع داده بازیابی می‌کنید)، می‌توانید آن را از طریق \fBresponse.headers\fP مشخص کنید به جای اینکه در دکوراتور \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> تعیین شود: .INDENT 0.0 .INDENT 3.5 .sp .EX import os from mimetypes import guess_type from webob.static import FileIter from pecan import expose, response class RootController(object): @expose() def download(self): f = open(\(aq/path/to/some/file\(aq, \(aqrb\(aq) response.app_iter = FileIter(f) response.headers[\(aqContent\-Type\(aq] = guess_type(f.name) response.headers[ \(aqContent\-Disposition\(aq ] = \(aqattachment; filename=\(dq%s\(dq\(aq % os.path.basename(f.name) .EE .UNINDENT .UNINDENT .SS مدیریت بارگذاری فایل‌ها (Handling File Uploads) .sp Pecan مدیریت بارگذاری فایل‌ها را از طریق فرم‌های استاندارد multipart ساده می‌کند. کافی است فرم خود را با یک ورودی فایل تعریف کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX
.EE .UNINDENT .UNINDENT .sp سپس می‌توانید فایل بارگذاری‌شده را از شیء request در کنترلر (controller) برنامه بخوانید: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, request class RootController(object): @expose() def upload(self): assert isinstance(request.POST[\(aqfile\(aq], cgi.FieldStorage) data = request.POST[\(aqfile\(aq].file.read() .EE .UNINDENT .UNINDENT.SS "ذخیره‌سازی امن از نظر ریسه به ازای هر درخواست (Thread\-Safe Per\-Request Storage)" .sp جهت سهولت، Pecan روی هر درخواست یک دیکشنری Python فراهم می‌کند که می‌توان در تمام طول چرخه حیات یک درخواست مجزا، به شکلی امن از نظر ریسه (thread\-safe) به آن دسترسی داشت و آن را تغییر داد: .INDENT 0.0 .INDENT 3.5 .sp .EX pecan.request.context[\(aqcurrent_user\(aq] = some_user print pecan.request.context.items() .EE .UNINDENT .UNINDENT .sp این قابلیت به‌ویژه در شرایطی کاربرد دارد که بخواهید فراداده/زمینه (metadata/context) مربوط به یک درخواست را ذخیره کرده (مثلاً در میان‌افزارها یا قلاب‌های per\-routing) و بعداً به آن دسترسی داشته باشید (مثلاً در کد کنترلر). .sp برای کنترل دقیق‌تر روی درخواست، می‌توان به محیط WSGI زیرین برای یک درخواست معین Pecan از طریق \fBpecan.request.environ\fP\& دسترسی یافت و آن را تغییر داد. .SS "توابع کمکی (Helper Functions)" .sp همچنین Pecan توابع کمکی مفید متعددی را برای جابه‌جایی میان مسیرهای مختلف فراهم می‌کند. تابع \fBredirect()\fP \%<#\:pecan\:.core\:.redirect> به شما اجازه می‌دهد بازهدایت‌های داخلی یا \fBHTTP 302\fP صادر کنید. .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 ابزار کاربردی \fBredirect()\fP به همراه چندین تابع کمکی مفید دیگر در pecan.core \-\- Pecan Core \%<#\:pecan-core>\& مستند شده‌اند. .UNINDENT .UNINDENT .SS "تعیین نشانی وب برای یک کنترلر (Determining the URL for a Controller)" .sp با توجه به این‌که امکان تغییر چشمگیر مسیریابی در زمان اجرا وجود دارد، همیشه امکان تعیین دقیق یک نگاشت بین متد کنترلر و یک نشانی وب (URL) وجود ندارد. .sp برای مثال، در کد زیر که از \fB_lookup()\fP برای تغییر مسیریابی بر اساس یک شرط استفاده می‌کند: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, abort from somelib import get_user_region class DefaultRegionController(object): @expose() def name(self): return \(dqDefault Region\(dq class USRegionController(object): @expose() def name(self): return \(dqUS Region\(dq class RootController(object): @expose() def _lookup(self, user_id, *remainder): if get_user_region(user_id) == \(aqus\(aq: return USRegionController(), remainder else: return DefaultRegionController(), remainder .EE .UNINDENT .UNINDENT .sp این منطق به موقعیت مکانی یک کاربر معین و بازگرداندن یک کلاس کاملاً متفاوت بر اساس شرط وابسته است. یک تابع کمکی برای تعیین این‌که \fBUSRegionController.name\fP به کدام نشانی وب تعلق دارد، در انجام درست این کار ناموفق خواهد بود. .SH "قالب‌بندی در PECAN (TEMPLATING IN PECAN)" .sp ‏Pecan شامل پشتیبانی از انواع موتورهای قالب‌بندی است و همچنین افزودن پشتیبانی از موتورهای قالب جدید را آسان می‌سازد. در حال حاضر، Pecan از موارد زیر پشتیبانی می‌کند: .TS box center; l|l. T{ سیستم قالب T} T{ نام رندرکننده T} _ T{ Mako \% T} T{ mako T} _ T{ Genshi \% T} T{ genshi T} _ T{ Kajiki \% T} T{ kajiki T} _ T{ Jinja2 \% T} T{ jinja T} _ T{ JSON T} T{ json T} .TE .sp سیستم قالب پیش‌فرض \fBmako\fP است، اما می‌توان با ارسال کلید \fBdefault_renderer\fP در پیکربندی برنامه آن را تغییر داد: .INDENT 0.0 .INDENT 3.5 .sp .EX app = { \(aqdefault_renderer\(aq : \(aqkajiki\(aq, # ... } .EE .UNINDENT .UNINDENT.SS استفاده از رندرکننده‌های قالب (Using Template Renderers) .sp ماژول \fBpecan.decorators\fP \%<#\:module-pecan\:.decorators> دکوراتوری به نام \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> را تعریف می‌کند که برای مشخص کردن یک متد به عنوان کنترلر عمومی (public controller) به کار می‌رود. دکوراتور \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> یک آرگومان \fBtemplate\fP می‌پذیرد که می‌توان از آن برای تعیین مسیر فایل قالبِ مورد استفاده برای متد کنترلر مربوطه استفاده کرد. .INDENT 0.0 .INDENT 3.5 .sp .EX class MyController(object): @expose(\(aqpath/to/mako/template.html\(aq) def index(self): return dict(message=\(aqI am a mako template\(aq) .EE .UNINDENT .UNINDENT .sp دکوراتور \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> از موتور قالب پیش‌فرض استفاده خواهد کرد مگر اینکه نام یک رندرکننده دیگر به عنوان پیشوند به مسیر اضافه شده باشد. .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(\(aqkajiki:path/to/kajiki/template.html\(aq) def my_controller(self): return dict(message=\(aqI am a kajiki template\(aq) .EE .UNINDENT .UNINDENT .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 pecan.decorators \-\- دکوراتورهای Pecan (Pecan Decorators) \%<#\:pecan-decorators> .IP \(bu 2 pecan.core \-\- هسته Pecan (Pecan Core) \%<#\:pecan-core> .IP \(bu 2 کنترلرها و مسیریابی (Controllers and Routing) \%<#\:routing> .UNINDENT .UNINDENT .UNINDENT .SS بازنویسی قالب‌ها (Overriding Templates) .sp تابع \fBoverride_template()\fP \%<#\:pecan\:.core\:.override_template> به شما امکان می‌دهد قالب تعیین‌شده برای یک متد کنترلر را هنگام در معرض قرار گرفتن آن بازنویسی کنید. هنگامی که \fBoverride_template()\fP \%<#\:pecan\:.core\:.override_template> در داخل بدنه متد کنترلر فراخوانی شود، قالب مورد استفاده برای آن فراخوانی از متد را تغییر می‌دهد. .INDENT 0.0 .INDENT 3.5 .sp .EX class MyController(object): @expose(\(aqtemplate_one.html\(aq) def index(self): # ... override_template(\(aqtemplate_two.html\(aq) return dict(message=\(aqI will now render with template_two.html\(aq) .EE .UNINDENT .UNINDENT .SS رندر دستی (Manual Rendering) .sp تابع \fBrender()\fP \%<#\:pecan\:.core\:.render> به شما این امکان را می‌دهد که با استفاده از چارچوب قالب‌سازی Pecan خروجی را به‌صورت دستی رندر کنید. کافی است مسیر قالب و مقادیر مورد نیاز قالب را ارسال کنید؛ \fBrender()\fP \%<#\:pecan\:.core\:.render> خروجی رندرشده را در قالب متن برمی‌گرداند. .INDENT 0.0 .INDENT 3.5 .sp .EX @expose() def controller(self): return render(\(aqmy_template.html\(aq, dict(message=\(aqI am the namespace\(aq)) .EE .UNINDENT .UNINDENT.SS رندرکنندهٔ JSON (The JSON Renderer) .sp Pecan همچنین یک رندرکنندهٔ \fBJSON\fP ارائه می‌دهد که می‌توانید با در دسترس قرار دادن یک متد کنترل‌کننده با \fB@expose(\(aqjson\(aq)\fP از آن استفاده کنید. .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 سریال‌سازی JSON \%<#\:jsonify> .IP \(bu 2 pecan.jsonify \-\- پشتیبانی Pecan از JSON \%<#\:pecan-jsonify> .UNINDENT .UNINDENT .UNINDENT .SS تعریف رندرکننده‌های سفارشی (Defining Custom Renderers) .sp برای تعریف یک رندرکنندهٔ سفارشی، می‌توانید کلاسی ایجاد کنید که از پروتکل رندرکننده پیروی کند: .INDENT 0.0 .INDENT 3.5 .sp .EX class MyRenderer(object): def __init__(self, path, extra_vars): \(aq\(aq\(aq Your renderer is provided with a path to templates, as configured by your application, and any extra template variables, also as configured \(aq\(aq\(aq pass def render(self, template_path, namespace): \(aq\(aq\(aq Lookup the template based on the path, and render your output based upon the supplied namespace dictionary, as returned from the controller. \(aq\(aq\(aq return str(namespace) .EE .UNINDENT .UNINDENT .sp برای فعال‌سازی رندرکنندهٔ سفارشی خود، کلید \fBcustom_renderers\fP را در پیکربندی برنامهٔ خود تعریف کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX app = { \(aqcustom_renderers\(aq : { \(aqmy_renderer\(aq : MyRenderer }, # ... } .EE .UNINDENT .UNINDENT .sp \&... و رندرکننده را در متد \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> مشخص کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX class RootController(object): @expose(\(aqmy_renderer:template.html\(aq) def index(self): return dict(name=\(aqBob\(aq) .EE .UNINDENT .UNINDENT .SH "نوشتن وب‌سرویس‌های RESTful با کنترل‌کننده‌های عمومی (WRITING RESTFUL WEB SERVICES WITH GENERIC CONTROLLERS)" .sp Pecan با فراهم کردن روشی برای اورلود کردن URLها بر اساس متد درخواست، توسعهٔ وب‌سرویس‌های RESTful را ساده می‌کند. برای بیشتر APIها، استفاده از تعاریف \fIکنترل‌کنندهٔ عمومی (generic controller)\fP تمام آنچه را که برای ساخت رابط‌های قدرتمند RESTful نیاز دارید در اختیارتان می‌گذارد (و رویکرد \fIتوصیه‌شده\fP برای نوشتن وب‌سرویس‌های RESTful در Pecan است): .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import abort, expose # Note: this is *not* thread\-safe. In real life, use a persistent data store. BOOKS = { \(aq0\(aq: \(aqThe Last of the Mohicans\(aq, \(aq1\(aq: \(aqCatch\-22\(aq } class BookController(object): def __init__(self, id_): self.id_ = id_ assert self.book @property def book(self): if self.id_ in BOOKS: return dict(id=self.id_, name=BOOKS[self.id_]) abort(404) # HTTP GET // @expose(generic=True, template=\(aqjson\(aq) def index(self): return self.book # HTTP PUT // @index.when(method=\(aqPUT\(aq, template=\(aqjson\(aq) def index_PUT(self, **kw): BOOKS[self.id_] = kw[\(aqname\(aq] return self.book # HTTP DELETE // @index.when(method=\(aqDELETE\(aq, template=\(aqjson\(aq) def index_DELETE(self): del BOOKS[self.id_] return dict() class RootController(object): @expose() def _lookup(self, id_, *remainder): return BookController(id_), remainder # HTTP GET / @expose(generic=True, template=\(aqjson\(aq) def index(self): return [dict(id=k, name=v) for k, v in BOOKS.items()] # HTTP POST / @index.when(method=\(aqPOST\(aq, template=\(aqjson\(aq) def index_POST(self, **kw): id_ = str(len(BOOKS)) BOOKS[id_] = kw[\(aqname\(aq] return dict(id=id_, name=kw[\(aqname\(aq]) .EE .UNINDENT .UNINDENT.SH "نوشتن وب‌سرویس‌های RESTful با RESTCONTROLLER" .sp برای سازگاری با کتابخانهٔ TurboGears2 \%، فریم‌ورک Pecan یک راهکار مبتنی بر کلاس برای مسیریابی RESTful به نام \fBRestController\fP \%<#\:pecan\:.rest\:.RestController> نیز ارائه می‌دهد: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.rest import RestController from mymodel import Book class BooksController(RestController): @expose() def get(self, id): book = Book.get(id) if not book: abort(404) return book.title .EE .UNINDENT .UNINDENT .SS "نگاشت URL (URL Mapping)" .sp به‌طور پیش‌فرض، \fBRestController\fP \%<#\:pecan\:.rest\:.RestController> بدین صورت مسیریابی می‌کند: .TS box center; l|l|l. T{ متد T} T{ توضیحات T} T{ متد(ها) / URL(های) نمونه T} _ T{ get_one T} T{ نمایش یک رکورد. T} T{ GET /books/1 T} _ T{ get_all T} T{ نمایش تمام رکوردهای یک منبع. T} T{ GET /books/ T} _ T{ get T} T{ ترکیبی از get_one و get_all. T} T{ GET /books/ T} _ T{ GET /books/1 T} _ T{ new T} T{ نمایش صفحه‌ای برای ایجاد یک منبع جدید. T} T{ GET /books/new T} _ T{ edit T} T{ نمایش صفحه‌ای برای ویرایش یک منبع موجود. T} T{ GET /books/1/edit T} _ T{ post T} T{ ایجاد یک رکورد جدید. T} T{ POST /books/ T} _ T{ put T} T{ به‌روزرسانی یک رکورد موجود. T} T{ POST /books/1?_method=put T} _ T{ PUT /books/1 T} _ T{ get_delete T} T{ نمایش صفحهٔ تأیید حذف. T} T{ GET /books/1/delete T} _ T{ delete T} T{ حذف یک رکورد موجود. T} T{ POST /books/1?_method=delete T} _ T{ DELETE /books/1 T} .TE .sp کلاس \fBRestController\fP \%<#\:pecan\:.rest\:.RestController> در Pecan از رشته‌پرس‌وجوی \fB?_method=\fP برای دور زدن عدم پشتیبانی از افعال PUT و DELETE هنگام ارسال فرم‌ها در بیشتر مرورگرهای امروزی استفاده می‌کند. .sp علاوه بر مدیریت REST، کلاس \fBRestController\fP \%<#\:pecan\:.rest\:.RestController> همچنین از بازنویسی‌های مسیریابی \fBindex()\fP، \fB_default()\fP و \fB_lookup()\fP پشتیبانی می‌کند. .sp \fBهشدار:\fP .INDENT 0.0 .INDENT 3.5 اگر نیاز به بازنویسی \fB_route()\fP دارید، حتماً \fBRestController._route()\fP را در انتهای متد سفارشی خود فراخوانی کنید تا مسیریابی REST شرح‌داده‌شده در بالا همچنان انجام شود. .UNINDENT .UNINDENT.SS تودرتوسازی \fBRestController\fP .sp نمونه‌های \fBRestController\fP \%<#\:pecan\:.rest\:.RestController> می‌توانند به‌صورت تو در تو تعریف شوند تا منابع فرزند، پارامترهای لازم برای جستجوی منابع والد را دریافت کنند. .sp برای نمونه: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.rest import RestController from mymodel import Author, Book class BooksController(RestController): @expose() def get(self, author_id, id): author = Author.get(author_id) if not author_id: abort(404) book = author.get_book(id) if not book: abort(404) return book.title class AuthorsController(RestController): books = BooksController() @expose() def get(self, id): author = Author.get(id) if not author: abort(404) return author.name class RootController(object): authors = AuthorsController() .EE .UNINDENT .UNINDENT .sp دسترسی به مسیر \fB/authors/1/books/2\fP متد \fBBooksController.get()\fP را فراخوانی می‌کند که در آن \fBauthor_id\fP برابر با \fB1\fP و \fBid\fP برابر با \fB2\fP تنظیم شده است\&. .sp برای تعیین اینکه کدام آرگومان‌ها با منبع والد مرتبط هستند، Pecan به ترتیب امضای متد \fBget_one()\fP و سپس \fBget()\fP را در کنترلر والد بررسی می‌کند. اگر منبع والد تعداد متغیری از آرگومان‌ها را بپذیرد، Pecan همه موارد را تا رسیدن به نام کنترلر منبع فرزند (برای نمونه \fBbooks\fP در مثال بالا) به آن ارسال می‌کند. .SS تعریف عملیات سفارشی .sp افزون بر متدهای پیش‌فرض تعریف‌شده در بالا، می‌توانید با تعریف دیکشنری ویژه \fB_custom_actions\fP، رفتارهای بیشتری را به یک \fBRestController\fP \%<#\:pecan\:.rest\:.RestController> اضافه کنید. .sp برای نمونه: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.rest import RestController from mymodel import Book class BooksController(RestController): _custom_actions = { \(aqcheckout\(aq: [\(aqPOST\(aq] } @expose() def checkout(self, id): book = Book.get(id) if not book: abort(404) book.checkout() .EE .UNINDENT .UNINDENT .sp \fB_custom_actions\fP نام متدها را به فهرستی از افعال معتبر HTTP برای آن عملیات‌های سفارشی نگاشت می‌کند. در این مورد، متد \fBcheckout()\fP از فعل \fBPOST\fP پشتیبانی می‌کند\&..SH "پیکربندی برنامه‌های PECAN (CONFIGURING PECAN APPLICATIONS)" .sp پیکربندی Pecan بسیار آسان است. تا زمانی که از قراردادهای مشخصی پیروی کنید، استفاده، تنظیم و کار با پیکربندی بسیار شهودی خواهد بود. .sp فایل‌های پیکربندی Pecan از نوع پایتون خالص هستند. هر \(dqبخش\(dq (section) از پیکربندی، یک دیکشنری اختصاص داده‌شده به یک نام متغیر در ماژول پیکربندی است. .SS "مقادیر پیش‌فرض (Default Values)" .sp در زیر فهرست کاملی از مقادیر پیش‌فرضی که این چارچوب استفاده می‌کند آمده است: .INDENT 0.0 .INDENT 3.5 .sp .EX server = { \(aqport\(aq : \(aq8080\(aq, \(aqhost\(aq : \(aq0.0.0.0\(aq } app = { \(aqroot\(aq : None, \(aqmodules\(aq : [], \(aqstatic_root\(aq : \(aqpublic\(aq, \(aqtemplate_path\(aq : \(aq\(aq } .EE .UNINDENT .UNINDENT .SS "پیکربندی برنامه (Application Configuration)" .sp مقادیر پیکربندی \fBapp\fP توسط Pecan استفاده می‌شوند تا برنامه شما را درون یک برنامه معتبر WSGI \%\& قرار دهند. پیکربندی \fBapp\fP مختص برنامه شما است و شامل مقادیری مانند مکان کلاس کنترل‌کننده ریشه (root controller) می‌باشد. .sp یک پیکربندی متداول برنامه ممکن است به این شکل باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX app = { \(aqroot\(aq : \(aqproject.controllers.root.RootController\(aq, \(aqmodules\(aq : [\(aqproject\(aq], \(aqstatic_root\(aq : \(aq%(confdir)s/public\(aq, \(aqtemplate_path\(aq : \(aq%(confdir)s/project/templates\(aq, \(aqdebug\(aq : True } .EE .UNINDENT .UNINDENT .sp بیایید به هر مقدار و معنای آن نگاهی بیندازیم: .INDENT 0.0 .TP \fBmodules\fP فهرستی از ماژول‌ها که Pecan در آن‌ها به جستجوی برنامه‌ها می‌پردازد. به طور کلی این باید شامل یک مورد، یعنی نام بسته پایتون پروژه شما باشد. حداقل یکی از ماژول‌های فهرست‌شده باید شامل تابع \fBapp.setup_app\fP باشد که برای ایجاد برنامه WSGI فراخوانی می‌شود. به عبارت دیگر، این بسته باید مکانی باشد که فایل \fBapp.py\fP شما در آن قرار دارد، و این فایل باید حاوی یک تابع \fBsetup_app\fP باشد. .TP \fBroot\fP کنترل‌کننده ریشه برنامه شما. به یاد داشته باشید که رشته‌ای نشان‌دهنده یک مسیر پایتون به یک شیء قابل فراخوانی (callable) ارائه دهید (مانند \fB\(dqyourapp.controllers.root.RootController\(dq\fP). .TP \fBstatic_root\fP دایرکتوری که فایل‌های ایستای (static) شما در آن یافت می‌شوند (نسبت به ریشه پروژه). Pecan همراه با یک میان‌افزار (middleware) ارائه می‌شود که می‌تواند برای سرو فایل‌های ایستا (مانند فایل‌های CSS و Javascript) در طول فرایند توسعه استفاده شود. .TP \fBtemplate_path\fP به دایرکتوری اشاره می‌کند که فایل‌های قالب شما در آن قرار دارند (نسبت به ریشه پروژه). .TP \fBdebug\fP امکان نمایش ردگیری خطا (traceback) در مرورگر و اشکال‌زدایی تعاملی در طول فرایند توسعه را فعال می‌کند. .UNINDENT .sp \fBهشدار:\fP .INDENT 0.0 .INDENT 3.5 \fBapp\fP یک نام متغیر رزروشده برای آن بخش از پیکربندی است، بنابراین مطمئن شوید که آن را بازنویسی نکنید. .UNINDENT .UNINDENT .sp \fBهشدار:\fP .INDENT 0.0 .INDENT 3.5 اطمینان حاصل کنید که مقدار \fBdebug\fP در محیط‌های عملیاتی \fIهمیشه\fP روی \fBFalse\fP تنظیم شده باشد. .UNINDENT .UNINDENT .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 قالب پایه برنامه \%<#\:app-template> .UNINDENT .UNINDENT .UNINDENT.SS "پیکربندی سرور (Server Configuration)" .sp Pecan مقادیر پیش‌فرض معقولی را ارائه می‌دهد. این مقادیر را تغییر دهید تا میزبان و درگاهی که برنامهٔ WSGI شما روی آن سرویس‌دهی می‌شود، دگرگون گردند. .INDENT 0.0 .INDENT 3.5 .sp .EX server = { \(aqport\(aq : \(aq8080\(aq, \(aqhost\(aq : \(aq0.0.0.0\(aq } .EE .UNINDENT .UNINDENT .SS "پیکربندی‌های اضافی (Additional Configuration)" .sp ممکن است برنامهٔ شما در زمان اجرا به مقادیر پیکربندی دیگری (مانند اطلاعات احراز هویت API شخص ثالث) نیاز داشته باشد. این تنظیمات را در بلوک‌های اختصاصی خودشان در فایل پیکربندی قرار دهید. .INDENT 0.0 .INDENT 3.5 .sp .EX twitter = { \(aqapi_key\(aq : \(aqFOO\(aq, \(aqapi_secret\(aq : \(aqSECRET\(aq } .EE .UNINDENT .UNINDENT .SS "دسترسی به پیکربندی در زمان اجرا (Accessing Configuration at Runtime)" .sp شما می‌توانید در زمان اجرا از طریق \fBpecan.conf\fP\& به هر مقدار پیکربندی دسترسی داشته باشید. این موارد شامل مقادیر سفارشی، مقادیر مربوط به برنامه و مقادیر خاص سرور است. .sp برای مثال، اگر نیاز به تعیین یک مدیر (administrator) سراسری داشتید، می‌توانید این کار را به این صورت در فایل پیکربندی انجام دهید: .INDENT 0.0 .INDENT 3.5 .sp .EX administrator = \(aqfoo_bar_user\(aq .EE .UNINDENT .UNINDENT .sp و در \fBpecan.conf\fP به این شکل قابل دسترسی خواهد بود: .INDENT 0.0 .INDENT 3.5 .sp .EX >>> from pecan import conf >>> conf.administrator \(aqfoo_bar_user\(aq .EE .UNINDENT .UNINDENT .SS "تبدیل به دیکشنری (Dictionary Conversion)" .sp در شرایط خاصی ممکن است بخواهید با کلیدها و مقادیر دقیقاً در قالب دیکشنری رفتار کنید. شیء \fBConfig\fP \%<#\:pecan\:.configuration\:.Config> دارای یک متد کمکی برای این منظور است که یک نمایش دیکشنری از پیکربندی، شامل مقادیر تو در تو را بازمی‌گرداند. .sp در ادامه نحوهٔ دسترسی به متد \fBto_dict()\fP \%<#\:pecan\:.configuration\:.Config\:.to_dict> و آنچه به عنوان نتیجه بازمی‌گرداند (جهت اختصار کوتاه شده است) آورده شده است: .INDENT 0.0 .INDENT 3.5 .sp .EX >>> from pecan import conf >>> conf Config({\(aqapp\(aq: Config({\(aqerrors\(aq: {}, \(aqtemplate_path\(aq: \(aq\(aq, \(aqstatic_root\(aq: \(aqpublic\(aq, [...] >>> conf.to_dict() {\(aqapp\(aq: {\(aqerrors\(aq: {}, \(aqtemplate_path\(aq: \(aq\(aq, \(aqstatic_root\(aq: \(aqpublic\(aq, [...] .EE .UNINDENT .UNINDENT.SS افزودن پیشوند به کلیدهای دیکشنری (Prefixing Dictionary Keys) .sp \fBto_dict()\fP \%<#\:pecan\:.configuration\:.Config\:.to_dict> به شما این امکان را می‌دهد که در صورت نیاز به افزودن پیشوند به کلیدها در دیکشنری بازگردانده‌شده، یک آرگومان رشته‌ای اختیاری ارسال کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX >>> from pecan import conf >>> conf Config({\(aqapp\(aq: Config({\(aqerrors\(aq: {}, \(aqtemplate_path\(aq: \(aq\(aq, \(aqstatic_root\(aq: \(aqpublic\(aq, [...] >>> conf.to_dict(\(aqprefixed_\(aq) {\(aqprefixed_app\(aq: {\(aqprefixed_errors\(aq: {}, \(aqprefixed_template_path\(aq: \(aq\(aq, \(aqprefixed_static_root\(aq: \(aqprefixed_public\(aq, [...] .EE .UNINDENT .UNINDENT .SS کلیدهای نقطه‌دار، شناسه‌های غیرپایتونی و دیکشنری‌های بومی (Dotted Keys, Non\-Python Identifiers, and Native Dictionaries) .sp گاهی اوقات می‌خواهید یک گزینهٔ پیکربندی را مشخص کنید که شامل کلیدهای نقطه‌دار است یا یک شناسهٔ معتبر در Python نیست، مانند \fB()\fP\&. این شرایط به‌ویژه هنگام پیکربندی logging در Python رایج است. با ارسال یک کلید ویژه، یعنی \fB__force_dict__\fP، می‌توان با بلوک‌های پیکربندی مجزا مانند دیکشنری‌های بومی رفتار کرد. .INDENT 0.0 .INDENT 3.5 .sp .EX logging = { \(aqroot\(aq: {\(aqlevel\(aq: \(aqINFO\(aq, \(aqhandlers\(aq: [\(aqconsole\(aq]}, \(aqloggers\(aq: { \(aqsqlalchemy.engine\(aq: {\(aqlevel\(aq: \(aqINFO\(aq, \(aqhandlers\(aq: [\(aqconsole\(aq]}, \(aq__force_dict__\(aq: True }, \(aqformatters\(aq: { \(aqcustom\(aq: { \(aq()\(aq: \(aqmy.package.customFormatter\(aq } } } from myapp import conf assert isinstance(conf.logging.loggers, dict) assert isinstance(conf.logging.loggers[\(aqsqlalchemy.engine\(aq], dict) .EE .UNINDENT .UNINDENT .SH "امنیت و احراز هویت (SECURITY AND AUTHENTICATION)" .sp Pecan هیچ پشتیبانی از پیش‌آماده‌ای برای احراز هویت ارائه نمی‌دهد، اما ابزارهای لازم را فراهم می‌کند تا بتوانید احراز هویت و مجوزدهی را بر اساس نیاز خود مدیریت کنید. .SS مبانی دکوراتور \fBsecure\fP (secure Decorator Basics) .sp می‌توانید با استفاده از دکوراتور \fBsecure()\fP \%<#\:pecan\:.secure\:.secure>، کل زیردرخت‌های کنترلر \fIیا\fP فراخوانی متدهای مجزا را تحت کنترل دسترسی قرار دهید. .sp برای اعمال دکوراتور روی یک متد، از یک آرگومان استفاده کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX secure(\(aq\(aq) .EE .UNINDENT .UNINDENT .sp برای ایمن‌سازی یک کلاس، آن را با دو آرگومان فراخوانی کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX secure(object_instance, \(aq\(aq) .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.secure import secure class HighlyClassifiedController(object): pass class UnclassifiedController(object): pass class RootController(object): @classmethod def check_permissions(cls): if user_is_admin(): return True return False @expose() def index(self): # # This controller is unlocked to everyone, # and will not run any security checks. # return dict() @secure(\(aqcheck_permissions\(aq) @expose() def topsecret(self): # # This controller is top\-secret, and should # only be reachable by administrators. # return dict() highly_classified = secure(HighlyClassifiedController(), \(aqcheck_permissions\(aq) unclassified = UnclassifiedController() .EE .UNINDENT .UNINDENT.SS \fBSecureController\fP .sp به‌عنوان یک راهکار جایگزین، همین قابلیت را می‌توان با ایجاد زیرکلاس از \fBSecureController\fP \%<#\:pecan\:.secure\:.SecureController>\& متعلق به Pecan نیز پیاده‌سازی کرد. پیاده‌سازی‌های \fBSecureController\fP \%<#\:pecan\:.secure\:.SecureController> باید متد کلاسی \fBcheck_permissions()\fP \%<#\:pecan\:.secure\:.SecureControllerBase\:.check_permissions> را گسترش دهند تا اگر کاربر دسترسی‌های لازم به شاخهٔ کنترلر را دارد، مقدار \fBTrue\fP و در غیر این صورت مقدار \fBFalse\fP را برگرداند. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.secure import SecureController, unlocked class HighlyClassifiedController(object): pass class UnclassifiedController(object): pass class RootController(SecureController): @classmethod def check_permissions(cls): if user_is_admin(): return True return False @expose() @unlocked def index(self): # # This controller is unlocked to everyone, # and will not run any security checks. # return dict() @expose() def topsecret(self): # # This controller is top\-secret, and should # only be reachable by administrators. # return dict() highly_classified = HighlyClassifiedController() unclassified = unlocked(UnclassifiedController()) .EE .UNINDENT .UNINDENT .sp همچنین به استفاده از دکوراتور \fBunlocked()\fP \%<#\:pecan\:.secure\:.unlocked> در مثال بالا توجه کنید؛ از این دکوراتور می‌توان به شیوه‌ای مشابه برای باز کردن صریح دسترسی همگانی به یک کنترلر بدون هیچ‌گونه بررسی امنیتی استفاده کرد. .SS "نوشتن متدهای احراز هویت/مجوزدهی (Writing Authentication/Authorization Methods)" .sp متد \fBcheck_permissions()\fP \%<#\:pecan\:.secure\:.SecureControllerBase\:.check_permissions> باید برای تعیین وضعیت احراز هویت و مجوزدهی کاربر به کار رود. کدی که در اینجا پیاده‌سازی می‌کنید می‌تواند از بررسی‌های سادهٔ نشست (کاربر فعلی به عنوان مدیر سیستم احراز هویت شده است) تا اتصال به یک سرویس LDAP متغیر باشد. .SS "اطلاعات بیشتر دربارهٔ \fBsecure\fP (More on \fBsecure\fP)" .sp متد \fBsecure()\fP \%<#\:pecan\:.secure\:.secure> کاربردهای پیشرفتهٔ گوناگونی دارد که به شما امکان می‌دهد خط‌مشی‌های امنیتی پایداری برای برنامهٔ خود تعریف کنید. .sp نخست، می‌توانید نام یک متد کلاس یا یک متد نمونه از کنترلر را در قالب یک رشته ارسال کنید تا به عنوان متد \fBcheck_permissions()\fP \%<#\:pecan\:.secure\:.SecureControllerBase\:.check_permissions> استفاده شود. متدهای نمونه به‌ویژه در صورتی کاربرد دارند که بخواهید دسترسی به ویژگی‌های نمونه‌ای از یک مدل را اعتبارسنجی کنید. مثال زیر از یک فایل‌سیستم مجازی پایه را در نظر بگیرید. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.secure import secure from myapp.session import get_current_user from myapp.model import FileObject class FileController(object): def __init__(self, name): self.file_object = FileObject(name) def read_access(self): self.file_object.read_access(get_current_user()) def write_access(self): self.file_object.write_access(get_current_user()) @secure(\(aqwrite_access\(aq) @expose() def upload_file(self): pass @secure(\(aqread_access\(aq) @expose() def download_file(self): pass class RootController(object): @expose() def _lookup(self, name, *remainder): return FileController(name), remainder .EE .UNINDENT .UNINDENT .sp متد \fBsecure()\fP \%<#\:pecan\:.secure\:.secure> همچنین یک آرگومان از نوع تابع می‌پذیرد. هنگام ارسال یک تابع، اطمینان حاصل کنید که تابع مورد نظر از فایلی دیگر وارد شده باشد یا در همان فایل پیش از تعریف کلاس تعریف شده باشد، در غیر این صورت احتمالاً در زمان وارد کردن ماژول با خطا مواجه خواهید شد. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.secure import secure from myapp.auth import user_authenitcated class RootController(object): @secure(user_authenticated) @expose() def index(self): return \(aqLogged in\(aq .EE .UNINDENT .UNINDENT .sp همچنین می‌توانید از متد \fBsecure()\fP \%<#\:pecan\:.secure\:.secure> برای تغییر رفتار یک \fBSecureController\fP \%<#\:pecan\:.secure\:.SecureController>\& استفاده کنید. دکوریت کردن یک متد یا بسته‌بندی (wrap) یک زیرکنترلر به Pecan اعلام می‌کند که به جای متد پیش‌فرض کنترلر، از یک تابع امنیتی دیگر استفاده کند. این قابلیت برای شرایطی که به سطح یا نوع متفاوتی از امنیت نیاز دارید بسیار مفید است. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.secure import SecureController, secure from myapp.auth import user_authenticated, admin_user class ApiController(object): pass class RootController(SecureController): @classmethod def check_permissions(cls): return user_authenticated() @classmethod def check_api_permissions(cls): return admin_user() @expose() def index(self): return \(aqlogged in user\(aq api = secure(ApiController(), \(aqcheck_api_permissions\(aq) .EE .UNINDENT .UNINDENT .sp در مثال بالا، Pecan \fIتنها\fP زمانی \fBadmin_user()\fP را فراخوانی می‌کند که درخواستی برای \fB/api/\fP ثبت شود..SS "چندین کنترل‌کننده امن (Multiple Secure Controllers)" .sp کنترل‌کننده‌های امن را می‌توان به‌صورت تودرتو قرار داد تا سطوح امنیتی افزایشی را روی کنترل‌کننده‌های فرعی فراهم کنند. در مثال زیر، هنگامی که درخواستی برای \fB/admin/index/\fP ثبت می‌شود، Pecan ابتدا \fBcheck_permissions()\fP \%<#\:pecan\:.secure\:.SecureControllerBase\:.check_permissions> را روی \fBRootController\fP و سپس \fBcheck_permissions()\fP \%<#\:pecan\:.secure\:.SecureControllerBase\:.check_permissions> را روی \fBAdminController\fP فراخوانی می‌کند\&. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.secure import SecureController from myapp.auth import user_logged_in, is_admin class AdminController(SecureController): @classmethod def check_permissions(cls): return is_admin() @expose() def index(self): return \(aqadmin dashboard\(aq class RootController(SecureController): @classmethod def check_permissions(cls): return user_logged_in @expose() def index(self): return \(aquser dashboard\(aq .EE .UNINDENT .UNINDENT .SH "قلاب‌های PECAN (PECAN HOOKS)" .sp اگرچه استفاده از میان‌افزار WSGI با Pecan آسان است، اما دسترسی به بخش‌های درونی Pecan از داخل میان‌افزار می‌تواند دشوار (گاهی غیرممکن) باشد. قلاب‌های Pecan راهکاری برای تعامل با این چارچوب کاری بدون نیاز به نوشتن میان‌افزار جداگانه هستند. .sp قلاب‌ها به شما این امکان را می‌دهند که کد خود را در نقاط کلیدی در طول چرخه حیات درخواست خود اجرا کنید: .INDENT 0.0 .IP \(bu 2 \fBon_route()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_route>: پیش از اینکه Pecan برای مسیریابی یک درخواست به یک کنترل‌کننده تلاش کند، فراخوانی می‌شود .IP \(bu 2 \fBbefore()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.before>: پس از مسیریابی، اما پیش از اجرای کد کنترل‌کننده فراخوانی می‌شود .IP \(bu 2 \fBafter()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.after>: پس از اجرای کد کنترل‌کننده فراخوانی می‌شود .IP \(bu 2 \fBon_error()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_error>: هنگامی که یک درخواست یک استثنا ایجاد کند، فراخوانی می‌شود .UNINDENT .SS "پیاده‌سازی قلاب PECAN (Implementating a Pecan Hook)" .sp در مثال زیر، یک قلاب ساده اطلاعاتی درباره درخواست جمع‌آوری کرده و آن را در \fBstdout\fP چاپ می‌کند\&. .sp پیاده‌سازی قلاب شما باید \fBPecanHook\fP \%<#\:pecan\:.hooks\:.PecanHook> را وارد (import) کند تا بتواند به‌عنوان کلاس پایه استفاده شود. از آنجا، می‌توانید متدهای \fBon_route()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_route>، \fBbefore()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.before>، \fBafter()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.after> یا \fBon_error()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_error> را برای تعریف رفتار مورد نظر بازنویسی کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan.hooks import PecanHook class SimpleHook(PecanHook): def before(self, state): print \(dq\enabout to enter the controller...\(dq def after(self, state): print \(dq\enmethod: \et %s\(dq % state.request.method print \(dq\enresponse: \et %s\(dq % state.response.status .EE .UNINDENT .UNINDENT .sp به هر یک از متدهای \fBon_route()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_route>، \fBbefore()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.before> و \fBafter()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.after> یک شیء وضعیت مشترک ارسال می‌شود که شامل اطلاعات مفیدی است؛ از جمله اشیاء request و response، و اینکه کدام کنترل‌کننده توسط مسیریابی Pecan انتخاب شده است: .INDENT 0.0 .INDENT 3.5 .sp .EX class SimpleHook(PecanHook): def on_route(self, state): print \(dq\enabout to map the URL to a Python method (controller)...\(dq assert state.controller is None # Routing hasn\(aqt occurred yet assert isinstance(state.request, webob.Request) assert isinstance(state.response, webob.Response) assert isinstance(state.hooks, list) # A list of hooks to apply def before(self, state): print \(dq\enabout to enter the controller...\(dq if state.request.path == \(aq/\(aq: # # \(gastate.controller\(ga is a reference to the actual # \(ga@pecan.expose()\(ga\-ed controller that will be routed to # and used to generate the response body # assert state.controller.__func__ is RootController.index.__func__ assert isinstance(state.arguments, inspect.Arguments) print state.arguments.args print state.arguments.varargs print state.arguments.keywords assert isinstance(state.request, webob.Request) assert isinstance(state.response, webob.Response) assert isinstance(state.hooks, list) .EE .UNINDENT .UNINDENT .sp به \fBon_error()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_error> یک شیء وضعیت مشترک \fBو\fP استثنای اصلی پاس داده می‌شود. اگر یک گرداننده \fBon_error()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_error> یک شیء Response برگرداند، این پاسخ به کاربر نهایی تحویل داده می‌شود و هیچ قلاب \fBon_error()\fP \%<#\:pecan\:.hooks\:.PecanHook\:.on_error> دیگری اجرا نخواهد شد: .INDENT 0.0 .INDENT 3.5 .sp .EX class CustomErrorHook(PecanHook): def on_error(self, state, exc): if isinstance(exc, SomeExceptionType): return webob.Response(\(aqCustom Error!\(aq, status=500) .EE .UNINDENT .UNINDENT.SS اتصال قلاب‌ها (Attaching Hooks) .sp قلاب‌ها می‌توانند در سطح کل پروژه با تعیین فهرستی از قلاب‌ها در فایل پیکربندی پروژه‌تان ضمیمه شوند. .INDENT 0.0 .INDENT 3.5 .sp .EX app = { \(aqroot\(aq : \(aq...\(aq # ... \(aqhooks\(aq: lambda: [SimpleHook()] } .EE .UNINDENT .UNINDENT .sp همچنین می‌توان با استفاده از ویژگی \fB__hooks__\fP در یک یا چند کنترلر و ارث‌بری از \fBHookController\fP \%<#\:pecan\:.hooks\:.HookController>\&، قلاب‌ها را به‌صورت انتخابی روی کنترلرها و زیرکنترلرهای آن‌ها اعمال کرد. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.hooks import HookController from my_hooks import SimpleHook class SimpleController(HookController): __hooks__ = [SimpleHook()] @expose(\(aqjson\(aq) def index(self): print \(dqDO SOMETHING!\(dq return dict() .EE .UNINDENT .UNINDENT .sp اکنون که \fBSimpleHook\fP اضافه شده است، بیایید ببینیم هنگام اجرای برنامه و باز کردن آن در مرورگر وب چه رخ می‌دهد. .INDENT 0.0 .INDENT 3.5 .sp .EX pecan serve config.py serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 about to enter the controller... DO SOMETHING! method: GET response: 200 OK .EE .UNINDENT .UNINDENT .sp قلاب‌ها می‌توانند از کلاس والد یا mixinها به ارث برده شوند. فقط مطمئن شوید که از \fBHookController\fP \%<#\:pecan\:.hooks\:.HookController>\& ارث‌بری می‌کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from pecan.hooks import PecanHook, HookController class ParentHook(PecanHook): priority = 1 def before(self, state): print \(dq\enabout to enter the parent controller...\(dq class CommonHook(PecanHook): priority = 2 def before(self, state): print \(dq\enjust a common hook...\(dq class SubHook(PecanHook): def before(self, state): print \(dq\enabout to enter the subcontroller...\(dq class SubMixin(object): __hooks__ = [SubHook()] # We\(aqll use the same instance for both controllers, # to avoid double calls common = CommonHook() class SubController(HookController, SubMixin): __hooks__ = [common] @expose(\(aqjson\(aq) def index(self): print \(dq\enI AM THE SUB!\(dq return dict() class RootController(HookController): __hooks__ = [common, ParentHook()] @expose(\(aqjson\(aq) def index(self): print \(dq\enI AM THE ROOT!\(dq return dict() sub = SubController() .EE .UNINDENT .UNINDENT .sp بیایید ببینیم با اجرای برنامه چه اتفاقی می‌افتد. ابتدا بارگذاری کنترلر ریشه: .INDENT 0.0 .INDENT 3.5 .sp .EX pecan serve config.py serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 GET / HTTP/1.1\(dq 200 about to enter the parent controller... just a common hook I AM THE ROOT! .EE .UNINDENT .UNINDENT .sp سپس بارگذاری زیرکنترلر: .INDENT 0.0 .INDENT 3.5 .sp .EX pecan serve config.py serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 GET /sub HTTP/1.1\(dq 200 about to enter the parent controller... just a common hook about to enter the subcontroller... I AM THE SUB! .EE .UNINDENT .UNINDENT .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 مطمئن شوید مقادیر اولویت (priority) مناسبی برای قلاب‌های تو‌در‌تو تنظیم کرده‌اید تا با ترتیب مورد نظر اجرا شوند. .UNINDENT .UNINDENT .sp \fBهشدار:\fP .INDENT 0.0 .INDENT 3.5 اگر دو قلاب از یک نوع، به‌صورت نمونه‌های متفاوتی به یک کنترلر والد و فرزند ارسال شوند، دو بار اضافه/اجرا خواهند شد. اگر به‌صورت یک متغیر نمونه ارسال شوند \- برای هر دو کنترلر تنها یک بار فراخوانی خواهند شد. .UNINDENT .UNINDENT.SS قلاب‌های همراه با Pecan .sp Pecan شامل چند قلاب در هستهٔ خود است. این بخش کاربردهای مختلف آن‌ها، نحوهٔ پیکربندی و نمونه‌هایی از سناریوهای رایج را شرح می‌دهد. .SS RequestViewerHook .sp این قلاب برای اهداف اشکال‌زدایی مفید است. این قلاب به تمام صفت‌های شیء \fBresponse\fP به‌علاوهٔ چند صفت دیگر که مختص این فریم‌ورک هستند دسترسی دارد. .sp دو روش اصلی وجود دارد که این قلاب می‌تواند اطلاعات مربوط به یک درخواست را ارائه دهد: .INDENT 0.0 .IP 1. 3 خروجی ترمینال یا ثبت وقایع (از طریق یک جریان شبه‌فایل مانند \fBstdout\fP) .IP 2. 3 کلیدهای سفارشی سرایند در پاسخ واقعی. .UNINDENT .sp به‌طور پیش‌فرض، هر دو خروجی فعال هستند. .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 pecan.hooks \-\- قلاب‌های Pecan \%<#\:pecan-hooks> .UNINDENT .UNINDENT .UNINDENT .SS پیکربندی RequestViewerHook .sp چندین روش برای پیکربندی مناسب و اجرای این قلاب وجود دارد. با این حال، دانستن این نکته مفید است که برای راه‌اندازی و اجرای آن به هیچ پیکربندی اولیه‌ای نیاز نیست. .sp به‌طور پیش‌فرض، اطلاعات مربوط به این موارد را خروجی می‌دهد: .INDENT 0.0 .IP \(bu 2 path : نشانی url استفاده‌شده برای ایجاد این پاسخ را نمایش می‌دهد .IP \(bu 2 status : پاسخ دریافتی از سرور (مانند \(aq200 OK\(aq) .IP \(bu 2 method : متد درخواست (مانند \(aqGET\(aq، \(aqPOST\(aq، \(aqPUT یا \(aqDELETE\(aq) .IP \(bu 2 controller : متد کنترل‌کنندهٔ واقعی در Pecan که مسئول پاسخ است .IP \(bu 2 params : فهرستی از تاپل‌ها برای پارامترهای ارائه‌شده در زمان درخواست .IP \(bu 2 hooks : هر قلابی که در برنامه استفاده شده باشد در اینجا فهرست خواهد شد. .UNINDENT .sp پیکربندی پیش‌فرض این مقادیر را از طریق \fBstdout\fP در ترمینال نمایش می‌دهد و همچنین آن‌ها را به سرایندهای پاسخ (به فرم \fBX\-Pecan\-item_name\fP) اضافه می‌کند. .sp خروجی ترمینال برای یک درخواست \fI/favicon.ico\fP ممکن است به این شکل باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX path \- /favicon.ico status \- 404 Not Found method \- GET controller \- The resource could not be found. params \- [] hooks \- [\(aqRequestViewerHook\(aq] .EE .UNINDENT .UNINDENT .sp در مورد بالا، فایل پیدا نشد و اطلاعات در \fIstdout\fP چاپ شد\&. علاوه بر این، سرایندهای زیر در پاسخ HTTP حضور خواهند داشت: .INDENT 0.0 .INDENT 3.5 .sp .EX X\-Pecan\-path /favicon.ico X\-Pecan\-status 404 Not Found X\-Pecan\-method GET X\-Pecan\-controller The resource could not be found. X\-Pecan\-params [] X\-Pecan\-hooks [\(aqRequestViewerHook\(aq] .EE .UNINDENT .UNINDENT .sp دیکشنری پیکربندی انعطاف‌پذیر است (هیچ‌یک از کلیدها الزامی نیستند) و می‌تواند شامل دو کلید باشد: \fBitems\fP و \fBblacklist\fP\&. .sp در صورتی که قلاب مستقیماً پیکربندی شود، به این صورت خواهد بود (برای اختصار کوتاه شده است): .INDENT 0.0 .INDENT 3.5 .sp .EX \&... \(aqhooks\(aq: lambda: [ RequestViewerHook({\(aqitems\(aq:[\(aqpath\(aq]}) ] .EE .UNINDENT .UNINDENT.SS تغییر قالب خروجی (Modifying Output Format) .sp فهرست \fBitems\fP اطلاعاتی را مشخص می‌کند که هوک بازمی‌گرداند. گاهی اوقات با توجه به نیاز توسعه، به بخش خاصی از اطلاعات یا دسته‌ای از آن‌ها نیاز خواهید داشت؛ از این رو لازم است مقادیر پیش‌فرض تغییر کرده و فهرستی از موارد مشخص شود. .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 هنگام مشخص کردن فهرستی از موارد، این فهرست مقادیر پیش‌فرض را کاملاً لغو (override) می‌کند؛ بنابراین اگر تنها یک مورد مشخص شود، فقط همان مورد توسط هوک بازگردانده خواهد شد. .UNINDENT .UNINDENT .sp هوک به تک‌تک مشخصه‌های شیء درخواست (request object) دسترسی دارد و دسترسی آن فقط محدود به موارد پیش‌فرضی که نمایش داده می‌شوند نیست؛ بنابراین می‌توانید اطلاعات نمایش‌داده‌شده را با دقت تنظیم کنید. .sp این فهرستی است شامل تمام مشخصه‌های ممکنی که هوک به آن‌ها دسترسی دارد (مستقیماً از \fIwebob\fP): .TS box center; l|l. T{ T} T{ T} _ T{ accept T} T{ make_tempfile T} _ T{ accept_charset T} T{ max_forwards T} _ T{ accept_encoding T} T{ method T} _ T{ accept_language T} T{ params T} _ T{ application_url T} T{ path T} _ T{ as_string T} T{ path_info T} _ T{ authorization T} T{ path_info_peek T} _ T{ blank T} T{ path_info_pop T} _ T{ body T} T{ path_qs T} _ T{ body_file T} T{ path_url T} _ T{ body_file_raw T} T{ postvars T} _ T{ body_file_seekable T} T{ pragma T} _ T{ cache_control T} T{ query_string T} _ T{ call_application T} T{ queryvars T} _ T{ charset T} T{ range T} _ T{ content_length T} T{ referer T} _ T{ content_type T} T{ referrer T} _ T{ cookies T} T{ relative_url T} _ T{ copy T} T{ remote_addr T} _ T{ copy_body T} T{ remote_user T} _ T{ copy_get T} T{ remove_conditional_headers T} _ T{ date T} T{ request_body_tempfile_limit T} _ T{ decode_param_names T} T{ scheme T} _ T{ environ T} T{ script_name T} _ T{ from_file T} T{ server_name T} _ T{ from_string T} T{ server_port T} _ T{ get_response T} T{ str_GET T} _ T{ headers T} T{ str_POST T} _ T{ host T} T{ str_cookies T} _ T{ host_url T} T{ str_params T} _ T{ http_version T} T{ str_postvars T} _ T{ if_match T} T{ str_queryvars T} _ T{ if_modified_since T} T{ unicode_errors T} _ T{ if_none_match T} T{ upath_info T} _ T{ if_range T} T{ url T} _ T{ if_unmodified_since T} T{ urlargs T} _ T{ is_body_readable T} T{ urlvars T} _ T{ is_body_seekable T} T{ uscript_name T} _ T{ is_xhr T} T{ user_agent T} _ T{ make_body_seekable T} T{ T} .TE.TE .sp و این‌ها موارد خاصی از Pecan و hook هستند: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 controller .IP \(bu 2 hooks .IP \(bu 2 params (در واقع params از طریق \fIwebob\fP در دسترس است، اما برای خوانایی بهتر توسط hook تجزیه می‌شود) .UNINDENT .UNINDENT .UNINDENT .SS "قرار دادن مسیرهای خاص در فهرست سیاه (Blacklisting Certain Paths)" .sp گاهی اوقات دریافت اطلاعات دربارهٔ \fIتک‌تک\fP درخواست‌ها آزاردهنده است. برای محدود کردن خروجی، فهرست مسیرهای URL که نمی‌خواهید داده‌های آن‌ها دریافت شود را در قالب \fBblacklist\fP ارسال کنید. .sp تطبیق در ابتدای مسیر URL انجام می‌شود، بنابراین هنگام استفاده از این ویژگی احتیاط کنید. برای مثال، اگر پیکربندی را به این صورت ارسال کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX { \(aqblacklist\(aq: [\(aq/f\(aq] } .EE .UNINDENT .UNINDENT .sp این کار هیچ URLی را که با \fBf\fP آغاز شود نشان نخواهد داد، و عملاً شبیه به یک عبارت باقاعده با تطبیق الگو (globbing) عمل می‌کند (اما نه به آن اندازه قدرتمند). .sp برای هر تعداد مسدودسازی که نیاز دارید، کافی است موارد دلخواه خود را به تعداد نیاز اضافه کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX { \(aqblacklist\(aq : [\(aq/favicon.ico\(aq, \(aq/javascript\(aq, \(aq/images\(aq] } .EE .UNINDENT .UNINDENT .sp مجدداً یادآوری می‌شود که کلید \fBblacklist\fP می‌تواند همراه با کلید \fBitems\fP استفاده شود یا نشود (استفاده از آن اجباری نیست). .SH "سریال‌سازی JSON (JSON SERIALIZATION)" .sp Pecan شامل سامانه‌ای ساده و با استفادهٔ آسان برای تولید و ارائهٔ JSON است. برای شروع، فایلی به نام \fBjson.py\fP در پروژهٔ خود بسازید و آن را در \fBapp.py\fP پروژه‌تان وارد (import) کنید. .sp ماژول \fBjson\fP شما شامل مجموعه‌ای از قوانین برای تولید JSON از اشیایی خواهد بود که در کنترلر خود برمی‌گردانید. .sp فرض کنید در برنامهٔ Pecan خود کنترلری داریم که می‌خواهیم از آن برای بازگرداندن خروجی JSON برای یک شیء \fBUser\fP استفاده کنیم: .INDENT 0.0 .INDENT 3.5 .sp .EX from myproject.lib import get_current_user class UsersController(object): @expose(\(aqjson\(aq) def current_user(self): \(aq\(aq\(aq return an instance of myproject.model.User which represents the current authenticated user \(aq\(aq\(aq return get_current_user() .EE .UNINDENT .UNINDENT .sp برای کارکرد درست این کنترلر، Pecan باید بداند چگونه شیء \fBUser\fP را به انواع داده‌های سازگار با JSON تبدیل کند. یکی از روش‌ها برای مشخص کردن نحوهٔ تبدیل شیء به JSON برای Pecan، تعریف یک قاعده در \fBjson.py\fP است: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan.jsonify import jsonify from myproject import model @jsonify.register(model.User) def jsonify_user(user): return dict( name = user.name, email = user.email, birthday = user.birthday.isoformat() ) .EE .UNINDENT .UNINDENT .sp در این مثال، هنگامی که نمونه‌ای از کلاس \fBmodel.User\fP از کنترلری که برای بازگرداندن JSON پیکربندی شده است بازگردانده می‌شود، قاعدهٔ \fBjsonify_user()\fP برای تبدیل شیء به داده‌های سازگار با JSON فراخوانی خواهد شد. توجه داشته باشید که این قاعده یک رشتهٔ JSON تولید نمی‌کند، بلکه یک دیکشنری پایتون تولید می‌کند که فقط شامل انواع داده‌های سازگار با JSON است. .sp به عنوان روشی جایگزین، می‌توان قاعده را روی خود شیء و با تعیین متد \fB__json__()\fP در کلاس مشخص کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX class User(object): def __init__(self, name, email, birthday): self.name = name self.email = email self.birthday = birthday def __json__(self): return dict( name = self.name, email = self.email, birthday = self.birthday.isoformat() ) .EE .UNINDENT .UNINDENT .sp مزیت استفاده از ماژول \fBjson.py\fP این است که تمام قوانین JSON شما در یک مکان متمرکز تعریف می‌شوند، اما برخی پروژه‌ها سادگی پیوسته‌بودن مستقیم قوانین JSON به اشیاء مدل خود را ترجیح می‌دهند..SH "متغیرهای محلی زمینه/نخ در برابر ارسال صریح آرگومان (CONTEXT/THREAD-LOCALS VS. EXPLICIT ARGUMENT PASSING)" .sp در هر برنامه pecan، متغیرهای سطح ماژول \fBpecan.request\fP و \fBpecan.response\fP اشیای پراکسی هستند که همیشه به درخواست و پاسخی که در نخ جاری پردازش می‌شود اشاره دارند. .sp این \fIمحلی‌بودن نخ\fP (thread locality) تضمین می‌کند که می‌توانید در یک محیط چندنخی (multi\-threaded) بدون نیاز به دست‌به‌دست کردن مداوم ارجاعات اشیا در کد خود، به‌طور ایمن به یک ارجاع سراسری به درخواست و پاسخ جاری دسترسی داشته باشید؛ این قابلیتی در pecan است که نوشتن برنامه‌های وب سنتی را ساده‌تر و کم‌حجم‌تر می‌کند. .sp برخی افراد بر این باورند که متغیرهای محلی نخ بیش از حد ضمنی یا جادویی هستند، و ارسال صریح ارجاع در طولانی‌مدت بسیار واضح‌تر و نگهداری‌پذیرتر است. علاوه‌بر این، پیاده‌سازی پیش‌فرض ارائه‌شده توسط pecan از \fBthreading.local()\fP برای مرتبط ساختن این اشیای پراکسی محلی زمینه با \fIشناسه نخ\fP نخِ سرور جاری استفاده می‌کند. در مدل‌های سرور ناهمگام (asynchronous) \- که در آن‌ها کارهای زیادی برای مدت‌زمان کوتاهی بر روی یک نخِ مشترکِ \fIواحد\fP اجرا می‌شوند \- پشتیبانی از این سازوکار نیازمند مانکی‌پچ (monkeypatching) کردن \fBthreading.local()\fP است تا رفتاری محلی شبیه به greenlet داشته باشد. .SS "غیرفعال‌سازی پراکسی‌های محلی نخ (Disabling Thread-Local Proxies)" .sp اگر مطمئن هستید که \fIنمی‌خواهید\fP از متغیرهای محلی زمینه/نخ در پروژه خود استفاده کنید، می‌توانید با مشخص کردن آرگومان \fBuse_context_locals=False\fP در فایل پیکربندی برنامه‌تان این کار را انجام دهید: .INDENT 0.0 .INDENT 3.5 .sp .EX app = { \(aqroot\(aq: \(aqproject.controllers.root.RootController\(aq, \(aqmodules\(aq: [\(aqproject\(aq], \(aqstatic_root\(aq: \(aq%(confdir)s/public\(aq, \(aqtemplate_path\(aq: \(aq%(confdir)s/project/templates\(aq, \(aqdebug\(aq: True, \(aquse_context_locals\(aq: False } .EE .UNINDENT .UNINDENT .sp علاوه‌بر این، لازم است \fBتمام\fP کنترلرهای pecan خود را به‌روزرسانی کنید تا آرگومان‌های موقعیتی را برای درخواست و پاسخ جاری بپذیرند: .INDENT 0.0 .INDENT 3.5 .sp .EX class RootController(object): @pecan.expose(\(aqjson\(aq) def index(self, req, resp): return dict(method=req.method) # path: / @pecan.expose() def greet(self, req, resp, name): return name # path: /greet/joe .EE .UNINDENT .UNINDENT .sp \fIضروری است\fP که آرگومان‌های درخواست و پاسخ \fBبعد از\fP \fBself\fP و قبل از هرگونه آرگومان موقعیتی فرم قرار گیرند. .SH "PECAN در خط فرمان (COMMAND LINE PECAN)" .sp هر برنامه Pecan را می‌توان با استفاده از دستور درونی \fBpecan\fP از خط فرمان کنترل و بازرسی کرد. مثال‌های استفاده از \fBpecan\fP در این سند به گونه‌ای در نظر گرفته شده‌اند که از دایرکتوری ریشه پروژه شما اجرا شوند. .SS "میزبانی برنامه Pecan برای توسعه (Serving a Pecan App For Development)" .sp نرم‌افزار Pecan همراه با یک سرور توسعه سبک WSGI مبتنی بر ماژول \fBwsgiref.simple_server\fP در پایتون عرضه می‌شود \%\&. .sp میزبانی برنامه Pecan به سادگیِ اجرای دستور \fBpecan serve\fP است: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve config.py Starting server in PID 000. serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 .EE .UNINDENT .UNINDENT .sp و سپس مشاهده آن در مرورگرتان. .sp \fBhost\fP و \fBport\fP سرور در فایل پیکربندی شما مطابق آنچه در Server Configuration \%<#\:server-configuration>\& شرح داده شده است، قابل تغییر است..SS بارگذاری مجدد خودکار با تغییر فایل‌ها .sp ایجاد وقفه برای راه‌اندازی مجدد سرور توسعه در حین کار می‌تواند مخل تمرکز باشد، از این رو \fBpecan serve\fP پرچم \fB\-\-reload\fP را برای تسهیل کار ارائه می‌دهد. .sp برای ارائه این قابلیت، Pecan از کتابخانه پایتون watchdog \% استفاده می‌کند. پیش از ادامه، باید آن را برای استفاده در محیط توسعه نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install watchdog Downloading/unpacking watchdog \&... Successfully installed watchdog .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve \-\-reload config.py Monitoring for changes... Starting server in PID 000. serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 .EE .UNINDENT .UNINDENT .sp در حین کار، Pecan به هرگونه رویداد تغییر فایل یا دایرکتوری در پروژه شما گوش می‌دهد و فرایند سرور را به‌طور بی‌صدا در پس‌زمینه مجدداً راه‌اندازی می‌کند. .SS پوسته تعاملی .sp برنامه‌های Pecan همچنین همراه با یک پوسته تعاملی پایتون ارائه می‌شوند که می‌تواند برای اجرای عبارت‌ها در محیطی بسیار مشابه با محیط اجرای برنامه شما به کار رود. برای فراخوانی یک پوسته تعاملی، از دستور \fBpecan shell\fP استفاده کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan shell config.py Pecan Interactive Shell Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) [GCC 4.2.1 (Based on Apple Inc. build 5658) The following objects are available: wsgiapp \- This project\(aqs WSGI App instance conf \- The current configuration app \- webtest.TestApp wrapped around wsgiapp >>> conf Config({ \(aqapp\(aq: Config({ \(aqroot\(aq: \(aqmyapp.controllers.root.RootController\(aq, \(aqmodules\(aq: [\(aqmyapp\(aq], \(aqstatic_root\(aq: \(aq/Users/somebody/myapp/public\(aq, \(aqtemplate_path\(aq: \(aq/Users/somebody/myapp/project/templates\(aq, \(aqerrors\(aq: {\(aq404\(aq: \(aq/error/404\(aq}, \(aqdebug\(aq: True }), \(aqserver\(aq: Config({ \(aqhost\(aq: \(aq0.0.0.0\(aq, \(aqport\(aq: \(aq8080\(aq }) }) >>> app >>> app.get(\(aq/\(aq) <200 OK text/html body=\(aq\en ...\en\en\(aq/936> .EE .UNINDENT .UNINDENT .sp برای خروج از پوسته تعاملی کلیدهای \fBCtrl\-D\fP (یا در ویندوز \fBCtrl\-Z\fP) را فشار دهید. .SS استفاده از یک پوسته جایگزین .sp دستور \fBpecan shell\fP دارای پشتیبانی اختیاری از پوسته‌های جایگزین IPython \% و bpython \% است که هر یک از آن‌ها را می‌توان با پرچم \fB\-\-shell\fP (یا نام مستعار کوتاه‌شده آن، \fB\-s\fP) مشخص کرد؛ به عنوان مثال: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan shell \-\-shell=ipython config.py $ pecan shell \-s bpython config.py .EE .UNINDENT .UNINDENT.SS پیکربندی از طریق یک متغیر محیطی .sp در تمام مثال‌های نمایش‌داده‌شده، مشاهده خواهید کرد که دستورات \fBpecan\fP یک مسیر فایل را به عنوان فایل پیکربندی می‌پذیرفتند. راهکار جایگزین، مشخص کردن فایل پیکربندی در یک متغیر محیطی (\fBPECAN_CONFIG\fP) است. .sp این کار کاملاً اختیاری است؛ اگر مسیر فایل به‌صورت صریح ارسال شود، Pecan پیش از بررسی متغیر محیطی، آن را در اولویت قرار می‌دهد. .sp برای مثال، جهت ارائه (serve) یک برنامهٔ Pecan، می‌توان متغیری را export کرد و سپس هنگامی که هیچ مسیری مشخص نشده باشد، مجدداً از آن استفاده نمود. .INDENT 0.0 .INDENT 3.5 .sp .EX $ export PECAN_CONFIG=/path/to/app/config.py $ pecan serve Starting server in PID 000. serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 .EE .UNINDENT .UNINDENT .sp توجه داشته باشید که مسیر باید به یک فایل پیکربندی معتبر pecan ارجاع دهد، در غیر این صورت دستور با پیامی مبنی بر نامعتبر بودن مسیر (به عنوان مثال، اگر یک دایرکتوری ارسال شود) با خطا مواجه خواهد شد. .sp اگر \fBPECAN_CONFIG\fP تنظیم نشده باشد و هیچ پیکربندی‌ای ارسال نگردد، دستور با خطا متوقف خواهد شد زیرا قادر به یافتن فایل پیکربندی نخواهد بود. .SS گسترش \fBpecan\fP با دستورات سفارشی .sp اگرچه دستورات بسته‌بندی‌شده همراه Pecan کاربردی هستند، اما سودمندی واقعی ابزارهای خط فرمان آن در قابلیت گسترش‌پذیری نهفته است. بسیار مطلوب است که بتوان یک اسکریپت پایتون نوشت که بتواند «در محیط Pecan» کار کند و به مواردی مانند فایل پیکربندی تجزیه‌شدهٔ برنامه یا یک نمونهٔ شبیه‌سازی‌شده از خود برنامه (مانند نمونهٔ ارائه‌شده در دستور \fBpecan shell\fP) دسترسی داشته باشد. .SS نوشتن یک دستور سفارشی Pecan .sp به عنوان مثال، بیایید دستوری ایجاد کنیم که بتواند یک درخواست شبیه‌سازی‌شدهٔ HTTP GET را به برنامهٔ شما ارسال کرده و نتیجه را چاپ کند. فراخوانی آن از خط فرمان ممکن است شبیه به این باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan wget config.py /path/to/some/resource .EE .UNINDENT .UNINDENT .sp فرض کنید توزیعی دارید که بسته‌ای به نام \fBmyapp\fP در آن قرار دارد و درون این بسته، ماژولی به نام \fBwget.py\fP موجود است: .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/myapp/wget.py import pecan from webtest import TestApp class GetCommand(pecan.commands.BaseCommand): \(aq\(aq\(aq Issues a (simulated) HTTP GET and returns the request body. \(aq\(aq\(aq arguments = pecan.commands.BaseCommand.arguments + ({ \(aqname\(aq: \(aqpath\(aq, \(aqhelp\(aq: \(aqthe URI path of the resource to request\(aq },) def run(self, args): super(GetCommand, self).run(args) app = TestApp(self.load_app()) print app.get(args.path).body .EE .UNINDENT .UNINDENT .sp بیایید این مورد را بخش‌به‌بخش تحلیل کنیم..SS بازنویسی متد \fBrun\fP .sp ابتدا، از \fBBaseCommand\fP \%<#\:pecan\:.commands\:.base\:.BaseCommand> یک زیرکلاس ساخته و متد \fBrun()\fP \%<#\:pecan\:.commands\:.base\:.BaseCommandParent\:.run> را گسترش می‌دهیم تا: .INDENT 0.0 .IP \(bu 2 یک برنامه Pecan را بارگذاری کند \- \fBload_app()\fP \%<#\:pecan\:.core\:.load_app> .IP \(bu 2 آن را در یک محیط ساختگی WSGI قرار دهد \- \fBTestApp\fP \% .IP \(bu 2 یک درخواست HTTP GET به آن ارسال کند \- \fBget()\fP \% .UNINDENT .SS تعریف آرگومان‌های سفارشی .sp مشخصه کلاسی \fBarguments\fP برای تعریف آرگومان‌های خط فرمان مختص به دستور سفارشی شما استفاده می‌شود. در این مثال متوجه خواهید شد که ما به جای بازنویسی کامل، در حال \fIافزودن\fP به فهرست آرگومان‌های ارائه‌شده توسط \fBBaseCommand\fP \%<#\:pecan\:.commands\:.base\:.BaseCommand> (که پیشاپیش یک آرگومان برای \fBconfig_file\fP ارائه می‌دهد) هستیم. .sp قالب مشخصه کلاسی \fBarguments\fP یک \fBtuple\fP \% از دیکشنری‌ها است، که هر دیکشنری نشان‌دهنده تعریف یک آرگومان با همان قالبی است که توسط ماژول \fBargparse\fP پایتون \% پذیرفته می‌شود (به‌طور دقیق‌تر، \fBadd_argument()\fP \%). با ارائه فهرستی از آرگومان‌ها در این قالب، دستور \fBpecan\fP می‌تواند دستورات سفارشی شما را در خروجی راهنما و نحوه استفاده (usage) خود بگنجاند. .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan \-h usage: pecan [\-h] command ... positional arguments: command wget Issues a (simulated) HTTP GET and returns the request body serve Open an interactive shell with the Pecan app loaded ... $ pecan wget \-h usage: pecan wget [\-h] config_file path $ pecan wget config.py /path/to/some/resource .EE .UNINDENT .UNINDENT .sp علاوه بر این، متوجه خواهید شد که خط نخست docstring مربوط به \fBGetCommand\fP \-\- \fBIssues a (simulated) HTTP GET and returns the request body\fP \-\- به‌طور خودکار برای توصیف دستور \fBwget\fP در خروجی \fB$ pecan \-h\fP\& به کار می‌رود. پیروی از این روال به شما اجازه می‌دهد تا به سادگی خلاصه‌ای از دستور خود را در ابزار خط فرمان Pecan ادغام کنید. .SS ثبت یک دستور سفارشی .sp اکنون که دستور سفارشی خود را نوشته‌اید، باید وجود آن را به \fBsetup.py\fP بسته خود اعلام کرده و مجدداً آن را نصب کنید. در فایل \fBsetup.py\fP بسته خود، فراخوانی \fBsetup()\fP\& را خواهید یافت. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/setup.py \&... setup( name=\(aqmyapp\(aq, version=\(aq0.1\(aq, author=\(aqJoe Somebody\(aq, ... ) .EE .UNINDENT .UNINDENT .sp با فرض اینکه از قبل وجود نداشته باشد، آرگومان \fBentry_points\fP را به فراخوانی \fBsetup()\fP اضافه می‌کنیم و یک تعریف \fB[pecan.command]\fP برای دستور سفارشی شما تعیین می‌کنیم: .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/setup.py \&... setup( name=\(aqmyapp\(aq, version=\(aq0.1\(aq, author=\(aqJoe Somebody\(aq, ... entry_points=\(dq\(dq\(dq [pecan.command] wget = myapp.wget:GetCommand \(dq\(dq\(dq ) .EE .UNINDENT .UNINDENT .sp پس از انجام این کار، پروژه خود را در حالت توسعه (development) دوباره نصب کنید تا نقطه ورود جدید ثبت شود. .INDENT 0.0 .INDENT 3.5 .sp .EX $ python setup.py develop .EE .UNINDENT .UNINDENT .sp سپس آن را امتحان کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan wget config.py /path/to/some/resource .EE .UNINDENT .UNINDENT.SH "توسعه محلی برنامه‌های PECAN (DEVELOPING PECAN APPLICATIONS LOCALLY)" .SS "بارگذاری مجدد خودکار با تغییر فایل‌ها (Reloading Automatically as Files Change)" .sp متوقف کردن کار برای راه‌اندازی مجدد سرور توسعه می‌تواند مخل تمرکز باشد، از این رو \fBpecan serve\fP پرچم \fB\-\-reload\fP را برای ساده‌تر کردن کارها فراهم کرده است. .sp برای ارائه این قابلیت، Pecan از کتابخانه پایتون watchdog \% استفاده می‌کند. پیش از ادامه، باید آن را برای استفاده در محیط توسعه نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install watchdog Downloading/unpacking watchdog \&... Successfully installed watchdog .EE .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve \-\-reload config.py Monitoring for changes... Starting server in PID 000. serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 .EE .UNINDENT .UNINDENT .sp همگام با کار شما، Pecan تمام رویدادهای تغییر فایل یا دایرکتوری در پروژه‌تان را زیر نظر گرفته و به‌صورت بی‌صدا فرایند سرور شما را در پس‌زمینه مجدداً راه‌اندازی می‌کند. .SS "اشکال‌زدایی برنامه‌های Pecan (Debugging Pecan Applications)" .sp برنامه Pecan به همراه یک میان‌افزار اشکال‌زدایی ساده برای کمک به عیب‌یابی مشکلات در برنامه‌هایتان ارائه می‌شود. برای فعال‌سازی میان‌افزار اشکال‌زدایی، کافی است پرچم \fBdebug\fP را در فایل پیکربندی خود روی \fBTrue\fP تنظیم کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX app = { ... \(aqdebug\(aq: True, ... } .EE .UNINDENT .UNINDENT .sp پس از فعال‌سازی، در صورت بروز استثناهای زمان اجرا، این میان‌افزار به‌طور خودکار استثناهای صادرشده توسط برنامه را گرفته و ردپای پشته پایتون و محیط WSGI را در مرورگر شما نمایش می‌دهد. .sp برای بهبود اشکال‌زدایی، از جمله پشتیبانی از یک کنسول تعاملی مبتنی بر مرورگر، Pecan از کتابخانه پایتون \fIbacklash \fP استفاده می‌کند. پیش از ادامه، باید آن را برای استفاده در محیط توسعه نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install backlash Downloading/unpacking backlash \&... Successfully installed backlash .EE .UNINDENT .UNINDENT .SS "ارائه فایل‌های ایستا (Serving Static Files)" .sp برنامه Pecan دارای یک میان‌افزار ساده برای سرو کردن CSS، Javascript، تصاویر و سایر فایل‌های ایستا است. می‌توانید با اطمینان از مشخص شدن گزینه‌های زیر در فایل پیکربندی، آن را تنظیم کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX app = { ... \(aqdebug\(aq: True, \(aqstatic_root\(aq: \(aq%(confdir)/public } .EE .UNINDENT .UNINDENT .sp که در آن \fBstatic_root\fP یک مسیر مطلق به دایرکتوری‌ای است که فایل‌های ایستای شما در آن قرار دارند. برای سهولت، این مسیر می‌تواند شامل متغیر \fB%(confdir)\fP باشد که Pecan در زمان اجرا آن را با مسیر مطلق فایل پیکربندی شما جایگزین می‌کند. .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 در محیط عملیاتی (production)، مقدار \fBapp.debug\fP \fIهرگز\fP نباید روی \fBTrue\fP تنظیم شود، بنابراین باید فایل‌های ایستای خود را از طریق وب‌سرور عملیاتی ارائه دهید. .UNINDENT .UNINDENT.SH "استقرار PECAN در محیط عملیاتی (DEPLOYING PECAN IN PRODUCTION)" .sp روش‌های گوناگونی برای استقرار یک پروژهٔ Pecan در یک محیط عملیاتی وجود دارد. مثال‌های زیر با هدف ارائهٔ \fIجهت‌دهی کلی\fP آورده شده‌اند، نه دستورالعمل‌های صریح؛ فرآیند استقرار معمولاً به شدت وابسته به نیازها و اهداف هر برنامه است، بنابراین ممکن است نتیجه برای شما متفاوت باشد. .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 اگرچه Pecan به همراه یک کارگزار ساده \fIبرای استفاده در مرحلهٔ توسعه\fP (\fBpecan serve\fP) عرضه می‌شود، استفاده از یک کارگزار \fIآماده برای محیط عملیاتی (production\-ready)\fP مشابه مواردی که در این سند شرح داده شده‌اند، \fBبه‌شدت توصیه می‌شود\fP\&. .UNINDENT .UNINDENT .SS نصب Pecan .sp چند گزینهٔ محبوب برای نصب Pecan در محیط‌های عملیاتی در دسترس است: .INDENT 0.0 .IP \(bu 2 استفاده از setuptools \%\&. مدیریت Pecan به عنوان یک وابستگی در فایل \fBsetup.py\fP پروژه تا در کنار پروژه نصب شود (برای مثال، \fBpython /path/to/project/setup.py install\fP). پروژهٔ پیش‌فرض Pecan که در Creating Your First Pecan Application \%<#\:quick-start> شرح داده شده است، این فرآیند را با گنجاندن Pecan به عنوان وابستگی پروژهٔ شما تسهیل می‌کند. .IP \(bu 2 استفاده از pip \%\&. از \fBpip freeze\fP و \fBpip install\fP برای ایجاد و نصب از روی یک فایل \fBrequirements.txt\fP برای پروژه استفاده کنید. .IP \(bu 2 از طریق دستورالعمل‌های دستی موجود در Installation \%<#\:installation>\&. .UNINDENT .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 صرف‌نظر از روشی که انتخاب می‌کنید، اکیداً توصیه می‌شود که تمام عملیات‌های نصبِ استقرار در یک محیط مجازی پایتون (virtualenv) \% انجام شوند. .UNINDENT .UNINDENT .SS غیرفعال‌سازی حالت اشکال‌زدایی (Debug Mode) .sp \fBهشدار:\fP .INDENT 0.0 .INDENT 3.5 یکی از مهم‌ترین گام‌ها پیش از استقرار یک برنامهٔ Pecan در محیط عملیاتی، اطمینان از غیرفعال بودن \fBDebug Mode\fP است که یک محیط اشکال‌زدایی توسعه‌محور برای ردگیری خطاهای زمان اجرا (tracebacks) فراهم می‌کند. عدم غیرفعال‌سازی این ابزار توسعه در محیط عملیاتی شما، \fIقطعاً\fP به مشکلات امنیتی جدی منجر خواهد شد. در فایل پیکربندی عملیاتی خود، مطمئن شوید که \fBdebug\fP روی \fBFalse\fP تنظیم شده است\&. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/production_config.py app = { ... \(aqdebug\(aq: False } .EE .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS Pecan و WSGI .sp استاندارد WSGI یک استاندارد در پایتون است که یک رابط استاندارد بین سرورها و برنامه را توصیف می‌کند. هر برنامهٔ Pecan یک \(dqWSGI application\(dq نیز نامیده می‌شود چرا که رابط WSGI را پیاده‌سازی می‌کند؛ از این رو هر سروری که با WSGI سازگار باشد (\(dqWSGI compatible\(dq) را می‌توان برای سرویس‌دهی به برنامه به کار گرفت. چند نمونهٔ پرکاربرد عبارتند از: .INDENT 0.0 .IP \(bu 2 mod_wsgi \% .IP \(bu 2 uWSGI \% .IP \(bu 2 Gunicorn \% .IP \(bu 2 waitress \% .IP \(bu 2 CherryPy \% .UNINDENT .sp به طور کلی، نقطهٔ ورود WSGI به هر برنامهٔ Pecan را می‌توان با استفاده از \fBdeploy()\fP \%<#\:pecan\:.deploy\:.deploy> ایجاد کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan.deploy import deploy application = deploy(\(aq/path/to/some/app/config.py\(aq) .EE .UNINDENT .UNINDENT.SS "ملاحظات مربوط به فایل‌های ایستا" .sp ‏Pecan همراه با میان‌افزار ارائهٔ فایل‌های ایستا (مانند CSS، Javascript، تصاویر) عرضه می‌شود که استفاده از آن در محیط عملیاتی \fBتوصیه نمی‌شود\fP. .sp در محیط عملیاتی، Pecan خود فایل‌های رسانه‌ای را ارائه نمی‌دهد؛ بلکه این وظیفه را به وب‌سرور انتخابی شما واگذار می‌کند. .sp برای ارائهٔ فایل‌های ایستا در محیط عملیاتی، بهتر است با ارائهٔ این فایل‌ها به صورت جداگانه از برنامهٔ WSGI خود، تفکیک وظایف را رعایت کنید (عمدتاً به دلایل عملکردی). روش‌های محبوب متعددی برای انجام این کار وجود دارد که در اینجا به دو مورد اشاره می‌شود: .INDENT 0.0 .IP 1. 3 راه‌اندازی یک سرور پراکسی (مانند nginx \%، cherokee \%، CherryPy یا lighttpd \%) برای ارائهٔ فایل‌های ایستا و هدایت درخواست‌های برنامه به برنامهٔ کاربردی WSGI شما: .INDENT 3.0 .INDENT 3.5 .sp .EX ─── , e.g., Apache, nginx, cherokee (0.0.0.0:80) ─── │ ├── Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5000 or /tmp/some.sock) ├── Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5001 or /tmp/some.sock) ├── Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5002 or /tmp/some.sock) └── Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5003 or /tmp/some.sock) .EE .UNINDENT .UNINDENT .IP 2. 3 ارائهٔ فایل‌های ایستا از طریق یک سرویس، میزبان مجازی یا CDN مجزا. .UNINDENT .SS "دستورالعمل‌های رایج" .SS Apache + mod_wsgi .sp ماژول mod_wsgi \% یک ماژول محبوب Apache است که می‌تواند برای میزبانی هر برنامهٔ پایتون سازگار با WSGI (شامل برنامهٔ Pecan شما) استفاده شود. .sp برای شروع، مستندات نصب و پیکربندی \% مربوط به mod_wsgi را بررسی کنید. .sp برای نمونه، فرض کنیم پروژهٔ ما، \fBsimpleapp\fP، در مسیر \fB/var/www/simpleapp\fP قرار دارد و یک virtualenv \% در مسیر \fB/var/www/venv\fP با تمام وابستگی‌های لازم (از جمله Pecan) ایجاد شده است. علاوه بر این، به دلایل امنیتی، کاربر \fBuser1\fP و گروه \fBgroup1\fP را ایجاد کرده‌ایم تا برنامه تحت دسترسی آنها اجرا شود. .sp گام نخست، ایجاد یک فایل \fB\&.wsgi\fP است که mod_wsgi از آن به عنوان نقطهٔ ورود برنامهٔ شما استفاده خواهد کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX # /var/www/simpleapp/app.wsgi from pecan.deploy import deploy application = deploy(\(aq/var/www/simpleapp/config.py\(aq) .EE .UNINDENT .UNINDENT .sp سپس، پیکربندی Apache را برای برنامهٔ خود اضافه کنید. در اینجا یک نمونهٔ ساده آورده شده است: .INDENT 0.0 .INDENT 3.5 .sp .EX ServerName example.com WSGIDaemonProcess simpleapp user=user1 group=group1 threads=5 python\-path=/var/www/venv/lib/python2.7/site\-packages WSGIScriptAlias / /var/www/simpleapp/app.wsgi WSGIProcessGroup simpleapp WSGIApplicationGroup %{GLOBAL} Order deny,allow Allow from all .EE .UNINDENT .UNINDENT .sp برای دریافت دستورالعمل‌ها و مثال‌های بیشتر در رابطه با سوار کردن برنامه‌های WSGI با استفاده از mod_wsgi، به مستندات mod_wsgi \%\& مراجعه کنید. .sp در پایان، Apache را بازراه‌اندازی کرده و آن را آزمایش کنید..SS uWSGI .sp کارگزار uWSGI \% یک کارگزار کانتینر برنامهٔ کاربردی سریع، خودترمیم‌شونده و سازگار با توسعه‌دهندگان و مدیران سیستم است که به زبان C خالص نوشته شده است. این ابزار از پروتکل uwsgi \% استفاده می‌کند، اما از پروتکل‌های دیگر نیز پشتیبانی می‌کند (http، fastcgi...). .sp اجرای برنامه‌های Pecan با uWSGI بسیار ساده است: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install uwsgi $ pecan create simpleapp && cd simpleapp $ python setup.py develop $ uwsgi \-\-http\-socket :8080 \-\-venv /path/to/virtualenv \-\-pecan config.py .EE .UNINDENT .UNINDENT .sp یا با استفاده از یک سوکت Unix (که برای مثال می‌توان nginx را برای پراکسی کردن به آن پیکربندی کرد \%): .INDENT 0.0 .INDENT 3.5 .sp .EX $ uwsgi \-s /tmp/uwsgi.sock \-\-venv /path/to/virtualenv \-\-pecan config.py .EE .UNINDENT .UNINDENT .SS Gunicorn .sp کارگزار Gunicorn \% یا \(dqGreen Unicorn\(dq، یک کارگزار HTTP مبتنی بر WSGI برای UNIX است. این ابزار از مدل پردازشی pre\-fork استفاده می‌کند که از پروژهٔ Unicorn در زبان Ruby پورت شده است. این کارگزار از هر دوی eventlet و greenlet پشتیبانی می‌کند. .sp اجرای یک برنامهٔ Pecan روی Gunicorn ساده است. بیایید مراحل آن را با یک پروژهٔ پیش‌فرض Pecan دنبال کنیم: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install gunicorn $ pecan create simpleapp && cd simpleapp $ python setup.py develop $ gunicorn_pecan config.py .EE .UNINDENT .UNINDENT .SS CherryPy .sp کارگزار CherryPy \% یک وب‌سرور مبتنی بر مخزن ریسمان‌ها (thread\-pooled)، سازگار با استاندارد HTTP/1.1 و WSGI ارائه می‌دهد که تماماً با پایتون پیاده‌سازی شده است. این ابزار می‌تواند به سادگی از برنامه‌های Pecan پشتیبانی کند و حتی فایل‌های ایستا (static) را مانند یک سرور محیط عملیاتی سرویس‌دهی نماید. .sp مثال‌های زیر با هدف استفاده از CherryPy به عنوان کارگزار مسئول اجرای برنامهٔ Pecan در کنار سرویس‌دهی فایل‌های ایستا تنظیم شده‌اند. .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install cherrypy $ pecan create simpleapp && cd simpleapp $ python setup.py develop .EE .UNINDENT .UNINDENT .sp برای اجرا با CherryPy، ساده‌ترین روش ایجاد یک اسکریپت در ریشهٔ پروژه (در کنار \fBsetup.py\fP) است تا بتوانیم نحوهٔ سرویس‌دهی برنامهٔ نمونه‌مان را مشخص کنیم. اسکریپت مورد نظر (با نام \fBrun.py\fP) به این شکل است: .INDENT 0.0 .INDENT 3.5 .sp .EX import os import cherrypy from cheroot import wsgi from cheroot.wsgi import PathInfoDispatcher from pecan.deploy import deploy simpleapp_wsgi_app = deploy(\(aq/path/to/production_config.py\(aq) public_path = os.path.abspath(os.path.join(os.path.dirname(__file__), \(aqpublic\(aq)) # A dummy class for our Root object # necessary for some CherryPy machinery class Root(object): pass def make_static_config(static_dir_name): \(dq\(dq\(dq All custom static configurations are set here, since most are common, it makes sense to generate them just once. \(dq\(dq\(dq static_path = os.path.join(\(aq/\(aq, static_dir_name) path = os.path.join(public_path, static_dir_name) configuration = { static_path: { \(aqtools.staticdir.on\(aq: True, \(aqtools.staticdir.dir\(aq: path } } return cherrypy.tree.mount(Root(), \(aq/\(aq, config=configuration) # Assuming your app has media on different paths, like \(aqcss\(aq, and \(aqimages\(aq application = PathInfoDispatcher({ \(aq/\(aq: simpleapp_wsgi_app, \(aq/css\(aq: make_static_config(\(aqcss\(aq), \(aq/images\(aq: make_static_config(\(aqimages\(aq) }) server = wsgi.Server((\(aq0.0.0.0\(aq, 8080), application, server_name=\(aqsimpleapp\(aq) try: server.start() except KeyboardInterrupt: print(\(dqTerminating server...\(dq) server.stop() .EE .UNINDENT .UNINDENT .sp برای راه‌اندازی کارگزار، کافی است آن را با مفسر Python اجرا کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ python run.py .EE .UNINDENT .UNINDENT.SH "ثبت وقایع (LOGGING)" .sp Pecan با ارسال گزینه‌های پیکربندی ثبت وقایع به تابع logging.config.dictConfig \% از ماژول \fBlogging\fP \% کتابخانه استاندارد پایتون استفاده می‌کند. مستندات کامل قالب \fBdictConfig()\fP بهترین منبع اطلاعات برای پیکربندی ثبت وقایع است، اما برای شروع، این فصل چند مثال ساده در اختیارتان می‌گذارد. .SS پیکربندی ثبت وقایع .sp نمونه‌ای از پیکربندی ثبت وقایع همراه با پروژه quickstart معرفی‌شده در «ایجاد اولین برنامه Pecan» \%<#\:quick-start> ارائه شده است: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan create myapp .EE .UNINDENT .UNINDENT .sp پیکربندی پیش‌فرض یک handler و دو logger را تعریف می‌کند. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/config.py app = { ... } server = { ... } logging = { \(aqroot\(aq : {\(aqlevel\(aq: \(aqINFO\(aq, \(aqhandlers\(aq: [\(aqconsole\(aq]}, \(aqloggers\(aq: { \(aqmyapp\(aq: {\(aqlevel\(aq: \(aqDEBUG\(aq, \(aqhandlers\(aq: [\(aqconsole\(aq]} }, \(aqhandlers\(aq: { \(aqconsole\(aq: { \(aqlevel\(aq: \(aqDEBUG\(aq, \(aqclass\(aq: \(aqlogging.StreamHandler\(aq, \(aqformatter\(aq: \(aqsimple\(aq } }, \(aqformatters\(aq: { \(aqsimple\(aq: { \(aqformat\(aq: (\(aq%(asctime)s %(levelname)\-5.5s [%(name)s]\(aq \(aq[%(threadName)s] %(message)s\(aq) } } } .EE .UNINDENT .UNINDENT .INDENT 0.0 .IP \(bu 2 \fBconsole\fP پیام‌ها را با استفاده از فرمت‌کننده \fBsimple\fP در \fBstderr\fP ثبت می‌کند. .IP \(bu 2 \fBmyapp\fP پیام‌های ارسال‌شده در سطحی بالاتر یا برابر با \fBDEBUG\fP را به handler با نام \fBconsole\fP ارسال می‌کند .IP \(bu 2 \fBroot\fP پیام‌های در سطحی بالاتر یا برابر با سطح \fBINFO\fP را به handler با نام \fBconsole\fP ارسال می‌کند .UNINDENT .SS نوشتن پیام‌های ثبت وقایع در برنامه شما .sp ثبت‌کننده (logger) با نام \fBmyapp\fP برای استفاده شما در برنامه Pecan رزرو شده است. .sp پس از پیکربندی ثبت وقایع، می‌توانید فراخوانی‌های ثبت وقایع را در کد خود قرار دهید. استفاده از چارچوب ثبت وقایع بسیار ساده است. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/myapp/controllers/root.py from pecan import expose import logging logger = logging.getLogger(__name__) class RootController(object): @expose() def index(self): if bad_stuff(): logger.error(\(aqUh\-oh!\(aq) return dict() .EE .UNINDENT .UNINDENT.SS ثبت گزارش در فایل‌ها و سایر مکان‌ها .sp کتابخانهٔ \fBlogging\fP پایتون \% گرداننده‌های متنوعی را تعریف می‌کند که در نوشتن گزارش‌ها روی فایل کمک می‌کنند. چند مورد کاربردی از آن‌ها عبارتند از: .INDENT 0.0 .IP \(bu 2 \fBFileHandler\fP \% \- برای ثبت پیام‌ها در فایلی روی سیستم‌فایل استفاده می‌شود .IP \(bu 2 \fBRotatingFileHandler\fP \% \- مشابه \fBFileHandler\fP \% است، اما همچنین گزارش‌ها را به‌طور دوره‌ای چرخش (rotate) می‌دهد .IP \(bu 2 \fBSysLogHandler\fP \% \- برای ثبت پیام‌ها در syslog یونیکس استفاده می‌شود .IP \(bu 2 \fBSMTPHandler\fP \% \- برای ثبت پیام‌ها و ارسال به یک آدرس ایمیل از طریق SMTP استفاده می‌شود .UNINDENT .sp استفاده از هر یک از آن‌ها به سادگیِ تعریف یک گرداننده جدید در بلوک \fBlogging\fP برنامه و انتساب آن به یک یا چند لاگر است. .SS ثبت درخواست‌ها با Paste Translogger .sp بستهٔ Paste \% (که همراه با Pecan عرضه نمی‌شود) شامل میان‌افزار \fBTransLogger\fP برای ثبت درخواست‌ها در قالب Apache Combined Log Format \%\& است. TransLogger در ترکیب با ثبت گزارش مبتنی بر فایل می‌تواند برای ایجاد فایل \fBaccess.log\fP مشابه با \fBApache\fP استفاده شود. .sp برای افزودن این میان‌افزار، متد \fBsetup_app\fP را در فایل \fBapp.py\fP پروژهٔ خود به شکل زیر تغییر دهید: .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/myapp/app.py from pecan import make_app from paste.translogger import TransLogger def setup_app(config): # ... app = make_app( config.app.root # ... ) app = TransLogger(app, setup_console_handler=False) return app .EE .UNINDENT .UNINDENT .sp به‌طور پیش‌فرض، \fBTransLogger\fP لاگری با نام \fBwsgi\fP ایجاد می‌کند، بنابراین باید در فایل پیکربندی Pecan یک گردانندهٔ جدید (مبتنی بر فایل) برای این لاگر مشخص کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/config.py app = { ... } server = { ... } logging = { \(aqloggers\(aq: { # ... \(aqwsgi\(aq: {\(aqlevel\(aq: \(aqINFO\(aq, \(aqhandlers\(aq: [\(aqlogfile\(aq], \(aqqualname\(aq: \(aqwsgi\(aq} }, \(aqhandlers\(aq: { # ... \(aqlogfile\(aq: { \(aqclass\(aq: \(aqlogging.FileHandler\(aq, \(aqfilename\(aq: \(aq/etc/access.log\(aq, \(aqlevel\(aq: \(aqINFO\(aq, \(aqformatter\(aq: \(aqmessageonly\(aq } }, \(aqformatters\(aq: { # ... \(aqmessageonly\(aq: {\(aqformat\(aq: \(aq%(message)s\(aq} } } .EE .UNINDENT .UNINDENT.SH "آزمودن برنامه‌های کاربردی PECAN (TESTING PECAN APPLICATIONS)" .sp آزمون‌ها تا زمانی که اجراکنندهٔ آزمون (test runner) بتواند آن‌ها را شناسایی کند، می‌توانند در هر کجای پروژهٔ Pecan شما قرار داشته باشند. به‌طور سنتی، آن‌ها در بسته‌ای به نام \fBmyapp.tests\fP\& قرار می‌گیرند. .sp سازوکار پیشنهادی برای آزمون‌های واحد (unit testing) و یکپارچه‌سازی (integration testing) یک برنامهٔ کاربردی Pecan، پیمانهٔ \fBunittest\fP \% است. .SS "شناسایی آزمون و ابزارهای دیگر (Test Discovery and Other Tools)" .sp آزمون‌های یک پروژهٔ Pecan را می‌توان به سادگی با دستور \fBpython setup.py test\fP فراخوانی کرد، هرچند امکان اجرای آزمون‌هایتان با ابزارهای مختلف شناسایی و خودکارسازی نیز وجود دارد. به‌ویژه، پروژه‌های Pecan به خوبی با nose \%، pytest \% و tox \%\& کار می‌کنند. .SS "نوشتن آزمون‌های کارکردی با WebTest (Writing Functional Tests with WebTest)" .sp یک \fBآزمون واحد\fP معمولاً به اشیاء \(dqشبیه‌سازی‌شده (mock)\(dq یا \(dqجعلی (fake)\(dq متکی است تا به کُد تحت آزمون، بستر کافی برای اجرا داده شود. بدین ترتیب، تنها یک واحد منفرد از کُد منبع آزمایش می‌شود. .sp یک مجموعهٔ آزمون کارآمد، \fBآزمون‌های واحد\fP را با \fBآزمون‌های کارکردی\fP ترکیب می‌کند. در چارچوب یک برنامهٔ Pecan، آزمون‌های کارکردی را می‌توان با کمک کتابخانهٔ \fBwebtest\fP \% نوشت. به این ترتیب، امکان نوشتن آزمون‌هایی وجود دارد که رفتار چرخهٔ حیات یک درخواست HTTP را از مسیریابی کنترل‌کننده تا پاسخ HTTP بررسی و اعتبارسنجی می‌کنند. نمونهٔ زیر مشابه همان کُدی است که در پروژهٔ شروع سریع (quickstart) نرم‌افزار Pecan گنجانده شده است. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/myapp/tests/__init__.py import os from unittest import TestCase from pecan import set_config from pecan.testing import load_test_app class FunctionalTest(TestCase): \(dq\(dq\(dq Used for functional tests where you need to test your literal application and its integration with the framework. \(dq\(dq\(dq def setUp(self): self.app = load_test_app(os.path.join( os.path.dirname(__file__), \(aqconfig.py\(aq )) def tearDown(self): set_config({}, overwrite=True) .EE .UNINDENT .UNINDENT .sp ابزار آزمایشی که همراه با Pecan عرضه می‌شود، یعنی \fBpecan.testing.load_test_app()\fP \%<#\:pecan\:.testing\:.load_test_app>، می‌تواند مسیر فایلی را که نشان‌دهندهٔ یک فایل پیکربندی Pecan است به عنوان ورودی بپذیرد، و نمونه‌ای از برنامهٔ کاربردی را که در محیط \fBTestApp\fP \% بسته‌بندی شده است بازمی‌گرداند. .sp از این مرحله، گسترش کلاس پایهٔ \fBFunctionalTest\fP و نوشتن آزمون‌هایی که درخواست‌های شبیه‌سازی‌شدهٔ HTTP را ارسال می‌کنند امکان‌پذیر خواهد بود. .INDENT 0.0 .INDENT 3.5 .sp .EX class TestIndex(FunctionalTest): def test_index(self): resp = self.app.get(\(aq/\(aq) assert resp.status_int == 200 assert \(aqHello, World\(aq in resp.body .EE .UNINDENT .UNINDENT .sp \fBهمچنین ببینید:\fP .INDENT 0.0 .INDENT 3.5 برای کسب اطلاعات بیشتر دربارهٔ متدهای در دسترس در یک نمونه از \fBTestApp\fP \%، مستندات \fBwebtest\fP \% را بررسی کنید. .UNINDENT .UNINDENT.SS "متغیرهای ویژه آزمون (Special Testing Variables)" .sp گاهی اوقات ادعاها (assertions) پیرامون بدنهٔ پاسخ درخواست‌های خاص کافی نیست. برای کمک به بازرسی، برنامه‌های کاربردی Pecan مجموعه‌ای ویژه از \(dqمتغیرهای آزمون\(dq را برای هر شیء \fBTestResponse\fP \% فراهم می‌کنند. .sp فرض کنید برنامهٔ کاربردی Pecan شما دارای کنترلری باشد که یک \fBname\fP را به عنوان یک آرگومان اختیاری در URL دریافت می‌کند. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/myapp/controllers/root.py from pecan import expose class RootController(object): @expose(\(aqindex.html\(aq) def index(self, name=\(aqJoe\(aq): \(dq\(dq\(dqA request to / will access this controller\(dq\(dq\(dq return dict(name=name) .EE .UNINDENT .UNINDENT .sp و آن نام را در قالب خود (و در نتیجه، در بدنهٔ پاسخ) رندر می‌کند. .INDENT 0.0 .INDENT 3.5 .sp .EX # myapp/myapp/templates/index.html Hello, ${name}! .EE .UNINDENT .UNINDENT .sp یک آزمون کارکردی (functional test) برای این کنترلر ممکن است ساختاری شبیه به این داشته باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX class TestIndex(FunctionalTest): def test_index(self): resp = self.app.get(\(aq/\(aq) assert resp.status_int == 200 assert \(aqHello, Joe!\(aq in resp.body .EE .UNINDENT .UNINDENT .sp افزون بر \fBwebtest.TestResponse.body\fP، Pecan همچنین \fBwebtest.TestResponse.namespace\fP (که نمایانگر فضای نام قالبِ بازگردانده‌شده از کنترلر است) و \fBwebtest.TestResponse.template_name\fP (شامل نام قالب استفاده‌شده) را ارائه می‌دهد. .INDENT 0.0 .INDENT 3.5 .sp .EX class TestIndex(FunctionalTest): def test_index(self): resp = self.app.get(\(aq/\(aq) assert resp.status_int == 200 assert resp.namespace == {\(aqname\(aq: \(aqJoe\(aq} assert resp.template_name == \(aqindex.html\(aq .EE .UNINDENT .UNINDENT .sp به این ترتیب، آزمایش مقدار بازگشتی و قالب رندرشدهٔ هر یک از کنترلرها به صورت مجزا امکان‌پذیر است. .SH "تولید و اعتبارسنجی فرم‌ها (GENERATING AND VALIDATING FORMS)" .sp چارچوب Pecan هیچ ساختار تحمیلی (opinionated) برای کار با کتابخانه‌های تولید و اعتبارسنجی فرم ارائه نمی‌دهد، اما می‌توان با حداقل تلاش کتابخانهٔ مورد نظر خود را درون‌ریزی کرد. .sp این بخش به تشریح بهترین روش‌ها برای ادغام کتابخانهٔ محبوب فرم‌ها، WTForms \%، در پروژهٔ Pecan شما می‌پردازد..SS تعریف ساختار فرم .sp کار را با ساخت یک فرم پایه با فیلد اجباری \fBfirst_name\fP و فیلد اختیاری \fBlast_name\fP آغاز می‌کنیم. .INDENT 0.0 .INDENT 3.5 .sp .EX from wtforms import Form, TextField, validators class MyForm(Form): first_name = TextField(u\(aqFirst Name\(aq, validators=[validators.required()]) last_name = TextField(u\(aqLast Name\(aq, validators=[validators.optional()]) class SomeController(object): pass .EE .UNINDENT .UNINDENT .SS رندر کردن فرم در یک قالب .sp در مرحله بعد، یک کنترل‌کننده اضافه می‌کنیم و یک نمونه از فرم را به قالب انتقال می‌دهیم. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from wtforms import Form, TextField, validators class MyForm(Form): first_name = TextField(u\(aqFirst Name\(aq, validators=[validators.required()]) last_name = TextField(u\(aqLast Name\(aq, validators=[validators.optional()]) class SomeController(object): @expose(template=\(aqindex.html\(aq) def index(self): return dict(form=MyForm()) .EE .UNINDENT .UNINDENT .sp این فایل قالب Mako \% است: .INDENT 0.0 .INDENT 3.5 .sp .EX
${form.first_name.label}: ${form.first_name}
${form.last_name.label}: ${form.last_name}
.EE .UNINDENT .UNINDENT .SS اعتبارسنجی مقادیر POST .sp با استفاده از همان تعریف \fBMyForm\fP، در صورت اعتبارسنجی موفق فرم کاربر را تغییر مسیر می‌دهیم، در غیر این صورت، فرم مجدداً رندر می‌شود. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, request from wtforms import Form, TextField, validators class MyForm(Form): first_name = TextField(u\(aqFirst Name\(aq, validators=[validators.required()]) last_name = TextField(u\(aqLast Name\(aq, validators=[validators.optional()]) class SomeController(object): @expose(template=\(aqindex.html\(aq) def index(self): my_form = MyForm(request.POST) if request.method == \(aqPOST\(aq and my_form.validate(): # save_values() redirect(\(aq/success\(aq) else: return dict(form=my_form) .EE .UNINDENT .UNINDENT.SH "کار با نشست‌ها و احراز هویت کاربر (WORKING WITH SESSIONS AND USER AUTHENTICATION)" .sp پکان (Pecan) هیچ پشتیبانی تحمیلی یا چارچوب‌محوری (opinionated) برای مدیریت نشست‌های کاربر ارائه نمی‌دهد، اما می‌توان با کمترین تلاش، آن را به چارچوب نشست دلخواه خود متصل کرد. .sp این مقاله، بهترین الگوها (best practices) را برای یکپارچه‌سازی چارچوب محبوب مدیریت نشست، Beaker \%، در پروژه Pecan شما شرح می‌دهد. .SS "راه‌اندازی مدیریت نشست (Setting up Session Management)" .sp برای راه‌اندازی مدیریت نشست، چندین رویکرد مختلف وجود دارد. یک رویکرد استفاده از میان‌افزار (middleware) در WSGI است. رویکرد دیگر، استفاده از قلاب‌های پکان (Pecan Hooks) \%<#\:hooks>\& است. .sp در اینجا نمونه‌ای از پوشش‌دهی برنامه WSGI شما با استفاده از \fBSessionMiddleware\fP \% از چارچوب Beaker در فایل \fBapp.py\fP پروژه آورده شده است\&. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import conf, make_app from beaker.middleware import SessionMiddleware from test_project import model app = make_app( ... ) app = SessionMiddleware(app, conf.beaker) .EE .UNINDENT .UNINDENT .sp و دیکشنری متناظر با آن در فایل پیکربندی شما: .INDENT 0.0 .INDENT 3.5 .sp .EX beaker = { \(aqsession.key\(aq : \(aqsessionkey\(aq, \(aqsession.type\(aq : \(aqcookie\(aq, \(aqsession.validate_key\(aq : \(aq05d2175d1090e31f42fa36e63b8d2aad\(aq, \(aq__force_dict__\(aq : True } .EE .UNINDENT .UNINDENT .SH "کار با پایگاه‌های داده، تراکنش‌ها و ORMها (WORKING WITH DATABASES, TRANSACTIONS, AND ORM'S)" .sp پکان (Pecan) هیچ ساختار از پیش تعیین‌شده یا تحمیلی برای کار با پایگاه‌های داده ارائه نمی‌دهد، اما ادغام آن با ORM دلخواه شما بسیار آسان است. این مقاله بهترین شیوه‌ها را برای یکپارچه‌سازی ORM محبوب پایتون، SQLAlchemy \%، در پروژه Pecan شرح می‌دهد. .SS "\fBinit_model\fP و آماده‌سازی مدل (\fBinit_model\fP and Preparing Your Model)" .sp پروژه پیش‌فرض quickstart در Pecan شامل یک دایرکتوری پایه (stub) خالی است تا مدل داده‌ای خود را بنا به نیاز خود در آن پیاده‌سازی کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX \&. └── test_project ├── app.py ├── __init__.py ├── controllers ├── model │\ \ ├── __init__.py └── templates .EE .UNINDENT .UNINDENT .sp به‌طور پیش‌فرض، این ماژول حاوی یک تابع ویژه به نام \fBinit_model()\fP است\&. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import conf def init_model(): \(dq\(dq\(dq This is a stub method which is called at application startup time. If you need to bind to a parsed database configuration, set up tables or ORM classes, or perform any database initialization, this is the recommended place to do it. For more information working with databases, and some common recipes, see https://pecan.readthedocs.io/en/latest/databases.html \(dq\(dq\(dq pass .EE .UNINDENT .UNINDENT .sp هدف از این تابع، تعیین اتصالات (bindings) بر اساس فایل پیکربندی شما و ایجاد موتورها (engines)، استخرها (pools) و موارد ضروری مطابق با ORM یا جعبه‌ابزار پایگاه داده انتخابی شماست. .sp علاوه بر این، ماژول \fBmodel\fP پروژه شما می‌تواند برای تعریف توابعی جهت عملیات متداول پایگاه داده، مانند آغاز تراکنش‌ها، ثبت قطعی (commit) یا بازگردانی (rollback) عملیات و پاک‌سازی نشست (session) استفاده شود. همچنین این مکان در پروژه شما جایی است که تعاریف اشیاء و روابط (relations) باید در آن تعریف شوند. در ادامه، نمونه‌ای از فایل پیکربندی Pecan همراه با اتصالات پایگاه داده آورده شده است. .INDENT 0.0 .INDENT 3.5 .sp .EX # Server Specific Configurations server = { ... } # Pecan Application Configurations app = { ... } # Bindings and options to pass to SQLAlchemy\(aqs \(ga\(gacreate_engine\(ga\(ga sqlalchemy = { \(aqurl\(aq : \(aqmysql://root:@localhost/dbname?charset=utf8&use_unicode=0\(aq, \(aqecho\(aq : False, \(aqecho_pool\(aq : False, \(aqpool_recycle\(aq : 3600, \(aqencoding\(aq : \(aqutf\-8\(aq } .EE .UNINDENT .UNINDENT .sp و نمونه‌ای از پیاده‌سازی پایه‌ای مدل که می‌تواند برای پیکربندی و اتصال از طریق SQLAlchemy به کار رود: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import conf from sqlalchemy import create_engine, MetaData from sqlalchemy.orm import scoped_session, sessionmaker Session = scoped_session(sessionmaker()) metadata = MetaData() def _engine_from_config(configuration): configuration = dict(configuration) url = configuration.pop(\(aqurl\(aq) return create_engine(url, **configuration) def init_model(): conf.sqlalchemy.engine = _engine_from_config(conf.sqlalchemy) def start(): Session.bind = conf.sqlalchemy.engine metadata.bind = Session.bind def commit(): Session.commit() def rollback(): Session.rollback() def clear(): Session.remove() .EE .UNINDENT .UNINDENT.SS اتصال درون برنامه (Binding Within the Application) .sp رویکردهای متعددی برای دربرگرفتن درخواست‌های برنامه شما با فراخوانی توابع مناسب مدل وجود دارد. یک رویکرد، میان‌افزار WSGI است. ما همچنین قلاب‌های پکان (Pecan Hooks) \%<#\:hooks>\& را توصیه می‌کنیم. پکان به همراه \fBTransactionHook\fP \%<#\:pecan\:.hooks\:.TransactionHook> ارائه می‌شود؛ قلابی که می‌تواند برای محصور کردن درخواست‌ها در تراکنش‌های پایگاه داده برای شما استفاده شود. برای استفاده از آن، کافی است آن را در فایل \fBapp.py\fP پروژه خود قرار داده و مجموعه‌ای از توابع مرتبط با اتصال پایگاه داده را به آن ارسال کنید. .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import conf, make_app from pecan.hooks import TransactionHook from test_project import model app = make_app( conf.app.root, static_root = conf.app.static_root, template_path = conf.app.template_path, debug = conf.app.debug, hooks = [ TransactionHook( model.start, model.start_read_only, model.commit, model.rollback, model.clear ) ] ) .EE .UNINDENT .UNINDENT .sp در مثال بالا، در درخواست‌های HTTP از نوع \fBPOST\fP، \fBPUT\fP و \fBDELETE\fP، قلاب \fBTransactionHook\fP \%<#\:pecan\:.hooks\:.TransactionHook> با پیروی از این قوانین به طور خودکار به تراکنش رسیدگی می‌کند: .INDENT 0.0 .IP 1. 3 پیش از تعیین مسیریابی کنترلر، \fBmodel.start()\fP فراخوانی می‌شود. این تابع باید به موتور SQLAlchemy مناسب متصل شده و یک تراکنش را آغاز کند. .IP 2. 3 کد کنترلر اجرا شده و بازمی‌گردد. .IP 3. 3 اگر کنترلر یا رندر قالب با شکست مواجه شده و یک استثنا صادر کند، \fBmodel.rollback()\fP فراخوانی شده و استثنای اصلی مجدداً صادر می‌شود (re\-raised). این به شما امکان می‌دهد تراکنش پایگاه داده خود را به عقب برگردانید (rollback) تا در صورت وقوع استثناها در کد برنامه، از ثبت تغییرات جلوگیری شود. .IP 4. 3 اگر کنترلر با موفقیت بازگردد، \fBmodel.commit()\fP و \fBmodel.clear()\fP فراخوانی می‌شوند. .UNINDENT .sp در عملیات‌های خنثی یا پایا (مانند درخواست‌های HTTP از نوع \fBGET\fP و \fBHEAD\fP)، قلاب \fBTransactionHook\fP \%<#\:pecan\:.hooks\:.TransactionHook> تراکنش‌ها را طبق قوانین متفاوتی مدیریت می‌کند. .INDENT 0.0 .IP 1. 3 تابع \fBmodel.start_read_only()\fP فراخوانی می‌شود. این تابع باید به موتور SQLAlchemy شما متصل شود. .IP 2. 3 کد کنترلر اجرا شده و بازمی‌گردد. .IP 3. 3 اگر کنترلر با موفقیت بازگردد، \fBmodel.clear()\fP فراخوانی می‌شود. .UNINDENT .sp همچنین توجه داشته باشید که یک دکوراتور مفید به نام \fBafter_commit()\fP \%<#\:pecan\:.decorators\:.after_commit> در pecan.decorators \-\- دکوراتورهای پکان \%<#\:pecan-decorators>\& ارائه شده است. .SS جداسازی خواندن و نوشتن (Splitting Reads and Writes) .sp به‌کارگیری راهبرد بالا با استفاده از \fBTransactionHook\fP \%<#\:pecan\:.hooks\:.TransactionHook>، جداسازی عملیات خواندن و نوشتن پایگاه داده را بر اساس متدهای HTTP بسیار ساده می‌سازد (یعنی درخواست‌های GET/HEAD فقط‌خواندنی هستند و می‌توانند به یک پایگاه داده وابسته (slave) فقط‌خواندنی هدایت شوند، در حالی که درخواست‌های POST/PUT/DELETE نیازمند نوشتن بوده و همیشه به یک پایگاه داده اصلی (master) با امتیازات خواندن/نوشتن متصل می‌شوند). همچنین می‌توان \fBTransactionHook\fP \%<#\:pecan\:.hooks\:.TransactionHook> را گسترش داد یا پیاده‌سازی قلاب سفارشی خود را برای کنترل دقیق‌تر بر مکان و زمان فراخوانی اتصالات پایگاه داده نوشت. .sp با فرض یک پیکربندی master/standby، که در آن master درخواست‌های نوشتن را می‌پذیرد و standby تنها می‌تواند درخواست‌های خواندن را دریافت کند، یک پیکربندی Pecan برای sqlalchemy می‌تواند به این صورت باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX # Server Specific Configurations server = { ... } # Pecan Application Configurations app = { ... } # Master database sqlalchemy_w = { \(aqurl\(aq: \(aqpostgresql+psycopg2://root:@master_host/dbname\(aq, \(aqpool_recycle\(aq: 3600, \(aqencoding\(aq: \(aqutf\-8\(aq } # Read Only database sqlalchemy_ro = { \(aqurl\(aq: \(aqpostgresql+psycopg2://root:@standby_host/dbname\(aq, \(aqpool_recycle\(aq: 3600, \(aqencoding\(aq: \(aqutf\-8\(aq } .EE .UNINDENT .UNINDENT .sp با توجه به تنظیمات پیکربندی منحصربه‌فرد برای هر پایگاه داده، اتصالات باید نسبت به آنچه که quickstart پیش‌فرض Pecan ارائه می‌دهد تغییر کند (بخش init_model و Preparing Your Model را ببینید) تا پاسخگوی هر دو نوع درخواست‌های نوشتن و فقط‌خواندنی باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import conf from sqlalchemy import create_engine, MetaData from sqlalchemy.orm import scoped_session, sessionmaker Session = scoped_session(sessionmaker()) metadata = MetaData() def init_model(): conf.sqlalchemy_w.engine = _engine_from_config(conf.sqlalchemy_w) conf.sqlalchemy_ro.engine = _engine_from_config(conf.sqlalchemy_ro) def _engine_from_config(configuration): configuration = dict(configuration) url = configuration.pop(\(aqurl\(aq) return create_engine(url, **configuration) def start(): Session.bind = conf.sqlalchemy_w.engine metadata.bind = conf.sqlalchemy_w.engine def start_read_only(): Session.bind = conf.sqlalchemy_ro.engine metadata.bind = conf.sqlalchemy_ro.engine def commit(): Session.commit() def rollback(): Session.rollback() def clear(): Session.close() def flush(): Session.flush() .EE .UNINDENT .UNINDENT.SH "اسناد خطای سفارشی (CUSTOM ERROR DOCUMENTS)" .sp در این مقاله یک برنامهٔ Pecan را به‌گونه‌ای پیکربندی می‌کنیم که هر زمان سرور وضعیت \fB404 Page Not Found\fP را بازگرداند، یک صفحهٔ خطای سفارشی نمایش داده شود. .sp این مقاله فرض می‌کند که شما پیش‌تر یک برنامهٔ آزمایشی را طبق توضیحات «ایجاد نخستین برنامهٔ Pecan» \%<#\:quick-start>\& ساخته‌اید. .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 اگرچه این مثال بر روی پیام \fBHTTP 404\fP تمرکز دارد، اما همین سازوکار را می‌توان برای تعریف اقدامات سفارشی برای هر یک از کدهای وضعیت پاسخ \fBHTTP\fP در دامنهٔ ۴۰۰ و ۵۰۰ نیز به‌کار برد. توصیه می‌شود از این قابلیت با دقت و هوشمندی استفاده کنید. .UNINDENT .UNINDENT .SS "نمای کلی (Overview)" .sp Pecan سفارشی‌سازی اسناد خطا را در دو مرحلهٔ ساده امکان‌پذیر می‌کند: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 پیکربندی مسیریابی (Routing) پیام‌های وضعیت HTTP که می‌خواهید در \fBconfig.py\fP برنامه‌تان مدیریت شوند .IP \(bu 2 نوشتن کنترلرهای سفارشی (Custom Controllers) برای مدیریت پیام‌های وضعیتی که پیکربندی کرده‌اید .UNINDENT .UNINDENT .UNINDENT .SS "پیکربندی مسیریابی (Configure Routing)" .sp بیایید برنامهٔ \fBtest_project\fP خود را طوری پیکربندی کنیم که پیام‌های \fBHTTP 404 Page Not Found\fP را به یک کنترلر سفارشی هدایت کند. .sp ابتدا \fBtest_project/config.py\fP را به‌روزرسانی می‌کنیم تا یک error\-handler جدید مشخص شود. .INDENT 0.0 .INDENT 3.5 .sp .EX # Pecan Application Configurations app = { \(aqroot\(aq : \(aqtest_project.controllers.root.RootController\(aq, \(aqmodules\(aq : [\(aqtest_project\(aq], \(aqstatic_root\(aq : \(aq%(confdir)s/public\(aq, \(aqtemplate_path\(aq : \(aq%(confdir)s/test_project/templates\(aq, \(aqreload\(aq : True, \(aqdebug\(aq : True, # modify the \(aqerrors\(aq key to direct HTTP status codes to a custom # controller \(aqerrors\(aq : { #404 : \(aq/error/404\(aq, 404 : \(aq/notfound\(aq, \(aq__force_dict__\(aq : True } } .EE .UNINDENT .UNINDENT .sp اکنون Pecan به‌جای صفحهٔ خطای پیش‌فرض، پیام‌های 404 را به متد کنترلر \fBnotfound\fP هدایت خواهد کرد. .SS "نوشتن کنترلرهای سفارشی (Write Custom Controllers)" .sp ساده‌ترین راه برای پیاده‌سازی گردانندهٔ خطا این است که آن را به کلاس \fBtest_project.root.RootController\fP اضافه کنید (معمولاً در \fBtest_project/controllers/root.py\fP). .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from webob.exc import status_map class RootController(object): @expose(generic=True, template=\(aqindex.html\(aq) def index(self): return dict() @index.when(method=\(aqPOST\(aq) def index_post(self, q): redirect(\(aqhttps://pecan.readthedocs.io/en/latest/search.html?q=%s\(aq % q) ## custom handling of \(aq404 Page Not Found\(aq messages @expose(\(aqerror.html\(aq) def notfound(self): return dict(status=404, message=\(dqtest_project does not have this page\(dq) @expose(\(aqerror.html\(aq) def error(self, status): try: status = int(status) except ValueError: status = 0 message = getattr(status_map.get(status), \(aqexplanation\(aq, \(aq\(aq) return dict(status=status, message=message) .EE .UNINDENT .UNINDENT .sp و تمام! .sp دقت کنید تنها قطعه کدی که به \fBRootController\fP خود اضافه کردیم این بود: .INDENT 0.0 .INDENT 3.5 .sp .EX ## custom handling of \(aq404 Page Not Found\(aq messages @expose(\(aqerror.html\(aq) def notfound(self): return dict(status=404, message=\(dqtest_project does not have this page\(dq) .EE .UNINDENT .UNINDENT .sp ما صرفاً کنترلر \fBnotfound\fP را با استفاده از \fBexpose()\fP \%<#\:pecan\:.decorators\:.expose> به قالب \fBerror.html\fP متصل کردیم (قالبی که هنگام ساخت \fBtest_project\fP به‌راحتی برای ما ایجاد شده و در مسیر \fBtest_project/templates/\fP قرار گرفته بود). همانند هر کنترلر دیگر در Pecan، دیکشنری‌ای از متغیرها را برمی‌گردانیم تا توسط رندرکنندهٔ قالب جای‌گذاری شوند. .sp اکنون می‌توانیم قالب خطا را ویرایش کرده یا یک قالب کاملاً تازه بنویسیم تا صفحهٔ وضعیت خطای 404 در \fBtest_project\fP را به هر شکلی که می‌خواهیم زیبا و مرتب طراحی کنیم..SH "برنامه نمونه: پردازش ساده فرم‌ها (EXAMPLE APPLICATION: SIMPLE FORMS PROCESSING)" .sp این راهنما شما را در ساخت یک برنامه وب ساده Pecan که پردازش ساده‌ای روی فرم‌ها انجام می‌دهد، راهنمایی می‌کند. .SS "راه‌اندازی پروژه (Project Setup)" .sp ابتدا، باید Pecan را نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install pecan .EE .UNINDENT .UNINDENT .sp از پشتیبانی قالب پایه‌ای Pecan برای آغاز یک پروژه جدید استفاده کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan create mywebsite $ cd mywebsite .EE .UNINDENT .UNINDENT .sp پروژه جدید را در حالت توسعه (development mode) نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ python setup.py develop .EE .UNINDENT .UNINDENT .sp با آماده شدن پروژه، به پوشه \fBtemplates\fP بروید و فایل \fBindex.html\fP را ویرایش کنید. آن را طوری تغییر دهید که شبیه به این باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX <%inherit file=\(dqlayout.html\(dq /> <%def name=\(dqtitle()\(dq> Welcome to Pecan!

Enter a message:

Enter your first name:

% if not form_post_data is UNDEFINED:

${form_post_data[\(aqfirst_name\(aq]}, your message is: ${form_post_data[\(aqmessage\(aq]}

% endif
.EE .UNINDENT .UNINDENT .sp \fBچه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 محتویات برچسب \fBform\fP را طوری تغییر دادیم که شامل دو برچسب \fBinput\fP باشد. نام اولی \fBmessage\fP و نام دومی \fBfirst_name\fP است. .IP 2. 3 بررسی‌ای اضافه کردیم تا در صورت تعریف نشدن \fBform_post_data\fP، پیام یا عبارت نمایش داده نشود. .IP 3. 3 کدی برای نمایش پیام حاصل از عملیات \fBPOST\fP کاربر اضافه کردیم. .UNINDENT .sp اکنون به پوشه \fBcontrollers\fP بروید و فایل \fBroot.py\fP را ویرایش کنید. درون کلاس \fBRootController\fP دو تابع وجود خواهد داشت که هنگام درخواست مرورگر وب شما به نقطه پایانی \fB\(aq/\(aq\fP، فایل \fBindex.html\fP را نمایش می‌دهند. اگر کاربر مقداری داده در کادر متنی وارد کرده و روی دکمه ارسال کلیک کند، پیام شخصی‌سازی‌شده به او نمایش داده خواهد شد. .sp فایل \fBroot.py\fP را تغییر دهید تا به این صورت باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose class RootController(object): @expose(generic=True, template=\(aqindex.html\(aq) def index(self): return dict() @index.when(method=\(aqPOST\(aq, template=\(aqindex.html\(aq) def index_post(self, **kwargs): return dict(form_post_data=kwargs) .EE .UNINDENT .UNINDENT .sp \fBچه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 تابع \fBindex\fP را برای رندر کردن صفحه وب اولیه \fBindex.html\fP تغییر دادیم. .IP 2. 3 تابع \fBindex_post\fP را تغییر دادیم تا داده‌های ارسال‌شده را از طریق آرگومان‌های کلیدواژه‌ای بازگرداند. .UNINDENT .sp برنامه را اجرا کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve config.py .EE .UNINDENT .UNINDENT .sp یک مرورگر وب باز کنید: \%.SS افزودن اعتبارسنجی .sp پیامی را در کادر متنی به همراه نامی در کادر متنی دوم وارد کرده و دکمهٔ submit را فشار دهید. پس از ارسال مجدد صفحه (post back)، باید پیامی شخصی‌سازی‌شده را مشاهده کنید که زیر فرم نمایش داده می‌شود. .sp یک مشکلی که ممکن است متوجه آن شده باشید این است که اگر پیام یا نامی را وارد نکنید، صرفاً هیچ مقداری برای آن بخش از پیام نمایش داده نمی‌شود. بیایید کمی اعتبارسنجی اضافه کنیم تا اطمینان حاصل شود که پیام و نام واقعاً وارد شده‌اند. برای این کار، از WTForms \% استفاده خواهیم کرد، اما می‌توانید برای پروژه‌های خود هر چیز دیگری را جایگزین کنید. .sp پشتیبانی از کتابخانهٔ WTForms \% را اضافه کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install wtforms .EE .UNINDENT .UNINDENT .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 به یاد داشته باشید که Pecan در زمینهٔ انتخاب یک کتابخانهٔ خاص هنگام کار با تولید فرم، اعتبارسنجی و غیره تحمیل‌گر نیست. کتابخانه‌های مورد نظر خود را انتخاب کرده و آن‌ها را با Pecan یکپارچه کنید. این تنها یک روش برای انجام این کار است، روش‌های بسیار دیگری نیز وجود دارد؛ بنابراین با خیالی آسوده در پروژه‌های خود هر طور که می‌خواهید آن را پیاده‌سازی کنید. .UNINDENT .UNINDENT .sp به فایل \fBroot.py\fP بازگردید و آن را بدین شکل ویرایش کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, request from wtforms import Form, TextField, validators class PersonalizedMessageForm(Form): message = TextField(u\(aqEnter a message\(aq, validators=[validators.required()]) first_name = TextField(u\(aqEnter your first name\(aq, validators=[validators.required()]) class RootController(object): @expose(generic=True, template=\(aqindex.html\(aq) def index(self): return dict(form=PersonalizedMessageForm()) @index.when(method=\(aqPOST\(aq, template=\(aqindex.html\(aq) def index_post(self): form = PersonalizedMessageForm(request.POST) if form.validate(): return dict(message=form.message.data, first_name=form.first_name.data) else: return dict(form=form) .EE .UNINDENT .UNINDENT .sp \fBچه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 کلاس \fBPersonalizedMessageForm\fP را با دو فیلد متنی و یک اعتبارسنج فیلد اجباری برای هر کدام اضافه کردیم .IP 2. 3 تابع \fBindex\fP را تغییر دادیم تا یک نمونهٔ جدید از کلاس \fBPersonalizedMessageForm\fP ایجاد کرده و آن را بازگرداند .IP 3. 3 تابع \fBindex_post\fP را تغییر دادیم تا داده‌های ارسال‌شده (POST) را گردآوری و اعتبارسنجی کند. اگر معتبر باشد، داده‌های بازگشتی را برای نمایش در صفحهٔ وب تنظیم کند. در غیر این صورت، فرمی را ارسال کند که حاوی داده‌ها به‌علاوهٔ پیام(های) خطا خواهد بود .UNINDENT .sp فایل \fBindex.html\fP را بدین صورت ویرایش کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX <%inherit file=\(dqlayout.html\(dq /> ## provide definitions for blocks we want to redefine <%def name=\(dqtitle()\(dq> Welcome to Pecan!

% if not form:

${first_name}, your message is: ${message}

% else:
${form.message.label}: ${form.message} % if form.message.errors: ${form.message.errors[0]} % endif
${form.first_name.label}: ${form.first_name} % if form.first_name.errors: ${form.first_name.errors[0]} % endif
% endif
.EE .UNINDENT .UNINDENT .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 به یاد داشته باشید که هنگام استفاده از کتابخانهٔ WTForms \% می‌توانید پیام‌های خطا و موارد بیشتر را سفارشی‌سازی کنید. همچنین شما قوانین اعتبارسنجی متعددی دارید، بنابراین حتماً تمام خطاها را دریافت کنید؛ این امر بدین معنی است که بر خلاف مثال سادهٔ بالا که تنها نخستین خطای موجود در لیست را دریافت می‌کند، به یک حلقه نیاز خواهید داشت. برای اطلاعات بیشتر مستندات \% را ببینید. .UNINDENT .UNINDENT .sp برنامه را اجرا کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve config.py .EE .UNINDENT .UNINDENT .sp یک مرورگر وب را باز کنید: \% .sp فرم را با داده‌های معتبر و همچنین بدون وارد کردن هیچ داده‌ای آزمایش کنید..SH "برنامه نمونه: AJAX ساده (EXAMPLE APPLICATION: SIMPLE AJAX)" .sp این راهنما شما را در ساخت یک برنامه وب ساده با Pecan که از AJAX برای واکشی داده‌های JSON از سرور استفاده می‌کند، راهنمایی خواهد کرد. .SS "راه‌اندازی پروژه (Project Setup)" .sp ابتدا باید Pecan را نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pip install pecan .EE .UNINDENT .UNINDENT .sp از پشتیبانی قالب پایه‌ای Pecan برای آغاز یک پروژه جدید استفاده کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan create myajax $ cd myajax .EE .UNINDENT .UNINDENT .sp پروژه جدید را در حالت توسعه نصب کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX $ python setup.py develop .EE .UNINDENT .UNINDENT .SS "افزودن پشتیبانی از AJAX در جاوااسکریپت (Adding JavaScript AJAX Support)" .sp برای این پروژه باید پشتیبانی از jQuery \% را اضافه کنیم. برای افزودن jQuery به پوشه \fBtemplates\fP رفته و فایل \fBlayout.html\fP را ویرایش کنید. .sp افزودن پشتیبانی jQuery آسان است؛ در واقع تنها به یک خط کد نیاز داریم: .INDENT 0.0 .INDENT 3.5 .sp .EX .EE .UNINDENT .UNINDENT .sp کد جاوااسکریپت برای برقراری فراخوانی AJAX کمی عمیق‌تر و مفصل‌تر است، اما اگر تاکنون با jQuery کار کرده باشید، برایتان ناآشنا نخواهد بود. .sp فایل \fBlayout.html\fP به این شکل خواهد بود: .INDENT 0.0 .INDENT 3.5 .sp .EX ${self.title()} ${self.style()} ${self.javascript()} ${self.body()} <%def name=\(dqtitle()\(dq> Default Title <%def name=\(dqstyle()\(dq> <%def name=\(dqjavascript()\(dq> .EE .UNINDENT .UNINDENT .sp \fBدقیقاً چه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 در بخش \fBhead\fP، پشتیبانی از jQuery را از طریق CDN گوگل \% اضافه کردیم .IP 2. 3 کد جاوااسکریپت را برای برقراری فراخوانی AJAX به سرور از طریق HTTP \fBGET\fP با ارسال \fBid\fP پروژه جهت واکشی اطلاعات بیشتر اضافه کردیم .IP 3. 3 پس از فعال شدن رویداد \fBonSuccess\fP با بازگشت داده‌ها، آن را دریافت کرده و در صفحه وب زیر بخش کنترل‌ها نمایش می‌دهیم .UNINDENT.SS افزودن HTML بیشتر .sp در مرحله بعد، بیایید فایل \fBindex.html\fP را ویرایش کنیم. برای پشتیبانی از تعامل AJAX بین صفحه وب و Pecan، کدهای HTML را اضافه خواهیم کرد. فایل \fBindex.html\fP را تغییر دهید تا به این صورت باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX <%inherit file=\(dqlayout.html\(dq /> <%def name=\(dqtitle()\(dq> Welcome to Pecan!

Select a project to get details:

.EE .UNINDENT .UNINDENT .sp \fBدقیقاً چه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 یک کنترل کشویی و یک دکمه ثبت (submit) برای تعامل کاربر اضافه کردیم. کاربران می‌توانند یک پروژه متن‌باز را انتخاب کرده و جزئیات بیشتری درباره آن دریافت کنند. .UNINDENT .SS ساخت مدل با پشتیبانی از JSON .sp کارهای مربوط به HTML و JavaScript اکنون به پایان رسیده است. در این مرحله می‌توانیم مدلی را درون پوشه \fBmodel\fP به پروژه خود اضافه کنیم. فایلی به نام \fBprojects.py\fP در آنجا ایجاد کرده و موارد زیر را به آن اضافه کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX class Project(object): def __init__(self, name, licensing, repository, documentation): self.name = name self.licensing = licensing self.repository = repository self.documentation = documentation def __json__(self): return dict( name=self.name, licensing=self.licensing, repository=self.repository, documentation=self.documentation ) .EE .UNINDENT .UNINDENT .sp \fBدقیقاً چه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 مدلی به نام \fBProject\fP ایجاد کردیم که می‌تواند داده‌های مختص پروژه را نگه‌داری کند. .IP 2. 3 یک متد \fB__json__\fP اضافه کردیم تا یک نمونه از \fBProject class\fP به‌راحتی به‌صورت JSON نمایش داده شود. کنترلری که به‌زودی خواهیم ساخت از این قابلیت JSON استفاده خواهد کرد. .UNINDENT .sp \fBنکته:\fP .INDENT 0.0 .INDENT 3.5 راه‌های دیگری نیز برای بازگرداندن JSON در Pecan وجود دارد؛ برای اطلاعات بیشتر بخش سریال‌سازی JSON \%<#\:jsonify> را بررسی کنید. .UNINDENT .UNINDENT .SS کار با کنترلرها .sp نیازی نیست تغییر عمده‌ای در فایل \fBroot.py\fP در پوشه \fBcontrollers\fP اعمال کنیم، جز افزودن پشتیبانی از یک کنترلر جدید که آن را \fBProjectsController\fP می‌نامیم. فایل \fBroot.py\fP را به این شکل تغییر دهید: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose from myajax.controllers.projects import ProjectsController class RootController(object): projects = ProjectsController() @expose(generic=True, template=\(aqindex.html\(aq) def index(self): return dict() .EE .UNINDENT .UNINDENT .sp \fBدقیقاً چه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 برخی از کدهای قالبی (boilerplate) اولیه را چون از آن‌ها استفاده نمی‌کنیم حذف کردیم. .IP 2. 3 پشتیبانی از \fBProjectsController\fP آینده را اضافه کردیم. .UNINDENT .sp بخش نهایی، افزودن فایلی به نام \fBprojects.py\fP به پوشه \fBcontrollers\fP است. این فایل جدید میزبان \fBProjectsController\fP خواهد بود که به درخواست‌های ورودی AJAX \fBGET\fP (در مورد ما) گوش می‌دهد و پاسخ JSON مناسب را بازمی‌گرداند. .sp کد زیر را به فایل \fBprojects.py\fP اضافه کنید: .INDENT 0.0 .INDENT 3.5 .sp .EX from pecan import expose, response from pecan.rest import RestController from myajax.model.projects import Project class ProjectsController(RestController): # Note: You would probably store this information in a database # This is just for simplicity and demonstration purposes def __init__(self): self.projects = [ Project(name=\(aqOpenStack\(aq, licensing=\(aqApache 2\(aq, repository=\(aqhttp://github.com/openstack\(aq, documentation=\(aqhttp://docs.openstack.org\(aq), Project(name=\(aqPecan\(aq, licensing=\(aqBSD\(aq, repository=\(aqhttp://github.com/pecan/pecan\(aq, documentation=\(aqhttps://pecan.readthedocs.io\(aq), Project(name=\(aqstevedore\(aq, licensing=\(aqApache 2\(aq, repository=\(aqhttp://github.com/dreamhost/pecan\(aq, documentation=\(aqhttp://docs.openstack.org/developer/stevedore/\(aq) ] @expose(\(aqjson\(aq, content_type=\(aqapplication/json\(aq) def get(self, id): response.status = 200 return self.projects[int(id)] .EE .UNINDENT .UNINDENT .sp \fBدقیقاً چه کاری انجام دادیم؟\fP .INDENT 0.0 .IP 1. 3 یک متغیر کلاس محلی به نام \fBprojects\fP ایجاد کردیم که مشخصات سه پروژه متن‌باز را نگه‌داری می‌کند. به‌طور معمول این نوع داده‌ها احتمالاً در یک پایگاه‌داده قرار می‌گیرند. .IP 2. 3 کدی را برای کنترلر جدید اضافه کردیم که به نقطه پایانی (endpoint) \fBprojects\fP گوش می‌دهد و بر اساس \fBid\fP ارائه‌شده از صفحه وب، JSON را بازمی‌گرداند. .UNINDENT .sp اجرای برنامه: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve config.py .EE .UNINDENT .UNINDENT .sp مرورگر وب را باز کنید: \% .sp چیز دیگری هم وجود دارد که می‌توانیم اضافه کنیم. اگر یک \fBid\fP ارسال شود که پیدا نشود چه؟ در این حالت باید یک خطای مناسب \fBHTTP 404\fP فرستاده شود. برای این منظور، \fBProjectsController\fP را تغییر خواهیم داد. .sp تابع \fBget\fP را تغییر دهید تا به این صورت باشد: .INDENT 0.0 .INDENT 3.5 .sp .EX @expose(\(aqjson\(aq, content_type=\(aqapplication/json\(aq) def get(self, id): try: response.status = 200 return self.projects[int(id)] except (IndexError, ValueError) as ex: abort(404) .EE .UNINDENT .UNINDENT.sp برای آزمایش این مورد، نیاز داریم یک \fBid\fP نامعتبر را به \fBProjectsController\fP\& ارسال کنیم. این کار را می‌توان با رفتن به فایل \fBindex.html\fP و افزودن یک برچسب \fBoption\fP اضافی با مقدار \fBid\fP خارج از بازه ۰\-۲ انجام داد. .INDENT 0.0 .INDENT 3.5 .sp .EX

Select a project to get details:

.EE .UNINDENT .UNINDENT .sp می‌توانید ببینید که ما \fBWSME\fP را با مقدار ۳ به فهرست افزوده‌ایم. .sp اجرای برنامه: .INDENT 0.0 .INDENT 3.5 .sp .EX $ pecan serve config.py .EE .UNINDENT .UNINDENT .sp یک مرورگر وب باز کنید: \% .sp گزینه \fBWSME\fP را از فهرست انتخاب کنید. باید باز شدن جعبه گفتگوی خطا را مشاهده کنید. .sp کد منبع Pecan با استفاده از docstringها و کامنت‌های پایتون به‌خوبی مستندسازی شده است. علاوه بر این، ما مستندات API را از docstringها در اینجا تولید کرده‌ایم: .SH "PECAN.CORE -- هسته PECAN (PECAN CORE)" .sp ماژول \fBpecan.core\fP ماژول پایه برای ایجاد و گسترش Pecan است. منطق اصلی برای پردازش درخواست‌ها و پاسخ‌های HTTP در اینجا قرار دارد. .INDENT 0.0 .TP .B class pecan.core.Pecan(*args, **kw) کلاس‌های پایه: \fBPecanBase\fP .sp شیء برنامه Pecan. معمولاً به‌جای ایجاد دستی، با استفاده از \fBpecan.make_app\fP ایجاد می‌شود. .sp یک نمونه از برنامه Pecan ایجاد می‌کند که یک برنامه WSGI است. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBroot\fP \-\- رشته‌ای نشان‌دهنده یک شیء کنترل‌کننده ریشه (مانند \(dqmyapp.controller.root.RootController\(dq) .IP \(bu 2 \fBdefault_renderer\fP \-\- موتور رندر قالب پیش‌فرض برای استفاده. پیش‌فرض mako است. .IP \(bu 2 \fBtemplate_path\fP \-\- یک مسیر نسبی در فایل‌سیستم (از ریشه پروژه) که فایل‌های قالب در آن قرار دارند. پیش‌فرض \(aqtemplates\(aq است. .IP \(bu 2 \fBhooks\fP \-\- یک شیء قابل فراخوانی که فهرستی از \fBpecan.hooks.PecanHook\fP \%<#\:pecan\:.hooks\:.PecanHook> را بازمی‌گرداند. .IP \(bu 2 \fBcustom_renderers\fP \-\- اشیاء رندرکننده سفارشی، به‌صورت یک دیکشنری با کلید نام موتور. .IP \(bu 2 \fBextra_template_vars\fP \-\- هرگونه متغیر برای تزریق خودکار به فضای نام (namespace) قالب. .IP \(bu 2 \fBforce_canonical\fP \-\- یک مقدار بولی که مشخص می‌کند آیا این پروژه باید به نشانی‌های وب متعارف (canonical URLs) نیاز داشته باشد یا خیر. .IP \(bu 2 \fBguess_content_type_from_ext\fP \-\- یک مقدار بولی که مشخص می‌کند آیا این پروژه باید از پسوند موجود در نشانی وب برای حدس زدن نوع محتوای بازگشتی استفاده کند یا خیر. .IP \(bu 2 \fBuse_context_locals\fP \-\- در صورت \fITrue\fP بودن، \fIpecan.request\fP و \fIpecan.response\fP به‌صورت ارجاع‌های محلی نخ (thread\-local) در دسترس خواهند بود. .IP \(bu 2 \fBrequest_cls\fP \-\- می‌تواند برای مشخص کردن یک شیء سفارشی \fIpecan.request\fP استفاده شود. پیش‌فرض \fIpecan.Request\fP\& است. .IP \(bu 2 \fBresponse_cls\fP \-\- می‌تواند برای مشخص کردن یک شیء سفارشی \fIpecan.response\fP استفاده شود. پیش‌فرض \fIpecan.Response\fP\& است. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B find_controller(_state) گرداننده اصلی درخواست برای برنامه‌های Pecan. .UNINDENT .INDENT 7.0 .TP .B handle_hooks(hooks, *args, **kw) قلاب‌های (hooks) نوع مشخص‌شده را پردازش می‌کند. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBhook_type\fP \-\- نوع قلاب، شامل \fBbefore\fP، \fBafter\fP، \fBon_error\fP و \fBon_route\fP\&. .IP \(bu 2 \fB*args\fP \-\- .sp آرگومان‌هایی برای ارسال به قلاب‌ها. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.core.Request(environ, charset=None, unicode_errors=None, decode_param_names=None, **kw) کلاس‌های پایه: \fBRequest\fP .UNINDENT .INDENT 0.0 .TP .B class pecan.core.Response(body=None, status=None, headerlist=None, app_iter=None, content_type=None, conditional_response=None, charset=, **kw) کلاس‌های پایه: \fBResponse\fP .UNINDENT .INDENT 0.0 .TP .B pecan.core.abort(status_code, detail=\(aq\(aq, headers=None, comment=None, **kw) یک کد وضعیت HTTP را مطابق با موارد مشخص‌شده برمی‌انگیزد (Raise). برای بازگرداندن کدهای وضعیتی مانند 401 Unauthorized یا 403 Forbidden کاربرد دارد. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBstatus_code\fP \-\- کد وضعیت HTTP به‌صورت یک عدد صحیح. .IP \(bu 2 \fBdetail\fP \-\- پیامی برای ارسال همراه با آن، به‌صورت یک رشته. .IP \(bu 2 \fBheaders\fP \-\- یک دیکشنری از سرآیندها برای ارسال همراه با پاسخ. .IP \(bu 2 \fBcomment\fP \-\- یک توضیح (کامنت) برای گنجاندن در پاسخ. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.core.load_app(config, **kwargs) برای بارگذاری یک برنامه \fBPecan\fP و محیط آن بر اساس پیکربندی ارائه‌شده استفاده می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBconfig\fP \-\- می‌تواند یک دیکشنری حاوی پیکربندی یا رشته‌ای باشد که نام فایل پیکربندی (نسبی) را نشان می‌دهد .UNINDENT .sp یک شیء pecan.Pecan بازمی‌گرداند .UNINDENT .INDENT 0.0 .TP .B pecan.core.override_template(template, content_type=None) درون یک کنترل‌کننده فراخوانی می‌شود تا قالبی را که در پاسخ شما استفاده می‌شود بازنویسی (override) کند. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBtemplate\fP \-\- یک مسیر معتبر به یک فایل قالب، دقیقاً همان‌گونه که در یک \fB@expose\fP\& مشخص می‌کنید. .IP \(bu 2 \fBcontent_type\fP \-\- یک نوع معتبر MIME برای استفاده در response.func_closure .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.core.redirect(location=None, internal=False, code=None, headers=None, add_slash=False, request=None) یک تغییر مسیر (redirect)، چه داخلی و چه خارجی انجام می‌دهد. تغییر مسیر داخلی ریدایرکت را در سمت سرور انجام می‌دهد، در حالی که تغییر مسیر خارجی از کد وضعیت HTTP 302 استفاده می‌کند. .INDENT 7.0.TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBlocation\fP \-\- نشانی HTTP برای تغییر مسیر به آن. .IP \(bu 2 \fBinternal\fP \-\- یک مقدار بولی که مشخص می‌کند آیا تغییر مسیر باید داخلی باشد یا خیر. .IP \(bu 2 \fBcode\fP \-\- کد وضعیت HTTP برای استفاده در تغییر مسیر. پیش‌فرض 302 است. .IP \(bu 2 \fBheaders\fP \-\- هرگونه هدر HTTP برای ارسال همراه با پاسخ، در قالب یک دیکشنری. .IP \(bu 2 \fBrequest\fP \-\- نمونه \fBpecan.Request\fP مورد استفاده. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.core.render(template, namespace, app=None) قالب مشخص‌شده را با استفاده از چارچوب رندر Pecan و فضای‌نام قالب مشخص‌شده در قالب یک دیکشنری رندر می‌کند. در کنترلری کاربرد دارد که هیچ قالبی در \fB@expose\fP\& برای آن مشخص نشده است. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBtemplate\fP \-\- مسیر قالب شما، همان‌طور که در \fB@expose\fP\& مشخص می‌کنید. .IP \(bu 2 \fBnamespace\fP \-\- فضای‌نام مورد استفاده برای رندر قالب، در قالب یک دیکشنری. .IP \(bu 2 \fBapp\fP \-\- نمونه \fBpecan.Pecan\fP مورد استفاده .UNINDENT .UNINDENT .UNINDENT .SH PECAN.COMMANDS \-\- دستورهای PECAN (PECAN COMMANDS) .sp ماژول \fBpecan.commands\fP اسکریپت کنسول \fBpecan\fP را پیاده‌سازی می‌کند که برای ارائه ابزارهای خط فرمان (به‌عنوان مثال) \fBpecan serve\fP و \fBpecan shell\fP به کار می‌رود. .INDENT 0.0 .TP .B class pecan.commands.base.BaseCommand کلاس‌های پایه: \fBBaseCommandParent\fP .sp یک رابط پایه برای دستورهای Pecan. .sp می‌تواند برای پشتیبانی از افزونه‌های دستور \fBpecan\fP در پروژه‌های مجزای Pecan گسترش داده شود، مانند: .sp $ \fBpecan my\-custom\-command config.py\fP .INDENT 7.0 .INDENT 3.5 .sp .EX # myapp/myapp/custom_command.py class CustomCommand(pecan.commands.base.BaseCommand): \(aq\(aq\(aq (First) line of the docstring is used to summarize the command. \(aq\(aq\(aq arguments = ({ \(aqname\(aq: \(aq\-\-extra_arg\(aq, \(aqhelp\(aq: \(aqan extra command line argument\(aq, \(aqoptional\(aq: True }) def run(self, args): super(SomeCommand, self).run(args) if args.extra_arg: pass .EE .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.base.BaseCommandParent کلاس‌های پایه: \fBobject\fP \% .sp یک رابط پایه برای دستورهای Pecan. .sp می‌تواند برای پشتیبانی از افزونه‌های دستور \fBpecan\fP در پروژه‌های مجزای Pecan گسترش داده شود، مانند: .sp $ \fBpecan my\-custom\-command config.py\fP .INDENT 7.0 .INDENT 3.5 .sp .EX # myapp/myapp/custom_command.py class CustomCommand(pecan.commands.base.BaseCommand): \(aq\(aq\(aq (First) line of the docstring is used to summarize the command. \(aq\(aq\(aq arguments = ({ \(aqname\(aq: \(aq\-\-extra_arg\(aq, \(aqhelp\(aq: \(aqan extra command line argument\(aq, \(aqoptional\(aq: True }) def run(self, args): super(SomeCommand, self).run(args) if args.extra_arg: pass .EE .UNINDENT .UNINDENT .INDENT 7.0 .TP .B run(args) باید توسط زیرکلاس‌ها پیاده‌سازی شود. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.base.CommandManager کلاس‌های پایه: \fBobject\fP \% .sp برای یافتن نقاط ورود (entry points) \fIpecan.command\fP استفاده می‌شود. .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.base.CommandRunner کلاس‌های پایه: \fBobject\fP \% .sp درخواست‌های اجرای دستور \fIpecan\fP را اعزام (dispatch) می‌کند. .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.base.HelpfulArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=, prefix_chars=\(aq\-\(aq, fromfile_prefix_chars=None, argument_default=None, conflict_handler=\(aqerror\(aq, add_help=True, allow_abbrev=True, exit_on_error=True, *, suggest_on_error=False, color=True) کلاس‌های پایه: \fBArgumentParser\fP \% .INDENT 7.0 .TP .B error(message: string) پیام نحوه استفاده را به همراه پیام مربوطه در stderr چاپ کرده و خارج می‌شود. .sp اگر این مورد را در یک زیرکلاس بازنویسی (override) کنید، نباید مقداری برگرداند \-\- بلکه باید یا خارج شود یا یک استثنا (exception) صادر کند. .UNINDENT .UNINDENT.SS \fBpecan.commands.server\fP \-\- سرور توسعه‌ی Pecan .sp دستور Serve برای Pecan. .INDENT 0.0 .TP .B class pecan.commands.serve.PecanWSGIRequestHandler(*args, **kwargs) کلاس‌های پایه: \fBWSGIRequestHandler\fP \%، \fBobject\fP \% .sp یک کلاس مدیریت درخواست wsgiref که امکان خروجی لاگ واقعی را بسته به پیکربندی برنامه فراهم می‌کند. .INDENT 7.0 .TP .B log_message(format, *args) متد \fBlog_message\fP را از سرور wsgiref بازنویسی می‌کند تا ثبت لاگ عادی با هر پیکربندی تنظیم‌شده در برنامه به درستی کار کند. .sp سطوح لاگ از کد وضعیت HTTP استنتاج می‌شوند؛ کدهای 4XX به عنوان هشدار (warning)، کدهای 5XX به عنوان خطا (error) و سایر موارد در سطح INFO در نظر گرفته می‌شوند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.serve.ServeCommand کلاس‌های پایه: \fBBaseCommand\fP .sp یک برنامه وب Pecan را میزبانی و ارائه می‌کند. .sp این دستور یک برنامه وب Pecan را با استفاده از فایل پیکربندی ارائه‌شده برای سرور و برنامه اجرا می‌کند. .INDENT 7.0 .TP .B run(args) باید توسط زیرکلاس‌ها پیاده‌سازی شود. .UNINDENT .INDENT 7.0 .TP .B serve(app, conf) رویکردی بسیار ساده برای یک سرور WSGI. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.commands.serve.gunicorn_run() دستور \fBgunicorn_pecan\fP برای راه‌اندازی برنامه‌های \fBpecan\fP .UNINDENT .SS \fBpecan.commands.shell\fP \-\- پوسته تعاملی Pecan .sp دستور Shell برای Pecan. .INDENT 0.0 .TP .B class pecan.commands.shell.BPythonShell کلاس‌های پایه: \fBobject\fP \% .sp باز کردن یک پوسته تعاملی bpython همراه با برنامه بارگذاری‌شده Pecan. .INDENT 7.0 .TP .B classmethod invoke(ns, banner) .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBns\fP \-\- فضای نام محلی .IP \(bu 2 \fBbanner\fP \-\- بنر آغازین پوسته تعاملی .UNINDENT .UNINDENT .sp تعبیه یک پوسته تعاملی bpython. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.shell.IPythonShell کلاس‌های پایه: \fBobject\fP \% .sp باز کردن یک پوسته تعاملی ipython همراه با برنامه بارگذاری‌شده Pecan. .INDENT 7.0 .TP .B classmethod invoke(ns, banner) .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBns\fP \-\- فضای نام محلی .IP \(bu 2 \fBbanner\fP \-\- بنر آغازین پوسته تعاملی .UNINDENT .UNINDENT .sp تعبیه یک پوسته تعاملی ipython. ابتدا رابط InteractiveShellEmbed را امتحان می‌کند و برای نسخه‌های قدیمی‌تر IPython به IPShellEmbed بازمی‌گردد. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.shell.NativePythonShell کلاس‌های پایه: \fBobject\fP \% .sp باز کردن یک پوسته تعاملی پایتون همراه با برنامه بارگذاری‌شده Pecan. .INDENT 7.0 .TP .B classmethod invoke(ns, banner) .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBns\fP \-\- فضای نام محلی .IP \(bu 2 \fBbanner\fP \-\- بنر آغازین پوسته تعاملی .UNINDENT .UNINDENT .sp تعبیه یک پوسته تعاملی بومی پایتون. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.commands.shell.ShellCommand کلاس‌های پایه: \fBBaseCommand\fP .sp باز کردن یک پوسته تعاملی همراه با برنامه بارگذاری‌شده Pecan. تلاش برای فراخوانی نوع پوسته پایتون مشخص‌شده (ipython، bpython و غیره). در صورتی که نوع درخواستی نصب نشده باشد، به پوسته بومی پایتون بازمی‌گردد. .INDENT 7.0 .TP .B invoke_shell(locs, banner) نوع مناسب پوسته پایتون را فراخوانی می‌کند. در صورتی که نوع درخواستی (ipython، bpython و غیره) نصب نشده باشد، به پوسته بومی پایتون بازمی‌گردد. .UNINDENT .INDENT 7.0 .TP .B load_model(config) بارگذاری ماژول افزونه مدل .UNINDENT .INDENT 7.0 .TP .B run(args) بارگذاری برنامه pecan، آماده‌سازی متغیرهای محلی (locals)، تنظیم بنر و فراخوانی پوسته پایتون. .UNINDENT .UNINDENT.SH "PECAN.CONFIGURATION \-\- موتور پیکربندی PECAN (PECAN CONFIGURATION ENGINE)" .sp ماژول \fBpecan.configuration\fP پیاده‌سازی یک موتور پیکربندی مبتنی بر پایتون را برای برنامه‌های Pecan فراهم می‌کند. .INDENT 0.0 .TP .B class pecan.configuration.Config(conf_dict=None, filename=\(aq\(aq) کلاس‌های پایه: \fBobject\fP \% .sp کلاس پایه برای پیکربندی‌های Pecan. .sp ایجاد یک شیء پیکربندی Pecan از یک دیکشنری یا نام فایل. .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBconf_dict\fP \-\- یک دیکشنری پایتون برای استفاده در پیکربندی. .IP \(bu 2 \fBfilename\fP \-\- نام فایل مورد استفاده برای پیکربندی. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B to_dict(prefix=None) شیء Config را به صورت بازگشتی به یک دیکشنری معتبر تبدیل می‌کند. .INDENT 7.0 .TP .B پارامترها \fBprefix\fP \-\- یک رشته برای پیشوند زدن اختیاری به تمام کلیدها در دیکشنری بازگردانده‌شده. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B update(conf_dict) این پیکربندی را با یک دیکشنری به‌روزرسانی می‌کند. .INDENT 7.0 .TP .B پارامترها \fBconf_dict\fP \-\- یک دیکشنری پایتون برای به‌روزرسانی این پیکربندی. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.configuration.ConfigDict کلاس‌های پایه: \fBdict\fP \% .UNINDENT .INDENT 0.0 .TP .B pecan.configuration.conf_from_dict(conf_dict) یک دیکشنری پیکربندی از یک دیکشنری می‌سازد. .INDENT 7.0 .TP .B پارامترها \fBconf_dict\fP \-\- دیکشنری پیکربندی. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.configuration.conf_from_file(filepath) یک دیکشنری پیکربندی از یک فایل می‌سازد. .INDENT 7.0 .TP .B پارامترها \fBfilepath\fP \-\- مسیر فایل. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.configuration.get_conf_path_from_env() اگر متغیر محیطی \fBPECAN_CONFIG\fP وجود داشته باشد و به یک مسیر معتبر اشاره کند، آن را بازمی‌گرداند؛ در غیر این صورت یک \fBRuntimeError\fP ایجاد خواهد کرد\&. .UNINDENT .INDENT 0.0 .TP .B pecan.configuration.initconf() پیکربندی پیش‌فرض را مقداردهی اولیه کرده و آن را در \fBpecan.configuration.conf\fP در دسترس قرار می‌دهد، که همچنین در \fBpecan.conf\fP نیز در دسترس است\&. .UNINDENT .INDENT 0.0 .TP .B pecan.configuration.set_config(config, overwrite=False) پیکربندی سراسری را به‌روزرسانی می‌کند. .INDENT 7.0 .TP .B پارامترها \fBconfig\fP \-\- می‌تواند یک دیکشنری حاوی پیکربندی، یا یک رشته باشد که نام فایل پیکربندی (نسبی) را نشان می‌دهد. .UNINDENT .UNINDENT.SH PECAN.DECORATORS -- دکوراتورهای PECAN (PECAN DECORATORS) .sp ماژول \fBpecan.decorators\fP شامل دکوراتورهای مفیدی برای ایجاد برنامه‌های Pecan است. .INDENT 0.0 .TP .B pecan.decorators.accept_noncanonical(func) یک متد کنترلر را به عنوان پذیرندهٔ URLهای غیرمعیار (non\-canonical) علامت‌گذاری می‌کند. .UNINDENT .INDENT 0.0 .TP .B pecan.decorators.after_commit(action) در صورت استفاده از \fBpecan.hooks\fP \%<#\:module-pecan\:.hooks> \fBTransactionHook\fP، به شما امکان می‌دهد متد یک کنترلر را علامت‌گذاری کنید تا پس از اعمال موفقیت‌آمیز تراکنش (commit)، یک کنش قابل‌فراخوانی (callable) را اجرا کند. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBaction\fP \-\- شیء قابل‌فراخوانی برای فراخوانی پس از اعمال موفقیت‌آمیز commit. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.decorators.after_rollback(action) در صورت استفاده از \fBpecan.hooks\fP \%<#\:module-pecan\:.hooks> \fBTransactionHook\fP، به شما امکان می‌دهد متد یک کنترلر را علامت‌گذاری کنید تا پس از بازگردانی موفقیت‌آمیز تراکنش (rollback)، یک کنش قابل‌فراخوانی (callable) را اجرا کند. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBaction\fP \-\- شیء قابل‌فراخوانی برای فراخوانی پس از بازگردانی موفقیت‌آمیز rollback. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.decorators.expose(template=None, generic=False, route=None, **kw) دکوراتوری که برای علامت‌گذاری متدهای کنترلر به عنوان «عرضه‌شده» (\(dqexposed\(dq) جهت دسترسی از طریق HTTP و پیکربندی آن دسترسی استفاده می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBtemplate\fP \-\- مسیر یک قالب، به صورت نسبی نسبت به دایرکتوری پایهٔ قالب‌ها. همچنین می‌تواند رشته‌ای دریافت کند که نمایانگر یک رندرساز (renderer) خاص یا سفارشی باشد، مانند \fB\(aqjson\(aq\fP برای رندرساز JSON \%<#\:expose-json>\&. .IP \(bu 2 \fBcontent_type\fP \-\- نوع محتوا (content\-type) مورد استفاده برای این قالب. .IP \(bu 2 \fBgeneric\fP \-\- مقداری بولی که این کنترلر را به عنوان یک کنترلر «عمومی» (\(dqgeneric\(dq) علامت‌گذاری می‌کند، که از توابع چندریختی بر پایهٔ توابع عمومی \fBfunctools.singledispatch\fP استفاده می‌کند. به شما امکان می‌دهد یک کنترلر واحد را بر اساس متد HTTP به چندین مسیر تقسیم کنید. .IP \(bu 2 \fBroute\fP \-\- نام بخش مسیر برای تطبیق (به استثنای نویسه‌های جداکننده، مانند \fI/\fP). به طور پیش‌فرض نام خود تابع در نظر گرفته می‌شود، اما می‌تواند برای برطرف‌سازی مسیرهایی استفاده شود که نام‌های معتبر تابع پایتون نیستند؛ به عنوان مثال اگر بخواهید تابعی را به .nf \(ga .fi some\-special\-path\(aq مسیریابی کنید. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.decorators.transactional(ignore_redirects=True) در صورت استفاده از \fBpecan.hooks\fP \%<#\:module-pecan\:.hooks> \fBTransactionHook\fP، به شما امکان می‌دهد یک متد یا کلاس کنترلر را صرف‌نظر از متد HTTP، به عنوان قرارگرفته در یک تراکنش علامت‌گذاری کنید. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBignore_redirects\fP \-\- مشخص می‌کند که آیا قلاب (hook) باید تغییرمسیرها (redirects) را برای این کنترلر نادیده بگیرد یا خیر. .UNINDENT .UNINDENT.SH "PECAN.DEPLOY \- استقرار PECAN (PECAN DEPLOY)" .sp ماژول \fBpecan.deploy\fP شامل فیکسچرهایی برای کمک به استقرار برنامه‌های کاربردی Pecan است. .INDENT 0.0 .TP .B pecan.deploy.deploy(config) با دریافت یک config (فرهنگ‌لغتی از نام فایل‌های نسبی)، یک برنامهٔ WSGI پیکربندی‌شده را بازمی‌گرداند. .UNINDENT .SH "PECAN.HOOKS \- قلاب‌های PECAN (PECAN HOOKS)" .sp ماژول \fBpecan.hooks\fP شامل پشتیبانی از ایجاد \fBhooks\fP (قلاب‌ها) در Pecan است که روشی ساده برای مداخله در فرایند پردازش درخواست‌های ورودی به برنامهٔ شما به‌منظور انجام وظایف فرافردی (cross\-cutting) فراهم می‌کند. .INDENT 0.0 .TP .B class pecan.hooks.HookController کلاس‌های پایه: \fBobject\fP \% .sp یک کلاس پایه برای کنترلرهایی که مایل به تعیین قلاب‌ها روی متدهای کنترلر خود هستند. کافی است فهرستی از اشیاء قلاب به نام \fB__hooks__\fP را به‌عنوان یک صفت کلاسی در کنترلر خود ایجاد کنید. .UNINDENT .INDENT 0.0 .TP .B class pecan.hooks.PecanHook کلاس‌های پایه: \fBobject\fP \% .sp یک کلاس پایه برای قلاب‌های Pecan. برای ساخت قلاب‌های سفارشی خود از این کلاس ارث‌بری کنید. با تنظیم صفت \fBpriority\fP برای قلاب می‌توانید اولویت آن را مشخص کنید که مقدار پیش‌فرض آن ۱۰۰ است. .INDENT 7.0 .TP .B after(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مدیریت درخواست توسط کنترلر فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B before(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مسیریابی، اما پیش از ارسال درخواست به کنترلر شما فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B on_error(state, e) این متد را بازنویسی کنید تا قلابی ایجاد شود که هنگام رخ دادن یک استثنا (exception) در کنترلر شما فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .IP \(bu 2 \fBe\fP \-\- شیء \fBException\fP که برانگیخته شده است. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B on_route(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که در آغاز فرایند مسیریابی فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.hooks.RequestViewerHook(config=None, writer=<_io.TextIOWrapper name=\(aq\(aq mode=\(aqw\(aq encoding=\(aqutf\-8\(aq>, terminal=True, headers=True) کلاس‌های پایه: \fBPecanHook\fP .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBconfig\fP \-\- یک فرهنگ‌لغت (اختیاری) که می‌تواند کلیدهای \fBitems\fP و/یا \fBblacklist\fP را نگه دارد. .IP \(bu 2 \fBwriter\fP \-\- نویسندهٔ جریان (stream writer) مورد استفاده. تا زمانی که جریان ورودی دارای یک متد قابل فراخوانی \fBwrite\fP باشد، می‌تواند خروجی را به جریان‌های دیگر هدایت کند. .IP \(bu 2 \fBterminal\fP \-\- خروجی را به نویسندهٔ جریان انتخابی (معمولاً ترمینال) می‌فرستد .IP \(bu 2 \fBheaders\fP \-\- مقادیر را روی سرایندهای X\-HTTP تنظیم می‌کند .UNINDENT .UNINDENT .sp اطلاعاتی دربارهٔ آنچه در یک درخواست منفرد رخ می‌دهد بازمی‌گرداند. این قلاب موارد مشخصی را برای گزارش‌دهی می‌پذیرد اما در صورتی که هیچ موردی ارسال نشود از فهرست پیش‌فرضی از موارد استفاده می‌کند. بر اساس \fBurl\fP درخواست‌شده، موارد می‌توانند در سیاه‌فهرست نیز قرار گیرند. پیکربندی منعطف است، می‌تواند ارسال شود (یا نشود) و شامل برخی یا تمام کلیدهای پشتیبانی‌شده باشد. .sp \fBitems\fP .sp این کلید شامل مواردی است که این قلاب نمایش خواهد داد. هنگامی که این کلید ارسال شود، تنها موارد درون فهرست استفاده خواهند شد. موارد معتبر شامل \fIهر\fP موردی است که شیء \fBrequest\fP دارد؛ به‌طور پیش‌فرض از موارد زیر استفاده می‌شود: .INDENT 7.0 .IP \(bu 2 path .IP \(bu 2 status .IP \(bu 2 method .IP \(bu 2 controller .IP \(bu 2 params .IP \(bu 2 hooks .UNINDENT .sp \fBنکته:\fP .INDENT 7.0 .INDENT 3.5 این کلید همواره باید از یک \fBlist\fP از موارد برای استفاده بهره ببرد. .UNINDENT .UNINDENT .sp \fBblacklist\fP .sp این کلید مواردی را نگه می‌دارد که بر اساس \fBurl\fP در سیاه‌فهرست قرار خواهند گرفت\&. اگر نیاز به حذف آدرس‌هایی باشد که با \fI/javascript\fP شروع می‌شوند، این کلید به شکل زیر خواهد بود: .INDENT 7.0 .INDENT 3.5 .sp .EX \(aqblacklist\(aq: [\(aq/javascript\(aq] .EE .UNINDENT .UNINDENT .sp این فهرست می‌تواند شامل هر تعداد موردی که نیاز است برای قرار گرفتن در سیاه‌فهرست باشد. قلاب بررسی خواهد کرد که آدرس url با موارد موجود در این فهرست شروع نشود تا نتایج را نمایش دهد، در غیر این صورت نادیده گرفته خواهد شد. .sp \fBنکته:\fP .INDENT 7.0 .INDENT 3.5 این کلید همواره باید از یک \fBlist\fP از موارد برای استفاده بهره ببرد. .UNINDENT .UNINDENT .sp برای مستندات تفصیلی‌تر دربارهٔ این قلاب، لطفاً RequestViewerHook \%<#\:requestviewerhook> را ببینید. .INDENT 7.0 .TP .B after(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مدیریت درخواست توسط کنترلر فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B format_hooks(hooks) تلاش می‌کند تا اشیاء قلاب را قالب‌بندی کند تا خواناتر شوند مختص Pecan (در شیء request موجود نیست) .UNINDENT .INDENT 7.0.TP .B get_controller(state) نام کنترلر (controller) واقعی را از برنامه بازمی‌یابد مختص Pecan (در شیء request در دسترس نیست) .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.hooks.TransactionHook(start, start_ro, commit, rollback, clear) کلاس‌های پایه: \fBPecanHook\fP .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBstart\fP \-\- یک callable که به یک پایگاه‌داده با قابلیت نوشتن متصل شده و یک تراکنش را آغاز می‌کند. .IP \(bu 2 \fBstart_ro\fP \-\- یک callable که به یک پایگاه‌دادهٔ فقط‌خواندنی متصل می‌شود. .IP \(bu 2 \fBcommit\fP \-\- یک callable که تراکنش فعال را ثبت (commit) می‌کند. .IP \(bu 2 \fBrollback\fP \-\- یک callable که تراکنش فعال را بازگردانی (roll back) می‌کند. .IP \(bu 2 \fBclear\fP \-\- یک callable که بافتار (context) فعلی شما را پاکسازی می‌کند. .UNINDENT .UNINDENT .sp یک قلاب (hook) پایه‌ای چارچوب برای پشتیبانی از قرار دادن درخواست‌ها در تراکنش‌ها. به‌طور پیش‌فرض، تمام درخواست‌ها به جز \fBGET\fP و \fBHEAD\fP را درون یک تراکنش قرار می‌دهد. متد \fBis_transactional\fP را بازنویسی (override) کنید تا قواعد سفارشی خود را برای این‌که چه درخواست‌هایی باید تراکنشی باشند، تعریف نمایید. .INDENT 7.0 .TP .B after(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از رسیدگی به درخواست توسط کنترلر، فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B before(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مسیریابی، اما قبل از ارسال درخواست به کنترلر شما فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B is_transactional(state) بر اساس وضعیت (state) درخواست، تعیین می‌کند که آیا یک درخواست باید درون یک تراکنش قرار گیرد یا خیر. به‌طور پیش‌فرض، به همراه رعایت دکوراتور \fBtransactional\fP از :mod:pecan.decorators، تمامی درخواست‌ها به جز \fBGET\fP و \fBHEAD\fP را درون یک تراکنش قرار می‌دهد. .INDENT 7.0 .TP .B پارامترها \fBstate\fP \-\- شیء state در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B on_error(state, e) این متد را بازنویسی کنید تا قلابی ایجاد شود که در صورت رخ دادن یک استثنا (exception) در کنترلر شما، فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .IP \(bu 2 \fBe\fP \-\- شیء \fBException\fP که ایجاد شده است. .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B on_route(state) این متد را بازنویسی کنید تا قلابی ایجاد شود که در زمان شروع مسیریابی فراخوانی می‌شود. .INDENT 7.0 .TP .B پارامترها \fBstate\fP \-\- شیء \fBstate\fP در Pecan برای درخواست جاری. .UNINDENT .UNINDENT .UNINDENT.SH "PECAN.MIDDLEWARE.DEBUG \-\- میان‌افزار اشکال‌زدایی PECAN" .SH "PECAN.JSONIFY \-\- پشتیبانی JSON در PECAN" .sp ماژول \fBpecan.jsonify\fP شامل پشتیبانی از ایجاد قواعد \fBJSON\fP با استفاده از توابع عمومی است. .INDENT 0.0 .TP .B class pecan.jsonify.GenericFunctionJSON(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) کلاس‌های پایه: \fBGenericJSON\fP .INDENT 7.0 .TP .B default(obj) یک شیء را تبدیل کرده و ساختاری سازگار با \fBJSON\fP برمی‌گرداند. .INDENT 7.0 .TP .B پارامترها \fBobj\fP \-\- شیء یا ساختاری که قرار است به یک ساختار تبدیل‌پذیر به \fBJSON\fP تبدیل شود .UNINDENT .sp حالت‌های خاص زیر را به ترتیب در نظر می‌گیرد: .INDENT 7.0 .IP \(bu 2 .INDENT 2.0 .TP .B شیء دارای یک ویژگی قابل فراخوانی __json__() تعریف‌شده باشد نتیجهٔ فراخوانی __json__() را برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء date و datetime شیء تبدیل‌شده به str را برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء Decimal شیء تبدیل‌شده به float را برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء SQLAlchemy نسخه‌ای از object.__dict__ را با حذف پارامترهای داخلی SQLAlchemy برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء ResultProxy در SQLAlchemy شیء تکرارپذیر ResultProxy را به فهرستی از تاپل‌های حاوی تمام داده‌های مجموعهٔ نتایج تبدیل کرده و فهرست را به همراه تعداد سطرها (\(dqrow\(dq) در یک دیکشنری برمی‌گرداند. .sp \fBنکته:\fP .INDENT 7.0 .INDENT 3.5 {\(aqcount\(aq: 5, \(aqrows\(aq: [(\(aqEd Jones\(aq,), (\(aqPete Jones\(aq,), (\(aqWendy Williams\(aq,), (\(aqMary Contrary\(aq,), (\(aqFred Smith\(aq,)]} .UNINDENT .UNINDENT .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء RowProxy در SQLAlchemy شیء مکان‌نمای RowProxy را به یک دیکشنری تبدیل می‌کند، که احتمالاً در این فرآیند رفتار دیکشنری مرتب آن از دست می‌رود اما آن را با JSON سازگار می‌سازد. .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء webob.multidict.MultiDict دیکشنری MultiDict.mixed() را برمی‌گرداند که تضمین می‌شود با JSON سازگار است. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.jsonify.GenericJSON(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) کلاس‌های پایه: \fBJSONEncoder\fP \% .sp کدگذار عمومی JSON. چندین تلاش برای تبدیل صحیح اشیاء پاسخ درخواستی به JSON انجام می‌دهد. .INDENT 7.0 .TP .B default(obj) یک شیء را تبدیل کرده و ساختاری سازگار با \fBJSON\fP برمی‌گرداند. .INDENT 7.0 .TP .B پارامترها \fBobj\fP \-\- شیء یا ساختاری که قرار است به یک ساختار تبدیل‌پذیر به \fBJSON\fP تبدیل شود .UNINDENT .sp حالت‌های خاص زیر را به ترتیب در نظر می‌گیرد: .INDENT 7.0 .IP \(bu 2 .INDENT 2.0 .TP .B شیء دارای یک ویژگی قابل فراخوانی __json__() تعریف‌شده باشد نتیجهٔ فراخوانی __json__() را برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء date و datetime شیء تبدیل‌شده به str را برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء Decimal شیء تبدیل‌شده به float را برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء SQLAlchemy نسخه‌ای از object.__dict__ را با حذف پارامترهای داخلی SQLAlchemy برمی‌گرداند .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء ResultProxy در SQLAlchemy شیء تکرارپذیر ResultProxy را به فهرستی از تاپل‌های حاوی تمام داده‌های مجموعهٔ نتایج تبدیل کرده و فهرست را به همراه تعداد سطرها (\(dqrow\(dq) در یک دیکشنری برمی‌گرداند. .sp \fBنکته:\fP .INDENT 7.0 .INDENT 3.5 {\(aqcount\(aq: 5, \(aqrows\(aq: [(\(aqEd Jones\(aq,), (\(aqPete Jones\(aq,), (\(aqWendy Williams\(aq,), (\(aqMary Contrary\(aq,), (\(aqFred Smith\(aq,)]} .UNINDENT .UNINDENT .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء RowProxy در SQLAlchemy شیء مکان‌نمای RowProxy را به یک دیکشنری تبدیل می‌کند، که احتمالاً در این فرآیند رفتار دیکشنری مرتب آن از دست می‌رود اما آن را با JSON سازگار می‌سازد. .UNINDENT .IP \(bu 2 .INDENT 2.0 .TP .B اشیاء webob.multidict.MultiDict دیکشنری MultiDict.mixed() را برمی‌گرداند که تضمین می‌شود با JSON سازگار است. .UNINDENT .UNINDENT .UNINDENT .UNINDENT.SH "PECAN.REST \-\- کنترل‌کننده REST در PECAN (PECAN REST CONTROLLER)" .sp ماژول \fBpecan.rest\fP شامل پشتیبانی برای نوشتن کنترل‌کننده‌های کاملاً \fBRESTful\fP در برنامهٔ Pecan شما است. .INDENT 0.0 .TP .B class pecan.rest.RestController(*args, **kwargs) کلاس‌های پایه: \fBobject\fP \% .sp یک کلاس پایه برای کنترل‌کننده‌های مبتنی بر \fBREST\fP. برای پیاده‌سازی یک کنترل‌کنندهٔ REST از این کلاس ارث‌بری کنید. .sp کلاس \fBRestController\fP مجموعه‌ای از توابع مسیریابی را پیاده‌سازی می‌کند که مسیریابی پیش‌فرض pecan را با رفتاری سازگار با مسیریابی RESTful بازنویسی می‌کنند. این سازوکار، هدایت به کنترل‌کننده‌های منبع (resource) درخواست‌شده و همچنین مدیریت مناسب متدهای متداول REST (\fBGET\fP، \fBPOST\fP، \fBPUT\fP، \fBDELETE\fP) و متدهای عملیاتی سفارشی را پوشش می‌دهد. .sp برای اطلاعات بیشتر در مورد توسعهٔ برنامه‌های تحت وب \fBRESTful\fP با Pecan، بخش Writing RESTful Web Services with Generic Controllers \%<#\:rest>\& را ببینید. .UNINDENT .SH "PECAN.ROUTING \-\- مسیریابی در PECAN (PECAN ROUTING)" .sp ماژول \fBpecan.routing\fP مبنای تمام مسیریابی‌های تفویض شیء (object\-dispatch) در Pecan است. .INDENT 0.0 .TP .B pecan.routing.find_object(obj, remainder, notfound_handlers, request) مسیر url را برای یافتن عملیاتی که یک کنترل‌کننده برای آن پیاده‌سازی شده «پیمایش» (\(aqwalk\(aq) می‌کند و آن شیء کنترل‌کننده را به همراه آنچه از باقی‌مانده (remainder) به جا مانده است برمی‌گرداند. .UNINDENT .INDENT 0.0 .TP .B pecan.routing.lookup_controller(obj, remainder, request=None) مسیر url درخواست‌شده را پیمایش می‌کند و شیء کنترل‌کنندهٔ مناسب، شامل مسیرهای پیش‌فرض را برمی‌گرداند. .sp خطاهای رایج را به‌خوبی مدیریت می‌کند. .UNINDENT .INDENT 0.0 .TP .B pecan.routing.route(*args) این تابع برای تعریف یک مسیر صریح برای بخشی از مسیر (path segment) به کار می‌رود. .sp به‌طور کلی فقط در شرایطی می‌خواهید از این تابع استفاده کنید که بخش مورد نظر شما از مسیر، یک نام متغیر یا تابع معتبر در Python نباشد. .sp برای مثال، اگر می‌خواستید بتوانید به مسیر زیر هدایت شوید: .sp /path/with\-dashes/ .sp \&... ساختار زیر یک نحو (syntax) نامعتبر در Python است: .INDENT 7.0 .INDENT 3.5 .sp .EX class Controller(object): with\-dashes = SubController() .EE .UNINDENT .UNINDENT .sp \&... بنابراین در عوض مسیر را به‌طور صریح تعریف می‌کنید: .INDENT 7.0 .INDENT 3.5 .sp .EX class Controller(object): pass pecan.route(Controller, \(aqwith\-dashes\(aq, SubController()) .EE .UNINDENT .UNINDENT .UNINDENT .SH "PECAN.SECURE \-\- کنترل‌کننده‌های امن PECAN (PECAN SECURE CONTROLLERS)" .sp ماژول \fBpecan.secure\fP شامل چارچوبی پایه برای تعبیهٔ امنیت در برنامه‌های شما است. .INDENT 0.0 .TP .B pecan.secure.secure(func_or_obj, check_permissions_for_obj=None) این متد بسته به نحوهٔ فراخوانی، یک متد یا کلاس را ایمن‌سازی می‌کند. .INDENT 7.0 .TP .B برای دکوریت کردن یک متد از یک آرگومان استفاده کنید: @secure() .TP .B برای ایمن‌سازی یک کلاس، با دو آرگومان فراخوانی کنید: secure(, ) .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.secure.unlocked(func_or_obj) این متد قفل یک متد یا صفت (attribute) کلاس را در یک SecureController باز می‌کند. می‌تواند برای دکوریت کردن یا بسته‌بندی (wrap) یک ویژگی استفاده شود. .UNINDENT .INDENT 0.0 .TP .B class pecan.secure.SecureControllerBase کلاس‌های پایه: \fBobject\fP \% .INDENT 7.0 .TP .B classmethod check_permissions() برای اعطای دسترسی، مقدار \fITrue\fP یا \fIFalse\fP را برمی‌گرداند. در زیرکلاس‌های \fBSecureController\fP پیاده‌سازی می‌شود. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.secure.SecureController کلاس‌های پایه: \fBSecureControllerBase\fP .sp برای اعمال امنیت بر روی یک کنترل‌کننده استفاده می‌شود. پیاده‌سازی‌های SecureController باید متد \fIcheck_permissions\fP را گسترش دهند تا مقدار True یا False (بسته به این که آیا کاربر دسترسی‌های لازم به کنترل‌کننده را دارد یا خیر) برگرداند. .UNINDENT.SH "PECAN.TEMPLATING \- قالب‌سازی PECAN (PECAN TEMPLATING)" .sp ماژول \fBpecan.templating\fP شامل پشتیبانی از انواع موتورهای قالب‌سازی و همچنین توانایی ایجاد موتورهای قالب اختصاصی توسط شما است. .INDENT 0.0 .TP .B class pecan.templating.ExtraNamespace(extras=None) کلاس‌های پایه: \fBobject\fP \% .sp متغیرهای اضافی برای فضای‌نام قالب جهت ارسال به رندرکننده به‌عنوان پارامترهای نام‌دار. .INDENT 7.0 .TP .B پارامترها \fBextras\fP \-\- دیکشنری پارامترهای اضافی. پیش‌فرض یک dict خالی است. .UNINDENT .INDENT 7.0 .TP .B make_ns(ns) فضای‌نام قالبی را که به‌صورت \fIتنبلانه (lazily)\fP ایجاد شده است، برمی‌گرداند. .UNINDENT .INDENT 7.0 .TP .B update(d) دیکشنری متغیرهای اضافی را برای فضای‌نام به‌روزرسانی می‌کند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.templating.GenshiRenderer(path, extra_vars) کلاس‌های پایه: \fBobject\fP \% .sp رندرکننده توکار \fBGenshi\fP را تعریف می‌کند. .INDENT 7.0 .TP .B render(template_path, namespace) رندر کردن \fBGenshi\fP را پیاده‌سازی می‌کند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.templating.JinjaRenderer(path, extra_vars) کلاس‌های پایه: \fBobject\fP \% .sp رندرکننده توکار \fBJinja\fP را تعریف می‌کند. .INDENT 7.0 .TP .B render(template_path, namespace) رندر کردن \fBJinja\fP را پیاده‌سازی می‌کند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.templating.JsonRenderer(path, extra_vars) کلاس‌های پایه: \fBobject\fP \% .sp رندرکننده توکار \fBJSON\fP را تعریف می‌کند. .INDENT 7.0 .TP .B render(template_path, namespace) رندر کردن \fBJSON\fP را پیاده‌سازی می‌کند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.templating.KajikiRenderer(path, extra_vars) کلاس‌های پایه: \fBobject\fP \% .sp رندرکننده توکار \fBKajiki\fP را تعریف می‌کند. .INDENT 7.0 .TP .B render(template_path, namespace) رندر کردن \fBKajiki\fP را پیاده‌سازی می‌کند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.templating.MakoRenderer(path, extra_vars) کلاس‌های پایه: \fBobject\fP \% .sp رندرکننده توکار \fBMako\fP را تعریف می‌کند. .INDENT 7.0 .TP .B render(template_path, namespace) رندر کردن \fBMako\fP را پیاده‌سازی می‌کند. .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class pecan.templating.RendererFactory(custom_renderers=None, extra_vars=None) کلاس‌های پایه: \fBobject\fP \% .sp اشیاء شناخته‌شدهٔ Renderer را ایجاد می‌کند. .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBcustom_renderers\fP \-\- رندرکننده‌های سفارشی‌تعریف‌شده برای ایجاد .IP \(bu 2 \fBextra_vars\fP \-\- متغیرهای اضافی برای فضای‌نام قالب .UNINDENT .UNINDENT .INDENT 7.0 .TP .B add_renderers(custom_dict) یک رندرکننده سفارشی را اضافه می‌کند. .INDENT 7.0 .TP .B پارامترها \fBcustom_dict\fP \-\- یک دیکشنری از رندرکننده‌های سفارشی جهت افزودن .UNINDENT .UNINDENT .INDENT 7.0 .TP .B available(name) اگر کلاس رندرکننده استعلام‌شده در دسترس باشد، مقدار true برمی‌گرداند. .INDENT 7.0 .TP .B پارامترها \fBname\fP \-\- نام رندرکننده .UNINDENT .UNINDENT .INDENT 7.0 .TP .B get(name, template_path) شیء رندرکننده را برمی‌گرداند. .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBname\fP \-\- نام رندرکننده درخواستی .IP \(bu 2 \fBtemplate_path\fP \-\- مسیر فایل قالب .UNINDENT .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.templating.format_genshi_error(exc_value) قالب‌بندی خطای رندرکننده \fBGenshi\fP را پیاده‌سازی می‌کند. .UNINDENT .INDENT 0.0 .TP .B pecan.templating.format_jinja_error(exc_value) قالب‌بندی خطای رندرکننده \fBJinja\fP را پیاده‌سازی می‌کند. .UNINDENT .INDENT 0.0 .TP .B pecan.templating.format_line_context(filename, lineno, context=10) زمینه خط (line context) را برای رندر کردن خطا قالب‌بندی می‌کند. .INDENT 7.0 .TP .B پارامترها .INDENT 7.0 .IP \(bu 2 \fBfilename\fP \-\- مکان فایلی که خطا در آن رخ داده است .IP \(bu 2 \fBlineno\fP \-\- شماره خط دارای خطا .IP \(bu 2 \fBcontext\fP \-\- تعداد خطوط کدی که باید قبل و بعد از خط دارای خطا نمایش داده شوند. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.templating.format_mako_error(exc_value) قالب‌بندی خطای رندرکننده \fBMako\fP را پیاده‌سازی می‌کند. .UNINDENT.SH "PECAN.TESTING \-\- آزمون‌های PECAN (PECAN TESTING)" .sp ماژول \fBpecan.testing\fP شامل فیکسچرهایی (fixtures) جهت کمک به آزمون برنامه‌های Pecan است. .INDENT 0.0 .TP .B pecan.testing.load_test_app(config=None, **kwargs) برای آزمون‌های کارکردی (functional tests) که نیاز به آزمودن برنامهٔ واقعی خود و یکپارچگی آن با چارچوب کاری (framework) دارید، استفاده می‌شود. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBconfig\fP \-\- می‌تواند یک دیکشنری حاوی پیکربندی، یک رشته نشان‌دهندهٔ مسیر (نسبی) فایل پیکربندی یا \fBNone\fP باشد که در صورت \fBNone\fP بودن، به متغیر محیطی \fBPECAN_CONFIG\fP رجوع خواهد شد. .UNINDENT .sp یک برنامهٔ WSGI از نوع pecan.Pecan را که درون نمونه‌ای از webtest.TestApp قرار گرفته است برمی‌گرداند. .INDENT 7.0 .TP .B :: app = load_test_app(\(aqpath/to/some/config.py\(aq) .sp resp = app.get(\(aq/path/to/some/resource\(aq).status_int assert resp.status_int == 200 .sp resp = app.post(\(aq/path/to/some/resource\(aq, params={\(aqparam\(aq: \(aqvalue\(aq}) assert resp.status_int == 302 .UNINDENT .sp در صورتی که متغیر محیطی تنظیم شده باشد، می‌توانید \fBload_test_app\fP را بدون پارامتر نیز فراخوانی کنید: .INDENT 7.0 .INDENT 3.5 .sp .EX app = load_test_app() resp = app.get(\(aq/path/to/some/resource\(aq).status_int assert resp.status_int == 200 .EE .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B pecan.testing.reset_global_config() هنگامی که آزمون‌ها پیکربندی برنامه را تغییر می‌دهند، این تغییرات ممکن است باقی بمانند و سایر آزمون‌هایی را که به یک پیکربندی دست‌نخورده وابسته‌اند آلوده کنند. این تابع کمکی با بازنویسی پیکربندی با \fBpecan.configuration.DEFAULT\fP\&، آن را بازنشانی می‌کند. .UNINDENT .SH "PECAN.UTIL \-\- ابزارهای PECAN (PECAN UTILS)" .sp ماژول \fBpecan.util\fP شامل توابع کمکی و کاربردی برای Pecan است. .INDENT 0.0 .TP .B pecan.util.getargspec(method) پیمایش در میان لایه‌های دکوراتورها برای تلاش جهت یافتن argspec واقعی یک متد. .UNINDENT .SH 1.8.0 .INDENT 0.0 .IP \(bu 2 جایگزینی pkg_resources منسوخ‌شده با importlib.metadata و importlib.resources (\%) .IP \(bu 2 حداقل نسخهٔ Python اکنون ۳.۱۰ است؛ پشتیبانی از Python 3.8 و 3.9 حذف شد (\%) .UNINDENT .SH 1.7.0 .INDENT 0.0 .IP \(bu 2 افزوده شدن پشتیبانی رسمی از Python 3.8 تا 3.13 (\%) .IP \(bu 2 افزونه‌هایی که pecan از طریق \fIpecan.ext\fP وارد (import) می‌کرد حذف شده‌اند (\%) .UNINDENT .SH 1.6.0 .INDENT 0.0 .IP \(bu 2 حذف وابستگی pecan به \% که دیگر به‌طور فعال نگهداری نمی‌شود (\%) در نتیجه، رابط خط فرمان (CLI) مربوط به pecan دیگر سطوح لاگ را رنگی چاپ نخواهد کرد .IP \(bu 2 حذف پشتیبانی از Python 3.7 و نسخه‌های پیش از آن .UNINDENT.SH 1.5.1 .INDENT 0.0 .IP \(bu 2 رفع یک باگ نصب ناشی از اسکریپت ورودی تکراری (\%) .UNINDENT .SH 1.5.0 .INDENT 0.0 .IP \(bu 2 pecan دیگر وابستگی به six ندارد (\%) .IP \(bu 2 اکنون pecan از SQLAlchemy 2.0 پشتیبانی می‌کند (\%) .IP \(bu 2 pecan دیگر از SQLAlchemy 1.3 پشتیبانی نمی‌کند .UNINDENT .SH 1.4.2 .INDENT 0.0 .IP \(bu 2 pecan دیگر به webtest وابسته نیست (\%) .UNINDENT .SH 1.4.1 .INDENT 0.0 .IP \(bu 2 افزودن پشتیبانی از Python 3.10 .IP \(bu 2 افزودن دسته‌بندی‌کننده‌های trove برای Python 3.6 \- 3.9 .IP \(bu 2 رفع یک باگ مربوط به setuptools به عنوان وابستگی (\%) .IP \(bu 2 رفع باگی که در زمان استفاده با برخی از نسخه‌های SQLAlchemy باعث از کار افتادن pecan می‌شد (\%) .UNINDENT .SH 1.4.0 .INDENT 0.0 .IP \(bu 2 اکنون pecan به webob >= 1.8 نیاز دارد .IP \(bu 2 رفع باگ هنگام تجزیه برخی از سرایندهای Accept (\%) .IP \(bu 2 حذف پشتیبانی رسمی از Python 3.5 .UNINDENT .SH 1.3.3 .INDENT 0.0 .IP \(bu 2 رفع یک باگ در RestController که برخی از درخواست‌های @secure را به اشتباه مسیریابی می‌کرد (\%) .IP \(bu 2 حذف پشتیبانی رسمی از Python 3.3 .UNINDENT .SH 1.3.2 .INDENT 0.0 .IP \(bu 2 اکنون pecan با نسخه‌های کمتر و بیشتر از 1.8 در webob کار می‌کند (\%) .UNINDENT .SH 1.3.1 .INDENT 0.0 .IP \(bu 2 تثبیت نسخه‌ی webob روی 1.8> به دلیل تغییرات ناسازگار در تجزیه سرایند Accept (\%) (\%) .UNINDENT .SH 1.3.0 .INDENT 0.0 .IP \(bu 2 اکنون پشتیبانی رسمی از Python 3.6 در pecan فراهم شده است .IP \(bu 2 پشتیبانی از Python 2.6 در pecan متوقف شد .UNINDENT .SH 1.2.1 .INDENT 0.0 .IP \(bu 2 بازگردانی یک تغییر/پس‌رفت پایدار API (در انتشار 1.2) (\%). این تغییر در یک ارتقای نسخه‌ی اصلی در آینده دوباره منتشر خواهد شد. .UNINDENT .SH 1.2 .INDENT 0.0 .IP \(bu 2 افزودن پیام خطای بهتر در هنگام تعیین یک رندرکننده نامعتبر قالب در \fIpecan.expose()\fP (\%). .IP \(bu 2 کنترل‌کننده‌های Pecan که \fINone\fP برمی‌گردانند، اکنون به عنوان \fIHTTP 204 No Content\fP در نظر گرفته می‌شوند (\%). .IP \(bu 2 آرگومان \fImethod\fP در \fIpecan.expose()\fP برای کنترل‌کننده‌های عمومی دیگر اختیاری نیست (\%). .UNINDENT.SH 1.1.2 .INDENT 0.0 .IP \(bu 2 رفع باگی که در آن بدنه پاسخ‌های HTTP با قالب‌بندی JSON از قابلیت ثبت نوع JSON در pecan استفاده نمی‌کردند (\%) (\%). .IP \(bu 2 به‌روزرسانی کد و مثال‌های مستندات برای پشتیبانی از انتقال readthedocs از \fIreadthedocs.org\fP به \fIreadthedocs.io\fP\&. .UNINDENT .SH 1.1.1 .INDENT 0.0 .IP \(bu 2 پکان اکنون رسماً از Python 3.5 پشتیبانی می‌کند. .IP \(bu 2 پکان اکنون در Python 3.5 و بالاتر به جای \fIinspect.getargspec\fP از \fIinspect.signature\fP استفاده می‌کند (زیرا \fIinspect.getargspec\fP در این نسخه‌های Python 3 منسوخ شده است). .IP \(bu 2 رفع باگی که هنگام استفاده از \fIpecan.redirect(..., internal=True)\fP باعث می‌شد قلاب‌های \(dqafter\(dq چندین بار اجرا شوند (\%). .UNINDENT .SH 1.1.0 .INDENT 0.0 .IP \(bu 2 اکنون \fIpecan.middleware.debug.DebugMiddleware\fP استثناها را در سطح ERROR ثبت می‌کند (\%). .IP \(bu 2 رفع یک باگ Javascript در داربست پیش‌فرض پروژه (\%). .UNINDENT .SH 1.0.5 .INDENT 0.0 .IP \(bu 2 رفع باگ در تشخیص argspec کنترلر هنگام استفاده از دکوراتورهای مبتنی بر کلاس (\%). .UNINDENT .SH 1.0.4 .INDENT 0.0 .IP \(bu 2 رفع نشت دستگیره فایل باز هنگامی که pecan خطاها را برای قالب‌های Jinja2 و Genshi رندر می‌کند (\%). .IP \(bu 2 رفع باگی که باعث تکراری شدن خروجی لاگ در پروژه‌های ایجادشده با \fIpecan create\fP می‌شد (\%). .UNINDENT .SH 1.0.3 .INDENT 0.0 .IP \(bu 2 رفع باگی در \fIpecan.hooks.HookController\fP برای نسخه‌های جدیدتر Python3.4 (\%). .UNINDENT .SH 1.0.2 .INDENT 0.0 .IP \(bu 2 رفع یک حالت خاص در \fIpecan.util.getargspec\fP که در برخی شرایط هنگام استفاده از Python 2.6 باعث بازگرداندن argspec نادرست می‌شد. .IP \(bu 2 افزودن یک \fIthreading.lock\fP به پایش فایل‌سیستم در \fIpecan serve \-\-reload\fP برای جلوگیری از راه‌اندازی‌های مجدد غیرضروری سرور. .UNINDENT .SH 1.0.1 .INDENT 0.0 .IP \(bu 2 رفع باگی که در آن پسوند فایل برای URLهای دارای اسلش پایانی (\fIfile.html\fP در مقابل \fIfile.html/\fP) به‌درستی حدس زده نمی‌شد و در نتیجه منجر به سرآیندهای نادرست Content\-Type می‌گردید. .IP \(bu 2 رفع باگی ظریف در انتساب صفت/آیتم در \fIpecan.config.Configuration\fP که باعث می‌شد برخی از انواع تغییرات پیکربندی در سکوت با شکست مواجه شوند. .UNINDENT .SH 1.0.0 .INDENT 0.0 .IP \(bu 2 جایگزینی میان‌افزار دیباگر pecan با یک وابستگی (اختیاری) به بسته \fIbacklash\fP. توسعه‌دهندگانی که می‌خواهند ردپای خطاها (tracebacks) در سطح برنامه را به‌صورت تعاملی اشکال‌زدایی کنند، باید \fIpip install backlash\fP را در محیط توسعه خود اجرا کنند. .IP \(bu 2 رفع یک باگ مرتبط با Content\-Type: هنگامی که یک content_type صریح به‌عنوان یک آرگومان به \fIpecan.expose()\fP ارسال می‌شود، اکنون نسبت به رندرکننده پیش‌فرض در سطح برنامه اولویت دارد. .IP \(bu 2 رفع باگی که مانع استفاده از برخی نویسه‌های مشخص‌شده در RFC3986 در بخش‌های مسیر می‌شد. .IP \(bu 2 رفع باگی در \fIpecan.abort\fP که ردپای پشته اصلی را سرکوب می‌کرد (و مانع از عملکرد مؤثر ابزارهای پایش مانند NewRelic می‌شد). .UNINDENT.SH 0.9.0 .INDENT 0.0 .IP \(bu 2 پشتیبانی از Python 3.2 متوقف شده است. .IP \(bu 2 قابلیت جدیدی اضافه شد که به کاربران امکان می‌دهد بخش‌های مسیر سفارشی را برای کنترل‌کننده‌ها مشخص کنند. این قابلیت به‌ویژه برای بخش‌های مسیری مفید است که شناسه‌های معتبر Python نیستند (مانند بخش‌های مسیری که شامل نویسه‌های نشانه‌گذاری خاصی مانند \fI/some/~path~/\fP هستند). .IP \(bu 2 گزینهٔ پیکربندی جدیدی به نام \fIapp.debugger\fP اضافه شد که به توسعه‌دهندگان اجازه می‌دهد هنگام اشکال‌زدایی تعاملی با \fIDebugMiddleware\fP در pecan، دیباگری جایگزین برای \fIpdb\fP (مانند \fIipdb\fP) تعیین کنند. .IP \(bu 2 پروژه‌های جدید quickstart در pecan تغییر کردند تا سطح ثبت گزارش برای \fIpecan\fP در محیط توسعه به‌طور پیش‌فرض روی \fIDEBUG\fP تنظیم شود. .IP \(bu 2 باگی برطرف شد که مانع از استفاده از \fIstaticmethods\fP به عنوان کنترل‌کننده می‌شد. .IP \(bu 2 باگی در رمزگشایی در نحوهٔ مدیریت بخش‌های مسیر URL نقل‌قول‌شده (quoted) و رشته‌های پرس‌وجو (query strings) توسط pecan برطرف شد. .IP \(bu 2 چندین باگ در نحوهٔ مدیریت بخش‌های مسیر Unicode توسط pecan برطرف شد (برای مثال، اکنون می‌توانید مسیرهایی در pecan تعریف کنید که شامل نویسه‌های ایموجی باشند). .IP \(bu 2 چندین باگ در RestController برطرف شد که باعث می‌شد به جای \fIHTTP 405 Method Not Allowed\fP، کد \fIHTTP 404 Not Found\fP را بازگرداند. علاوه بر این، اکنون RestController هنگام بازگرداندن \fIHTTP 405 Method Not Allowed\fP، هدرهای معتبر \fIAllow\fP را بازمی‌گرداند. .IP \(bu 2 باگی برطرف شد که اجازه می‌داد متدهای خاص pecan (\fI_route\fP، \fI_lookup\fP، \fI_default\fP) به عنوان متدهای عمومی REST نشانه‌گذاری شوند. .IP \(bu 2 در مستندات pecan بر لزوم تنظیم \fIdebug=False\fP در استقرار‌های محیط عملیاتی (production) تأکید بیشتری شد. .UNINDENT .SH 0.8.3 .INDENT 0.0 .IP \(bu 2 رفتار pecan تغییر یافت تا موارد خاص کدگذاری درخواست را با سازگاری و انعطاف بیشتری مدیریت کند. اکنون برنامه‌های pecan با یک HTTP 400 (به جای یک UnicodeDecodeError دریافت‌نشده که منجر به HTTP 500 می‌شد) پاسخ می‌دهند، هرگاه: \- درخواست‌های HTTP POST از داده‌های غیر Unicode تشکیل شده باشند \- مسیرهای درخواست شامل نویسه‌های percent\-encoded نامعتبر باشند، مانند: .INDENT 2.0 .INDENT 3.5 \fB/some/path/%aa/\fP .UNINDENT .UNINDENT .IP \(bu 2 بهبود جزئیات گزارش (verbosity) برای خطاهای مرتبط با واردسازی (import) در فایل‌های پیکربندی pecan، به‌ویژه مواردی که شامل importهای نسبی هستند. .UNINDENT .SH 0.8.2 .INDENT 0.0 .IP \(bu 2 باگی را برطرف می‌کند که پشتیبانی از متغیرهای رشته پرس‌وجوی چندمقداری (مانند \fI?check=a&check=b\fP) را مختل می‌کرد. .UNINDENT .SH 0.8.1 .INDENT 0.0 .IP \(bu 2 بهبود تشخیص بازگشت بی‌نهایت (infinite recursion) برای PecanHook و pypy. این تغییر باگی را برطرف می‌کند که در pecan + pypy کشف شده بود و هنگام استفاده از فراکلاس (metaclass) در PecanHook می‌توانست منجر به بازگشت بی‌نهایت شود. .IP \(bu 2 باگی برطرف شد که مانع از استفاده از @staticmethod در کنترل‌کننده‌های @exposed می‌شد. .IP \(bu 2 باگی جزئی در محاسبهٔ آرگومان‌های کنترل‌کننده برطرف شد. .UNINDENT .SH 0.8.0 .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 برای درخواست‌های HTTP POST، نگاشت بدنهٔ درخواست‌های JSON به آرگومان‌های کلیدواژه‌ای کنترل‌کننده. .IP \(bu 2 بهبود تشخیص argspec و انعطاف‌پذیری برای کنترل‌کننده‌های بسته‌بندی‌شده (wrapped controllers). .IP \(bu 2 هنگامی که آرگومان‌های مسیر برای RestController نادرست هستند، بازگرداندن HTTP 404 به جای 400. .IP \(bu 2 هنگام تشخیص عدم وجود محتوا برای HTTP 204، خطای UnicodeDecodeError به‌درستی دریافت و مدیریت شود. .IP \(bu 2 باگی در مسیریابی برای زیرکنترل‌کننده‌های عمومی (generic subcontrollers) برطرف شد. .IP \(bu 2 باگی در مدیریت توابع عمومی در زمان غیرفعال بودن context locals برطرف شد. .IP \(bu 2 باگی که ترتیب آرگومان‌ها را در توابع عمومی برهم می‌زد برطرف شد. .IP \(bu 2 حذف دستور \fIassert\fP برای کنترل جریان؛ این دستور می‌تواند با \fIpython \-O\fP بهینه‌سازی و حذف شود. .UNINDENT .UNINDENT .UNINDENT.SH 0.7.0 .INDENT 0.0 .IP \(bu 2 رفع یک حالت خاص (edge case) در مسیریابی RestController که می‌بایست کد HTTP 400 برمی‌گرداند، اما در عوض یک استثنا ایجاد می‌کرد (و در نتیجه، HTTP 500 برگردانده می‌شد). .IP \(bu 2 رفع پیکربندی نادرست ثبت‌کننده ریشه (root logger) برای پروژه‌های راه‌اندازی سریع (quickstarted) در pecan. .IP \(bu 2 افزودن \fIpecan.state.arguments\fP، قابلیتی جدید برای بازرسی آرگومان‌های فراخوانی کنترلر. .IP \(bu 2 رفع خطای بازگشت بی‌نهایت در اعمال PecanHook. ایجاد زیرکلاس از هر دو کلاس \fIrest.RestController\fP و \fIhooks.HookController\fP منجر به خطای بازگشت بی‌نهایت در اعمال قلاب‌ها می‌شد (که مانع از شروع برنامه‌ها می‌گردید). .IP \(bu 2 آزمون‌های Pecan اکنون در توزیع کد منبع آن گنجانده شده‌اند. .UNINDENT .SH 0.6.1 .INDENT 0.0 .IP \(bu 2 رفع باگی که باعث می‌شد pecan به اشتباه برای بدنه پاسخ‌های غیرخالی، کد HTTP 204 بازگرداند. .UNINDENT .SH 0.6.0 .INDENT 0.0 .IP \(bu 2 افزودن پشتیبانی از غیرفعال‌سازی متغیرهای محلی نخ (threadlocals) در \fIpecan.request\fP و \fIpecan.response\fP در سطح برنامه WSGI به نفع ارسال صریح ارجاع. برای اطلاعات بیشتر، بخش Context/Thread\-Locals vs. Explicit Argument Passing \%<#\:contextlocals>\& را ببینید. .IP \(bu 2 افزودن پشتیبانی بهتر از ترکیب قلاب‌ها (hook composition) از طریق زیرکلاس‌سازی و mixinها. برای اطلاعات بیشتر، بخش Attaching Hooks \%<#\:attaching-hooks>\& را ببینید. .IP \(bu 2 افزودن پشتیبانی از تعیین پیاده‌سازی‌های سفارشی درخواست و پاسخ در سطح برنامه WSGI برای افرادی که می‌خواهند قابلیت‌های ارائه‌شده توسط کلاس‌های پایه در \fIwebob\fP را گسترش دهند\&. .IP \(bu 2 کنترلرهای Pecan اکنون می‌توانند یک نمونه صریح از \fIwebob.Response\fP را برگردانند تا رندر قالب و سریال‌سازی Pecan را دور بزنند (short\-circuit). .IP \(bu 2 برای متدهای عمومی که کد HTTP 405 بازمی‌گردانند، pecan اکنون یک سرآیند \fIAllow\fP تولید می‌کند تا متدهای مجاز را به کلاینت اطلاع دهد. .IP \(bu 2 رفع باگی در پایبندی به RFC2616: اگر یک متد اکسپوزشده هیچ بدنه پاسخی (یا فضای نامی) بازنگرداند، pecan اکنون پاسخ HTTP 204 را (به جای HTTP 200) اعمال می‌کند. .IP \(bu 2 رفع باگی در پایبندی به RFC2616: هنگامی که pecan با HTTP 204 یا HTTP 304 پاسخ می‌دهد، سرآیند \fIContent\-Type\fP به طور خودکار حذف می‌شود (زیرا این نوع پاسخ‌های HTTP حاوی محتوای بدنه نیستند). .IP \(bu 2 رفع یک باگ: اکنون هنگامی که کلاینت‌ها از طریق سرآیند \fIAccept\fP درخواست JSON دارند، استثناهای HTTP مربوط به \fIwebob\fP به صورت JSON سریال‌سازی می‌شوند، نه در قالب بازنمایی بومی HTML خود. .IP \(bu 2 رفع باگی که برنامه‌های مشخص‌کننده \fIdefault_renderer = json\fP را از کار می‌انداخت\&. .UNINDENT .SH 0.5.0 .INDENT 0.0 .IP \(bu 2 این انتشار پشتیبانی رسمی از pypy را اضافه می‌کند. .IP \(bu 2 افزودن لاگ رنگی درخواست‌ها به دستور \fIpecan serve\fP. .IP \(bu 2 افزودن اسکلت‌بندی (scaffold) برای تولید آسان یک REST API پایه. .IP \(bu 2 افزودن امکان ارسال آرگومان‌های کلیدواژه‌ای دلخواه به \fIpecan.testing.load_test_app\fP\&. .IP \(bu 2 رفع یک باگ مرتبط با بازگشت (recursion) در میان‌افزار اسناد خطا. .IP \(bu 2 رفع باگی در دستور \fIgunicorn_pecan\fP که باعث نشت داده‌های \fIthreading.local\fP بین نخ‌های سبک (green threads) مربوط به eventlet/gevent می‌شد. .IP \(bu 2 بهبود مستندات از طریق اصلاحات و آموزش‌های گام‌به‌گام برای برنامه‌های نمونه pecan. .UNINDENT .SH 0.4.5 .INDENT 0.0 .IP \(bu 2 رفع باگ اسلش پایانی برای \fIRestController\fPهایی که متد \fI_lookup\fP دارند. .IP \(bu 2 پاک‌سازی ارجاع برنامه WSGI از وضعیت threadlocal در هر درخواست (جهت جلوگیری از نشت حافظه احتمالی، به‌ویژه در هنگام آزمون). .IP \(bu 2 بهبود مستندات pecan و تصحیح ارجاعات intersphinx. .IP \(bu 2 ‏pecan از Python 3.4 پشتیبانی می‌کند. .UNINDENT.SH 0.4.4 .INDENT 0.0 .IP \(bu 2 حذف به‌خاطرسپاری (memoization) برخی از مشخصه‌های controller، که می‌توانست منجر به نشت حافظه در جستجوهای پویای controller شود. .UNINDENT .SH 0.4.3 .INDENT 0.0 .IP \(bu 2 رفع چندین باگ در RestController. .IP \(bu 2 رفع یک باگ در مدیریت امنیت برای controllerهای عمومی. .IP \(bu 2 رفع باگ در گرداننده‌های \fI_default\fP استفاده‌شده در \fIRestController\fP\&. .IP \(bu 2 ماندگاری \fIpecan.request.context\fP در میان تغییرمسیرهای داخلی. .UNINDENT .SH 0.4.2 .INDENT 0.0 .IP \(bu 2 حذف بهینه‌سازی مسیریابی‌ای که موجب خرابی افزونهٔ WSME pecan می‌شد. .UNINDENT .SH 0.4.1 .INDENT 0.0 .IP \(bu 2 انتقال پروژه به زیرساخت StackForge در \%، شامل بازبینی کد Gerrit، یکپارچه‌سازی مداوم Jenkins و بازتاب در GitHub. .IP \(bu 2 افزودن یک افزونهٔ pecan برای کارساز محبوب uwsgi در \%\&. .IP \(bu 2 جایگزینی وابستگی \fBsimplegeneric\fP با تابع جدید \fBfunctools.singledispatch\fP جهت آماده‌سازی برای پشتیبانی از Python 3.4. .IP \(bu 2 بهینه‌سازی مسیریابی dispatch در هستهٔ pecan برای دستیابی به زمان‌های پاسخ‌دهی به مراتب سریع‌تر. .UNINDENT .SH 0.3.2 .INDENT 0.0 .IP \(bu 2 اعمال تغییراتی جهت ساده‌سازی نحوهٔ ارسال \fBpecan.conf.app\fP به برنامه‌های جدید. .IP \(bu 2 رفع یک باگ مسیریابی برای برخی پیکربندی‌های controller با \fB_lookup\fP. .IP \(bu 2 بهبود مستندات مربوط به مدیریت بارگذاری فایل‌ها. .IP \(bu 2 منسوخ شدن گزینهٔ پیکربندی \fBpecan.conf.requestviewer\fP. .UNINDENT .SH 0.3.1 .INDENT 0.0 .IP \(bu 2 قلاب‌های \fBon_error\fP اکنون می‌توانند اشیاء Pecan Response را بازگردانند. .IP \(bu 2 به‌روزرسانی‌های جزئی در مستندات و ابزارهای انتشار. .UNINDENT .SH 0.3.0 .INDENT 0.0 .IP \(bu 2 اکنون Pecan از Python 2.6، 2.7، 3.2 و 3.3 پشتیبانی می‌کند. .UNINDENT .SH 0.2.4 .INDENT 0.0 .IP \(bu 2 افزودن پشتیبانی از متدهای \fB_lookup\fP به عنوان راهکار جایگزین (fallback) در RestController. .IP \(bu 2 بهبودهای گوناگون در مستندات پروژه. .UNINDENT .SH 0.2.3 .INDENT 0.0 .IP \(bu 2 افزودن بهینه‌سازی‌های گوناگون به \fBpecan.core\fP که زمان پردازش درخواست را برای مسیریابی dispatch سادهٔ اشیاء حدود ۳۰٪ بهبود می‌بخشد. .IP \(bu 2 ذخیرهٔ استثناهای ناشی از \fBabort\fP در WSGI environ تا بعداً در پردازش درخواست (برای نمونه توسط سایر میان‌افزارها یا قلاب‌های pecan) قابل دسترس باشند. .IP \(bu 2 افزایش پایداری TransactionHook تا هنگام بروز استثناها در \fIسایر\fP قلاب‌های pecan در طول یک درخواست، کمتر در معرض شکست قرار گیرد. .IP \(bu 2 بازآرایی متن راهنمای quickstart به طوری که کاربران مرحله‌ای ضروری را از دست ندهند. .UNINDENT.SH 0.2.2 .INDENT 0.0 .IP \(bu 2 رفع مبهم‌سازی کدهای JavaScript برجسته‌سازی نحو برای بسته‌بندی debian. .IP \(bu 2 انتقال آزمون‌های ساخت scaffold به tox. .IP \(bu 2 افزودن پشتیبانی از تعیین فایل پیکربندی pecan از طریق متغیر محیطی \fBPECAN_CONFIG\fP\&. .IP \(bu 2 رفع باگ در متدهای \fBDELETE\fP درون دو (یا چند) \fBRestControllers\fP تو در تو. .IP \(bu 2 افزودن مستندات برای بازگرداندن کدهای وضعیت خاص HTTP. .UNINDENT .SH 0.2.1 .INDENT 0.0 .IP \(bu 2 گنجاندن مجوز، readme و \fBrequirements.txt\fP در بسته‌های توزیع. .IP \(bu 2 بهبود بررسی با \fBdir()\fP برای \fBpecan.request\fP و \fBpecan.response\fP\&. .IP \(bu 2 رفع باگی که مانع از اتصال (mount) برنامه‌های pecan در مسیرهای مجازی WSGI می‌شد. .UNINDENT .SH 0.2.0 .INDENT 0.0 .IP \(bu 2 به‌روزرسانی آزمون‌های داربست‌بندی (scaffolding) پایه پروژه برای تکرارپذیری بیشتر. .IP \(bu 2 افزودن یک گزینه پیکربندی در سطح برنامه برای غیرفعال کردن حدس نوع محتوا (content-type) بر اساس URL\&. .IP \(bu 2 اصلاح وابستگی نادرست آزمون به Jinja؛ نام درست Jinja2 است. .IP \(bu 2 رفع باگ مربوط به مسیریابی در \fBRestController\fP\&. این مورد #156 را برطرف می‌کند. .IP \(bu 2 افزودن سند صریح \fBCONTRIBUTING.rst\fP\&. .IP \(bu 2 بهبود دسترسی و دید مستندات مربوط به استقرار. .IP \(bu 2 افزودن پشتیبانی از اسکریپت کنسولی \fBgunicorn_pecan\fP\&. .IP \(bu 2 حذف و نشانه‌گذاری چند import بدون استفاده (و جایگزین‌های py26). .IP \(bu 2 رفع باگ: عدم حذف پسوند نقطه‌دار از مسیر مگر اینکه یک mimetype منطبق داشته باشد. .IP \(bu 2 افزودن آزمونی به فرآیند ساخت پروژه scaffold جهت اطمینان از پاس شدن آزمون pep8. .IP \(bu 2 اصلاح خروجی گمراه‌کننده دستور \fB$ pecan \-\-version\fP\&. .UNINDENT .SH 0.2.0B .INDENT 0.0 .IP \(bu 2 رفع باگ در \fBSecureController\fP\&. رفع مشکل #131. .IP \(bu 2 استخراج وابستگی‌های فایل‌های ایستا (static) میان‌افزار اشکال‌زدایی به فایل‌های فیزیکی. .IP \(bu 2 بهبود آزمونی که ممکن بود به دلیل شرایط رقابتی (race condition) ناموفق باشد. .IP \(bu 2 بهبود مستندات مربوط به قالب پیکربندی و \fBapp.py\fP\&. .IP \(bu 2 افزودن پشتیبانی از تشخیص نوع محتوا از طریق هدرهای Accept در HTTP. .IP \(bu 2 تصحیح دستورالعمل‌های نصب از مبدأ (سورس) در \fBREADME\fP\&. .IP \(bu 2 اصلاح یک مثال کد نادرست در مستندات Hooks. .IP \(bu 2 مستندات: اصلاح اشتباه تایپی جزئی در مثال مسیریابی با \fB*args\fP\&. .UNINDENT .SH "مجوز (LICENSE)" .sp فریم‌ورک Pecan و مستندات آن تحت مجوز BSD منتشر شده‌اند: .INDENT 0.0 .INDENT 3.5 .sp .EX Copyright (c) <2010>, Pecan Framework All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \(dqAS IS\(dq AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .EE .UNINDENT .UNINDENT.SH "نویسنده (AUTHOR)" Jonathan LaCour .SH "کپی‌رایت و تکثیر (COPYRIGHT)" 2010, Jonathan LaCour .\" End of generated man page.