PECAN(1) Pecan PECAN(1)

pecan - مستندات Pecan

به Pecan خوش آمدید؛ یک چارچوب وب چابک پایتون که از CherryPy، TurboGears و Pylons الهام گرفته شده است. Pecan در ابتدا توسط توسعه‌دهندگان ShootQ http://shootq.com در زمان فعالیت در Pictage http://pictage.com ایجاد شد.

Pecan برای پر کردن خلأیی در دنیای چارچوب‌های وب Python ساخته شد – یک چارچوب بسیار سبک‌وزن که مسیریابی به سبک object-dispatch را ارائه می‌دهد. Pecan قصد ندارد یک چارچوب "full stack" باشد و از این رو به صورت پیش‌فرض شامل مواردی چون نشست‌ها (sessions) یا پایگاه‌های داده نمی‌شود (هرچند آموزش‌هایی برای ادغام این موارد تنها با چند خط کد توسط خودتان فراهم شده است). در عوض، تمرکز Pecan بر خودِ HTTP است.

اگرچه این چارچوب سبک است، اما Pecan مجموعه‌ای گسترده از قابلیت‌ها را برای ساخت برنامه‌های کاربردی مبتنی بر HTTP ارائه می‌دهد، از جمله:

  • قابلیت Object-dispatch برای مسیریابی آسان
  • پشتیبانی کامل از کنترل‌کننده‌های سبک REST
  • چارچوب امنیتی توسعه‌پذیر
  • پشتیبانی توسعه‌پذیر از زبان قالب (template language)
  • پشتیبانی توسعه‌پذیر از JSON
  • پیکربندی آسان مبتنی بر Python

توصیه می‌کنیم Pecan را با pip http://www.pip-installer.org نصب کنید، اما می‌توانید از easy_install نیز استفاده کنید. ایجاد فضایی در محیط کاری شما که در آن Pecan از سایر بسته‌ها مجزا و ایزوله باشد، بهترین شیوه است.

برای شروع کار با یک محیط برای Pecan، توصیه می‌کنیم با استفاده از virtualenv http://www.virtualenv.org یک محیط مجازی جدید http://www.virtualenv.org ایجاد کنید:

$ virtualenv pecan-env
$ cd pecan-env
$ source bin/activate

دستورات بالا یک محیط مجازی ایجاد کرده و آن را فعال می‌کنند. این کار وابستگی‌های نصب‌شدهٔ Pecan را از بسته‌های سیستمی شما ایزوله می‌کند و در صورت نیاز اشکال‌زدایی مشکلات را ساده‌تر می‌سازد.

سپس، Pecan را نصب می‌کنیم:

$ pip install pecan

اگر می‌خواهید آخرین نسخه توسعه Pecan را اجرا کنید، باید git را نصب کرده و مخزن را از GitHub کلون نمایید:

$ git clone https://github.com/pecan/pecan.git

با فرض اینکه محیط مجازی شما هنوز فعال است، setup.py را برای نصب نسخه توسعه فراخوانی کنید:

$ cd pecan
$ python setup.py develop

نکته:

شاخه توسعه master ناپایدار است و معمولاً برای استفاده در محیط عملیاتی توصیه نمی‌شود.

همچنین می‌توانید مستقیماً از GitHub با استفاده از pip نصب کنید:

$ pip install -e git://github.com/pecan/pecan.git#egg=pecan

بیایید یک پروژه نمونه کوچک با Pecan ایجاد کنیم.

نکته:

این راهنما نحوه نصب Pecan را پوشش نمی‌دهد. در صورت نیاز به دستورالعمل‌های نصب Pecan، به بخش نصب <#installation> مراجعه کنید.

برنامه Pecan شامل یک قالب پایه برای شروع یک پروژه جدید است. در شل خود، دستور زیر را وارد کنید:

$ pecan create test_project

این مثال از test_project به عنوان نام پروژه شما استفاده می‌کند، اما می‌توانید آن را با هر نام بسته معتبر Python که مایلید جایگزین کنید.

به دایرکتوری پروژه‌ای که تازه ایجاد کرده‌اید بروید:

$ cd test_project

شما باید آن را در "حالت توسعه" (development mode) مستقر کنید، به طوری که در sys.path در دسترس باشد، اما همچنان بتوان آن را مستقیماً از توزیع منبع آن ویرایش کرد:

$ python setup.py develop

پروژه جدید شما شامل این فایل‌ها خواهد بود:

$ 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

تعداد فایل‌ها و دایرکتوری‌ها ممکن است بر اساس نسخه Pecan متفاوت باشد، اما ساختار بالا باید دید کلی از آنچه انتظار می‌رود را به شما بدهد.

بیایید فایل‌های ایجاد شده توسط قالب را بررسی کنیم:

تمام فایل‌های ایستا (مانند CSS، Javascript و تصاویر) در اینجا قرار دارند. Pecan با یک سرویس‌دهنده فایل ساده همراه است که هنگام توسعه، این فایل‌های ایستا را ارائه می‌دهد.

ساختار برنامه Pecan عموماً از الگوی MVC <http://en.wikipedia.org/wiki/Model–view–controller> پیروی می‌کند. دایرکتوری‌های زیر test_project شامل مدل‌ها، کنترل‌کننده‌ها و قالب‌های شما هستند.

دایرکتوری دربرگیرنده فایل‌های کنترل‌کننده (controller) شما.
تمام قالب‌های (templates) شما در اینجا قرار می‌گیرند.
دربرگیرنده فایل‌های مدل (model) شما.

در نهایت، دایرکتوری برای نگهداری آزمون‌های واحد (unit) و یکپارچه‌سازی (integration):

تمام آزمون‌های مربوط به برنامه شما.

فایل test_project/app.py چگونگی ایجاد برنامه Pecan را کنترل می‌کند. این فایل باید حاوی یک تابع setup_app() باشد که شیء برنامه WSGI را برمی‌گرداند. معمولاً نیازی به ویرایش فایل app.py ارائه شده توسط قالب پایه برنامه نخواهید داشت، مگر اینکه نیاز به سفارشی‌سازی برنامه خود به روشی داشته باشید که با استفاده از پیکربندی امکان‌پذیر نباشد. به بخش پیکربندی مبتنی بر پایتون (Python-Based Configuration) در ادامه مراجعه کنید.

برای جلوگیری از وابستگی‌های غیرضروری و حفظ بیشترین انعطاف‌پذیری ممکن، Pecan هیچ پایگاه داده یا ORM (نگاشت شیء-رابطه‌ای http://en.wikipedia.org/wiki/Object-relational_mapping) را تحمیل نمی‌کند. اگر پروژه شما با یک پایگاه داده در ارتباط است، می‌توانید کدی به model/__init__.py اضافه کنید تا اتصالات پایگاه داده را از فایل پیکربندی شما بارگیری کند و جدول‌ها و تعاریف ORM را مشخص نماید..SS اجرای برنامه

قالب پایهٔ پروژه، فایل پیکربندی را با تنظیمات اولیه‌ای که برای اجرای برنامهٔ Pecan خود نیاز دارید در config.py ایجاد می‌کند. این فایل شامل میزبان و درگاهی است که کارساز باید روی آن اجرا شود، مکانی از دیسک که کنترل‌کننده‌ها و قالب‌های شما در آن ذخیره شده‌اند، و نام دایرکتوری حاوی فایل‌های ایستا (static).

اگر تنها دستور pecan serve را با ارسال config.py به عنوان فایل پیکربندی اجرا کنید، کارساز توسعه راه‌اندازی شده و برنامه را ارائه می‌دهد:

$ pecan serve config.py
Starting server in PID 000.
serving on 0.0.0.0:8080, view at http://127.0.0.1:8080

محل فایل پیکربندی و خود آرگومان بسیار انعطاف‌پذیر هستند - می‌توانید یک مسیر مطلق یا نسبی را به فایل ارسال کنید.

برای سهولت در استفاده، فایل‌های پیکربندی Pecan از نوع پایتون خالص هستند--آن‌ها حتی به عنوان فایل‌های .py ذخیره می‌شوند.

فایل پیکربندی پیش‌فرض (تولیدشده) شما باید به این صورت باشد:

# Server Specific Configurations
server = {
    'port': '8080',
    'host': '0.0.0.0'
}
# Pecan Application Configurations
app = {
    'root': '${package}.controllers.root.RootController',
    'modules': ['${package}'],
    'static_root': '%(confdir)s/public',
    'template_path': '%(confdir)s/${package}/templates',
    'debug': True,
    'errors': {
        '404': '/error/404',
        '__force_dict__': True
    }
}
logging = {
    'loggers': {
        'root' : {'level': 'INFO', 'handlers': ['console']},
        '${package}': {'level': 'DEBUG', 'handlers': ['console']}
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        }
    },
    'formatters': {
        'simple': {
            'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
                       '[%(threadName)s] %(message)s')
        }
    }
}
# Custom Configurations must be in Python dictionary format::
#
# foo = {'bar':'baz'}
#
# All configurations are accessible at::
# pecan.conf

همچنین می‌توانید پیکربندی‌های سفارشی خود را به صورت دیکشنری‌های پایتون اضافه کنید.

موارد زیادی برای پوشش دادن وجود دارد، بنابراین در فصلی دیگر مجدداً به فایل‌های پیکربندی بازخواهیم گشت (Configuring Pecan Applications <#configuration>)..SS ریشه برنامه (The Application Root)

کنترلر ریشه یا Root Controller نقطه ورود برنامه شما است. می‌توانید آن را مشابه مسیر URL ریشه برنامه خود (در این حالت، http://localhost:8080) در نظر بگیرید.

این کنترلر در قالب پروژه (test_project.controllers.root.RootController) به این شکل است:

from pecan import expose
from webob.exc import status_map
class RootController(object):
    @expose(generic=True, template='index.html')
    def index(self):
        return dict()
    @index.when(method='POST')
    def index_post(self, q):
        redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q)
    @expose('error.html')
    def error(self, status):
        try:
            status = int(status)
        except ValueError:
            status = 0
        message = getattr(status_map.get(status), 'explanation', '')
        return dict(status=status, message=message)

در صورت نیاز می‌توانید کلاس‌ها و متدهای بیشتری را مشخص کنید، اما در حال حاضر بیایید پروژه نمونه را کنترلر به کنترلر بررسی کنیم:

@expose(generic=True, template='index.html')
def index(self):
    return dict()

متد index() از طریق دکوراتور expose() <#pecan.decorators.expose> (که به نوبه خود از قالب index.html استفاده می‌کند) در ریشه برنامه (http://127.0.0.1:8080) به عنوان در دسترس عموم نشانه‌گذاری شده است؛ بنابراین هر درخواست HTTP GET که به ریشه برنامه شما (/) برسد، به این متد هدایت خواهد شد.

توجه داشته باشید که متد index() یک دیکشنری پایتون را برمی‌گرداند. این دیکشنری به عنوان یک فضای نام برای تبدیل قالب مشخص‌شده (index.html) به HTML استفاده می‌شود و سازوکار اصلی انتقال داده از کنترلر به قالب است.

@index.when(method='POST')
def index_post(self, q):
    redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q)

متد index_post() یک آرگومان HTTP POST دریافت می‌کند (q). از آنجا که آرگومان method برای @index.when() روی 'POST' تنظیم شده است، هر درخواست HTTP POST به ریشه برنامه (در پروژه نمونه، ارسال یک فرم) به این متد هدایت خواهد شد.

@expose('error.html')
def error(self, status):
    try:
        status = int(status)
    except ValueError:
        status = 0
    message = getattr(status_map.get(status), 'explanation', '')
    return dict(status=status, message=message)

در نهایت، متد error() را داریم که به برنامه امکان می‌دهد صفحه‌های سفارشی را برای برخی از خطاهای HTTP نمایش دهد (404 و غیره...)..SS "اجرای آزمون‌ها برای برنامه شما (Running the Tests For Your Application)"

برنامه شما شامل چند آزمون نمونه است که می‌توانید آن‌ها را اجرا، جایگزین یا به آن‌ها مواردی اضافه کنید. برای اجرای آن‌ها:

$ pip install tox && tox -e py

خود آزمون‌ها را می‌توان در ماژول tests در پروژه خود پیدا کرد.

آماده استقرار برنامه جدید Pecan خود هستید؟ نگاهی به Deploying Pecan in Production <#deployment> بیندازید.

‏Pecan از یک راهبرد مسیریابی موسوم به object-dispatch برای نگاشت یک درخواست HTTP به یک کنترل‌کننده، و سپس متدی که باید فراخوانی شود، استفاده می‌کند. ‏object-dispatch با تقسیم مسیر به فهرستی از مؤلفه‌ها و سپس پیمایش یک مسیر شیء، با شروع از کنترل‌کننده ریشه آغاز می‌شود. شما می‌توانید کنترل‌کننده‌های برنامه خود را درختی از اشیاء تصور کنید (شاخه‌های درخت اشیاء مستقیماً به مسیرهای URL نگاشت می‌شوند).

بیایید به یک برنامه کتاب‌فروشی ساده نگاهی بیندازیم:

from pecan import expose
class BooksController(object):
    @expose()
    def index(self):
        return "Welcome to book section."
    @expose()
    def bestsellers(self):
        return "We have 5 books in the top 10."
class CatalogController(object):
    @expose()
    def index(self):
        return "Welcome to the catalog."
    books = BooksController()
class RootController(object):
    @expose()
    def index(self):
        return "Welcome to store.example.com!"
    @expose()
    def hours(self):
        return "Open 24/7 on the web."
    catalog = CatalogController()

یک درخواست برای /catalog/books/bestsellers از فروشگاه برخط، با شکستن درخواست به catalog، books و bestsellers توسط Pecan آغاز می‌شود. سپس، Pecan مقدار catalog را روی کنترل‌کننده ریشه جستجو می‌کند. با استفاده از شیء catalog، سپس Pecan مقدار books و پس از آن bestsellers را جستجو خواهد کرد. اگر URL با یک اسلش خاتمه یابد چه؟ Pecan وجود متد index را روی آخرین شیء کنترل‌کننده بررسی خواهد کرد.

برای روشن‌تر شدن مطلب، مسیرهای زیر:

└── /
    ├── /hours
    └── /catalog
         └── /catalog/books
            └── /catalog/books/bestsellers

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

└── RootController.index
    ├── RootController.hours
    └── CatalogController.index
         └── BooksController.index
            └── BooksController.bestsellers

شما از طریق expose() <#pecan.decorators.expose> به Pecan اعلام می‌کنید که کدام متدها در یک کلاس به‌صورت عمومی قابل‌مشاهده هستند. اگر متدی با expose() <#pecan.decorators.expose> تزیین نشده باشد، Pecan هرگز درخواستی را به آن هدایت نخواهد کرد.

expose() <#pecan.decorators.expose> می‌تواند به روش‌های مختلفی استفاده شود. ساده‌ترین حالت شامل ارسال نکردن هیچ آرگومانی است. در این سناریو، کنترل‌کننده رشته‌ای را برمی‌گرداند که نشان‌دهنده بدنه پاسخ HTML است.

from pecan import expose
class RootController(object):
    @expose()
    def hello(self):
        return 'Hello World'

یک مورد استفاده متداول‌تر، مشخص کردن یک قالب و یک فضای نام (namespace) است <#templates>:

from pecan import expose
class RootController(object):
    @expose('html_template.mako')
    def hello(self):
        return {'msg': 'Hello!'}
<!-- html_template.mako -->
<html>
    <body>${msg}</body>
</html>

همچنین Pecan دارای پشتیبانی داخلی از یک رندرکننده ویژه JSON است <#expose-json>، که فضاهای نام قالب را به متن رندرشده JSON تبدیل می‌کند:

from pecan import expose
class RootController(object):
    @expose('json')
    def hello(self):
        return {'msg': 'Hello!'}

فراخوانی‌های expose() <#pecan.decorators.expose> همچنین می‌توانند به‌صورت پشته‌ای (روی هم) قرار گیرند، که به شما امکان می‌دهد محتوا را بسته به نحوه درخواست آن، به روش‌های متفاوتی سریال‌سازی کنید:

from pecan import expose
class RootController(object):
    @expose('json')
    @expose('text_template.mako', content_type='text/plain')
    @expose('html_template.mako')
    def hello(self):
        return {'msg': 'Hello!'}

متوجه خواهید شد که ما expose() <#pecan.decorators.expose> را سه بار با آرگومان‌های متفاوت فراخوانی کردیم.

@expose('json')

مورد اول به Pecan می‌گوید زمانی که کلاینت /hello.json را درخواست می‌کند یا اگر یک هدر Accept: application/json وجود داشته باشد، فضای نام پاسخ را با استفاده از سریال‌سازی JSON سریال‌سازی کند.

@expose('text_template.mako', content_type='text/plain')

مورد دوم به Pecan می‌گوید زمانی که کلاینت /hello.txt را درخواست می‌کند یا از طریق یک هدر Accept نوع text/plain را درخواست می‌کند، از فایل قالب text_template.mako استفاده کند.

@expose('html_template.mako')

مورد سوم به Pecan می‌گوید زمانی که کلاینت /hello.html را درخواست می‌کند، از فایل قالب html_template.mako استفاده کند. اگر کلاینت /hello را درخواست کند، Pecan به‌طور پیش‌فرض از نوع محتوای text/html استفاده خواهد کرد؛ در غیاب یک نوع محتوای صریح، Pecan فرض می‌کند که کلاینت HTML می‌خواهد.

همچنین ببینید:

•
pecan.decorators -- تزیین‌کننده‌های Pecan <#pecan-decorators>

گاه ممکن است بخواهید در مسیریابی خود از بخشی در مسیر استفاده کنید که به دلیل محدودیت‌های ساختار نحوی Python، با رویکرد اعلانی Pecan در مسیریابی همخوانی ندارد. به عنوان مثال، اگر بخواهید برای مسیری شامل خط تیره مانند /some-path/ مسیریابی انجام دهید، قطعه‌کد زیر در Python معتبر نیست:

class RootController(object):
    @pecan.expose()
    def some-path(self):
        return dict()

برای رفع این مشکل، pecan به شما اجازه می‌دهد تا در دکوراتور expose() <#pecan.decorators.expose> یک بخش مسیر را به‌طور صریح مشخص کنید:

class RootController(object):
    @pecan.expose(route='some-path')
    def some_path(self):
        return dict()

در این مثال، برنامه‌ی pecan به درخواست‌های فرستاده‌شده به /some-path/ با پاسخ HTTP 200 پاسخ خواهد داد، اما درخواست‌های ارسال‌شده به /some_path/ منجر به HTTP 404 خواهند شد.

همچنین می‌توان از route() <#pecan.routing.route> به‌طور صریح به‌عنوان جایگزینی برای آرگومان route در expose() <#pecan.decorators.expose> استفاده کرد:

class RootController(object):
    @pecan.expose()
    def some_path(self):
        return dict()
pecan.route('some-path', RootController.some_path)

مسیریابی به کنترلرهای فرزند (child controllers) را نیز می‌توان به روشی مشابه با بهره‌گیری از route() <#pecan.routing.route> مدیریت کرد:

class ChildController(object):
    @pecan.expose()
    def child(self):
        return dict()
class RootController(object):
    pass
pecan.route(RootController, 'child-path', ChildController())

در این مثال، برنامه‌ی pecan به درخواست‌های فرستاده‌شده به /child-path/child/ با HTTP 200 پاسخ خواهد داد.

آرگومان generic در expose() <#pecan.decorators.expose> امکان چندریختی یا بازتعریف (overloading) نشانی‌های URL را بر اساس متد درخواست فراهم می‌کند. در مثال زیر، یک URL یکسان می‌تواند با استفاده از کنترلرهای عمومی (generic controllers) به دو متد مختلف سرویس‌دهی شود (یکی برای رسیدگی به HTTP GET و دیگری برای HTTP POST):

from pecan import expose
class RootController(object):
    # HTTP GET /
    @expose(generic=True, template='json')
    def index(self):
        return dict()
    # HTTP POST /
    @index.when(method='POST', template='json')
    def index_POST(self, **kw):
        uuid = create_something()
        return dict(uuid=uuid)

گاهی اوقات، مسیریابی استاندارد ارجاع به شیء (object-dispatch) برای هدایت صحیح یک URL به یک کنترلر کافی نیست. Pecan چندین راهکار برای میان‌بُر زدن در سیستم ارجاع به شیء ارائه می‌دهد تا پردازش URLها با کنترل بیشتری انجام پذیرد؛ از جمله متدهای ویژهٔ _lookup()، _default() و _route(). تعریف این متدها روی شیءهای کنترلر شما، انعطاف‌پذیری بیشتری را برای پردازش تمام یا بخشی از یک URL فراهم می‌آورد.

متد ویژهٔ _lookup() روشی را برای پردازش بخشی از یک URL و سپس بازگرداندن یک شیء کنترلر جدید جهت هدایت بخش باقی‌مانده فراهم می‌کند.

یک متد _lookup() می‌تواند یک یا چند آرگومان را بپذیرد، که بخش‌هایی از مسیر URL هستند که باید پردازش شوند (تفکیک‌شده با /). متد _lookup() همچنین باید آرگومان‌های مکانی متغیر را که نشان‌دهندهٔ ادامهٔ مسیر هستند دریافت کند، و هر بخشی از مسیر را که خود پردازش نمی‌کند در مقدار بازگشتی خود بگنجاند. مثال زیر از یک لیست *remainder استفاده می‌کند که با ادامه یافتن الگوریتم ارجاع به شیء (object-dispatch)، به کنترلر بازگردانده‌شده ارسال خواهد شد.

علاوه بر کاربرد در ساخت پویای کنترلرها، متد _lookup() به عنوان آخرین راه‌حل نیز فراخوانی می‌شود؛ زمانی که هیچ متد کنترلر دیگری با URL همخوانی نداشته باشد و متد _default() نیز تعریف نشده باشد.

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)

یک درخواست HTTP GET به /8/name نام دانش‌آموزی را بازمی‌گرداند که در آن primary_key == 8 باشد.

متد _default() به عنوان آخرین راه‌حل، هنگامی که هیچ متد کنترلر دیگری از طریق ارجاع استاندارد به شیء با URL تطابق نداشته باشد، فراخوانی می‌شود.

from pecan import expose
class RootController(object):
    @expose()
    def english(self):
        return 'hello'
    @expose()
    def french(self):
        return 'bonjour'
    @expose()
    def _default(self):
        return 'I cannot say hello in that language'

در مثال بالا، درخواستی به /spanish به RootController._default() هدایت خواهد شد..SS تعریف مسیریابی سفارشی با _route

متد _route() به کنترل‌کننده اجازه می‌دهد سازوکار مسیریابی Pecan را به‌طور کامل بازنویسی کند. خود Pecan از متد _route() برای پیاده‌سازی RestController <#pecan.rest.RestController> استفاده می‌کند. اگر می‌خواهید یک سیستم مسیریابی جایگزین بر بستر Pecan طراحی کنید، تعریف یک کلاس کنترل‌کنندهٔ پایه که متد _route() را مشخص کند، به شما امکان کنترل کامل را می‌دهد.

برای هر درخواست HTTP، سامانهٔ Pecan یک ارجاع محلی به رشته (thread-local) <#contextlocals> به شیء درخواست و پاسخ، pecan.request و pecan.response، نگه می‌دارد. این‌ها به ترتیب نمونه‌هایی از pecan.Request و pecan.Response هستند و می‌توان از داخل کد کنترل‌کنندهٔ Pecan با آن‌ها تعامل داشت:

@pecan.expose()
def login(self):
    assert pecan.request.path == '/login'
    username = pecan.request.POST.get('username')
    password = pecan.request.POST.get('password')
    pecan.response.status = 403
    pecan.response.text = 'Bad Login!'

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

  • بررسی اجزای URI
  • تعیین جنبه‌هایی از درخواست، مانند نشانی IP کاربر یا سرآیند referer
  • تنظیم سرآیندهای خاص پاسخ
  • رندر کردن دستی بدنهٔ پاسخ

با تغییر ویژگی status در شیء پاسخ، یک کد وضعیت HTTP مشخص (مانند 203 Non-Authoritative Information) تنظیم کنید.

from pecan import expose, response
class RootController(object):
    @expose('json')
    def hello(self):
        response.status = 203
        return {'foo': 'bar'}

برای برانگیختن خطاهای HTTP از تابع کمکی abort() <#pecan.core.abort> استفاده کنید.

from pecan import expose, abort
class RootController(object):
    @expose('json')
    def hello(self):
        abort(404)

تابع abort() <#pecan.core.abort> یک نمونه از WSGIHTTPException را برمی‌انگیزد که توسط Pecan برای رندر کردن بدنه‌های پیش‌فرض پاسخ در خطاهای HTTP استفاده می‌شود. این استثنا در محیط درخواست WSGI (environ) در pecan.original_exception ذخیره می‌شود، جایی که بعداً در چرخهٔ درخواست (برای مثال توسط میان‌افزارهای دیگر یا Custom Error Documents <#errors>) قابل دسترسی است.

اگر می‌خواهید یک پاسخ صریح را بازگردانید، می‌توانید این کار را با استفاده از Response <#pecan.core.Response> انجام دهید:

from pecan import expose, Response
class RootController(object):
    @expose()
    def hello(self):
        return Response('Hello, World!', 202)

پیاده‌سازی‌های درخواست (request) و پاسخ (response) ارائه‌شده توسط WebOb قدرتمند هستند، اما گاهی اوقات ممکن است گسترش رفتارهای ویژه‌ی برنامه بر روی درخواست و پاسخ شما مفید باشد (مانند تجزیه‌ی سفارشی سرایندهای درخواست یا سریال‌سازی سفارشی بدنه‌ی پاسخ). برای انجام این کار، کلاس‌های سفارشی تعریف کنید که به ترتیب از pecan.Request و pecan.Response ارث‌بری کنند:

class MyRequest(pecan.Request):
    pass
class MyResponse(pecan.Response):
    pass

و پیکربندی برنامه‌ی خود را برای استفاده از آن‌ها تغییر دهید:

from myproject import MyRequest, MyResponse
app = {
    'root' : 'project.controllers.root.RootController',
    'modules' : ['project'],
    'static_root'   : '%(confdir)s/public',
    'template_path' : '%(confdir)s/project/templates',
    'request_cls': MyRequest,
    'response_cls': MyResponse
}

در Pecan، متغیرهای GET و POST در پروتکل HTTP که در طول فرآیند مسیریابی (routing) مصرف نمی‌شوند، می‌توانند به عنوان آرگومان به متد کنترل‌کننده منتقل شوند.

بسته به امضای (signature) متد، این متغیرها می‌توانند به‌طور صریح به آرگومان‌ها نگاشت شوند:

from pecan import expose
class RootController(object):
    @expose()
    def index(self, arg):
        return arg
    @expose()
    def kwargs(self, **kwargs):
        return str(kwargs)
$ curl http://localhost:8080/?arg=foo
foo
$ curl http://localhost:8080/kwargs?a=1&b=2&c=3
{u'a': u'1', u'c': u'3', u'b': u'2'}

یا می‌توانند بر اساس موقعیت (positionally) مصرف شوند:

from pecan import expose
class RootController(object):
    @expose()
    def args(self, *args):
        return ','.join(args)
$ curl http://localhost:8080/args/one/two/three
one,two,three

همین نتیجه را می‌توان با متغیرهای بدنه در HTTP POST نیز به دست آورد:

from pecan import expose
class RootController(object):
    @expose()
    def index(self, arg):
        return arg
$ curl -X POST "http://localhost:8080/" -H "Content-Type: application/x-www-form-urlencoded" -d "arg=foo"
foo

از آنجا که Pecan دسترسی مستقیم به Request زیرین را در اختیارتان می‌گذارد، ارائه یک فایل ایستا برای دانلود به سادگیِ تنظیم app_iter در WSGI و مشخص کردن نوع محتوا است:

import os
from random import choice
from webob.static import FileIter
from pecan import expose, response
class RootController(object):
    @expose(content_type='image/gif')
    def gifs(self):
        filepath = choice((
            "/path/to/funny/gifs/catdance.gif",
            "/path/to/funny/gifs/babydance.gif",
            "/path/to/funny/gifs/putindance.gif"
        ))
        f = open(filepath, 'rb')
        response.app_iter = FileIter(f)
        response.headers[
            'Content-Disposition'
        ] = 'attachment; filename="%s"' % os.path.basename(f.name)

اگر نوع محتوا را از قبل نمی‌دانید (برای نمونه، اگر فایل‌ها و نوع محتوای آن‌ها را از یک منبع داده بازیابی می‌کنید)، می‌توانید آن را از طریق response.headers مشخص کنید به جای اینکه در دکوراتور expose() <#pecan.decorators.expose> تعیین شود:

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('/path/to/some/file', 'rb')
        response.app_iter = FileIter(f)
        response.headers['Content-Type'] = guess_type(f.name)
        response.headers[
            'Content-Disposition'
        ] = 'attachment; filename="%s"' % os.path.basename(f.name)

Pecan مدیریت بارگذاری فایل‌ها را از طریق فرم‌های استاندارد multipart ساده می‌کند. کافی است فرم خود را با یک ورودی فایل تعریف کنید:

<form action="/upload" method="POST" enctype="multipart/form-data">
  <input type="file" name="file" />
  <button type="submit">Upload</button>
</form>

سپس می‌توانید فایل بارگذاری‌شده را از شیء request در کنترلر (controller) برنامه بخوانید:

from pecan import expose, request
class RootController(object):
    @expose()
    def upload(self):
        assert isinstance(request.POST['file'], cgi.FieldStorage)
        data = request.POST['file'].file.read()

جهت سهولت، Pecan روی هر درخواست یک دیکشنری Python فراهم می‌کند که می‌توان در تمام طول چرخه حیات یک درخواست مجزا، به شکلی امن از نظر ریسه (thread-safe) به آن دسترسی داشت و آن را تغییر داد:

pecan.request.context['current_user'] = some_user
print pecan.request.context.items()

این قابلیت به‌ویژه در شرایطی کاربرد دارد که بخواهید فراداده/زمینه (metadata/context) مربوط به یک درخواست را ذخیره کرده (مثلاً در میان‌افزارها یا قلاب‌های per-routing) و بعداً به آن دسترسی داشته باشید (مثلاً در کد کنترلر).

برای کنترل دقیق‌تر روی درخواست، می‌توان به محیط WSGI زیرین برای یک درخواست معین Pecan از طریق pecan.request.environ دسترسی یافت و آن را تغییر داد.

همچنین Pecan توابع کمکی مفید متعددی را برای جابه‌جایی میان مسیرهای مختلف فراهم می‌کند. تابع redirect() <#pecan.core.redirect> به شما اجازه می‌دهد بازهدایت‌های داخلی یا HTTP 302 صادر کنید.

همچنین ببینید:

ابزار کاربردی redirect() به همراه چندین تابع کمکی مفید دیگر در pecan.core -- Pecan Core <#pecan-core> مستند شده‌اند.

با توجه به این‌که امکان تغییر چشمگیر مسیریابی در زمان اجرا وجود دارد، همیشه امکان تعیین دقیق یک نگاشت بین متد کنترلر و یک نشانی وب (URL) وجود ندارد.

برای مثال، در کد زیر که از _lookup() برای تغییر مسیریابی بر اساس یک شرط استفاده می‌کند:

from pecan import expose, abort
from somelib import get_user_region
class DefaultRegionController(object):
    @expose()
    def name(self):
        return "Default Region"
class USRegionController(object):
    @expose()
    def name(self):
        return "US Region"
class RootController(object):
    @expose()
    def _lookup(self, user_id, *remainder):
        if get_user_region(user_id) == 'us':
            return USRegionController(), remainder
        else:
            return DefaultRegionController(), remainder

این منطق به موقعیت مکانی یک کاربر معین و بازگرداندن یک کلاس کاملاً متفاوت بر اساس شرط وابسته است. یک تابع کمکی برای تعیین این‌که USRegionController.name به کدام نشانی وب تعلق دارد، در انجام درست این کار ناموفق خواهد بود.

‏Pecan شامل پشتیبانی از انواع موتورهای قالب‌بندی است و همچنین افزودن پشتیبانی از موتورهای قالب جدید را آسان می‌سازد. در حال حاضر، Pecan از موارد زیر پشتیبانی می‌کند:

سیستم قالب نام رندرکننده
Mako http://www.makotemplates.org mako
Genshi http://genshi.edgewall.org genshi
Kajiki http://kajiki.pythonisito.com kajiki
Jinja2 http://jinja.pocoo.org jinja
JSON json

سیستم قالب پیش‌فرض mako است، اما می‌توان با ارسال کلید default_renderer در پیکربندی برنامه آن را تغییر داد:

app = {
    'default_renderer' : 'kajiki',
    # ...
}

ماژول pecan.decorators <#module-pecan.decorators> دکوراتوری به نام expose() <#pecan.decorators.expose> را تعریف می‌کند که برای مشخص کردن یک متد به عنوان کنترلر عمومی (public controller) به کار می‌رود. دکوراتور expose() <#pecan.decorators.expose> یک آرگومان template می‌پذیرد که می‌توان از آن برای تعیین مسیر فایل قالبِ مورد استفاده برای متد کنترلر مربوطه استفاده کرد.

class MyController(object):
    @expose('path/to/mako/template.html')
    def index(self):
        return dict(message='I am a mako template')

دکوراتور expose() <#pecan.decorators.expose> از موتور قالب پیش‌فرض استفاده خواهد کرد مگر اینکه نام یک رندرکننده دیگر به عنوان پیشوند به مسیر اضافه شده باشد.

@expose('kajiki:path/to/kajiki/template.html')
def my_controller(self):
    return dict(message='I am a kajiki template')

همچنین ببینید:

  • pecan.decorators -- دکوراتورهای Pecan (Pecan Decorators) <#pecan-decorators>
  • pecan.core -- هسته Pecan (Pecan Core) <#pecan-core>
  • کنترلرها و مسیریابی (Controllers and Routing) <#routing>

تابع override_template() <#pecan.core.override_template> به شما امکان می‌دهد قالب تعیین‌شده برای یک متد کنترلر را هنگام در معرض قرار گرفتن آن بازنویسی کنید. هنگامی که override_template() <#pecan.core.override_template> در داخل بدنه متد کنترلر فراخوانی شود، قالب مورد استفاده برای آن فراخوانی از متد را تغییر می‌دهد.

class MyController(object):
    @expose('template_one.html')
    def index(self):
        # ...
        override_template('template_two.html')
        return dict(message='I will now render with template_two.html')

تابع render() <#pecan.core.render> به شما این امکان را می‌دهد که با استفاده از چارچوب قالب‌سازی Pecan خروجی را به‌صورت دستی رندر کنید. کافی است مسیر قالب و مقادیر مورد نیاز قالب را ارسال کنید؛ render() <#pecan.core.render> خروجی رندرشده را در قالب متن برمی‌گرداند.

@expose()
def controller(self):
    return render('my_template.html', dict(message='I am the namespace'))

Pecan همچنین یک رندرکنندهٔ JSON ارائه می‌دهد که می‌توانید با در دسترس قرار دادن یک متد کنترل‌کننده با @expose('json') از آن استفاده کنید.

همچنین ببینید:

  • سریال‌سازی JSON <#jsonify>
  • pecan.jsonify -- پشتیبانی Pecan از JSON <#pecan-jsonify>

برای تعریف یک رندرکنندهٔ سفارشی، می‌توانید کلاسی ایجاد کنید که از پروتکل رندرکننده پیروی کند:

class MyRenderer(object):
    def __init__(self, path, extra_vars):
        '''
        Your renderer is provided with a path to templates,
        as configured by your application, and any extra
        template variables, also as configured
        '''
        pass
    def render(self, template_path, namespace):
        '''
        Lookup the template based on the path, and render
        your output based upon the supplied namespace
        dictionary, as returned from the controller.
        '''
        return str(namespace)

برای فعال‌سازی رندرکنندهٔ سفارشی خود، کلید custom_renderers را در پیکربندی برنامهٔ خود تعریف کنید:

app = {
    'custom_renderers' : {
        'my_renderer' : MyRenderer
    },
    # ...
}

... و رندرکننده را در متد expose() <#pecan.decorators.expose> مشخص کنید:

class RootController(object):
    @expose('my_renderer:template.html')
    def index(self):
        return dict(name='Bob')

Pecan با فراهم کردن روشی برای اورلود کردن URLها بر اساس متد درخواست، توسعهٔ وب‌سرویس‌های RESTful را ساده می‌کند. برای بیشتر APIها، استفاده از تعاریف کنترل‌کنندهٔ عمومی (generic controller) تمام آنچه را که برای ساخت رابط‌های قدرتمند RESTful نیاز دارید در اختیارتان می‌گذارد (و رویکرد توصیه‌شده برای نوشتن وب‌سرویس‌های RESTful در Pecan است):

from pecan import abort, expose
# Note: this is *not* thread-safe.  In real life, use a persistent data store.
BOOKS = {
    '0': 'The Last of the Mohicans',
    '1': 'Catch-22'
}
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 /<id>/
    @expose(generic=True, template='json')
    def index(self):
        return self.book
    # HTTP PUT /<id>/
    @index.when(method='PUT', template='json')
    def index_PUT(self, **kw):
        BOOKS[self.id_] = kw['name']
        return self.book
    # HTTP DELETE /<id>/
    @index.when(method='DELETE', template='json')
    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='json')
    def index(self):
        return [dict(id=k, name=v) for k, v in BOOKS.items()]
    # HTTP POST /
    @index.when(method='POST', template='json')
    def index_POST(self, **kw):
        id_ = str(len(BOOKS))
        BOOKS[id_] = kw['name']
        return dict(id=id_, name=kw['name'])

برای سازگاری با کتابخانهٔ TurboGears2 http://turbogears.org، فریم‌ورک Pecan یک راهکار مبتنی بر کلاس برای مسیریابی RESTful به نام RestController <#pecan.rest.RestController> نیز ارائه می‌دهد:

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

به‌طور پیش‌فرض، RestController <#pecan.rest.RestController> بدین صورت مسیریابی می‌کند:

متد توضیحات متد(ها) / URL(های) نمونه
get_one نمایش یک رکورد. GET /books/1
get_all نمایش تمام رکوردهای یک منبع. GET /books/
get ترکیبی از get_one و get_all. GET /books/
GET /books/1
new نمایش صفحه‌ای برای ایجاد یک منبع جدید. GET /books/new
edit نمایش صفحه‌ای برای ویرایش یک منبع موجود. GET /books/1/edit
post ایجاد یک رکورد جدید. POST /books/
put به‌روزرسانی یک رکورد موجود. POST /books/1?_method=put
PUT /books/1
get_delete نمایش صفحهٔ تأیید حذف. GET /books/1/delete
delete حذف یک رکورد موجود. POST /books/1?_method=delete
DELETE /books/1

کلاس RestController <#pecan.rest.RestController> در Pecan از رشته‌پرس‌وجوی ?_method= برای دور زدن عدم پشتیبانی از افعال PUT و DELETE هنگام ارسال فرم‌ها در بیشتر مرورگرهای امروزی استفاده می‌کند.

علاوه بر مدیریت REST، کلاس RestController <#pecan.rest.RestController> همچنین از بازنویسی‌های مسیریابی index()، _default() و _lookup() پشتیبانی می‌کند.

هشدار:

اگر نیاز به بازنویسی _route() دارید، حتماً RestController._route() را در انتهای متد سفارشی خود فراخوانی کنید تا مسیریابی REST شرح‌داده‌شده در بالا همچنان انجام شود.

نمونه‌های RestController <#pecan.rest.RestController> می‌توانند به‌صورت تو در تو تعریف شوند تا منابع فرزند، پارامترهای لازم برای جستجوی منابع والد را دریافت کنند.

برای نمونه:

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()

دسترسی به مسیر /authors/1/books/2 متد BooksController.get() را فراخوانی می‌کند که در آن author_id برابر با 1 و id برابر با 2 تنظیم شده است.

برای تعیین اینکه کدام آرگومان‌ها با منبع والد مرتبط هستند، Pecan به ترتیب امضای متد get_one() و سپس get() را در کنترلر والد بررسی می‌کند. اگر منبع والد تعداد متغیری از آرگومان‌ها را بپذیرد، Pecan همه موارد را تا رسیدن به نام کنترلر منبع فرزند (برای نمونه books در مثال بالا) به آن ارسال می‌کند.

افزون بر متدهای پیش‌فرض تعریف‌شده در بالا، می‌توانید با تعریف دیکشنری ویژه _custom_actions، رفتارهای بیشتری را به یک RestController <#pecan.rest.RestController> اضافه کنید.

برای نمونه:

from pecan import expose
from pecan.rest import RestController
from mymodel import Book
class BooksController(RestController):
    _custom_actions = {
        'checkout': ['POST']
    }
    @expose()
    def checkout(self, id):
        book = Book.get(id)
        if not book:
            abort(404)
        book.checkout()

_custom_actions نام متدها را به فهرستی از افعال معتبر HTTP برای آن عملیات‌های سفارشی نگاشت می‌کند. در این مورد، متد checkout() از فعل POST پشتیبانی می‌کند..SH "پیکربندی برنامه‌های PECAN (CONFIGURING PECAN APPLICATIONS)"

پیکربندی Pecan بسیار آسان است. تا زمانی که از قراردادهای مشخصی پیروی کنید، استفاده، تنظیم و کار با پیکربندی بسیار شهودی خواهد بود.

فایل‌های پیکربندی Pecan از نوع پایتون خالص هستند. هر "بخش" (section) از پیکربندی، یک دیکشنری اختصاص داده‌شده به یک نام متغیر در ماژول پیکربندی است.

در زیر فهرست کاملی از مقادیر پیش‌فرضی که این چارچوب استفاده می‌کند آمده است:

server = {
    'port' : '8080',
    'host' : '0.0.0.0'
}
app = {
    'root' : None,
    'modules' : [],
    'static_root' : 'public',
    'template_path' : ''
}

مقادیر پیکربندی app توسط Pecan استفاده می‌شوند تا برنامه شما را درون یک برنامه معتبر WSGI http://www.wsgi.org/en/latest/what.html قرار دهند. پیکربندی app مختص برنامه شما است و شامل مقادیری مانند مکان کلاس کنترل‌کننده ریشه (root controller) می‌باشد.

یک پیکربندی متداول برنامه ممکن است به این شکل باشد:

app = {
    'root' : 'project.controllers.root.RootController',
    'modules' : ['project'],
    'static_root'   : '%(confdir)s/public',
    'template_path' : '%(confdir)s/project/templates',
    'debug' : True
}

بیایید به هر مقدار و معنای آن نگاهی بیندازیم:

فهرستی از ماژول‌ها که Pecan در آن‌ها به جستجوی برنامه‌ها می‌پردازد. به طور کلی این باید شامل یک مورد، یعنی نام بسته پایتون پروژه شما باشد. حداقل یکی از ماژول‌های فهرست‌شده باید شامل تابع app.setup_app باشد که برای ایجاد برنامه WSGI فراخوانی می‌شود. به عبارت دیگر، این بسته باید مکانی باشد که فایل app.py شما در آن قرار دارد، و این فایل باید حاوی یک تابع setup_app باشد.
کنترل‌کننده ریشه برنامه شما. به یاد داشته باشید که رشته‌ای نشان‌دهنده یک مسیر پایتون به یک شیء قابل فراخوانی (callable) ارائه دهید (مانند "yourapp.controllers.root.RootController").
دایرکتوری که فایل‌های ایستای (static) شما در آن یافت می‌شوند (نسبت به ریشه پروژه). Pecan همراه با یک میان‌افزار (middleware) ارائه می‌شود که می‌تواند برای سرو فایل‌های ایستا (مانند فایل‌های CSS و Javascript) در طول فرایند توسعه استفاده شود.
به دایرکتوری اشاره می‌کند که فایل‌های قالب شما در آن قرار دارند (نسبت به ریشه پروژه).
امکان نمایش ردگیری خطا (traceback) در مرورگر و اشکال‌زدایی تعاملی در طول فرایند توسعه را فعال می‌کند.

هشدار:

app یک نام متغیر رزروشده برای آن بخش از پیکربندی است، بنابراین مطمئن شوید که آن را بازنویسی نکنید.

هشدار:

اطمینان حاصل کنید که مقدار debug در محیط‌های عملیاتی همیشه روی False تنظیم شده باشد.

همچنین ببینید:

•
قالب پایه برنامه <#app-template>

Pecan مقادیر پیش‌فرض معقولی را ارائه می‌دهد. این مقادیر را تغییر دهید تا میزبان و درگاهی که برنامهٔ WSGI شما روی آن سرویس‌دهی می‌شود، دگرگون گردند.

server = {
    'port' : '8080',
    'host' : '0.0.0.0'
}

ممکن است برنامهٔ شما در زمان اجرا به مقادیر پیکربندی دیگری (مانند اطلاعات احراز هویت API شخص ثالث) نیاز داشته باشد. این تنظیمات را در بلوک‌های اختصاصی خودشان در فایل پیکربندی قرار دهید.

twitter = {
    'api_key' : 'FOO',
    'api_secret' : 'SECRET'
}

شما می‌توانید در زمان اجرا از طریق pecan.conf به هر مقدار پیکربندی دسترسی داشته باشید. این موارد شامل مقادیر سفارشی، مقادیر مربوط به برنامه و مقادیر خاص سرور است.

برای مثال، اگر نیاز به تعیین یک مدیر (administrator) سراسری داشتید، می‌توانید این کار را به این صورت در فایل پیکربندی انجام دهید:

administrator = 'foo_bar_user'

و در pecan.conf به این شکل قابل دسترسی خواهد بود:

>>> from pecan import conf
>>> conf.administrator
'foo_bar_user'

در شرایط خاصی ممکن است بخواهید با کلیدها و مقادیر دقیقاً در قالب دیکشنری رفتار کنید. شیء Config <#pecan.configuration.Config> دارای یک متد کمکی برای این منظور است که یک نمایش دیکشنری از پیکربندی، شامل مقادیر تو در تو را بازمی‌گرداند.

در ادامه نحوهٔ دسترسی به متد to_dict() <#pecan.configuration.Config.to_dict> و آنچه به عنوان نتیجه بازمی‌گرداند (جهت اختصار کوتاه شده است) آورده شده است:

>>> from pecan import conf
>>> conf
Config({'app': Config({'errors': {}, 'template_path': '', 'static_root': 'public', [...]
>>> conf.to_dict()
{'app': {'errors': {}, 'template_path': '', 'static_root': 'public', [...]

to_dict() <#pecan.configuration.Config.to_dict> به شما این امکان را می‌دهد که در صورت نیاز به افزودن پیشوند به کلیدها در دیکشنری بازگردانده‌شده، یک آرگومان رشته‌ای اختیاری ارسال کنید.

>>> from pecan import conf
>>> conf
Config({'app': Config({'errors': {}, 'template_path': '', 'static_root': 'public', [...]
>>> conf.to_dict('prefixed_')
{'prefixed_app': {'prefixed_errors': {}, 'prefixed_template_path': '', 'prefixed_static_root': 'prefixed_public', [...]

گاهی اوقات می‌خواهید یک گزینهٔ پیکربندی را مشخص کنید که شامل کلیدهای نقطه‌دار است یا یک شناسهٔ معتبر در Python نیست، مانند (). این شرایط به‌ویژه هنگام پیکربندی logging در Python رایج است. با ارسال یک کلید ویژه، یعنی __force_dict__، می‌توان با بلوک‌های پیکربندی مجزا مانند دیکشنری‌های بومی رفتار کرد.

logging = {
    'root': {'level': 'INFO', 'handlers': ['console']},
    'loggers': {
        'sqlalchemy.engine': {'level': 'INFO', 'handlers': ['console']},
        '__force_dict__': True
    },
    'formatters': {
        'custom': {
            '()': 'my.package.customFormatter'
        }
    }
}
from myapp import conf
assert isinstance(conf.logging.loggers, dict)
assert isinstance(conf.logging.loggers['sqlalchemy.engine'], dict)

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

می‌توانید با استفاده از دکوراتور secure() <#pecan.secure.secure>، کل زیردرخت‌های کنترلر یا فراخوانی متدهای مجزا را تحت کنترل دسترسی قرار دهید.

برای اعمال دکوراتور روی یک متد، از یک آرگومان استفاده کنید:

secure('<check_permissions_method_name>')

برای ایمن‌سازی یک کلاس، آن را با دو آرگومان فراخوانی کنید:

secure(object_instance, '<check_permissions_method_name>')
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('check_permissions')
    @expose()
    def topsecret(self):
        #
        # This controller is top-secret, and should
        # only be reachable by administrators.
        #
        return dict()
    highly_classified = secure(HighlyClassifiedController(), 'check_permissions')
    unclassified = UnclassifiedController()

به‌عنوان یک راهکار جایگزین، همین قابلیت را می‌توان با ایجاد زیرکلاس از SecureController <#pecan.secure.SecureController> متعلق به Pecan نیز پیاده‌سازی کرد. پیاده‌سازی‌های SecureController <#pecan.secure.SecureController> باید متد کلاسی check_permissions() <#pecan.secure.SecureControllerBase.check_permissions> را گسترش دهند تا اگر کاربر دسترسی‌های لازم به شاخهٔ کنترلر را دارد، مقدار True و در غیر این صورت مقدار False را برگرداند.

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())

همچنین به استفاده از دکوراتور unlocked() <#pecan.secure.unlocked> در مثال بالا توجه کنید؛ از این دکوراتور می‌توان به شیوه‌ای مشابه برای باز کردن صریح دسترسی همگانی به یک کنترلر بدون هیچ‌گونه بررسی امنیتی استفاده کرد.

متد check_permissions() <#pecan.secure.SecureControllerBase.check_permissions> باید برای تعیین وضعیت احراز هویت و مجوزدهی کاربر به کار رود. کدی که در اینجا پیاده‌سازی می‌کنید می‌تواند از بررسی‌های سادهٔ نشست (کاربر فعلی به عنوان مدیر سیستم احراز هویت شده است) تا اتصال به یک سرویس LDAP متغیر باشد.

متد secure() <#pecan.secure.secure> کاربردهای پیشرفتهٔ گوناگونی دارد که به شما امکان می‌دهد خط‌مشی‌های امنیتی پایداری برای برنامهٔ خود تعریف کنید.

نخست، می‌توانید نام یک متد کلاس یا یک متد نمونه از کنترلر را در قالب یک رشته ارسال کنید تا به عنوان متد check_permissions() <#pecan.secure.SecureControllerBase.check_permissions> استفاده شود. متدهای نمونه به‌ویژه در صورتی کاربرد دارند که بخواهید دسترسی به ویژگی‌های نمونه‌ای از یک مدل را اعتبارسنجی کنید. مثال زیر از یک فایل‌سیستم مجازی پایه را در نظر بگیرید.

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('write_access')
    @expose()
    def upload_file(self):
        pass
    @secure('read_access')
    @expose()
    def download_file(self):
        pass
class RootController(object):
    @expose()
    def _lookup(self, name, *remainder):
        return FileController(name), remainder

متد secure() <#pecan.secure.secure> همچنین یک آرگومان از نوع تابع می‌پذیرد. هنگام ارسال یک تابع، اطمینان حاصل کنید که تابع مورد نظر از فایلی دیگر وارد شده باشد یا در همان فایل پیش از تعریف کلاس تعریف شده باشد، در غیر این صورت احتمالاً در زمان وارد کردن ماژول با خطا مواجه خواهید شد.

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 'Logged in'

همچنین می‌توانید از متد secure() <#pecan.secure.secure> برای تغییر رفتار یک SecureController <#pecan.secure.SecureController> استفاده کنید. دکوریت کردن یک متد یا بسته‌بندی (wrap) یک زیرکنترلر به Pecan اعلام می‌کند که به جای متد پیش‌فرض کنترلر، از یک تابع امنیتی دیگر استفاده کند. این قابلیت برای شرایطی که به سطح یا نوع متفاوتی از امنیت نیاز دارید بسیار مفید است.

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 'logged in user'
    api = secure(ApiController(), 'check_api_permissions')

در مثال بالا، Pecan تنها زمانی admin_user() را فراخوانی می‌کند که درخواستی برای /api/ ثبت شود..SS "چندین کنترل‌کننده امن (Multiple Secure Controllers)"

کنترل‌کننده‌های امن را می‌توان به‌صورت تودرتو قرار داد تا سطوح امنیتی افزایشی را روی کنترل‌کننده‌های فرعی فراهم کنند. در مثال زیر، هنگامی که درخواستی برای /admin/index/ ثبت می‌شود، Pecan ابتدا check_permissions() <#pecan.secure.SecureControllerBase.check_permissions> را روی RootController و سپس check_permissions() <#pecan.secure.SecureControllerBase.check_permissions> را روی AdminController فراخوانی می‌کند.

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 'admin dashboard'
class RootController(SecureController):
    @classmethod
    def check_permissions(cls):
        return user_logged_in
    @expose()
    def index(self):
        return 'user dashboard'

اگرچه استفاده از میان‌افزار WSGI با Pecan آسان است، اما دسترسی به بخش‌های درونی Pecan از داخل میان‌افزار می‌تواند دشوار (گاهی غیرممکن) باشد. قلاب‌های Pecan راهکاری برای تعامل با این چارچوب کاری بدون نیاز به نوشتن میان‌افزار جداگانه هستند.

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

  • on_route() <#pecan.hooks.PecanHook.on_route>: پیش از اینکه Pecan برای مسیریابی یک درخواست به یک کنترل‌کننده تلاش کند، فراخوانی می‌شود
  • before() <#pecan.hooks.PecanHook.before>: پس از مسیریابی، اما پیش از اجرای کد کنترل‌کننده فراخوانی می‌شود
  • after() <#pecan.hooks.PecanHook.after>: پس از اجرای کد کنترل‌کننده فراخوانی می‌شود
  • on_error() <#pecan.hooks.PecanHook.on_error>: هنگامی که یک درخواست یک استثنا ایجاد کند، فراخوانی می‌شود

در مثال زیر، یک قلاب ساده اطلاعاتی درباره درخواست جمع‌آوری کرده و آن را در stdout چاپ می‌کند.

پیاده‌سازی قلاب شما باید PecanHook <#pecan.hooks.PecanHook> را وارد (import) کند تا بتواند به‌عنوان کلاس پایه استفاده شود. از آنجا، می‌توانید متدهای on_route() <#pecan.hooks.PecanHook.on_route>، before() <#pecan.hooks.PecanHook.before>، after() <#pecan.hooks.PecanHook.after> یا on_error() <#pecan.hooks.PecanHook.on_error> را برای تعریف رفتار مورد نظر بازنویسی کنید.

from pecan.hooks import PecanHook
class SimpleHook(PecanHook):
    def before(self, state):
        print "\nabout to enter the controller..."
    def after(self, state):
        print "\nmethod: \t %s" % state.request.method
        print "\nresponse: \t %s" % state.response.status

به هر یک از متدهای on_route() <#pecan.hooks.PecanHook.on_route>، before() <#pecan.hooks.PecanHook.before> و after() <#pecan.hooks.PecanHook.after> یک شیء وضعیت مشترک ارسال می‌شود که شامل اطلاعات مفیدی است؛ از جمله اشیاء request و response، و اینکه کدام کنترل‌کننده توسط مسیریابی Pecan انتخاب شده است:

class SimpleHook(PecanHook):
    def on_route(self, state):
        print "\nabout to map the URL to a Python method (controller)..."
        assert state.controller is None  # Routing hasn't 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 "\nabout to enter the controller..."
        if state.request.path == '/':
            #
            # `state.controller` is a reference to the actual
            # `@pecan.expose()`-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)

به on_error() <#pecan.hooks.PecanHook.on_error> یک شیء وضعیت مشترک و استثنای اصلی پاس داده می‌شود. اگر یک گرداننده on_error() <#pecan.hooks.PecanHook.on_error> یک شیء Response برگرداند، این پاسخ به کاربر نهایی تحویل داده می‌شود و هیچ قلاب on_error() <#pecan.hooks.PecanHook.on_error> دیگری اجرا نخواهد شد:

class CustomErrorHook(PecanHook):
    def on_error(self, state, exc):
        if isinstance(exc, SomeExceptionType):
            return webob.Response('Custom Error!', status=500)

قلاب‌ها می‌توانند در سطح کل پروژه با تعیین فهرستی از قلاب‌ها در فایل پیکربندی پروژه‌تان ضمیمه شوند.

app = {
    'root' : '...'
    # ...
    'hooks': lambda: [SimpleHook()]
}

همچنین می‌توان با استفاده از ویژگی __hooks__ در یک یا چند کنترلر و ارث‌بری از HookController <#pecan.hooks.HookController>، قلاب‌ها را به‌صورت انتخابی روی کنترلرها و زیرکنترلرهای آن‌ها اعمال کرد.

from pecan import expose
from pecan.hooks import HookController
from my_hooks import SimpleHook
class SimpleController(HookController):
    __hooks__ = [SimpleHook()]
    @expose('json')
    def index(self):
        print "DO SOMETHING!"
        return dict()

اکنون که SimpleHook اضافه شده است، بیایید ببینیم هنگام اجرای برنامه و باز کردن آن در مرورگر وب چه رخ می‌دهد.

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

قلاب‌ها می‌توانند از کلاس والد یا mixinها به ارث برده شوند. فقط مطمئن شوید که از HookController <#pecan.hooks.HookController> ارث‌بری می‌کنید.

from pecan import expose
from pecan.hooks import PecanHook, HookController
class ParentHook(PecanHook):
    priority = 1
    def before(self, state):
        print "\nabout to enter the parent controller..."
class CommonHook(PecanHook):
    priority = 2
    def before(self, state):
        print "\njust a common hook..."
class SubHook(PecanHook):
    def before(self, state):
        print "\nabout to enter the subcontroller..."
class SubMixin(object):
    __hooks__ = [SubHook()]
# We'll use the same instance for both controllers,
# to avoid double calls
common = CommonHook()
class SubController(HookController, SubMixin):
    __hooks__ = [common]
    @expose('json')
    def index(self):
        print "\nI AM THE SUB!"
        return dict()
class RootController(HookController):
    __hooks__ = [common, ParentHook()]
    @expose('json')
    def index(self):
        print "\nI AM THE ROOT!"
        return dict()
    sub = SubController()

بیایید ببینیم با اجرای برنامه چه اتفاقی می‌افتد. ابتدا بارگذاری کنترلر ریشه:

pecan serve config.py
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
GET / HTTP/1.1" 200
about to enter the parent controller...
just a common hook
I AM THE ROOT!

سپس بارگذاری زیرکنترلر:

pecan serve config.py
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
GET /sub HTTP/1.1" 200
about to enter the parent controller...
just a common hook
about to enter the subcontroller...
I AM THE SUB!

نکته:

مطمئن شوید مقادیر اولویت (priority) مناسبی برای قلاب‌های تو‌در‌تو تنظیم کرده‌اید تا با ترتیب مورد نظر اجرا شوند.

هشدار:

اگر دو قلاب از یک نوع، به‌صورت نمونه‌های متفاوتی به یک کنترلر والد و فرزند ارسال شوند، دو بار اضافه/اجرا خواهند شد. اگر به‌صورت یک متغیر نمونه ارسال شوند - برای هر دو کنترلر تنها یک بار فراخوانی خواهند شد.

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

این قلاب برای اهداف اشکال‌زدایی مفید است. این قلاب به تمام صفت‌های شیء response به‌علاوهٔ چند صفت دیگر که مختص این فریم‌ورک هستند دسترسی دارد.

دو روش اصلی وجود دارد که این قلاب می‌تواند اطلاعات مربوط به یک درخواست را ارائه دهد:

1.
خروجی ترمینال یا ثبت وقایع (از طریق یک جریان شبه‌فایل مانند stdout)
2.
کلیدهای سفارشی سرایند در پاسخ واقعی.

به‌طور پیش‌فرض، هر دو خروجی فعال هستند.

همچنین ببینید:

•
pecan.hooks -- قلاب‌های Pecan <#pecan-hooks>

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

به‌طور پیش‌فرض، اطلاعات مربوط به این موارد را خروجی می‌دهد:

  • path : نشانی url استفاده‌شده برای ایجاد این پاسخ را نمایش می‌دهد
  • status : پاسخ دریافتی از سرور (مانند '200 OK')
  • method : متد درخواست (مانند 'GET'، 'POST'، 'PUT یا 'DELETE')
  • controller : متد کنترل‌کنندهٔ واقعی در Pecan که مسئول پاسخ است
  • params : فهرستی از تاپل‌ها برای پارامترهای ارائه‌شده در زمان درخواست
  • hooks : هر قلابی که در برنامه استفاده شده باشد در اینجا فهرست خواهد شد.

پیکربندی پیش‌فرض این مقادیر را از طریق stdout در ترمینال نمایش می‌دهد و همچنین آن‌ها را به سرایندهای پاسخ (به فرم X-Pecan-item_name) اضافه می‌کند.

خروجی ترمینال برای یک درخواست /favicon.ico ممکن است به این شکل باشد:

path         - /favicon.ico
status       - 404 Not Found
method       - GET
controller   - The resource could not be found.
params       - []
hooks        - ['RequestViewerHook']

در مورد بالا، فایل پیدا نشد و اطلاعات در stdout چاپ شد. علاوه بر این، سرایندهای زیر در پاسخ HTTP حضور خواهند داشت:

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       ['RequestViewerHook']

دیکشنری پیکربندی انعطاف‌پذیر است (هیچ‌یک از کلیدها الزامی نیستند) و می‌تواند شامل دو کلید باشد: items و blacklist.

در صورتی که قلاب مستقیماً پیکربندی شود، به این صورت خواهد بود (برای اختصار کوتاه شده است):

...
'hooks': lambda: [
    RequestViewerHook({'items':['path']})
]

فهرست items اطلاعاتی را مشخص می‌کند که هوک بازمی‌گرداند. گاهی اوقات با توجه به نیاز توسعه، به بخش خاصی از اطلاعات یا دسته‌ای از آن‌ها نیاز خواهید داشت؛ از این رو لازم است مقادیر پیش‌فرض تغییر کرده و فهرستی از موارد مشخص شود.

نکته:

هنگام مشخص کردن فهرستی از موارد، این فهرست مقادیر پیش‌فرض را کاملاً لغو (override) می‌کند؛ بنابراین اگر تنها یک مورد مشخص شود، فقط همان مورد توسط هوک بازگردانده خواهد شد.

هوک به تک‌تک مشخصه‌های شیء درخواست (request object) دسترسی دارد و دسترسی آن فقط محدود به موارد پیش‌فرضی که نمایش داده می‌شوند نیست؛ بنابراین می‌توانید اطلاعات نمایش‌داده‌شده را با دقت تنظیم کنید.

این فهرستی است شامل تمام مشخصه‌های ممکنی که هوک به آن‌ها دسترسی دارد (مستقیماً از webob):

accept make_tempfile
accept_charset max_forwards
accept_encoding method
accept_language params
application_url path
as_string path_info
authorization path_info_peek
blank path_info_pop
body path_qs
body_file path_url
body_file_raw postvars
body_file_seekable pragma
cache_control query_string
call_application queryvars
charset range
content_length referer
content_type referrer
cookies relative_url
copy remote_addr
copy_body remote_user
copy_get remove_conditional_headers
date request_body_tempfile_limit
decode_param_names scheme
environ script_name
from_file server_name
from_string server_port
get_response str_GET
headers str_POST
host str_cookies
host_url str_params
http_version str_postvars
if_match str_queryvars
if_modified_since unicode_errors
if_none_match upath_info
if_range url
if_unmodified_since urlargs
is_body_readable urlvars
is_body_seekable uscript_name
is_xhr user_agent
make_body_seekable
و این‌ها موارد خاصی از Pecan و hook هستند:
0.0
3.5
0.0
• 2
controller
• 2
hooks
• 2
params (در واقع params از طریق webob در دسترس است، اما برای خوانایی بهتر توسط hook تجزیه می‌شود)
168u
168u
168u
"قرار دادن مسیرهای خاص در فهرست سیاه (Blacklisting Certain Paths)"
گاهی اوقات دریافت اطلاعات دربارهٔ تک‌تک درخواست‌ها آزاردهنده است. برای محدود کردن خروجی، فهرست مسیرهای URL که نمی‌خواهید داده‌های آن‌ها دریافت شود را در قالب blacklist ارسال کنید.
تطبیق در ابتدای مسیر URL انجام می‌شود، بنابراین هنگام استفاده از این ویژگی احتیاط کنید. برای مثال، اگر پیکربندی را به این صورت ارسال کنید:
0.0
3.5
{ 'blacklist': ['/f'] }
168u
168u
این کار هیچ URLی را که با f آغاز شود نشان نخواهد داد، و عملاً شبیه به یک عبارت باقاعده با تطبیق الگو (globbing) عمل می‌کند (اما نه به آن اندازه قدرتمند).
برای هر تعداد مسدودسازی که نیاز دارید، کافی است موارد دلخواه خود را به تعداد نیاز اضافه کنید:
0.0
3.5
{ 'blacklist' : ['/favicon.ico', '/javascript', '/images'] }
168u
168u
مجدداً یادآوری می‌شود که کلید blacklist می‌تواند همراه با کلید items استفاده شود یا نشود (استفاده از آن اجباری نیست).
"سریال‌سازی JSON (JSON SERIALIZATION)"
Pecan شامل سامانه‌ای ساده و با استفادهٔ آسان برای تولید و ارائهٔ JSON است. برای شروع، فایلی به نام json.py در پروژهٔ خود بسازید و آن را در app.py پروژه‌تان وارد (import) کنید.
ماژول json شما شامل مجموعه‌ای از قوانین برای تولید JSON از اشیایی خواهد بود که در کنترلر خود برمی‌گردانید.
فرض کنید در برنامهٔ Pecan خود کنترلری داریم که می‌خواهیم از آن برای بازگرداندن خروجی JSON برای یک شیء User استفاده کنیم:
0.0
3.5
from myproject.lib import get_current_user
class UsersController(object):
@expose('json')
def current_user(self):
'''
return an instance of myproject.model.User which represents
the current authenticated user
'''
return get_current_user()
168u
168u
برای کارکرد درست این کنترلر، Pecan باید بداند چگونه شیء User را به انواع داده‌های سازگار با JSON تبدیل کند. یکی از روش‌ها برای مشخص کردن نحوهٔ تبدیل شیء به JSON برای Pecan، تعریف یک قاعده در json.py است:
0.0
3.5
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()
)
168u
168u
در این مثال، هنگامی که نمونه‌ای از کلاس model.User از کنترلری که برای بازگرداندن JSON پیکربندی شده است بازگردانده می‌شود، قاعدهٔ jsonify_user() برای تبدیل شیء به داده‌های سازگار با JSON فراخوانی خواهد شد. توجه داشته باشید که این قاعده یک رشتهٔ JSON تولید نمی‌کند، بلکه یک دیکشنری پایتون تولید می‌کند که فقط شامل انواع داده‌های سازگار با JSON است.
به عنوان روشی جایگزین، می‌توان قاعده را روی خود شیء و با تعیین متد __json__() در کلاس مشخص کرد:
0.0
3.5
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()
)
168u
168u
مزیت استفاده از ماژول json.py این است که تمام قوانین JSON شما در یک مکان متمرکز تعریف می‌شوند، اما برخی پروژه‌ها سادگی پیوسته‌بودن مستقیم قوانین JSON به اشیاء مدل خود را ترجیح می‌دهند..SH "متغیرهای محلی زمینه/نخ در برابر ارسال صریح آرگومان (CONTEXT/THREAD-LOCALS VS. EXPLICIT ARGUMENT PASSING)"
در هر برنامه pecan، متغیرهای سطح ماژول pecan.request و
pecan.response اشیای پراکسی هستند که همیشه به درخواست و
پاسخی که در نخ جاری پردازش می‌شود اشاره دارند.
این محلی‌بودن نخ (thread locality) تضمین می‌کند که می‌توانید در یک محیط چندنخی (multi-threaded)
بدون نیاز به دست‌به‌دست کردن مداوم ارجاعات اشیا در کد خود، به‌طور ایمن به یک ارجاع سراسری
به درخواست و پاسخ جاری دسترسی داشته باشید؛ این قابلیتی در pecan است که
نوشتن برنامه‌های وب سنتی را ساده‌تر و کم‌حجم‌تر می‌کند.
برخی افراد بر این باورند که متغیرهای محلی نخ بیش از حد ضمنی یا جادویی هستند، و
ارسال صریح ارجاع در طولانی‌مدت بسیار واضح‌تر و نگهداری‌پذیرتر است.
علاوه‌بر این، پیاده‌سازی پیش‌فرض ارائه‌شده توسط pecan از
threading.local() برای مرتبط ساختن این اشیای پراکسی محلی زمینه با
شناسه نخ نخِ سرور جاری استفاده می‌کند. در مدل‌های سرور ناهمگام (asynchronous)
- که در آن‌ها کارهای زیادی برای مدت‌زمان کوتاهی بر روی یک نخِ مشترکِ واحد اجرا می‌شوند -
پشتیبانی از این سازوکار نیازمند مانکی‌پچ (monkeypatching) کردن
threading.local() است تا رفتاری محلی شبیه به greenlet داشته باشد.
"غیرفعال‌سازی پراکسی‌های محلی نخ (Disabling Thread-Local Proxies)"
اگر مطمئن هستید که نمی‌خواهید از متغیرهای محلی زمینه/نخ در
پروژه خود استفاده کنید، می‌توانید با مشخص کردن آرگومان
use_context_locals=False در فایل پیکربندی برنامه‌تان این کار را انجام دهید:
0.0
3.5
app = {
'root': 'project.controllers.root.RootController',
'modules': ['project'],
'static_root': '%(confdir)s/public',
'template_path': '%(confdir)s/project/templates',
'debug': True,
'use_context_locals': False
}
168u
168u
علاوه‌بر این، لازم است تمام کنترلرهای pecan خود را به‌روزرسانی کنید تا
آرگومان‌های موقعیتی را برای درخواست و پاسخ جاری بپذیرند:
0.0
3.5
class RootController(object):
@pecan.expose('json')
def index(self, req, resp):
return dict(method=req.method) # path: /
@pecan.expose()
def greet(self, req, resp, name):
return name # path: /greet/joe
168u
168u
ضروری است که آرگومان‌های درخواست و پاسخ بعد از
self و قبل از هرگونه آرگومان موقعیتی فرم قرار گیرند.
"PECAN در خط فرمان (COMMAND LINE PECAN)"
هر برنامه Pecan را می‌توان با استفاده از دستور درونی pecan از خط
فرمان کنترل و بازرسی کرد. مثال‌های استفاده از pecan
در این سند به گونه‌ای در نظر گرفته شده‌اند که از دایرکتوری ریشه پروژه شما اجرا شوند.
"میزبانی برنامه Pecan برای توسعه (Serving a Pecan App For Development)"
نرم‌افزار Pecan همراه با یک سرور توسعه سبک WSGI مبتنی بر
ماژول wsgiref.simple_server در پایتون عرضه می‌شود https://docs.python.org/3/library/wsgiref.html#module-wsgiref.simple_server.
میزبانی برنامه Pecan به سادگیِ اجرای دستور pecan serve است:
0.0
3.5
$ pecan serve config.py
Starting server in PID 000.
serving on 0.0.0.0:8080, view at http://127.0.0.1:8080
168u
168u
و سپس مشاهده آن در مرورگرتان.
host و port سرور در فایل پیکربندی شما مطابق آنچه
در Server Configuration <#server-configuration> شرح داده شده است، قابل تغییر است..SS بارگذاری مجدد خودکار با تغییر فایل‌ها
ایجاد وقفه برای راه‌اندازی مجدد سرور توسعه در حین کار می‌تواند مخل تمرکز باشد، از این رو
pecan serve پرچم --reload را برای تسهیل کار ارائه می‌دهد.
برای ارائه این قابلیت، Pecan از کتابخانه پایتون
watchdog https://pypi.python.org/pypi/watchdog استفاده می‌کند. پیش از ادامه،
باید آن را برای استفاده در محیط توسعه نصب کنید:
0.0
3.5
$ pip install watchdog
Downloading/unpacking watchdog
...
Successfully installed watchdog
168u
168u
0.0
3.5
$ 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
168u
168u
در حین کار، Pecan به هرگونه رویداد تغییر فایل یا دایرکتوری در پروژه شما گوش می‌دهد و
فرایند سرور را به‌طور بی‌صدا در پس‌زمینه مجدداً راه‌اندازی می‌کند.
پوسته تعاملی
برنامه‌های Pecan همچنین همراه با یک پوسته تعاملی پایتون ارائه می‌شوند که می‌تواند برای اجرای
عبارت‌ها در محیطی بسیار مشابه با محیط اجرای برنامه شما به کار رود. برای فراخوانی
یک پوسته تعاملی، از دستور pecan shell استفاده کنید:
0.0
3.5
$ 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's WSGI App instance
conf - The current configuration
app - webtest.TestApp wrapped around wsgiapp
>>> conf
Config({
'app': Config({
'root': 'myapp.controllers.root.RootController',
'modules': ['myapp'],
'static_root': '/Users/somebody/myapp/public',
'template_path': '/Users/somebody/myapp/project/templates',
'errors': {'404': '/error/404'},
'debug': True
}),
'server': Config({
'host': '0.0.0.0',
'port': '8080'
})
})
>>> app
<webtest.app.TestApp object at 0x101a830>
>>> app.get('/')
<200 OK text/html body='<html>\n ...\n\n'/936>
168u
168u
برای خروج از پوسته تعاملی کلیدهای Ctrl-D (یا در ویندوز Ctrl-Z) را فشار دهید.
استفاده از یک پوسته جایگزین
دستور pecan shell دارای پشتیبانی اختیاری از پوسته‌های جایگزین IPython http://ipython.org
و bpython http://bpython-interpreter.org است که هر یک از آن‌ها را می‌توان با پرچم
--shell (یا نام مستعار کوتاه‌شده آن، -s) مشخص کرد؛ به عنوان مثال:
0.0
3.5
$ pecan shell --shell=ipython config.py
$ pecan shell -s bpython config.py
168u
در تمام مثال‌های نمایش‌داده‌شده، مشاهده خواهید کرد که دستورات pecan
یک مسیر فایل را به عنوان فایل پیکربندی می‌پذیرفتند. راهکار جایگزین،
مشخص کردن فایل پیکربندی در یک متغیر محیطی (PECAN_CONFIG) است.
این کار کاملاً اختیاری است؛ اگر مسیر فایل به‌صورت صریح ارسال شود، Pecan
پیش از بررسی متغیر محیطی، آن را در اولویت قرار می‌دهد.
برای مثال، جهت ارائه (serve) یک برنامهٔ Pecan، می‌توان متغیری را export کرد و
سپس هنگامی که هیچ مسیری مشخص نشده باشد، مجدداً از آن استفاده نمود.
0.0
3.5
$ 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
168u
168u
توجه داشته باشید که مسیر باید به یک فایل پیکربندی معتبر pecan ارجاع دهد،
در غیر این صورت دستور با پیامی مبنی بر نامعتبر بودن مسیر (به عنوان مثال، اگر
یک دایرکتوری ارسال شود) با خطا مواجه خواهد شد.
اگر PECAN_CONFIG تنظیم نشده باشد و هیچ پیکربندی‌ای ارسال نگردد، دستور
با خطا متوقف خواهد شد زیرا قادر به یافتن فایل پیکربندی نخواهد بود.
گسترش pecan با دستورات سفارشی
اگرچه دستورات بسته‌بندی‌شده همراه Pecan کاربردی هستند، اما سودمندی واقعی
ابزارهای خط فرمان آن در قابلیت گسترش‌پذیری نهفته است. بسیار مطلوب است که بتوان
یک اسکریپت پایتون نوشت که بتواند «در محیط Pecan» کار کند و به مواردی مانند
فایل پیکربندی تجزیه‌شدهٔ برنامه یا یک نمونهٔ شبیه‌سازی‌شده از خود برنامه (مانند
نمونهٔ ارائه‌شده در دستور pecan shell) دسترسی داشته باشد.
نوشتن یک دستور سفارشی Pecan
به عنوان مثال، بیایید دستوری ایجاد کنیم که بتواند یک درخواست شبیه‌سازی‌شدهٔ
HTTP GET را به برنامهٔ شما ارسال کرده و نتیجه را چاپ کند. فراخوانی آن از
خط فرمان ممکن است شبیه به این باشد:
0.0
3.5
$ pecan wget config.py /path/to/some/resource
168u
168u
فرض کنید توزیعی دارید که بسته‌ای به نام myapp در آن قرار دارد و
درون این بسته، ماژولی به نام wget.py موجود است:
0.0
3.5
# myapp/myapp/wget.py
import pecan
from webtest import TestApp
class GetCommand(pecan.commands.BaseCommand):
'''
Issues a (simulated) HTTP GET and returns the request body.
'''
arguments = pecan.commands.BaseCommand.arguments + ({
'name': 'path',
'help': 'the URI path of the resource to request'
},)
def run(self, args):
super(GetCommand, self).run(args)
app = TestApp(self.load_app())
print app.get(args.path).body
168u
168u
بیایید این مورد را بخش‌به‌بخش تحلیل کنیم..SS بازنویسی متد run
ابتدا، از BaseCommand <#pecan.commands.base.BaseCommand> یک زیرکلاس ساخته و متد
run() <#pecan.commands.base.BaseCommandParent.run> را گسترش می‌دهیم تا:
0.0
• 2
یک برنامه Pecan را بارگذاری کند - load_app() <#pecan.core.load_app>
• 2
آن را در یک محیط ساختگی WSGI قرار دهد - TestApp https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#webtest.app.TestApp
• 2
یک درخواست HTTP GET به آن ارسال کند - get() https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#webtest.app.TestApp.get
168u
تعریف آرگومان‌های سفارشی
مشخصه کلاسی arguments برای تعریف آرگومان‌های خط فرمان مختص به
دستور سفارشی شما استفاده می‌شود. در این مثال متوجه خواهید شد که ما
به جای بازنویسی کامل، در حال افزودن به فهرست آرگومان‌های ارائه‌شده توسط BaseCommand <#pecan.commands.base.BaseCommand>
(که پیشاپیش یک آرگومان برای config_file ارائه می‌دهد) هستیم.
قالب مشخصه کلاسی arguments یک tuple https://docs.python.org/3/library/stdtypes.html#tuple از
دیکشنری‌ها است، که هر دیکشنری نشان‌دهنده تعریف یک آرگومان با همان قالبی است که توسط ماژول
argparse پایتون https://docs.python.org/3/library/argparse.html#module-argparse پذیرفته می‌شود (به‌طور دقیق‌تر،
add_argument() https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument). با ارائه فهرستی از
آرگومان‌ها در این قالب، دستور pecan می‌تواند دستورات سفارشی شما را
در خروجی راهنما و نحوه استفاده (usage) خود بگنجاند.
0.0
3.5
$ 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
168u
168u
علاوه بر این، متوجه خواهید شد که خط نخست docstring مربوط به
GetCommand -- Issues a (simulated) HTTP GET and returns the
request body -- به‌طور خودکار برای توصیف دستور wget در خروجی
$ pecan -h به کار می‌رود. پیروی از این روال به شما اجازه می‌دهد
تا به سادگی خلاصه‌ای از دستور خود را در ابزار خط فرمان Pecan ادغام کنید.
ثبت یک دستور سفارشی
اکنون که دستور سفارشی خود را نوشته‌اید، باید وجود آن را به setup.py
بسته خود اعلام کرده و مجدداً آن را نصب کنید. در فایل setup.py بسته
خود، فراخوانی setup() را خواهید یافت.
0.0
3.5
# myapp/setup.py
...
setup(
name='myapp',
version='0.1',
author='Joe Somebody',
...
)
168u
168u
با فرض اینکه از قبل وجود نداشته باشد، آرگومان entry_points را به
فراخوانی setup() اضافه می‌کنیم و یک تعریف [pecan.command] برای دستور سفارشی
شما تعیین می‌کنیم:
0.0
3.5
# myapp/setup.py
...
setup(
name='myapp',
version='0.1',
author='Joe Somebody',
...
entry_points="""
[pecan.command]
wget = myapp.wget:GetCommand
"""
)
168u
168u
پس از انجام این کار، پروژه خود را در حالت توسعه (development) دوباره نصب کنید تا
نقطه ورود جدید ثبت شود.
0.0
3.5
$ python setup.py develop
168u
168u
سپس آن را امتحان کنید.
0.0
3.5
$ pecan wget config.py /path/to/some/resource
168u
"بارگذاری مجدد خودکار با تغییر فایل‌ها (Reloading Automatically as Files Change)"
متوقف کردن کار برای راه‌اندازی مجدد سرور توسعه می‌تواند مخل تمرکز باشد، از این رو
pecan serve پرچم --reload را برای ساده‌تر کردن کارها فراهم کرده است.
برای ارائه این قابلیت، Pecan از کتابخانه پایتون
watchdog https://pypi.python.org/pypi/watchdog استفاده می‌کند. پیش از ادامه،
باید آن را برای استفاده در محیط توسعه نصب کنید:
0.0
3.5
$ pip install watchdog
Downloading/unpacking watchdog
...
Successfully installed watchdog
168u
168u
0.0
3.5
$ 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
168u
168u
همگام با کار شما، Pecan تمام رویدادهای تغییر فایل یا دایرکتوری در پروژه‌تان را زیر نظر گرفته
و به‌صورت بی‌صدا فرایند سرور شما را در پس‌زمینه مجدداً راه‌اندازی می‌کند.
"اشکال‌زدایی برنامه‌های Pecan (Debugging Pecan Applications)"
برنامه Pecan به همراه یک میان‌افزار اشکال‌زدایی ساده برای کمک به عیب‌یابی مشکلات
در برنامه‌هایتان ارائه می‌شود. برای فعال‌سازی میان‌افزار اشکال‌زدایی، کافی است پرچم
debug را در فایل پیکربندی خود روی True تنظیم کنید:
0.0
3.5
app = {
...
'debug': True,
...
}
168u
168u
پس از فعال‌سازی، در صورت بروز استثناهای زمان اجرا، این میان‌افزار به‌طور خودکار استثناهای
صادرشده توسط برنامه را گرفته و ردپای پشته پایتون و محیط WSGI را در مرورگر شما
نمایش می‌دهد.
برای بهبود اشکال‌زدایی، از جمله پشتیبانی از یک کنسول تعاملی مبتنی بر مرورگر، Pecan از
کتابخانه پایتون backlash
https://pypi.python.org/pypi/backlash استفاده می‌کند. پیش از ادامه،
باید آن را برای استفاده در محیط توسعه نصب کنید:
0.0
3.5
$ pip install backlash
Downloading/unpacking backlash
...
Successfully installed backlash
168u
168u
"ارائه فایل‌های ایستا (Serving Static Files)"
برنامه Pecan دارای یک میان‌افزار ساده برای سرو کردن CSS، Javascript،
تصاویر و سایر فایل‌های ایستا است. می‌توانید با اطمینان از مشخص شدن
گزینه‌های زیر در فایل پیکربندی، آن را تنظیم کنید:
0.0
3.5
app = {
...
'debug': True,
'static_root': '%(confdir)/public
}
168u
168u
که در آن static_root یک مسیر مطلق به دایرکتوری‌ای است که فایل‌های ایستای شما در
آن قرار دارند. برای سهولت، این مسیر می‌تواند شامل متغیر %(confdir)
باشد که Pecan در زمان اجرا آن را با مسیر مطلق فایل پیکربندی شما جایگزین می‌کند.
نکته:
0.0
3.5
در محیط عملیاتی (production)، مقدار app.debug هرگز نباید روی True تنظیم
شود، بنابراین باید فایل‌های ایستای خود را از طریق وب‌سرور عملیاتی ارائه دهید.
168u
روش‌های گوناگونی برای استقرار یک پروژهٔ Pecan در یک محیط عملیاتی وجود دارد. مثال‌های زیر با هدف ارائهٔ جهت‌دهی کلی آورده شده‌اند، نه دستورالعمل‌های صریح؛ فرآیند استقرار معمولاً به شدت وابسته به نیازها و اهداف هر برنامه است، بنابراین ممکن است نتیجه برای شما متفاوت باشد.
نکته:
0.0
3.5
اگرچه Pecan به همراه یک کارگزار ساده برای استفاده در مرحلهٔ توسعه (pecan serve) عرضه می‌شود، استفاده از یک کارگزار آماده برای محیط عملیاتی (production-ready) مشابه مواردی که در این سند شرح داده شده‌اند، به‌شدت توصیه می‌شود.
168u
168u
نصب Pecan
چند گزینهٔ محبوب برای نصب Pecan در محیط‌های عملیاتی در دسترس است:
0.0
• 2
استفاده از setuptools https://pypi.python.org/pypi/setuptools. مدیریت Pecan به عنوان یک وابستگی در فایل setup.py پروژه تا در کنار پروژه نصب شود (برای مثال، python /path/to/project/setup.py install). پروژهٔ پیش‌فرض Pecan که در Creating Your First Pecan Application <#quick-start> شرح داده شده است، این فرآیند را با گنجاندن Pecan به عنوان وابستگی پروژهٔ شما تسهیل می‌کند.
• 2
استفاده از pip http://www.pip-installer.org.
از pip freeze و pip install برای ایجاد و نصب از روی یک فایل requirements.txt برای پروژه استفاده کنید.
• 2
از طریق دستورالعمل‌های دستی موجود در Installation <#installation>.
168u
نکته:
0.0
3.5
صرف‌نظر از روشی که انتخاب می‌کنید، اکیداً توصیه می‌شود که تمام عملیات‌های نصبِ استقرار در یک محیط مجازی پایتون (virtualenv) http://www.virtualenv.org انجام شوند.
168u
168u
غیرفعال‌سازی حالت اشکال‌زدایی (Debug Mode)
هشدار:
0.0
3.5
یکی از مهم‌ترین گام‌ها پیش از استقرار یک برنامهٔ Pecan در محیط عملیاتی، اطمینان از غیرفعال بودن Debug Mode است که یک محیط اشکال‌زدایی توسعه‌محور برای ردگیری خطاهای زمان اجرا (tracebacks) فراهم می‌کند. عدم غیرفعال‌سازی این ابزار توسعه در محیط عملیاتی شما، قطعاً به مشکلات امنیتی جدی منجر خواهد شد. در فایل پیکربندی عملیاتی خود، مطمئن شوید که debug روی False تنظیم شده است.
0.0
3.5
# myapp/production_config.py
app = {
...
'debug': False
}
168u
168u
168u
168u
Pecan و WSGI
استاندارد WSGI یک استاندارد در پایتون است که یک رابط استاندارد بین سرورها و برنامه را توصیف می‌کند. هر برنامهٔ Pecan یک "WSGI application" نیز نامیده می‌شود چرا که رابط WSGI را پیاده‌سازی می‌کند؛ از این رو هر سروری که با WSGI سازگار باشد ("WSGI compatible") را می‌توان برای سرویس‌دهی به برنامه به کار گرفت. چند نمونهٔ پرکاربرد عبارتند از:
0.0
• 2
mod_wsgi http://code.google.com/p/modwsgi
• 2
uWSGI http://projects.unbit.it/uwsgi
• 2
Gunicorn http://gunicorn.org
• 2
waitress http://docs.pylonsproject.org/projects/waitress/en/latest
• 2
CherryPy http://cherrypy.org
168u
به طور کلی، نقطهٔ ورود WSGI به هر برنامهٔ Pecan را می‌توان با استفاده از deploy() <#pecan.deploy.deploy> ایجاد کرد:
0.0
3.5
from pecan.deploy import deploy
application = deploy('/path/to/some/app/config.py')
168u
‏Pecan همراه با میان‌افزار ارائهٔ فایل‌های ایستا (مانند CSS، Javascript، تصاویر) عرضه می‌شود که استفاده از آن در محیط عملیاتی توصیه نمی‌شود.
در محیط عملیاتی، Pecan خود فایل‌های رسانه‌ای را ارائه نمی‌دهد؛ بلکه این وظیفه را به وب‌سرور انتخابی شما واگذار می‌کند.
برای ارائهٔ فایل‌های ایستا در محیط عملیاتی، بهتر است با ارائهٔ این فایل‌ها به صورت جداگانه از برنامهٔ WSGI خود، تفکیک وظایف را رعایت کنید (عمدتاً به دلایل عملکردی). روش‌های محبوب متعددی برای انجام این کار وجود دارد که در اینجا به دو مورد اشاره می‌شود:
0.0
1. 3
راه‌اندازی یک سرور پراکسی (مانند nginx http://nginx.org/en، cherokee http://www.cherokee-project.com، CherryPy یا lighttpd http://www.lighttpd.net) برای ارائهٔ فایل‌های ایستا و هدایت درخواست‌های برنامه به برنامهٔ کاربردی WSGI شما:
3.0
3.5
<HTTP Client> ─── <Production/Proxy Server>, e.g., Apache, nginx, cherokee (0.0.0.0:80) ─── <Static Files>
│
├── <WSGI Server> Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5000 or /tmp/some.sock)
├── <WSGI Server> Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5001 or /tmp/some.sock)
├── <WSGI Server> Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5002 or /tmp/some.sock)
└── <WSGI Server> Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5003 or /tmp/some.sock)
168u
168u
2. 3
ارائهٔ فایل‌های ایستا از طریق یک سرویس، میزبان مجازی یا CDN مجزا.
168u
"دستورالعمل‌های رایج"
Apache + mod_wsgi
ماژول mod_wsgi http://code.google.com/p/modwsgi یک ماژول محبوب Apache است که می‌تواند برای میزبانی هر برنامهٔ پایتون سازگار با WSGI (شامل برنامهٔ Pecan شما) استفاده شود.
برای شروع، مستندات نصب و پیکربندی http://code.google.com/p/modwsgi/wiki/InstallationInstructions مربوط به mod_wsgi را بررسی کنید.
برای نمونه، فرض کنیم پروژهٔ ما، simpleapp، در مسیر /var/www/simpleapp قرار دارد و یک virtualenv http://www.virtualenv.org در مسیر /var/www/venv با تمام وابستگی‌های لازم (از جمله Pecan) ایجاد شده است. علاوه بر این، به دلایل امنیتی، کاربر user1 و گروه group1 را ایجاد کرده‌ایم تا برنامه تحت دسترسی آنها اجرا شود.
گام نخست، ایجاد یک فایل .wsgi است که mod_wsgi از آن به عنوان نقطهٔ ورود برنامهٔ شما استفاده خواهد کرد:
0.0
3.5
# /var/www/simpleapp/app.wsgi
from pecan.deploy import deploy
application = deploy('/var/www/simpleapp/config.py')
168u
168u
سپس، پیکربندی Apache را برای برنامهٔ خود اضافه کنید. در اینجا یک نمونهٔ ساده آورده شده است:
0.0
3.5
<VirtualHost *>
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
<Directory /var/www/simpleapp/>
WSGIProcessGroup simpleapp
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
168u
168u
برای دریافت دستورالعمل‌ها و مثال‌های بیشتر در رابطه با سوار کردن برنامه‌های WSGI با استفاده از mod_wsgi، به مستندات mod_wsgi http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide#Mounting_The_WSGI_Application مراجعه کنید.
در پایان، Apache را بازراه‌اندازی کرده و آن را آزمایش کنید..SS uWSGI
کارگزار uWSGI http://projects.unbit.it/uwsgi یک کارگزار کانتینر برنامهٔ کاربردی سریع، خودترمیم‌شونده و سازگار با توسعه‌دهندگان و مدیران سیستم است که به زبان C خالص نوشته شده است. این ابزار از پروتکل uwsgi http://projects.unbit.it/uwsgi/wiki/uwsgiProtocol استفاده می‌کند، اما از پروتکل‌های دیگر نیز پشتیبانی می‌کند (http، fastcgi...).
اجرای برنامه‌های Pecan با uWSGI بسیار ساده است:
0.0
3.5
$ pip install uwsgi
$ pecan create simpleapp && cd simpleapp
$ python setup.py develop
$ uwsgi --http-socket :8080 --venv /path/to/virtualenv --pecan config.py
168u
168u
یا با استفاده از یک سوکت Unix (که برای مثال می‌توان nginx را برای پراکسی کردن به آن پیکربندی کرد http://projects.unbit.it/uwsgi/wiki/RunOnNginx):
0.0
3.5
$ uwsgi -s /tmp/uwsgi.sock --venv /path/to/virtualenv --pecan config.py
168u
168u
Gunicorn
کارگزار Gunicorn http://gunicorn.org یا "Green Unicorn"، یک کارگزار HTTP مبتنی بر WSGI برای UNIX است. این ابزار از مدل پردازشی pre-fork استفاده می‌کند که از پروژهٔ Unicorn در زبان Ruby پورت شده است. این کارگزار از هر دوی eventlet و greenlet پشتیبانی می‌کند.
اجرای یک برنامهٔ Pecan روی Gunicorn ساده است. بیایید مراحل آن را با یک پروژهٔ پیش‌فرض Pecan دنبال کنیم:
0.0
3.5
$ pip install gunicorn
$ pecan create simpleapp && cd simpleapp
$ python setup.py develop
$ gunicorn_pecan config.py
168u
168u
CherryPy
کارگزار CherryPy http://cherrypy.org یک وب‌سرور مبتنی بر مخزن ریسمان‌ها (thread-pooled)، سازگار با استاندارد HTTP/1.1 و WSGI ارائه می‌دهد که تماماً با پایتون پیاده‌سازی شده است. این ابزار می‌تواند به سادگی از برنامه‌های Pecan پشتیبانی کند و حتی فایل‌های ایستا (static) را مانند یک سرور محیط عملیاتی سرویس‌دهی نماید.
مثال‌های زیر با هدف استفاده از CherryPy به عنوان کارگزار مسئول اجرای برنامهٔ Pecan در کنار سرویس‌دهی فایل‌های ایستا تنظیم شده‌اند.
0.0
3.5
$ pip install cherrypy
$ pecan create simpleapp && cd simpleapp
$ python setup.py develop
168u
168u
برای اجرا با CherryPy، ساده‌ترین روش ایجاد یک اسکریپت در ریشهٔ پروژه (در کنار setup.py) است تا بتوانیم نحوهٔ سرویس‌دهی برنامهٔ نمونه‌مان را مشخص کنیم. اسکریپت مورد نظر (با نام run.py) به این شکل است:
0.0
3.5
import os
import cherrypy
from cheroot import wsgi
from cheroot.wsgi import PathInfoDispatcher
from pecan.deploy import deploy
simpleapp_wsgi_app = deploy('/path/to/production_config.py')
public_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'public'))
# A dummy class for our Root object
# necessary for some CherryPy machinery
class Root(object):
pass
def make_static_config(static_dir_name):
"""
All custom static configurations are set here, since most are common, it
makes sense to generate them just once.
"""
static_path = os.path.join('/', static_dir_name)
path = os.path.join(public_path, static_dir_name)
configuration = {
static_path: {
'tools.staticdir.on': True,
'tools.staticdir.dir': path
}
}
return cherrypy.tree.mount(Root(), '/', config=configuration)
# Assuming your app has media on different paths, like 'css', and 'images'
application = PathInfoDispatcher({
'/': simpleapp_wsgi_app,
'/css': make_static_config('css'),
'/images': make_static_config('images')
})
server = wsgi.Server(('0.0.0.0', 8080), application, server_name='simpleapp')
try:
server.start()
except KeyboardInterrupt:
print("Terminating server...")
server.stop()
168u
168u
برای راه‌اندازی کارگزار، کافی است آن را با مفسر Python اجرا کنید:
0.0
3.5
$ python run.py
168u
Pecan با ارسال گزینه‌های پیکربندی ثبت وقایع به تابع logging.config.dictConfig http://docs.python.org/library/logging.config.html#configuration-dictionary-schema
از ماژول logging https://docs.python.org/3/library/logging.html#module-logging کتابخانه استاندارد پایتون استفاده می‌کند.
مستندات کامل قالب dictConfig() بهترین منبع اطلاعات برای پیکربندی ثبت وقایع است، اما برای شروع،
این فصل چند مثال ساده در اختیارتان می‌گذارد.
پیکربندی ثبت وقایع
نمونه‌ای از پیکربندی ثبت وقایع همراه با پروژه quickstart معرفی‌شده در «ایجاد اولین برنامه Pecan» <#quick-start> ارائه شده است:
0.0
3.5
$ pecan create myapp
168u
168u
پیکربندی پیش‌فرض یک handler و دو logger را تعریف می‌کند.
0.0
3.5
# myapp/config.py
app = { ... }
server = { ... }
logging = {
'root' : {'level': 'INFO', 'handlers': ['console']},
'loggers': {
'myapp': {'level': 'DEBUG', 'handlers': ['console']}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple'
}
},
'formatters': {
'simple': {
'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
'[%(threadName)s] %(message)s')
}
}
}
168u
168u
0.0
• 2
console پیام‌ها را با استفاده از فرمت‌کننده simple در stderr ثبت می‌کند.
• 2
myapp پیام‌های ارسال‌شده در سطحی بالاتر یا برابر با DEBUG را به handler با نام console
ارسال می‌کند
• 2
root پیام‌های در سطحی بالاتر یا برابر با سطح INFO را به handler با نام console
ارسال می‌کند
168u
نوشتن پیام‌های ثبت وقایع در برنامه شما
ثبت‌کننده (logger) با نام myapp برای استفاده شما در برنامه Pecan رزرو شده است.
پس از پیکربندی ثبت وقایع، می‌توانید فراخوانی‌های ثبت وقایع را در کد خود قرار دهید.
استفاده از چارچوب ثبت وقایع بسیار ساده است.
0.0
3.5
# 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('Uh-oh!')
return dict()
168u
کتابخانهٔ logging پایتون https://docs.python.org/3/library/logging.html#module-logging گرداننده‌های متنوعی را تعریف می‌کند که در نوشتن گزارش‌ها روی فایل کمک می‌کنند. چند مورد کاربردی از آن‌ها عبارتند از:
0.0
• 2
FileHandler https://docs.python.org/3/library/logging.handlers.html#logging.FileHandler - برای ثبت پیام‌ها در فایلی روی سیستم‌فایل استفاده می‌شود
• 2
RotatingFileHandler https://docs.python.org/3/library/logging.handlers.html#logging.handlers.RotatingFileHandler - مشابه
FileHandler https://docs.python.org/3/library/logging.handlers.html#logging.FileHandler است، اما همچنین گزارش‌ها را به‌طور دوره‌ای چرخش (rotate) می‌دهد
• 2
SysLogHandler https://docs.python.org/3/library/logging.handlers.html#logging.handlers.SysLogHandler - برای ثبت پیام‌ها در syslog یونیکس استفاده می‌شود
• 2
SMTPHandler https://docs.python.org/3/library/logging.handlers.html#logging.handlers.SMTPHandler - برای ثبت پیام‌ها و ارسال به یک آدرس ایمیل از طریق SMTP استفاده می‌شود
168u
استفاده از هر یک از آن‌ها به سادگیِ تعریف یک گرداننده جدید در بلوک logging برنامه و انتساب آن به یک یا چند لاگر است.
ثبت درخواست‌ها با Paste Translogger
بستهٔ Paste http://pythonpaste.org (که همراه با Pecan عرضه نمی‌شود) شامل میان‌افزار
TransLogger برای ثبت درخواست‌ها در قالب Apache Combined Log Format http://httpd.apache.org/docs/2.2/logs.html#combined است. TransLogger در ترکیب با ثبت گزارش مبتنی بر فایل می‌تواند برای ایجاد فایل access.log مشابه با Apache استفاده شود.
برای افزودن این میان‌افزار، متد setup_app را در فایل app.py پروژهٔ خود به شکل زیر تغییر دهید:
0.0
3.5
# 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
168u
168u
به‌طور پیش‌فرض، TransLogger لاگری با نام
wsgi ایجاد می‌کند، بنابراین باید در فایل پیکربندی Pecan یک گردانندهٔ جدید (مبتنی بر فایل) برای این لاگر مشخص کنید:
0.0
3.5
# myapp/config.py
app = { ... }
server = { ... }
logging = {
'loggers': {
# ...
'wsgi': {'level': 'INFO', 'handlers': ['logfile'], 'qualname': 'wsgi'}
},
'handlers': {
# ...
'logfile': {
'class': 'logging.FileHandler',
'filename': '/etc/access.log',
'level': 'INFO',
'formatter': 'messageonly'
}
},
'formatters': {
# ...
'messageonly': {'format': '%(message)s'}
}
}
168u
آزمون‌ها تا زمانی که اجراکنندهٔ آزمون (test runner) بتواند آن‌ها را شناسایی کند، می‌توانند در هر کجای پروژهٔ Pecan شما قرار داشته باشند. به‌طور سنتی، آن‌ها در بسته‌ای به نام myapp.tests قرار می‌گیرند.
سازوکار پیشنهادی برای آزمون‌های واحد (unit testing) و یکپارچه‌سازی (integration testing) یک برنامهٔ کاربردی Pecan، پیمانهٔ unittest https://docs.python.org/3/library/unittest.html#module-unittest است.
"شناسایی آزمون و ابزارهای دیگر (Test Discovery and Other Tools)"
آزمون‌های یک پروژهٔ Pecan را می‌توان به سادگی با دستور python setup.py test فراخوانی کرد، هرچند امکان اجرای آزمون‌هایتان با ابزارهای مختلف شناسایی و خودکارسازی نیز وجود دارد. به‌ویژه، پروژه‌های Pecan به خوبی با
nose http://pypi.python.org/pypi/nose/1.1.2، pytest http://pytest.org
و tox http://pypi.python.org/pypi/tox کار می‌کنند.
"نوشتن آزمون‌های کارکردی با WebTest (Writing Functional Tests with WebTest)"
یک آزمون واحد معمولاً به اشیاء "شبیه‌سازی‌شده (mock)" یا "جعلی (fake)" متکی است تا به کُد تحت آزمون، بستر کافی برای اجرا داده شود. بدین ترتیب، تنها یک واحد منفرد از کُد منبع آزمایش می‌شود.
یک مجموعهٔ آزمون کارآمد، آزمون‌های واحد را با آزمون‌های کارکردی ترکیب می‌کند. در چارچوب یک برنامهٔ Pecan، آزمون‌های کارکردی را می‌توان با کمک کتابخانهٔ webtest https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#module-webtest نوشت. به این ترتیب، امکان نوشتن آزمون‌هایی وجود دارد که رفتار چرخهٔ حیات یک درخواست HTTP را از مسیریابی کنترل‌کننده تا پاسخ HTTP بررسی و اعتبارسنجی می‌کنند. نمونهٔ زیر مشابه همان کُدی است که در پروژهٔ شروع سریع (quickstart) نرم‌افزار Pecan گنجانده شده است.
0.0
3.5
# 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):
"""
Used for functional tests where you need to test your
literal application and its integration with the framework.
"""
def setUp(self):
self.app = load_test_app(os.path.join(
os.path.dirname(__file__),
'config.py'
))
def tearDown(self):
set_config({}, overwrite=True)
168u
168u
ابزار آزمایشی که همراه با Pecan عرضه می‌شود، یعنی pecan.testing.load_test_app() <#pecan.testing.load_test_app>، می‌تواند مسیر فایلی را که نشان‌دهندهٔ یک فایل پیکربندی Pecan است به عنوان ورودی بپذیرد، و نمونه‌ای از برنامهٔ کاربردی را که در محیط TestApp https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#webtest.app.TestApp بسته‌بندی شده است بازمی‌گرداند.
از این مرحله، گسترش کلاس پایهٔ FunctionalTest و نوشتن آزمون‌هایی که درخواست‌های شبیه‌سازی‌شدهٔ HTTP را ارسال می‌کنند امکان‌پذیر خواهد بود.
0.0
3.5
class TestIndex(FunctionalTest):
def test_index(self):
resp = self.app.get('/')
assert resp.status_int == 200
assert 'Hello, World' in resp.body
168u
168u
همچنین ببینید:
0.0
3.5
برای کسب اطلاعات بیشتر دربارهٔ متدهای در دسترس در یک نمونه از
TestApp https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#webtest.app.TestApp،
مستندات webtest https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#module-webtest را بررسی کنید.
168u
گاهی اوقات ادعاها (assertions) پیرامون بدنهٔ پاسخ درخواست‌های خاص کافی نیست.
برای کمک به بازرسی، برنامه‌های کاربردی Pecan مجموعه‌ای ویژه از
"متغیرهای آزمون" را برای هر شیء TestResponse https://docs.pylonsproject.org/projects/webtest/en/latest/api.html#webtest.response.TestResponse فراهم می‌کنند.
فرض کنید برنامهٔ کاربردی Pecan شما دارای کنترلری باشد که یک
name را به عنوان یک آرگومان اختیاری در URL دریافت می‌کند.
0.0
3.5
# myapp/myapp/controllers/root.py
from pecan import expose
class RootController(object):
@expose('index.html')
def index(self, name='Joe'):
"""A request to / will access this controller"""
return dict(name=name)
168u
168u
و آن نام را در قالب خود (و در نتیجه، در بدنهٔ پاسخ) رندر می‌کند.
0.0
3.5
# myapp/myapp/templates/index.html
Hello, ${name}!
168u
168u
یک آزمون کارکردی (functional test) برای این کنترلر ممکن است ساختاری شبیه به این داشته باشد:
0.0
3.5
class TestIndex(FunctionalTest):
def test_index(self):
resp = self.app.get('/')
assert resp.status_int == 200
assert 'Hello, Joe!' in resp.body
168u
168u
افزون بر webtest.TestResponse.body، Pecan همچنین
webtest.TestResponse.namespace (که نمایانگر فضای نام قالبِ بازگردانده‌شده
از کنترلر است) و webtest.TestResponse.template_name (شامل نام قالب
استفاده‌شده) را ارائه می‌دهد.
0.0
3.5
class TestIndex(FunctionalTest):
def test_index(self):
resp = self.app.get('/')
assert resp.status_int == 200
assert resp.namespace == {'name': 'Joe'}
assert resp.template_name == 'index.html'
168u
168u
به این ترتیب، آزمایش مقدار بازگشتی و قالب رندرشدهٔ هر یک از کنترلرها
به صورت مجزا امکان‌پذیر است.
"تولید و اعتبارسنجی فرم‌ها (GENERATING AND VALIDATING FORMS)"
چارچوب Pecan هیچ ساختار تحمیلی (opinionated) برای کار با
کتابخانه‌های تولید و اعتبارسنجی فرم ارائه نمی‌دهد، اما می‌توان با
حداقل تلاش کتابخانهٔ مورد نظر خود را درون‌ریزی کرد.
این بخش به تشریح بهترین روش‌ها برای ادغام کتابخانهٔ محبوب فرم‌ها،
WTForms http://wtforms.simplecodes.com، در پروژهٔ Pecan شما می‌پردازد..SS تعریف ساختار فرم
کار را با ساخت یک فرم پایه با فیلد اجباری first_name
و فیلد اختیاری last_name آغاز می‌کنیم.
0.0
3.5
from wtforms import Form, TextField, validators
class MyForm(Form):
first_name = TextField(u'First Name', validators=[validators.required()])
last_name = TextField(u'Last Name', validators=[validators.optional()])
class SomeController(object):
pass
168u
168u
رندر کردن فرم در یک قالب
در مرحله بعد، یک کنترل‌کننده اضافه می‌کنیم و یک نمونه از فرم را به قالب انتقال می‌دهیم.
0.0
3.5
from pecan import expose
from wtforms import Form, TextField, validators
class MyForm(Form):
first_name = TextField(u'First Name', validators=[validators.required()])
last_name = TextField(u'Last Name', validators=[validators.optional()])
class SomeController(object):
@expose(template='index.html')
def index(self):
return dict(form=MyForm())
168u
168u
این فایل قالب Mako http://www.makeotemplates.org است:
0.0
3.5
<form method="post" action="/">
<div>
${form.first_name.label}:
${form.first_name}
</div>
<div>
${form.last_name.label}:
${form.last_name}
</div>
<input type="submit" value="submit">
</form>
168u
168u
اعتبارسنجی مقادیر POST
با استفاده از همان تعریف MyForm، در صورت اعتبارسنجی موفق فرم کاربر را
تغییر مسیر می‌دهیم، در غیر این صورت، فرم مجدداً رندر می‌شود.
0.0
3.5
from pecan import expose, request
from wtforms import Form, TextField, validators
class MyForm(Form):
first_name = TextField(u'First Name', validators=[validators.required()])
last_name = TextField(u'Last Name', validators=[validators.optional()])
class SomeController(object):
@expose(template='index.html')
def index(self):
my_form = MyForm(request.POST)
if request.method == 'POST' and my_form.validate():
# save_values()
redirect('/success')
else:
return dict(form=my_form)
168u
پکان (Pecan) هیچ پشتیبانی تحمیلی یا چارچوب‌محوری (opinionated) برای مدیریت نشست‌های کاربر ارائه نمی‌دهد، اما می‌توان با کمترین تلاش، آن را به چارچوب نشست دلخواه خود متصل کرد.
این مقاله، بهترین الگوها (best practices) را برای یکپارچه‌سازی چارچوب محبوب مدیریت نشست، Beaker http://beaker.groovie.org، در پروژه Pecan شما شرح می‌دهد.
"راه‌اندازی مدیریت نشست (Setting up Session Management)"
برای راه‌اندازی مدیریت نشست، چندین رویکرد مختلف وجود دارد. یک رویکرد استفاده از میان‌افزار (middleware) در WSGI است. رویکرد دیگر، استفاده از قلاب‌های پکان (Pecan Hooks) <#hooks> است.
در اینجا نمونه‌ای از پوشش‌دهی برنامه WSGI شما با استفاده از SessionMiddleware https://beaker.readthedocs.io/en/latest/modules/middleware.html#beaker.middleware.SessionMiddleware از چارچوب Beaker در فایل app.py پروژه آورده شده است.
0.0
3.5
from pecan import conf, make_app
from beaker.middleware import SessionMiddleware
from test_project import model
app = make_app(
...
)
app = SessionMiddleware(app, conf.beaker)
168u
168u
و دیکشنری متناظر با آن در فایل پیکربندی شما:
0.0
3.5
beaker = {
'session.key' : 'sessionkey',
'session.type' : 'cookie',
'session.validate_key' : '05d2175d1090e31f42fa36e63b8d2aad',
'__force_dict__' : True
}
168u
168u
"کار با پایگاه‌های داده، تراکنش‌ها و ORMها (WORKING WITH DATABASES, TRANSACTIONS, AND ORM'S)"
پکان (Pecan) هیچ ساختار از پیش تعیین‌شده یا تحمیلی برای کار با پایگاه‌های داده ارائه نمی‌دهد، اما ادغام آن با ORM دلخواه شما بسیار آسان است. این مقاله بهترین شیوه‌ها را برای یکپارچه‌سازی ORM محبوب پایتون، SQLAlchemy http://sqlalchemy.org، در پروژه Pecan شرح می‌دهد.
"init_model و آماده‌سازی مدل (init_model and Preparing Your Model)"
پروژه پیش‌فرض quickstart در Pecan شامل یک دایرکتوری پایه (stub) خالی است تا مدل داده‌ای خود را بنا به نیاز خود در آن پیاده‌سازی کنید.
0.0
3.5
.
└── test_project
├── app.py
├── __init__.py
├── controllers
├── model
│   ├── __init__.py
└── templates
168u
168u
به‌طور پیش‌فرض، این ماژول حاوی یک تابع ویژه به نام init_model() است.
0.0
3.5
from pecan import conf
def init_model():
"""
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
"""
pass
168u
168u
هدف از این تابع، تعیین اتصالات (bindings) بر اساس فایل پیکربندی شما و ایجاد موتورها (engines)، استخرها (pools) و موارد ضروری مطابق با ORM یا جعبه‌ابزار پایگاه داده انتخابی شماست.
علاوه بر این، ماژول model پروژه شما می‌تواند برای تعریف توابعی جهت عملیات متداول پایگاه داده، مانند آغاز تراکنش‌ها، ثبت قطعی (commit) یا بازگردانی (rollback) عملیات و پاک‌سازی نشست (session) استفاده شود. همچنین این مکان در پروژه شما جایی است که تعاریف اشیاء و روابط (relations) باید در آن تعریف شوند. در ادامه، نمونه‌ای از فایل پیکربندی Pecan همراه با اتصالات پایگاه داده آورده شده است.
0.0
3.5
# Server Specific Configurations
server = {
...
}
# Pecan Application Configurations
app = {
...
}
# Bindings and options to pass to SQLAlchemy's ``create_engine``
sqlalchemy = {
'url' : 'mysql://root:@localhost/dbname?charset=utf8&use_unicode=0',
'echo' : False,
'echo_pool' : False,
'pool_recycle' : 3600,
'encoding' : 'utf-8'
}
168u
168u
و نمونه‌ای از پیاده‌سازی پایه‌ای مدل که می‌تواند برای پیکربندی و اتصال از طریق SQLAlchemy به کار رود:
0.0
3.5
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('url')
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()
168u
رویکردهای متعددی برای دربرگرفتن درخواست‌های برنامه شما با فراخوانی توابع مناسب مدل وجود دارد. یک رویکرد، میان‌افزار WSGI است. ما همچنین قلاب‌های پکان (Pecan Hooks) <#hooks> را توصیه می‌کنیم. پکان به همراه TransactionHook <#pecan.hooks.TransactionHook> ارائه می‌شود؛ قلابی که می‌تواند برای محصور کردن درخواست‌ها در تراکنش‌های پایگاه داده برای شما استفاده شود. برای استفاده از آن، کافی است آن را در فایل app.py پروژه خود قرار داده و مجموعه‌ای از توابع مرتبط با اتصال پایگاه داده را به آن ارسال کنید.
0.0
3.5
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
)
]
)
168u
168u
در مثال بالا، در درخواست‌های HTTP از نوع POST، PUT و DELETE، قلاب TransactionHook <#pecan.hooks.TransactionHook> با پیروی از این قوانین به طور خودکار به تراکنش رسیدگی می‌کند:
0.0
1. 3
پیش از تعیین مسیریابی کنترلر، model.start() فراخوانی می‌شود. این تابع باید به موتور SQLAlchemy مناسب متصل شده و یک تراکنش را آغاز کند.
2. 3
کد کنترلر اجرا شده و بازمی‌گردد.
3. 3
اگر کنترلر یا رندر قالب با شکست مواجه شده و یک استثنا صادر کند، model.rollback() فراخوانی شده و استثنای اصلی مجدداً صادر می‌شود (re-raised). این به شما امکان می‌دهد تراکنش پایگاه داده خود را به عقب برگردانید (rollback) تا در صورت وقوع استثناها در کد برنامه، از ثبت تغییرات جلوگیری شود.
4. 3
اگر کنترلر با موفقیت بازگردد، model.commit() و model.clear() فراخوانی می‌شوند.
168u
در عملیات‌های خنثی یا پایا (مانند درخواست‌های HTTP از نوع GET و HEAD)، قلاب TransactionHook <#pecan.hooks.TransactionHook> تراکنش‌ها را طبق قوانین متفاوتی مدیریت می‌کند.
0.0
1. 3
تابع model.start_read_only() فراخوانی می‌شود. این تابع باید به موتور SQLAlchemy شما متصل شود.
2. 3
کد کنترلر اجرا شده و بازمی‌گردد.
3. 3
اگر کنترلر با موفقیت بازگردد، model.clear() فراخوانی می‌شود.
168u
همچنین توجه داشته باشید که یک دکوراتور مفید به نام after_commit() <#pecan.decorators.after_commit> در pecan.decorators -- دکوراتورهای پکان <#pecan-decorators> ارائه شده است.
جداسازی خواندن و نوشتن (Splitting Reads and Writes)
به‌کارگیری راهبرد بالا با استفاده از TransactionHook <#pecan.hooks.TransactionHook>، جداسازی عملیات خواندن و نوشتن پایگاه داده را بر اساس متدهای HTTP بسیار ساده می‌سازد (یعنی درخواست‌های GET/HEAD فقط‌خواندنی هستند و می‌توانند به یک پایگاه داده وابسته (slave) فقط‌خواندنی هدایت شوند، در حالی که درخواست‌های POST/PUT/DELETE نیازمند نوشتن بوده و همیشه به یک پایگاه داده اصلی (master) با امتیازات خواندن/نوشتن متصل می‌شوند). همچنین می‌توان TransactionHook <#pecan.hooks.TransactionHook> را گسترش داد یا پیاده‌سازی قلاب سفارشی خود را برای کنترل دقیق‌تر بر مکان و زمان فراخوانی اتصالات پایگاه داده نوشت.
با فرض یک پیکربندی master/standby، که در آن master درخواست‌های نوشتن را می‌پذیرد و standby تنها می‌تواند درخواست‌های خواندن را دریافت کند، یک پیکربندی Pecan برای sqlalchemy می‌تواند به این صورت باشد:
0.0
3.5
# Server Specific Configurations
server = {
...
}
# Pecan Application Configurations
app = {
...
}
# Master database
sqlalchemy_w = {
'url': 'postgresql+psycopg2://root:@master_host/dbname',
'pool_recycle': 3600,
'encoding': 'utf-8'
}
# Read Only database
sqlalchemy_ro = {
'url': 'postgresql+psycopg2://root:@standby_host/dbname',
'pool_recycle': 3600,
'encoding': 'utf-8'
}
168u
168u
با توجه به تنظیمات پیکربندی منحصربه‌فرد برای هر پایگاه داده، اتصالات باید نسبت به آنچه که quickstart پیش‌فرض Pecan ارائه می‌دهد تغییر کند (بخش init_model و Preparing Your Model را ببینید) تا پاسخگوی هر دو نوع درخواست‌های نوشتن و فقط‌خواندنی باشد:
0.0
3.5
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('url')
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()
168u
در این مقاله یک برنامهٔ Pecan را به‌گونه‌ای پیکربندی می‌کنیم که هر زمان سرور وضعیت 404 Page Not Found را بازگرداند، یک صفحهٔ خطای سفارشی نمایش داده شود.
این مقاله فرض می‌کند که شما پیش‌تر یک برنامهٔ آزمایشی را طبق توضیحات «ایجاد نخستین برنامهٔ Pecan» <#quick-start> ساخته‌اید.
نکته:
0.0
3.5
اگرچه این مثال بر روی پیام HTTP 404 تمرکز دارد، اما همین سازوکار را می‌توان برای تعریف اقدامات سفارشی برای هر یک از کدهای وضعیت پاسخ HTTP در دامنهٔ ۴۰۰ و ۵۰۰ نیز به‌کار برد. توصیه می‌شود از این قابلیت با دقت و هوشمندی استفاده کنید.
168u
168u
"نمای کلی (Overview)"
Pecan سفارشی‌سازی اسناد خطا را در دو مرحلهٔ ساده امکان‌پذیر می‌کند:
0.0
3.5
0.0
• 2
پیکربندی مسیریابی (Routing) پیام‌های وضعیت HTTP که می‌خواهید در config.py برنامه‌تان مدیریت شوند
• 2
نوشتن کنترلرهای سفارشی (Custom Controllers) برای مدیریت پیام‌های وضعیتی که پیکربندی کرده‌اید
168u
168u
168u
"پیکربندی مسیریابی (Configure Routing)"
بیایید برنامهٔ test_project خود را طوری پیکربندی کنیم که پیام‌های HTTP 404 Page Not Found را به یک کنترلر سفارشی هدایت کند.
ابتدا test_project/config.py را به‌روزرسانی می‌کنیم تا یک error-handler جدید مشخص شود.
0.0
3.5
# Pecan Application Configurations
app = {
'root' : 'test_project.controllers.root.RootController',
'modules' : ['test_project'],
'static_root' : '%(confdir)s/public',
'template_path' : '%(confdir)s/test_project/templates',
'reload' : True,
'debug' : True,
# modify the 'errors' key to direct HTTP status codes to a custom
# controller
'errors' : {
#404 : '/error/404',
404 : '/notfound',
'__force_dict__' : True
}
}
168u
168u
اکنون Pecan به‌جای صفحهٔ خطای پیش‌فرض، پیام‌های 404 را به متد کنترلر notfound هدایت خواهد کرد.
"نوشتن کنترلرهای سفارشی (Write Custom Controllers)"
ساده‌ترین راه برای پیاده‌سازی گردانندهٔ خطا این است که آن را به کلاس test_project.root.RootController اضافه کنید (معمولاً در test_project/controllers/root.py).
0.0
3.5
from pecan import expose
from webob.exc import status_map
class RootController(object):
@expose(generic=True, template='index.html')
def index(self):
return dict()
@index.when(method='POST')
def index_post(self, q):
redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q)
## custom handling of '404 Page Not Found' messages
@expose('error.html')
def notfound(self):
return dict(status=404, message="test_project does not have this page")
@expose('error.html')
def error(self, status):
try:
status = int(status)
except ValueError:
status = 0
message = getattr(status_map.get(status), 'explanation', '')
return dict(status=status, message=message)
168u
168u
و تمام!
دقت کنید تنها قطعه کدی که به RootController خود اضافه کردیم این بود:
0.0
3.5
## custom handling of '404 Page Not Found' messages
@expose('error.html')
def notfound(self):
return dict(status=404, message="test_project does not have this page")
168u
168u
ما صرفاً کنترلر notfound را با استفاده از expose() <#pecan.decorators.expose> به قالب error.html متصل کردیم (قالبی که هنگام ساخت test_project به‌راحتی برای ما ایجاد شده و در مسیر test_project/templates/ قرار گرفته بود). همانند هر کنترلر دیگر در Pecan، دیکشنری‌ای از متغیرها را برمی‌گردانیم تا توسط رندرکنندهٔ قالب جای‌گذاری شوند.
اکنون می‌توانیم قالب خطا را ویرایش کرده یا یک قالب کاملاً تازه بنویسیم تا صفحهٔ وضعیت خطای 404 در test_project را به هر شکلی که می‌خواهیم زیبا و مرتب طراحی کنیم..SH "برنامه نمونه: پردازش ساده فرم‌ها (EXAMPLE APPLICATION: SIMPLE FORMS PROCESSING)"
این راهنما شما را در ساخت یک برنامه وب ساده Pecan که پردازش ساده‌ای روی فرم‌ها انجام می‌دهد، راهنمایی می‌کند.
"راه‌اندازی پروژه (Project Setup)"
ابتدا، باید Pecan را نصب کنید:
0.0
3.5
$ pip install pecan
168u
168u
از پشتیبانی قالب پایه‌ای Pecan برای آغاز یک پروژه جدید استفاده کنید:
0.0
3.5
$ pecan create mywebsite
$ cd mywebsite
168u
168u
پروژه جدید را در حالت توسعه (development mode) نصب کنید:
0.0
3.5
$ python setup.py develop
168u
168u
با آماده شدن پروژه، به پوشه templates بروید و فایل index.html را ویرایش کنید. آن را طوری تغییر دهید که شبیه به این باشد:
0.0
3.5
<%inherit file="layout.html" />
<%def name="title()">
Welcome to Pecan!
</%def>
<header>
<h1><img src="/images/logo.png" /></h1>
</header>
<div id="content">
<form method="POST" action="/">
<fieldset>
<p>Enter a message: <input name="message" /></p>
<p>Enter your first name: <input name="first_name" /></p>
<input type="submit" value="Submit" />
</fieldset>
</form>
% if not form_post_data is UNDEFINED:
<p>${form_post_data['first_name']}, your message is: ${form_post_data['message']}</p>
% endif
</div>
168u
168u
چه کاری انجام دادیم؟
0.0
1. 3
محتویات برچسب form را طوری تغییر دادیم که شامل دو برچسب input باشد. نام اولی message و نام دومی first_name است.
2. 3
بررسی‌ای اضافه کردیم تا در صورت تعریف نشدن form_post_data، پیام یا عبارت نمایش داده نشود.
3. 3
کدی برای نمایش پیام حاصل از عملیات POST کاربر اضافه کردیم.
168u
اکنون به پوشه controllers بروید و فایل root.py را ویرایش کنید. درون کلاس RootController دو تابع وجود خواهد داشت که هنگام درخواست مرورگر وب شما به نقطه پایانی '/'، فایل index.html را نمایش می‌دهند. اگر کاربر مقداری داده در کادر متنی وارد کرده و روی دکمه ارسال کلیک کند، پیام شخصی‌سازی‌شده به او نمایش داده خواهد شد.
فایل root.py را تغییر دهید تا به این صورت باشد:
0.0
3.5
from pecan import expose
class RootController(object):
@expose(generic=True, template='index.html')
def index(self):
return dict()
@index.when(method='POST', template='index.html')
def index_post(self, **kwargs):
return dict(form_post_data=kwargs)
168u
168u
چه کاری انجام دادیم؟
0.0
1. 3
تابع index را برای رندر کردن صفحه وب اولیه index.html تغییر دادیم.
2. 3
تابع index_post را تغییر دادیم تا داده‌های ارسال‌شده را از طریق آرگومان‌های کلیدواژه‌ای بازگرداند.
168u
برنامه را اجرا کنید:
0.0
3.5
$ pecan serve config.py
168u
168u
یک مرورگر وب باز کنید: http://127.0.0.1:8080.SS افزودن اعتبارسنجی
پیامی را در کادر متنی به همراه نامی در کادر متنی دوم وارد کرده و دکمهٔ submit را فشار دهید. پس از ارسال مجدد صفحه (post back)، باید پیامی شخصی‌سازی‌شده را مشاهده کنید که زیر فرم نمایش داده می‌شود.
یک مشکلی که ممکن است متوجه آن شده باشید این است که اگر پیام یا نامی را وارد نکنید، صرفاً هیچ مقداری برای آن بخش از پیام نمایش داده نمی‌شود. بیایید کمی اعتبارسنجی اضافه کنیم تا اطمینان حاصل شود که پیام و نام واقعاً وارد شده‌اند. برای این کار، از WTForms http://wtforms.simplecodes.com استفاده خواهیم کرد، اما می‌توانید برای پروژه‌های خود هر چیز دیگری را جایگزین کنید.
پشتیبانی از کتابخانهٔ WTForms http://wtforms.simplecodes.com را اضافه کنید:
0.0
3.5
$ pip install wtforms
168u
168u
نکته:
0.0
3.5
به یاد داشته باشید که Pecan در زمینهٔ انتخاب یک کتابخانهٔ خاص هنگام کار با تولید فرم، اعتبارسنجی و غیره تحمیل‌گر نیست. کتابخانه‌های مورد نظر خود را انتخاب کرده و آن‌ها را با Pecan یکپارچه کنید. این تنها یک روش برای انجام این کار است، روش‌های بسیار دیگری نیز وجود دارد؛ بنابراین با خیالی آسوده در پروژه‌های خود هر طور که می‌خواهید آن را پیاده‌سازی کنید.
168u
168u
به فایل root.py بازگردید و آن را بدین شکل ویرایش کنید:
0.0
3.5
from pecan import expose, request
from wtforms import Form, TextField, validators
class PersonalizedMessageForm(Form):
message = TextField(u'Enter a message',
validators=[validators.required()])
first_name = TextField(u'Enter your first name',
validators=[validators.required()])
class RootController(object):
@expose(generic=True, template='index.html')
def index(self):
return dict(form=PersonalizedMessageForm())
@index.when(method='POST', template='index.html')
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)
168u
168u
چه کاری انجام دادیم؟
0.0
1. 3
کلاس PersonalizedMessageForm را با دو فیلد متنی و یک اعتبارسنج فیلد اجباری برای هر کدام اضافه کردیم
2. 3
تابع index را تغییر دادیم تا یک نمونهٔ جدید از کلاس PersonalizedMessageForm ایجاد کرده و آن را بازگرداند
3. 3
تابع index_post را تغییر دادیم تا داده‌های ارسال‌شده (POST) را گردآوری و اعتبارسنجی کند. اگر معتبر باشد، داده‌های بازگشتی را برای نمایش در صفحهٔ وب تنظیم کند. در غیر این صورت، فرمی را ارسال کند که حاوی داده‌ها به‌علاوهٔ پیام(های) خطا خواهد بود
168u
فایل index.html را بدین صورت ویرایش کنید:
0.0
3.5
<%inherit file="layout.html" />
## provide definitions for blocks we want to redefine
<%def name="title()">
Welcome to Pecan!
</%def>
<header>
<h1><img src="/images/logo.png" /></h1>
</header>
<div id="content">
% if not form:
<p>${first_name}, your message is: ${message}</p>
% else:
<form method="POST" action="/">
<div>
${form.message.label}:
${form.message}
% if form.message.errors:
<strong>${form.message.errors[0]}</strong>
% endif
</div>
<div>
${form.first_name.label}:
${form.first_name}
% if form.first_name.errors:
<strong>${form.first_name.errors[0]}</strong>
% endif
</div>
<input type="submit" value="Submit">
</form>
% endif
</div>
168u
168u
نکته:
0.0
3.5
به یاد داشته باشید که هنگام استفاده از کتابخانهٔ WTForms http://wtforms.simplecodes.com می‌توانید پیام‌های خطا و موارد بیشتر را سفارشی‌سازی کنید. همچنین شما قوانین اعتبارسنجی متعددی دارید، بنابراین حتماً تمام خطاها را دریافت کنید؛ این امر بدین معنی است که بر خلاف مثال سادهٔ بالا که تنها نخستین خطای موجود در لیست را دریافت می‌کند، به یک حلقه نیاز خواهید داشت. برای اطلاعات بیشتر مستندات http://wtforms.simplecodes.com را ببینید.
168u
168u
برنامه را اجرا کنید:
0.0
3.5
$ pecan serve config.py
168u
168u
یک مرورگر وب را باز کنید: http://127.0.0.1:8080
فرم را با داده‌های معتبر و همچنین بدون وارد کردن هیچ داده‌ای آزمایش کنید..SH "برنامه نمونه: AJAX ساده (EXAMPLE APPLICATION: SIMPLE AJAX)"
این راهنما شما را در ساخت یک برنامه وب ساده با Pecan که از AJAX برای واکشی داده‌های JSON از سرور استفاده می‌کند، راهنمایی خواهد کرد.
"راه‌اندازی پروژه (Project Setup)"
ابتدا باید Pecan را نصب کنید:
0.0
3.5
$ pip install pecan
168u
168u
از پشتیبانی قالب پایه‌ای Pecan برای آغاز یک پروژه جدید استفاده کنید:
0.0
3.5
$ pecan create myajax
$ cd myajax
168u
168u
پروژه جدید را در حالت توسعه نصب کنید:
0.0
3.5
$ python setup.py develop
168u
168u
"افزودن پشتیبانی از AJAX در جاوااسکریپت (Adding JavaScript AJAX Support)"
برای این پروژه باید پشتیبانی از jQuery http://jquery.com را اضافه کنیم. برای افزودن jQuery به پوشه templates رفته و فایل layout.html را ویرایش کنید.
افزودن پشتیبانی jQuery آسان است؛ در واقع تنها به یک خط کد نیاز داریم:
0.0
3.5
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
168u
168u
کد جاوااسکریپت برای برقراری فراخوانی AJAX کمی عمیق‌تر و مفصل‌تر است، اما اگر تاکنون با jQuery کار کرده باشید، برایتان ناآشنا نخواهد بود.
فایل layout.html به این شکل خواهد بود:
0.0
3.5
<html>
<head>
<title>${self.title()}</title>
${self.style()}
${self.javascript()}
</head>
<body>
${self.body()}
</body>
</html>
<%def name="title()">
Default Title
</%def>
<%def name="style()">
<link rel="stylesheet" type="text/css" media="screen" href="/css/style.css" />
</%def>
<%def name="javascript()">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script language="text/javascript" src="/javascript/shared.js"></script>
<script>
function onSuccess(data, status, jqXHR) {
// Use a template or something here instead
// Just for demo purposes
$("#result").html("<div>" +
"<p></p><strong>Project Name: " + data.name + "</strong></p>" +
"<p>Project License: " + data.licensing + "</p>" +
"<p><a href='" + data.repository + "'>Project Repository: " + data.repository + "</a></p>" +
"<p><a href='" + data.documentation + "'>Project Documentation: " + data.documentation + "</a></p>" +
"</div>");
}
function onError(jqXHR, textStatus, errorThrown) {
alert('HTTP Status Code: ' + jqXHR.status + ', ' + errorThrown);
}
$(document).ready(function () {
$("#submit").click(function () {
$.ajax({
url: "/projects/",
data: "id=" + $("#projects").val(),
contentType: 'application/json',
dataType: 'json',
success: onSuccess,
error: onError
});
return false;
});
});
</script>
</%def>
168u
168u
دقیقاً چه کاری انجام دادیم؟
0.0
1. 3
در بخش head، پشتیبانی از jQuery را از طریق CDN گوگل https://developers.google.com/speed/libraries/devguide اضافه کردیم
2. 3
کد جاوااسکریپت را برای برقراری فراخوانی AJAX به سرور از طریق HTTP GET با ارسال id پروژه جهت واکشی اطلاعات بیشتر اضافه کردیم
3. 3
پس از فعال شدن رویداد onSuccess با بازگشت داده‌ها، آن را دریافت کرده و در صفحه وب زیر بخش کنترل‌ها نمایش می‌دهیم
در مرحله بعد، بیایید فایل index.html را ویرایش کنیم. برای پشتیبانی از تعامل AJAX بین صفحه وب و Pecan، کدهای HTML را اضافه خواهیم کرد. فایل index.html را تغییر دهید تا به این صورت باشد:
0.0
3.5
<%inherit file="layout.html" />
<%def name="title()">
Welcome to Pecan!
</%def>
<header>
<h1><img src="/images/logo.png"/></h1>
</header>
<div id="content">
<p>Select a project to get details:</p>
<select id="projects">
<option value="0">OpenStack</option>
<option value="1">Pecan</option>
<option value="2">Stevedore</option>
</select>
<button id="submit" type="submit">Submit</button>
<div id="result"></div>
</div>
168u
168u
دقیقاً چه کاری انجام دادیم؟
0.0
1. 3
یک کنترل کشویی و یک دکمه ثبت (submit) برای تعامل کاربر اضافه کردیم. کاربران می‌توانند یک پروژه متن‌باز را انتخاب کرده و جزئیات بیشتری درباره آن دریافت کنند.
168u
ساخت مدل با پشتیبانی از JSON
کارهای مربوط به HTML و JavaScript اکنون به پایان رسیده است. در این مرحله می‌توانیم مدلی را درون پوشه model به پروژه خود اضافه کنیم. فایلی به نام projects.py در آنجا ایجاد کرده و موارد زیر را به آن اضافه کنید:
0.0
3.5
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
)
168u
168u
دقیقاً چه کاری انجام دادیم؟
0.0
1. 3
مدلی به نام Project ایجاد کردیم که می‌تواند داده‌های مختص پروژه را نگه‌داری کند.
2. 3
یک متد __json__ اضافه کردیم تا یک نمونه از Project class به‌راحتی به‌صورت JSON نمایش داده شود. کنترلری که به‌زودی خواهیم ساخت از این قابلیت JSON استفاده خواهد کرد.
168u
نکته:
0.0
3.5
راه‌های دیگری نیز برای بازگرداندن JSON در Pecan وجود دارد؛ برای اطلاعات بیشتر بخش سریال‌سازی JSON <#jsonify> را بررسی کنید.
168u
168u
کار با کنترلرها
نیازی نیست تغییر عمده‌ای در فایل root.py در پوشه controllers اعمال کنیم، جز افزودن پشتیبانی از یک کنترلر جدید که آن را ProjectsController می‌نامیم. فایل root.py را به این شکل تغییر دهید:
0.0
3.5
from pecan import expose
from myajax.controllers.projects import ProjectsController
class RootController(object):
projects = ProjectsController()
@expose(generic=True, template='index.html')
def index(self):
return dict()
168u
168u
دقیقاً چه کاری انجام دادیم؟
0.0
1. 3
برخی از کدهای قالبی (boilerplate) اولیه را چون از آن‌ها استفاده نمی‌کنیم حذف کردیم.
2. 3
پشتیبانی از ProjectsController آینده را اضافه کردیم.
168u
بخش نهایی، افزودن فایلی به نام projects.py به پوشه controllers است. این فایل جدید میزبان ProjectsController خواهد بود که به درخواست‌های ورودی AJAX GET (در مورد ما) گوش می‌دهد و پاسخ JSON مناسب را بازمی‌گرداند.
کد زیر را به فایل projects.py اضافه کنید:
0.0
3.5
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='OpenStack',
licensing='Apache 2',
repository='http://github.com/openstack',
documentation='http://docs.openstack.org'),
Project(name='Pecan',
licensing='BSD',
repository='http://github.com/pecan/pecan',
documentation='https://pecan.readthedocs.io'),
Project(name='stevedore',
licensing='Apache 2',
repository='http://github.com/dreamhost/pecan',
documentation='http://docs.openstack.org/developer/stevedore/')
]
@expose('json', content_type='application/json')
def get(self, id):
response.status = 200
return self.projects[int(id)]
168u
168u
دقیقاً چه کاری انجام دادیم؟
0.0
1. 3
یک متغیر کلاس محلی به نام projects ایجاد کردیم که مشخصات سه پروژه متن‌باز را نگه‌داری می‌کند. به‌طور معمول این نوع داده‌ها احتمالاً در یک پایگاه‌داده قرار می‌گیرند.
2. 3
کدی را برای کنترلر جدید اضافه کردیم که به نقطه پایانی (endpoint) projects گوش می‌دهد و بر اساس id ارائه‌شده از صفحه وب، JSON را بازمی‌گرداند.
168u
اجرای برنامه:
0.0
3.5
$ pecan serve config.py
168u
168u
مرورگر وب را باز کنید: http://127.0.0.1:8080
چیز دیگری هم وجود دارد که می‌توانیم اضافه کنیم. اگر یک id ارسال شود که پیدا نشود چه؟ در این حالت باید یک خطای مناسب HTTP 404 فرستاده شود. برای این منظور، ProjectsController را تغییر خواهیم داد.
تابع get را تغییر دهید تا به این صورت باشد:
0.0
3.5
@expose('json', content_type='application/json')
def get(self, id):
try:
response.status = 200
return self.projects[int(id)]
except (IndexError, ValueError) as ex:
abort(404)
168u
برای آزمایش این مورد، نیاز داریم یک id نامعتبر را به ProjectsController ارسال کنیم. این کار را می‌توان با رفتن به فایل index.html و افزودن یک برچسب option اضافی با مقدار id خارج از بازه ۰-۲ انجام داد.
0.0
3.5
<p>Select a project to get details:</p>
<select id="projects">
<option value="0">OpenStack</option>
<option value="1">Pecan</option>
<option value="2">Stevedore</option>
<option value="3">WSME</option>
</select>
168u
168u
می‌توانید ببینید که ما WSME را با مقدار ۳ به فهرست افزوده‌ایم.
اجرای برنامه:
0.0
3.5
$ pecan serve config.py
168u
168u
یک مرورگر وب باز کنید: http://127.0.0.1:8080
گزینه WSME را از فهرست انتخاب کنید. باید باز شدن جعبه گفتگوی خطا را مشاهده کنید.
کد منبع Pecan با استفاده از docstringها و کامنت‌های پایتون به‌خوبی مستندسازی شده است. علاوه بر این، ما مستندات API را از docstringها در اینجا تولید کرده‌ایم:
"PECAN.CORE -- هسته PECAN (PECAN CORE)"
ماژول pecan.core ماژول پایه برای ایجاد و گسترش Pecan است. منطق اصلی برای پردازش درخواست‌ها و پاسخ‌های HTTP در اینجا قرار دارد.
0.0
class pecan.core.Pecan(*args, **kw)
کلاس‌های پایه: PecanBase
شیء برنامه Pecan. معمولاً به‌جای ایجاد دستی، با استفاده از pecan.make_app ایجاد می‌شود.
یک نمونه از برنامه Pecan ایجاد می‌کند که یک برنامه WSGI است.
7.0
پارامترها (Parameters)
7.0
• 2
root -- رشته‌ای نشان‌دهنده یک شیء کنترل‌کننده ریشه (مانند "myapp.controller.root.RootController")
• 2
default_renderer -- موتور رندر قالب پیش‌فرض برای استفاده. پیش‌فرض mako است.
• 2
template_path -- یک مسیر نسبی در فایل‌سیستم (از ریشه پروژه) که فایل‌های قالب در آن قرار دارند. پیش‌فرض 'templates' است.
• 2
hooks -- یک شیء قابل فراخوانی که فهرستی از pecan.hooks.PecanHook <#pecan.hooks.PecanHook> را بازمی‌گرداند.
• 2
custom_renderers -- اشیاء رندرکننده سفارشی، به‌صورت یک دیکشنری با کلید نام موتور.
• 2
extra_template_vars -- هرگونه متغیر برای تزریق خودکار به فضای نام (namespace) قالب.
• 2
force_canonical -- یک مقدار بولی که مشخص می‌کند آیا این پروژه باید به نشانی‌های وب متعارف (canonical URLs) نیاز داشته باشد یا خیر.
• 2
guess_content_type_from_ext -- یک مقدار بولی که مشخص می‌کند آیا این پروژه باید از پسوند موجود در نشانی وب برای حدس زدن نوع محتوای بازگشتی استفاده کند یا خیر.
• 2
use_context_locals -- در صورت True بودن، pecan.request و pecan.response به‌صورت ارجاع‌های محلی نخ (thread-local) در دسترس خواهند بود.
• 2
request_cls -- می‌تواند برای مشخص کردن یک شیء سفارشی pecan.request استفاده شود. پیش‌فرض pecan.Request است.
• 2
response_cls -- می‌تواند برای مشخص کردن یک شیء سفارشی pecan.response استفاده شود. پیش‌فرض pecan.Response است.
168u
168u
7.0
find_controller(_state)
گرداننده اصلی درخواست برای برنامه‌های Pecan.
168u
7.0
handle_hooks(hooks, *args, **kw)
قلاب‌های (hooks) نوع مشخص‌شده را پردازش می‌کند.
7.0
پارامترها (Parameters)
7.0
• 2
hook_type -- نوع قلاب، شامل before، after، on_error و on_route.
• 2
*args --
آرگومان‌هایی برای ارسال به قلاب‌ها.
168u
168u
168u
168u
0.0
class pecan.core.Request(environ, charset=None, unicode_errors=None, decode_param_names=None, **kw)
کلاس‌های پایه: Request
168u
0.0
class pecan.core.Response(body=None, status=None, headerlist=None, app_iter=None, content_type=None, conditional_response=None, charset=<object object>, **kw)
کلاس‌های پایه: Response
168u
0.0
pecan.core.abort(status_code, detail='', headers=None, comment=None, **kw)
یک کد وضعیت HTTP را مطابق با موارد مشخص‌شده برمی‌انگیزد (Raise). برای بازگرداندن کدهای وضعیتی مانند 401 Unauthorized یا 403 Forbidden کاربرد دارد.
7.0
پارامترها (Parameters)
7.0
• 2
status_code -- کد وضعیت HTTP به‌صورت یک عدد صحیح.
• 2
detail -- پیامی برای ارسال همراه با آن، به‌صورت یک رشته.
• 2
headers -- یک دیکشنری از سرآیندها برای ارسال همراه با پاسخ.
• 2
comment -- یک توضیح (کامنت) برای گنجاندن در پاسخ.
168u
168u
168u
0.0
pecan.core.load_app(config, **kwargs)
برای بارگذاری یک برنامه Pecan و محیط آن بر اساس پیکربندی ارائه‌شده استفاده می‌شود.
7.0
پارامترها (Parameters)
config -- می‌تواند یک دیکشنری حاوی پیکربندی یا رشته‌ای باشد که نام فایل پیکربندی (نسبی) را نشان می‌دهد
168u
یک شیء pecan.Pecan بازمی‌گرداند
168u
0.0
pecan.core.override_template(template, content_type=None)
درون یک کنترل‌کننده فراخوانی می‌شود تا قالبی را که در پاسخ شما استفاده می‌شود بازنویسی (override) کند.
7.0
پارامترها (Parameters)
7.0
• 2
template -- یک مسیر معتبر به یک فایل قالب، دقیقاً همان‌گونه که در یک @expose مشخص می‌کنید.
• 2
content_type -- یک نوع معتبر MIME برای استفاده در response.func_closure
168u
168u
168u
0.0
pecan.core.redirect(location=None, internal=False, code=None, headers=None, add_slash=False, request=None)
یک تغییر مسیر (redirect)، چه داخلی و چه خارجی انجام می‌دهد. تغییر مسیر داخلی ریدایرکت را در سمت سرور انجام می‌دهد، در حالی که تغییر مسیر خارجی از کد وضعیت HTTP 302 استفاده می‌کند.
7.0.TP
پارامترها (Parameters)
7.0
• 2
location -- نشانی HTTP برای تغییر مسیر به آن.
• 2
internal -- یک مقدار بولی که مشخص می‌کند آیا تغییر مسیر باید داخلی باشد یا خیر.
• 2
code -- کد وضعیت HTTP برای استفاده در تغییر مسیر. پیش‌فرض 302 است.
• 2
headers -- هرگونه هدر HTTP برای ارسال همراه با پاسخ، در قالب یک دیکشنری.
• 2
request -- نمونه pecan.Request مورد استفاده.
168u
168u
168u
0.0
pecan.core.render(template, namespace, app=None)
قالب مشخص‌شده را با استفاده از چارچوب رندر Pecan و فضای‌نام قالب مشخص‌شده در قالب یک دیکشنری رندر می‌کند. در کنترلری کاربرد دارد که هیچ قالبی در @expose برای آن مشخص نشده است.
7.0
پارامترها (Parameters)
7.0
• 2
template -- مسیر قالب شما، همان‌طور که در @expose مشخص می‌کنید.
• 2
namespace -- فضای‌نام مورد استفاده برای رندر قالب، در قالب یک دیکشنری.
• 2
app -- نمونه pecan.Pecan مورد استفاده
168u
168u
168u
PECAN.COMMANDS -- دستورهای PECAN (PECAN COMMANDS)
ماژول pecan.commands اسکریپت کنسول pecan را پیاده‌سازی می‌کند که برای ارائه ابزارهای خط فرمان (به‌عنوان مثال) pecan serve و pecan shell به کار می‌رود.
0.0
class pecan.commands.base.BaseCommand
کلاس‌های پایه: BaseCommandParent
یک رابط پایه برای دستورهای Pecan.
می‌تواند برای پشتیبانی از افزونه‌های دستور pecan در پروژه‌های مجزای Pecan گسترش داده شود، مانند:
$ pecan my-custom-command config.py
7.0
3.5
# myapp/myapp/custom_command.py
class CustomCommand(pecan.commands.base.BaseCommand):
'''
(First) line of the docstring is used to summarize the command.
'''
arguments = ({
'name': '--extra_arg',
'help': 'an extra command line argument',
'optional': True
})
def run(self, args):
super(SomeCommand, self).run(args)
if args.extra_arg:
pass
168u
168u
168u
0.0
class pecan.commands.base.BaseCommandParent
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
یک رابط پایه برای دستورهای Pecan.
می‌تواند برای پشتیبانی از افزونه‌های دستور pecan در پروژه‌های مجزای Pecan گسترش داده شود، مانند:
$ pecan my-custom-command config.py
7.0
3.5
# myapp/myapp/custom_command.py
class CustomCommand(pecan.commands.base.BaseCommand):
'''
(First) line of the docstring is used to summarize the command.
'''
arguments = ({
'name': '--extra_arg',
'help': 'an extra command line argument',
'optional': True
})
def run(self, args):
super(SomeCommand, self).run(args)
if args.extra_arg:
pass
168u
168u
7.0
run(args)
باید توسط زیرکلاس‌ها پیاده‌سازی شود.
168u
168u
0.0
class pecan.commands.base.CommandManager
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
برای یافتن نقاط ورود (entry points) pecan.command استفاده می‌شود.
168u
0.0
class pecan.commands.base.CommandRunner
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
درخواست‌های اجرای دستور pecan را اعزام (dispatch) می‌کند.
168u
0.0
class pecan.commands.base.HelpfulArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=<class 'argparse.HelpFormatter'>, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True, allow_abbrev=True, exit_on_error=True, *, suggest_on_error=False, color=True)
کلاس‌های پایه: ArgumentParser https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser
7.0
error(message: string)
پیام نحوه استفاده را به همراه پیام مربوطه در stderr چاپ کرده و خارج می‌شود.
اگر این مورد را در یک زیرکلاس بازنویسی (override) کنید، نباید مقداری برگرداند -- بلکه باید یا خارج شود یا یک استثنا (exception) صادر کند.
168u
دستور Serve برای Pecan.
0.0
class pecan.commands.serve.PecanWSGIRequestHandler(*args, **kwargs)
کلاس‌های پایه: WSGIRequestHandler https://docs.python.org/3/library/wsgiref.html#wsgiref.simple_server.WSGIRequestHandler، object https://docs.python.org/3/library/functions.html#object
یک کلاس مدیریت درخواست wsgiref که امکان خروجی لاگ واقعی را بسته به پیکربندی برنامه فراهم می‌کند.
7.0
log_message(format, *args)
متد log_message را از سرور wsgiref بازنویسی می‌کند تا ثبت لاگ عادی با هر پیکربندی تنظیم‌شده در برنامه به درستی کار کند.
سطوح لاگ از کد وضعیت HTTP استنتاج می‌شوند؛ کدهای 4XX به عنوان هشدار (warning)، کدهای 5XX به عنوان خطا (error) و سایر موارد در سطح INFO در نظر گرفته می‌شوند.
168u
168u
0.0
class pecan.commands.serve.ServeCommand
کلاس‌های پایه: BaseCommand
یک برنامه وب Pecan را میزبانی و ارائه می‌کند.
این دستور یک برنامه وب Pecan را با استفاده از فایل پیکربندی ارائه‌شده برای سرور و برنامه اجرا می‌کند.
7.0
run(args)
باید توسط زیرکلاس‌ها پیاده‌سازی شود.
168u
7.0
serve(app, conf)
رویکردی بسیار ساده برای یک سرور WSGI.
168u
168u
0.0
pecan.commands.serve.gunicorn_run()
دستور gunicorn_pecan برای راه‌اندازی برنامه‌های pecan
168u
pecan.commands.shell -- پوسته تعاملی Pecan
دستور Shell برای Pecan.
0.0
class pecan.commands.shell.BPythonShell
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
باز کردن یک پوسته تعاملی bpython همراه با برنامه بارگذاری‌شده Pecan.
7.0
classmethod invoke(ns, banner)
7.0
پارامترها
7.0
• 2
ns -- فضای نام محلی
• 2
banner -- بنر آغازین پوسته تعاملی
168u
168u
تعبیه یک پوسته تعاملی bpython.
168u
168u
0.0
class pecan.commands.shell.IPythonShell
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
باز کردن یک پوسته تعاملی ipython همراه با برنامه بارگذاری‌شده Pecan.
7.0
classmethod invoke(ns, banner)
7.0
پارامترها
7.0
• 2
ns -- فضای نام محلی
• 2
banner -- بنر آغازین پوسته تعاملی
168u
168u
تعبیه یک پوسته تعاملی ipython.
ابتدا رابط InteractiveShellEmbed را امتحان می‌کند و برای نسخه‌های قدیمی‌تر IPython به IPShellEmbed بازمی‌گردد.
168u
168u
0.0
class pecan.commands.shell.NativePythonShell
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
باز کردن یک پوسته تعاملی پایتون همراه با برنامه بارگذاری‌شده Pecan.
7.0
classmethod invoke(ns, banner)
7.0
پارامترها
7.0
• 2
ns -- فضای نام محلی
• 2
banner -- بنر آغازین پوسته تعاملی
168u
168u
تعبیه یک پوسته تعاملی بومی پایتون.
168u
168u
0.0
class pecan.commands.shell.ShellCommand
کلاس‌های پایه: BaseCommand
باز کردن یک پوسته تعاملی همراه با برنامه بارگذاری‌شده Pecan.
تلاش برای فراخوانی نوع پوسته پایتون مشخص‌شده (ipython، bpython و غیره). در صورتی که نوع درخواستی نصب نشده باشد، به پوسته بومی پایتون بازمی‌گردد.
7.0
invoke_shell(locs, banner)
نوع مناسب پوسته پایتون را فراخوانی می‌کند.
در صورتی که نوع درخواستی (ipython، bpython و غیره) نصب نشده باشد، به پوسته بومی پایتون بازمی‌گردد.
168u
7.0
load_model(config)
بارگذاری ماژول افزونه مدل
168u
7.0
run(args)
بارگذاری برنامه pecan، آماده‌سازی متغیرهای محلی (locals)، تنظیم بنر و فراخوانی پوسته پایتون.
168u
ماژول pecan.configuration پیاده‌سازی یک موتور پیکربندی مبتنی بر پایتون را برای برنامه‌های Pecan فراهم می‌کند.
0.0
class pecan.configuration.Config(conf_dict=None, filename='')
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
کلاس پایه برای پیکربندی‌های Pecan.
ایجاد یک شیء پیکربندی Pecan از یک دیکشنری یا نام فایل.
7.0
پارامترها
7.0
• 2
conf_dict -- یک دیکشنری پایتون برای استفاده در پیکربندی.
• 2
filename -- نام فایل مورد استفاده برای پیکربندی.
168u
168u
7.0
to_dict(prefix=None)
شیء Config را به صورت بازگشتی به یک دیکشنری معتبر تبدیل می‌کند.
7.0
پارامترها
prefix -- یک رشته برای پیشوند زدن اختیاری به تمام کلیدها در دیکشنری بازگردانده‌شده.
168u
168u
7.0
update(conf_dict)
این پیکربندی را با یک دیکشنری به‌روزرسانی می‌کند.
7.0
پارامترها
conf_dict -- یک دیکشنری پایتون برای به‌روزرسانی این پیکربندی.
168u
168u
168u
0.0
class pecan.configuration.ConfigDict
کلاس‌های پایه: dict https://docs.python.org/3/library/stdtypes.html#dict
168u
0.0
pecan.configuration.conf_from_dict(conf_dict)
یک دیکشنری پیکربندی از یک دیکشنری می‌سازد.
7.0
پارامترها
conf_dict -- دیکشنری پیکربندی.
168u
168u
0.0
pecan.configuration.conf_from_file(filepath)
یک دیکشنری پیکربندی از یک فایل می‌سازد.
7.0
پارامترها
filepath -- مسیر فایل.
168u
168u
0.0
pecan.configuration.get_conf_path_from_env()
اگر متغیر محیطی PECAN_CONFIG وجود داشته باشد و به یک مسیر معتبر اشاره کند، آن را بازمی‌گرداند؛ در غیر این صورت یک RuntimeError ایجاد خواهد کرد.
168u
0.0
pecan.configuration.initconf()
پیکربندی پیش‌فرض را مقداردهی اولیه کرده و آن را در pecan.configuration.conf در دسترس قرار می‌دهد، که همچنین در pecan.conf نیز در دسترس است.
168u
0.0
pecan.configuration.set_config(config, overwrite=False)
پیکربندی سراسری را به‌روزرسانی می‌کند.
7.0
پارامترها
config -- می‌تواند یک دیکشنری حاوی پیکربندی، یا یک رشته باشد که نام فایل پیکربندی (نسبی) را نشان می‌دهد.
168u
ماژول pecan.decorators شامل دکوراتورهای مفیدی برای ایجاد برنامه‌های Pecan است.
0.0
pecan.decorators.accept_noncanonical(func)
یک متد کنترلر را به عنوان پذیرندهٔ URLهای غیرمعیار (non-canonical) علامت‌گذاری می‌کند.
168u
0.0
pecan.decorators.after_commit(action)
در صورت استفاده از pecan.hooks <#module-pecan.hooks> TransactionHook، به شما امکان می‌دهد متد یک کنترلر را علامت‌گذاری کنید تا پس از اعمال موفقیت‌آمیز تراکنش (commit)، یک کنش قابل‌فراخوانی (callable) را اجرا کند.
7.0
پارامترها (Parameters)
action -- شیء قابل‌فراخوانی برای فراخوانی پس از اعمال موفقیت‌آمیز commit.
168u
168u
0.0
pecan.decorators.after_rollback(action)
در صورت استفاده از pecan.hooks <#module-pecan.hooks> TransactionHook، به شما امکان می‌دهد متد یک کنترلر را علامت‌گذاری کنید تا پس از بازگردانی موفقیت‌آمیز تراکنش (rollback)، یک کنش قابل‌فراخوانی (callable) را اجرا کند.
7.0
پارامترها (Parameters)
action -- شیء قابل‌فراخوانی برای فراخوانی پس از بازگردانی موفقیت‌آمیز rollback.
168u
168u
0.0
pecan.decorators.expose(template=None, generic=False, route=None, **kw)
دکوراتوری که برای علامت‌گذاری متدهای کنترلر به عنوان «عرضه‌شده» ("exposed") جهت دسترسی از طریق HTTP و پیکربندی آن دسترسی استفاده می‌شود.
7.0
پارامترها (Parameters)
7.0
• 2
template -- مسیر یک قالب، به صورت نسبی نسبت به دایرکتوری پایهٔ قالب‌ها. همچنین می‌تواند رشته‌ای دریافت کند که نمایانگر یک رندرساز (renderer) خاص یا سفارشی باشد، مانند 'json' برای رندرساز JSON <#expose-json>.
• 2
content_type -- نوع محتوا (content-type) مورد استفاده برای این قالب.
• 2
generic -- مقداری بولی که این کنترلر را به عنوان یک کنترلر «عمومی» ("generic") علامت‌گذاری می‌کند، که از توابع چندریختی بر پایهٔ توابع عمومی functools.singledispatch استفاده می‌کند. به شما امکان می‌دهد یک کنترلر واحد را بر اساس متد HTTP به چندین مسیر تقسیم کنید.
• 2
route -- نام بخش مسیر برای تطبیق (به استثنای نویسه‌های جداکننده، مانند /). به طور پیش‌فرض نام خود تابع در نظر گرفته می‌شود، اما می‌تواند برای برطرف‌سازی مسیرهایی استفاده شود که نام‌های معتبر تابع پایتون نیستند؛ به عنوان مثال اگر بخواهید تابعی را به
`

some-special-path' مسیریابی کنید.
168u
168u
168u
0.0
pecan.decorators.transactional(ignore_redirects=True)
در صورت استفاده از pecan.hooks <#module-pecan.hooks> TransactionHook، به شما امکان می‌دهد یک متد یا کلاس کنترلر را صرف‌نظر از متد HTTP، به عنوان قرارگرفته در یک تراکنش علامت‌گذاری کنید.
7.0
پارامترها (Parameters)
ignore_redirects -- مشخص می‌کند که آیا قلاب (hook) باید تغییرمسیرها (redirects) را برای این کنترلر نادیده بگیرد یا خیر.
168u
ماژول pecan.deploy شامل فیکسچرهایی برای کمک به استقرار برنامه‌های کاربردی Pecan است.
0.0
pecan.deploy.deploy(config)
با دریافت یک config (فرهنگ‌لغتی از نام فایل‌های نسبی)، یک برنامهٔ WSGI پیکربندی‌شده را بازمی‌گرداند.
168u
"PECAN.HOOKS - قلاب‌های PECAN (PECAN HOOKS)"
ماژول pecan.hooks شامل پشتیبانی از ایجاد hooks (قلاب‌ها) در Pecan است که روشی ساده برای مداخله در فرایند پردازش درخواست‌های ورودی به برنامهٔ شما به‌منظور انجام وظایف فرافردی (cross-cutting) فراهم می‌کند.
0.0
class pecan.hooks.HookController
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
یک کلاس پایه برای کنترلرهایی که مایل به تعیین قلاب‌ها روی متدهای کنترلر خود هستند. کافی است فهرستی از اشیاء قلاب به نام __hooks__ را به‌عنوان یک صفت کلاسی در کنترلر خود ایجاد کنید.
168u
0.0
class pecan.hooks.PecanHook
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
یک کلاس پایه برای قلاب‌های Pecan. برای ساخت قلاب‌های سفارشی خود از این کلاس ارث‌بری کنید. با تنظیم صفت priority برای قلاب می‌توانید اولویت آن را مشخص کنید که مقدار پیش‌فرض آن ۱۰۰ است.
7.0
after(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مدیریت درخواست توسط کنترلر فراخوانی می‌شود.
7.0
پارامترها (Parameters)
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
7.0
before(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مسیریابی، اما پیش از ارسال درخواست به کنترلر شما فراخوانی می‌شود.
7.0
پارامترها (Parameters)
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
7.0
on_error(state, e)
این متد را بازنویسی کنید تا قلابی ایجاد شود که هنگام رخ دادن یک استثنا (exception) در کنترلر شما فراخوانی می‌شود.
7.0
پارامترها (Parameters)
7.0
• 2
state -- شیء state در Pecan برای درخواست جاری.
• 2
e -- شیء Exception که برانگیخته شده است.
168u
168u
168u
7.0
on_route(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که در آغاز فرایند مسیریابی فراخوانی می‌شود.
7.0
پارامترها (Parameters)
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
168u
0.0
class pecan.hooks.RequestViewerHook(config=None, writer=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, terminal=True, headers=True)
کلاس‌های پایه: PecanHook
7.0
پارامترها (Parameters)
7.0
• 2
config -- یک فرهنگ‌لغت (اختیاری) که می‌تواند کلیدهای items و/یا blacklist را نگه دارد.
• 2
writer -- نویسندهٔ جریان (stream writer) مورد استفاده. تا زمانی که جریان ورودی دارای یک متد قابل فراخوانی write باشد، می‌تواند خروجی را به جریان‌های دیگر هدایت کند.
• 2
terminal -- خروجی را به نویسندهٔ جریان انتخابی (معمولاً ترمینال) می‌فرستد
• 2
headers -- مقادیر را روی سرایندهای X-HTTP تنظیم می‌کند
168u
168u
اطلاعاتی دربارهٔ آنچه در یک درخواست منفرد رخ می‌دهد بازمی‌گرداند. این قلاب موارد مشخصی را برای گزارش‌دهی می‌پذیرد اما در صورتی که هیچ موردی ارسال نشود از فهرست پیش‌فرضی از موارد استفاده می‌کند. بر اساس url درخواست‌شده، موارد می‌توانند در سیاه‌فهرست نیز قرار گیرند.
پیکربندی منعطف است، می‌تواند ارسال شود (یا نشود) و شامل برخی یا تمام کلیدهای پشتیبانی‌شده باشد.
items
این کلید شامل مواردی است که این قلاب نمایش خواهد داد. هنگامی که این کلید ارسال شود، تنها موارد درون فهرست استفاده خواهند شد. موارد معتبر شامل هر موردی است که شیء request دارد؛ به‌طور پیش‌فرض از موارد زیر استفاده می‌شود:
7.0
• 2
path
• 2
status
• 2
method
• 2
controller
• 2
params
• 2
hooks
168u
نکته:
7.0
3.5
این کلید همواره باید از یک list از موارد برای استفاده بهره ببرد.
168u
168u
blacklist
این کلید مواردی را نگه می‌دارد که بر اساس url در سیاه‌فهرست قرار خواهند گرفت. اگر نیاز به حذف آدرس‌هایی باشد که با /javascript شروع می‌شوند، این کلید به شکل زیر خواهد بود:
7.0
3.5
'blacklist': ['/javascript']
168u
168u
این فهرست می‌تواند شامل هر تعداد موردی که نیاز است برای قرار گرفتن در سیاه‌فهرست باشد. قلاب بررسی خواهد کرد که آدرس url با موارد موجود در این فهرست شروع نشود تا نتایج را نمایش دهد، در غیر این صورت نادیده گرفته خواهد شد.
نکته:
7.0
3.5
این کلید همواره باید از یک list از موارد برای استفاده بهره ببرد.
168u
168u
برای مستندات تفصیلی‌تر دربارهٔ این قلاب، لطفاً RequestViewerHook <#requestviewerhook> را ببینید.
7.0
after(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مدیریت درخواست توسط کنترلر فراخوانی می‌شود.
7.0
پارامترها (Parameters)
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
7.0
format_hooks(hooks)
تلاش می‌کند تا اشیاء قلاب را قالب‌بندی کند تا خواناتر شوند
مختص Pecan (در شیء request موجود نیست)
168u
7.0.TP
get_controller(state)
نام کنترلر (controller) واقعی را از برنامه بازمی‌یابد
مختص Pecan (در شیء request در دسترس نیست)
168u
168u
0.0
class pecan.hooks.TransactionHook(start, start_ro, commit, rollback, clear)
کلاس‌های پایه: PecanHook
7.0
پارامترها
7.0
• 2
start -- یک callable که به یک پایگاه‌داده با قابلیت نوشتن متصل شده و یک تراکنش را آغاز می‌کند.
• 2
start_ro -- یک callable که به یک پایگاه‌دادهٔ فقط‌خواندنی متصل می‌شود.
• 2
commit -- یک callable که تراکنش فعال را ثبت (commit) می‌کند.
• 2
rollback -- یک callable که تراکنش فعال را بازگردانی (roll back) می‌کند.
• 2
clear -- یک callable که بافتار (context) فعلی شما را پاکسازی می‌کند.
168u
168u
یک قلاب (hook) پایه‌ای چارچوب برای پشتیبانی از قرار دادن درخواست‌ها در تراکنش‌ها. به‌طور پیش‌فرض، تمام درخواست‌ها به جز GET و HEAD را درون یک تراکنش قرار می‌دهد. متد is_transactional را بازنویسی (override) کنید تا قواعد سفارشی خود را برای این‌که چه درخواست‌هایی باید تراکنشی باشند، تعریف نمایید.
7.0
after(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از رسیدگی به درخواست توسط کنترلر، فراخوانی می‌شود.
7.0
پارامترها
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
7.0
before(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که پس از مسیریابی، اما قبل از ارسال درخواست به کنترلر شما فراخوانی می‌شود.
7.0
پارامترها
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
7.0
is_transactional(state)
بر اساس وضعیت (state) درخواست، تعیین می‌کند که آیا یک درخواست باید درون یک تراکنش قرار گیرد یا خیر. به‌طور پیش‌فرض، به همراه رعایت دکوراتور transactional از :mod:pecan.decorators، تمامی درخواست‌ها به جز GET و HEAD را درون یک تراکنش قرار می‌دهد.
7.0
پارامترها
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
7.0
on_error(state, e)
این متد را بازنویسی کنید تا قلابی ایجاد شود که در صورت رخ دادن یک استثنا (exception) در کنترلر شما، فراخوانی می‌شود.
7.0
پارامترها
7.0
• 2
state -- شیء state در Pecan برای درخواست جاری.
• 2
e -- شیء Exception که ایجاد شده است.
168u
168u
168u
7.0
on_route(state)
این متد را بازنویسی کنید تا قلابی ایجاد شود که در زمان شروع مسیریابی فراخوانی می‌شود.
7.0
پارامترها
state -- شیء state در Pecan برای درخواست جاری.
168u
168u
"PECAN.JSONIFY -- پشتیبانی JSON در PECAN"
ماژول pecan.jsonify شامل پشتیبانی از ایجاد قواعد JSON با استفاده از توابع عمومی است.
0.0
class pecan.jsonify.GenericFunctionJSON(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)
کلاس‌های پایه: GenericJSON
7.0
default(obj)
یک شیء را تبدیل کرده و ساختاری سازگار با JSON برمی‌گرداند.
7.0
پارامترها
obj -- شیء یا ساختاری که قرار است به یک ساختار تبدیل‌پذیر به
JSON تبدیل شود
168u
حالت‌های خاص زیر را به ترتیب در نظر می‌گیرد:
7.0
• 2
2.0
شیء دارای یک ویژگی قابل فراخوانی __json__() تعریف‌شده باشد
نتیجهٔ فراخوانی __json__() را برمی‌گرداند
168u
• 2
2.0
اشیاء date و datetime
شیء تبدیل‌شده به str را برمی‌گرداند
168u
• 2
2.0
اشیاء Decimal
شیء تبدیل‌شده به float را برمی‌گرداند
168u
• 2
2.0
اشیاء SQLAlchemy
نسخه‌ای از object.__dict__ را با حذف پارامترهای داخلی SQLAlchemy
برمی‌گرداند
168u
• 2
2.0
اشیاء ResultProxy در SQLAlchemy
شیء تکرارپذیر ResultProxy را به فهرستی از تاپل‌های حاوی
تمام داده‌های مجموعهٔ نتایج تبدیل کرده و فهرست را به همراه
تعداد سطرها ("row") در یک دیکشنری برمی‌گرداند.
نکته:
7.0
3.5
{'count': 5, 'rows': [('Ed Jones',), ('Pete Jones',),
('Wendy Williams',), ('Mary Contrary',), ('Fred Smith',)]}
168u
168u
168u
• 2
2.0
اشیاء RowProxy در SQLAlchemy
شیء مکان‌نمای RowProxy را به یک دیکشنری تبدیل می‌کند، که احتمالاً
در این فرآیند رفتار دیکشنری مرتب آن از دست می‌رود اما
آن را با JSON سازگار می‌سازد.
168u
• 2
2.0
اشیاء webob.multidict.MultiDict
دیکشنری MultiDict.mixed() را برمی‌گرداند که تضمین می‌شود
با JSON سازگار است.
168u
168u
168u
168u
0.0
class pecan.jsonify.GenericJSON(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)
کلاس‌های پایه: JSONEncoder https://docs.python.org/3/library/json.html#json.JSONEncoder
کدگذار عمومی JSON. چندین تلاش برای تبدیل صحیح اشیاء پاسخ
درخواستی به JSON انجام می‌دهد.
7.0
default(obj)
یک شیء را تبدیل کرده و ساختاری سازگار با JSON برمی‌گرداند.
7.0
پارامترها
obj -- شیء یا ساختاری که قرار است به یک ساختار تبدیل‌پذیر به
JSON تبدیل شود
168u
حالت‌های خاص زیر را به ترتیب در نظر می‌گیرد:
7.0
• 2
2.0
شیء دارای یک ویژگی قابل فراخوانی __json__() تعریف‌شده باشد
نتیجهٔ فراخوانی __json__() را برمی‌گرداند
168u
• 2
2.0
اشیاء date و datetime
شیء تبدیل‌شده به str را برمی‌گرداند
168u
• 2
2.0
اشیاء Decimal
شیء تبدیل‌شده به float را برمی‌گرداند
168u
• 2
2.0
اشیاء SQLAlchemy
نسخه‌ای از object.__dict__ را با حذف پارامترهای داخلی SQLAlchemy
برمی‌گرداند
168u
• 2
2.0
اشیاء ResultProxy در SQLAlchemy
شیء تکرارپذیر ResultProxy را به فهرستی از تاپل‌های حاوی
تمام داده‌های مجموعهٔ نتایج تبدیل کرده و فهرست را به همراه
تعداد سطرها ("row") در یک دیکشنری برمی‌گرداند.
نکته:
7.0
3.5
{'count': 5, 'rows': [('Ed Jones',), ('Pete Jones',),
('Wendy Williams',), ('Mary Contrary',), ('Fred Smith',)]}
168u
168u
168u
• 2
2.0
اشیاء RowProxy در SQLAlchemy
شیء مکان‌نمای RowProxy را به یک دیکشنری تبدیل می‌کند، که احتمالاً
در این فرآیند رفتار دیکشنری مرتب آن از دست می‌رود اما
آن را با JSON سازگار می‌سازد.
168u
• 2
2.0
اشیاء webob.multidict.MultiDict
دیکشنری MultiDict.mixed() را برمی‌گرداند که تضمین می‌شود
با JSON سازگار است.
168u
168u
168u
ماژول pecan.rest شامل پشتیبانی برای نوشتن کنترل‌کننده‌های کاملاً
RESTful در برنامهٔ Pecan شما است.
0.0
class pecan.rest.RestController(*args, **kwargs)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
یک کلاس پایه برای کنترل‌کننده‌های مبتنی بر REST. برای پیاده‌سازی یک
کنترل‌کنندهٔ REST از این کلاس ارث‌بری کنید.
کلاس RestController مجموعه‌ای از توابع مسیریابی را پیاده‌سازی می‌کند
که مسیریابی پیش‌فرض pecan را با رفتاری سازگار با مسیریابی RESTful بازنویسی
می‌کنند. این سازوکار، هدایت به کنترل‌کننده‌های منبع (resource) درخواست‌شده
و همچنین مدیریت مناسب متدهای متداول REST (GET، POST، PUT،
DELETE) و متدهای عملیاتی سفارشی را پوشش می‌دهد.
برای اطلاعات بیشتر در مورد توسعهٔ برنامه‌های تحت وب RESTful با Pecan،
بخش Writing RESTful Web Services with Generic Controllers <#rest> را ببینید.
168u
"PECAN.ROUTING -- مسیریابی در PECAN (PECAN ROUTING)"
ماژول pecan.routing مبنای تمام مسیریابی‌های تفویض شیء (object-dispatch)
در Pecan است.
0.0
pecan.routing.find_object(obj, remainder, notfound_handlers, request)
مسیر url را برای یافتن عملیاتی که یک کنترل‌کننده برای آن پیاده‌سازی شده
«پیمایش» ('walk') می‌کند و آن شیء کنترل‌کننده را به همراه آنچه از
باقی‌مانده (remainder) به جا مانده است برمی‌گرداند.
168u
0.0
pecan.routing.lookup_controller(obj, remainder, request=None)
مسیر url درخواست‌شده را پیمایش می‌کند و شیء کنترل‌کنندهٔ مناسب، شامل مسیرهای
پیش‌فرض را برمی‌گرداند.
خطاهای رایج را به‌خوبی مدیریت می‌کند.
168u
0.0
pecan.routing.route(*args)
این تابع برای تعریف یک مسیر صریح برای بخشی از مسیر (path segment) به کار می‌رود.
به‌طور کلی فقط در شرایطی می‌خواهید از این تابع استفاده کنید که بخش مورد نظر
شما از مسیر، یک نام متغیر یا تابع معتبر در Python نباشد.
برای مثال، اگر می‌خواستید بتوانید به مسیر زیر هدایت شوید:
/path/with-dashes/
... ساختار زیر یک نحو (syntax) نامعتبر در Python است:
7.0
3.5
class Controller(object):
with-dashes = SubController()
168u
168u
... بنابراین در عوض مسیر را به‌طور صریح تعریف می‌کنید:
7.0
3.5
class Controller(object):
pass
pecan.route(Controller, 'with-dashes', SubController())
168u
168u
168u
"PECAN.SECURE -- کنترل‌کننده‌های امن PECAN (PECAN SECURE CONTROLLERS)"
ماژول pecan.secure شامل چارچوبی پایه برای تعبیهٔ امنیت در
برنامه‌های شما است.
0.0
pecan.secure.secure(func_or_obj, check_permissions_for_obj=None)
این متد بسته به نحوهٔ فراخوانی، یک متد یا کلاس را ایمن‌سازی می‌کند.
7.0
برای دکوریت کردن یک متد از یک آرگومان استفاده کنید:
@secure(<check_permissions_method>)
برای ایمن‌سازی یک کلاس، با دو آرگومان فراخوانی کنید:
secure(<obj instance>, <check_permissions_method>)
168u
168u
0.0
pecan.secure.unlocked(func_or_obj)
این متد قفل یک متد یا صفت (attribute) کلاس را در یک SecureController باز می‌کند.
می‌تواند برای دکوریت کردن یا بسته‌بندی (wrap) یک ویژگی استفاده شود.
168u
0.0
class pecan.secure.SecureControllerBase
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
7.0
classmethod check_permissions()
برای اعطای دسترسی، مقدار True یا False را برمی‌گرداند. در زیرکلاس‌های
SecureController پیاده‌سازی می‌شود.
168u
168u
0.0
class pecan.secure.SecureController
کلاس‌های پایه: SecureControllerBase
برای اعمال امنیت بر روی یک کنترل‌کننده استفاده می‌شود. پیاده‌سازی‌های
SecureController باید متد check_permissions را گسترش دهند تا مقدار
True یا False (بسته به این که آیا کاربر دسترسی‌های لازم به کنترل‌کننده را دارد یا خیر)
برگرداند.
ماژول pecan.templating شامل پشتیبانی از انواع موتورهای قالب‌سازی و همچنین توانایی ایجاد موتورهای قالب اختصاصی توسط شما است.
0.0
class pecan.templating.ExtraNamespace(extras=None)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
متغیرهای اضافی برای فضای‌نام قالب جهت ارسال به رندرکننده به‌عنوان پارامترهای نام‌دار.
7.0
پارامترها
extras -- دیکشنری پارامترهای اضافی. پیش‌فرض یک dict خالی است.
168u
7.0
make_ns(ns)
فضای‌نام قالبی را که به‌صورت تنبلانه (lazily) ایجاد شده است، برمی‌گرداند.
168u
7.0
update(d)
دیکشنری متغیرهای اضافی را برای فضای‌نام به‌روزرسانی می‌کند.
168u
168u
0.0
class pecan.templating.GenshiRenderer(path, extra_vars)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
رندرکننده توکار Genshi را تعریف می‌کند.
7.0
render(template_path, namespace)
رندر کردن Genshi را پیاده‌سازی می‌کند.
168u
168u
0.0
class pecan.templating.JinjaRenderer(path, extra_vars)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
رندرکننده توکار Jinja را تعریف می‌کند.
7.0
render(template_path, namespace)
رندر کردن Jinja را پیاده‌سازی می‌کند.
168u
168u
0.0
class pecan.templating.JsonRenderer(path, extra_vars)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
رندرکننده توکار JSON را تعریف می‌کند.
7.0
render(template_path, namespace)
رندر کردن JSON را پیاده‌سازی می‌کند.
168u
168u
0.0
class pecan.templating.KajikiRenderer(path, extra_vars)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
رندرکننده توکار Kajiki را تعریف می‌کند.
7.0
render(template_path, namespace)
رندر کردن Kajiki را پیاده‌سازی می‌کند.
168u
168u
0.0
class pecan.templating.MakoRenderer(path, extra_vars)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
رندرکننده توکار Mako را تعریف می‌کند.
7.0
render(template_path, namespace)
رندر کردن Mako را پیاده‌سازی می‌کند.
168u
168u
0.0
class pecan.templating.RendererFactory(custom_renderers=None, extra_vars=None)
کلاس‌های پایه: object https://docs.python.org/3/library/functions.html#object
اشیاء شناخته‌شدهٔ Renderer را ایجاد می‌کند.
7.0
پارامترها
7.0
• 2
custom_renderers -- رندرکننده‌های سفارشی‌تعریف‌شده برای ایجاد
• 2
extra_vars -- متغیرهای اضافی برای فضای‌نام قالب
168u
168u
7.0
add_renderers(custom_dict)
یک رندرکننده سفارشی را اضافه می‌کند.
7.0
پارامترها
custom_dict -- یک دیکشنری از رندرکننده‌های سفارشی جهت افزودن
168u
168u
7.0
available(name)
اگر کلاس رندرکننده استعلام‌شده در دسترس باشد، مقدار true برمی‌گرداند.
7.0
پارامترها
name -- نام رندرکننده
168u
168u
7.0
get(name, template_path)
شیء رندرکننده را برمی‌گرداند.
7.0
پارامترها
7.0
• 2
name -- نام رندرکننده درخواستی
• 2
template_path -- مسیر فایل قالب
168u
168u
168u
168u
0.0
pecan.templating.format_genshi_error(exc_value)
قالب‌بندی خطای رندرکننده Genshi را پیاده‌سازی می‌کند.
168u
0.0
pecan.templating.format_jinja_error(exc_value)
قالب‌بندی خطای رندرکننده Jinja را پیاده‌سازی می‌کند.
168u
0.0
pecan.templating.format_line_context(filename, lineno, context=10)
زمینه خط (line context) را برای رندر کردن خطا قالب‌بندی می‌کند.
7.0
پارامترها
7.0
• 2
filename -- مکان فایلی که خطا در آن رخ داده است
• 2
lineno -- شماره خط دارای خطا
• 2
context -- تعداد خطوط کدی که باید قبل و بعد از خط دارای خطا نمایش داده شوند.
168u
168u
168u
0.0
pecan.templating.format_mako_error(exc_value)
قالب‌بندی خطای رندرکننده Mako را پیاده‌سازی می‌کند.
ماژول pecan.testing شامل فیکسچرهایی (fixtures) جهت کمک به آزمون برنامه‌های Pecan است.
0.0
pecan.testing.load_test_app(config=None, **kwargs)
برای آزمون‌های کارکردی (functional tests) که نیاز به آزمودن برنامهٔ واقعی خود و یکپارچگی آن با چارچوب کاری (framework) دارید، استفاده می‌شود.
7.0
پارامترها (Parameters)
config -- می‌تواند یک دیکشنری حاوی پیکربندی، یک رشته نشان‌دهندهٔ مسیر (نسبی) فایل پیکربندی یا None باشد که در صورت None بودن، به متغیر محیطی PECAN_CONFIG رجوع خواهد شد.
168u
یک برنامهٔ WSGI از نوع pecan.Pecan را که درون نمونه‌ای از webtest.TestApp قرار گرفته است برمی‌گرداند.
7.0
::
app = load_test_app('path/to/some/config.py')
resp = app.get('/path/to/some/resource').status_int
assert resp.status_int == 200
resp = app.post('/path/to/some/resource', params={'param': 'value'})
assert resp.status_int == 302
168u
در صورتی که متغیر محیطی تنظیم شده باشد، می‌توانید load_test_app را بدون پارامتر نیز فراخوانی کنید:
7.0
3.5
app = load_test_app()
resp = app.get('/path/to/some/resource').status_int
assert resp.status_int == 200
168u
168u
168u
0.0
pecan.testing.reset_global_config()
هنگامی که آزمون‌ها پیکربندی برنامه را تغییر می‌دهند، این تغییرات ممکن است باقی بمانند و سایر آزمون‌هایی را که به یک پیکربندی دست‌نخورده وابسته‌اند آلوده کنند. این تابع کمکی با بازنویسی پیکربندی با pecan.configuration.DEFAULT، آن را بازنشانی می‌کند.
168u
"PECAN.UTIL -- ابزارهای PECAN (PECAN UTILS)"
ماژول pecan.util شامل توابع کمکی و کاربردی برای Pecan است.
0.0
pecan.util.getargspec(method)
پیمایش در میان لایه‌های دکوراتورها برای تلاش جهت یافتن argspec واقعی یک متد.
168u
1.8.0
0.0
• 2
جایگزینی pkg_resources منسوخ‌شده با importlib.metadata و importlib.resources (https://github.com/pecan/pecan/pull/171)
• 2
حداقل نسخهٔ Python اکنون ۳.۱۰ است؛ پشتیبانی از Python 3.8 و 3.9 حذف شد (https://github.com/pecan/pecan/pull/171)
168u
1.7.0
0.0
• 2
افزوده شدن پشتیبانی رسمی از Python 3.8 تا 3.13 (https://github.com/pecan/pecan/pull/165)
• 2
افزونه‌هایی که pecan از طریق pecan.ext وارد (import) می‌کرد حذف شده‌اند (https://github.com/pecan/pecan/issues/157)
168u
1.6.0
0.0
• 2
حذف وابستگی pecan به https://pypi.org/project/logutils که دیگر به‌طور فعال نگهداری نمی‌شود (https://github.com/pecan/pecan/issues/159)
در نتیجه، رابط خط فرمان (CLI) مربوط به pecan دیگر سطوح لاگ را رنگی چاپ نخواهد کرد
• 2
حذف پشتیبانی از Python 3.7 و نسخه‌های پیش از آن
0.0
• 2
رفع یک باگ نصب ناشی از اسکریپت ورودی تکراری (https://github.com/pecan/pecan/pull/142)
168u
1.5.0
0.0
• 2
pecan دیگر وابستگی به six ندارد (https://github.com/pecan/pecan/issues/144)
• 2
اکنون pecan از SQLAlchemy 2.0 پشتیبانی می‌کند (https://github.com/pecan/pecan/issues/143)
• 2
pecan دیگر از SQLAlchemy 1.3 پشتیبانی نمی‌کند
168u
1.4.2
0.0
• 2
pecan دیگر به webtest وابسته نیست (https://github.com/pecan/pecan/issues/139)
168u
1.4.1
0.0
• 2
افزودن پشتیبانی از Python 3.10
• 2
افزودن دسته‌بندی‌کننده‌های trove برای Python 3.6 - 3.9
• 2
رفع یک باگ مربوط به setuptools به عنوان وابستگی
(https://github.com/pecan/pecan/pull/122)
• 2
رفع باگی که در زمان استفاده با برخی از نسخه‌های
SQLAlchemy باعث از کار افتادن pecan می‌شد (https://github.com/pecan/pecan/pulls)
168u
1.4.0
0.0
• 2
اکنون pecan به webob >= 1.8 نیاز دارد
• 2
رفع باگ هنگام تجزیه برخی از سرایندهای Accept
(https://github.com/Pylons/webob/issues/403)
• 2
حذف پشتیبانی رسمی از Python 3.5
168u
1.3.3
0.0
• 2
رفع یک باگ در RestController که برخی از درخواست‌های @secure را به اشتباه
مسیریابی می‌کرد (https://github.com/pecan/pecan/pull/105)
• 2
حذف پشتیبانی رسمی از Python 3.3
168u
1.3.2
0.0
• 2
اکنون pecan با نسخه‌های کمتر و بیشتر از 1.8 در webob کار می‌کند
(https://github.com/pecan/pecan/pull/99)
168u
1.3.1
0.0
• 2
تثبیت نسخه‌ی webob روی 1.8> به دلیل تغییرات ناسازگار در تجزیه سرایند Accept
(https://github.com/pecan/pecan/pull/97)
(https://github.com/Pylons/webob/pull/338)
168u
1.3.0
0.0
• 2
اکنون پشتیبانی رسمی از Python 3.6 در pecan فراهم شده است
• 2
پشتیبانی از Python 2.6 در pecan متوقف شد
168u
1.2.1
0.0
• 2
بازگردانی یک تغییر/پس‌رفت پایدار API (در انتشار 1.2)
(https://github.com/pecan/pecan/issues/72). این تغییر در
یک ارتقای نسخه‌ی اصلی در آینده دوباره منتشر خواهد شد.
168u
1.2
0.0
• 2
افزودن پیام خطای بهتر در هنگام تعیین یک رندرکننده نامعتبر قالب
در pecan.expose() (https://github.com/pecan/pecan/issues/81).
• 2
کنترل‌کننده‌های Pecan که None برمی‌گردانند، اکنون به عنوان HTTP 204 No
Content در نظر گرفته می‌شوند (https://github.com/pecan/pecan/issues/72).
• 2
آرگومان method در pecan.expose() برای کنترل‌کننده‌های عمومی دیگر
اختیاری نیست (https://github.com/pecan/pecan/pull/77).
0.0
• 2
رفع باگی که در آن بدنه پاسخ‌های HTTP با قالب‌بندی JSON از قابلیت ثبت نوع JSON در pecan استفاده نمی‌کردند
(http://pecan.readthedocs.io/en/latest/jsonify.html)
(https://github.com/pecan/pecan/issues/68).
• 2
به‌روزرسانی کد و مثال‌های مستندات برای پشتیبانی از انتقال readthedocs از
readthedocs.org به readthedocs.io.
168u
1.1.1
0.0
• 2
پکان اکنون رسماً از Python 3.5 پشتیبانی می‌کند.
• 2
پکان اکنون در Python 3.5 و بالاتر به جای inspect.getargspec از inspect.signature استفاده می‌کند
(زیرا inspect.getargspec در این نسخه‌های Python 3 منسوخ شده است).
• 2
رفع باگی که هنگام استفاده از
pecan.redirect(..., internal=True) باعث می‌شد قلاب‌های "after" چندین بار اجرا شوند
(https://github.com/pecan/pecan/issues/58).
168u
1.1.0
0.0
• 2
اکنون pecan.middleware.debug.DebugMiddleware استثناها را در سطح ERROR ثبت می‌کند
(https://github.com/pecan/pecan/pull/56).
• 2
رفع یک باگ Javascript در داربست پیش‌فرض پروژه
(https://github.com/pecan/pecan/pull/55).
168u
1.0.5
0.0
• 2
رفع باگ در تشخیص argspec کنترلر هنگام استفاده از دکوراتورهای مبتنی بر کلاس
(https://github.com/pecan/pecan/issues/47).
168u
1.0.4
0.0
• 2
رفع نشت دستگیره فایل باز هنگامی که pecan خطاها را برای قالب‌های Jinja2 و
Genshi رندر می‌کند (https://github.com/pecan/pecan/issues/30).
• 2
رفع باگی که باعث تکراری شدن خروجی لاگ در پروژه‌های ایجادشده
با pecan create می‌شد (https://github.com/pecan/pecan/issues/39).
168u
1.0.3
0.0
• 2
رفع باگی در pecan.hooks.HookController برای نسخه‌های جدیدتر Python3.4
(https://github.com/pecan/pecan/issues/19).
168u
1.0.2
0.0
• 2
رفع یک حالت خاص در pecan.util.getargspec که در برخی شرایط هنگام استفاده از Python 2.6
باعث بازگرداندن argspec نادرست می‌شد.
• 2
افزودن یک threading.lock به پایش فایل‌سیستم در pecan serve
--reload برای جلوگیری از راه‌اندازی‌های مجدد غیرضروری سرور.
168u
1.0.1
0.0
• 2
رفع باگی که در آن پسوند فایل برای URLهای دارای اسلش پایانی
(file.html در مقابل file.html/) به‌درستی حدس زده نمی‌شد و در نتیجه
منجر به سرآیندهای نادرست Content-Type می‌گردید.
• 2
رفع باگی ظریف در انتساب صفت/آیتم در pecan.config.Configuration
که باعث می‌شد برخی از انواع تغییرات پیکربندی در سکوت با شکست مواجه شوند.
168u
1.0.0
0.0
• 2
جایگزینی میان‌افزار دیباگر pecan با یک وابستگی (اختیاری) به
بسته backlash. توسعه‌دهندگانی که می‌خواهند ردپای خطاها (tracebacks) در سطح برنامه را
به‌صورت تعاملی اشکال‌زدایی کنند، باید pip install backlash را در محیط توسعه خود اجرا کنند.
• 2
رفع یک باگ مرتبط با Content-Type: هنگامی که یک content_type صریح
به‌عنوان یک آرگومان به pecan.expose() ارسال می‌شود، اکنون نسبت به
رندرکننده پیش‌فرض در سطح برنامه اولویت دارد.
• 2
رفع باگی که مانع استفاده از برخی نویسه‌های مشخص‌شده در RFC3986
در بخش‌های مسیر می‌شد.
• 2
رفع باگی در pecan.abort که ردپای پشته اصلی را سرکوب می‌کرد (و
مانع از عملکرد مؤثر ابزارهای پایش مانند NewRelic می‌شد).
0.0
• 2
پشتیبانی از Python 3.2 متوقف شده است.
• 2
قابلیت جدیدی اضافه شد که به کاربران امکان می‌دهد بخش‌های مسیر سفارشی را برای
کنترل‌کننده‌ها مشخص کنند. این قابلیت به‌ویژه برای بخش‌های مسیری مفید است که
شناسه‌های معتبر Python نیستند (مانند بخش‌های مسیری که شامل نویسه‌های
نشانه‌گذاری خاصی مانند /some/~path~/ هستند).
• 2
گزینهٔ پیکربندی جدیدی به نام app.debugger اضافه شد که به توسعه‌دهندگان
اجازه می‌دهد هنگام اشکال‌زدایی تعاملی با DebugMiddleware در pecan، دیباگری
جایگزین برای pdb (مانند ipdb) تعیین کنند.
• 2
پروژه‌های جدید quickstart در pecan تغییر کردند تا سطح ثبت گزارش برای pecan در
محیط توسعه به‌طور پیش‌فرض روی DEBUG تنظیم شود.
• 2
باگی برطرف شد که مانع از استفاده از staticmethods به عنوان کنترل‌کننده می‌شد.
• 2
باگی در رمزگشایی در نحوهٔ مدیریت بخش‌های مسیر URL نقل‌قول‌شده (quoted) و
رشته‌های پرس‌وجو (query strings) توسط pecan برطرف شد.
• 2
چندین باگ در نحوهٔ مدیریت بخش‌های مسیر Unicode توسط pecan برطرف شد (برای
مثال، اکنون می‌توانید مسیرهایی در pecan تعریف کنید که شامل نویسه‌های ایموجی باشند).
• 2
چندین باگ در RestController برطرف شد که باعث می‌شد به جای HTTP 405 Method Not
Allowed، کد HTTP 404 Not Found را بازگرداند. علاوه بر این، اکنون
RestController هنگام بازگرداندن HTTP 405 Method Not Allowed، هدرهای معتبر
Allow را بازمی‌گرداند.
• 2
باگی برطرف شد که اجازه می‌داد متدهای خاص pecan (_route، _lookup،
_default) به عنوان متدهای عمومی REST نشانه‌گذاری شوند.
• 2
در مستندات pecan بر لزوم تنظیم debug=False در استقرار‌های محیط عملیاتی
(production) تأکید بیشتری شد.
168u
0.8.3
0.0
• 2
رفتار pecan تغییر یافت تا موارد خاص کدگذاری درخواست را با سازگاری و انعطاف
بیشتری مدیریت کند. اکنون برنامه‌های pecan با یک HTTP 400 (به جای یک
UnicodeDecodeError دریافت‌نشده که منجر به HTTP 500 می‌شد) پاسخ می‌دهند، هرگاه:
- درخواست‌های HTTP POST از داده‌های غیر Unicode تشکیل شده باشند
- مسیرهای درخواست شامل نویسه‌های percent-encoded نامعتبر باشند، مانند:
2.0
3.5
/some/path/%aa/
168u
168u
• 2
بهبود جزئیات گزارش (verbosity) برای خطاهای مرتبط با واردسازی (import) در فایل‌های
پیکربندی pecan، به‌ویژه مواردی که شامل importهای نسبی هستند.
168u
0.8.2
0.0
• 2
باگی را برطرف می‌کند که پشتیبانی از متغیرهای رشته پرس‌وجوی چندمقداری (مانند
?check=a&check=b) را مختل می‌کرد.
168u
0.8.1
0.0
• 2
بهبود تشخیص بازگشت بی‌نهایت (infinite recursion) برای PecanHook و pypy. این تغییر
باگی را برطرف می‌کند که در pecan + pypy کشف شده بود و هنگام استفاده از فراکلاس
(metaclass) در PecanHook می‌توانست منجر به بازگشت بی‌نهایت شود.
• 2
باگی برطرف شد که مانع از استفاده از @staticmethod در کنترل‌کننده‌های @exposed
می‌شد.
• 2
باگی جزئی در محاسبهٔ آرگومان‌های کنترل‌کننده برطرف شد.
168u
0.8.0
0.0
3.5
0.0
• 2
برای درخواست‌های HTTP POST، نگاشت بدنهٔ درخواست‌های JSON به آرگومان‌های کلیدواژه‌ای کنترل‌کننده.
• 2
بهبود تشخیص argspec و انعطاف‌پذیری برای کنترل‌کننده‌های بسته‌بندی‌شده (wrapped controllers).
• 2
هنگامی که آرگومان‌های مسیر برای RestController نادرست هستند، بازگرداندن HTTP 404 به جای 400.
• 2
هنگام تشخیص عدم وجود محتوا برای HTTP 204، خطای UnicodeDecodeError به‌درستی دریافت و مدیریت شود.
• 2
باگی در مسیریابی برای زیرکنترل‌کننده‌های عمومی (generic subcontrollers) برطرف شد.
• 2
باگی در مدیریت توابع عمومی در زمان غیرفعال بودن context locals برطرف شد.
• 2
باگی که ترتیب آرگومان‌ها را در توابع عمومی برهم می‌زد برطرف شد.
• 2
حذف دستور assert برای کنترل جریان؛ این دستور می‌تواند با python -O بهینه‌سازی و حذف شود.
168u
168u
0.0
• 2
رفع یک حالت خاص (edge case) در مسیریابی RestController که می‌بایست کد HTTP 400 برمی‌گرداند، اما در عوض یک استثنا ایجاد می‌کرد (و در نتیجه، HTTP 500 برگردانده می‌شد).
• 2
رفع پیکربندی نادرست ثبت‌کننده ریشه (root logger) برای پروژه‌های راه‌اندازی سریع (quickstarted) در pecan.
• 2
افزودن pecan.state.arguments، قابلیتی جدید برای بازرسی آرگومان‌های فراخوانی کنترلر.
• 2
رفع خطای بازگشت بی‌نهایت در اعمال PecanHook. ایجاد زیرکلاس از هر دو کلاس
rest.RestController و hooks.HookController منجر به خطای بازگشت بی‌نهایت
در اعمال قلاب‌ها می‌شد (که مانع از شروع برنامه‌ها می‌گردید).
• 2
آزمون‌های Pecan اکنون در توزیع کد منبع آن گنجانده شده‌اند.
168u
0.6.1
0.0
• 2
رفع باگی که باعث می‌شد pecan به اشتباه برای بدنه پاسخ‌های غیرخالی، کد HTTP 204 بازگرداند.
168u
0.6.0
0.0
• 2
افزودن پشتیبانی از غیرفعال‌سازی متغیرهای محلی نخ (threadlocals) در pecan.request
و pecan.response در سطح برنامه WSGI به نفع ارسال صریح ارجاع.
برای اطلاعات بیشتر، بخش Context/Thread-Locals vs. Explicit Argument Passing <#contextlocals> را ببینید.
• 2
افزودن پشتیبانی بهتر از ترکیب قلاب‌ها (hook composition) از طریق زیرکلاس‌سازی و mixinها.
برای اطلاعات بیشتر، بخش Attaching Hooks <#attaching-hooks> را ببینید.
• 2
افزودن پشتیبانی از تعیین پیاده‌سازی‌های سفارشی درخواست و پاسخ در سطح برنامه WSGI
برای افرادی که می‌خواهند قابلیت‌های ارائه‌شده توسط کلاس‌های پایه در webob را گسترش دهند.
• 2
کنترلرهای Pecan اکنون می‌توانند یک نمونه صریح از webob.Response را برگردانند
تا رندر قالب و سریال‌سازی Pecan را دور بزنند (short-circuit).
• 2
برای متدهای عمومی که کد HTTP 405 بازمی‌گردانند، pecan اکنون یک سرآیند Allow
تولید می‌کند تا متدهای مجاز را به کلاینت اطلاع دهد.
• 2
رفع باگی در پایبندی به RFC2616: اگر یک متد اکسپوزشده هیچ بدنه پاسخی (یا فضای نامی) بازنگرداند،
pecan اکنون پاسخ HTTP 204 را (به جای HTTP 200) اعمال می‌کند.
• 2
رفع باگی در پایبندی به RFC2616: هنگامی که pecan با HTTP 204 یا HTTP 304 پاسخ می‌دهد،
سرآیند Content-Type به طور خودکار حذف می‌شود (زیرا این نوع پاسخ‌های HTTP حاوی محتوای بدنه نیستند).
• 2
رفع یک باگ: اکنون هنگامی که کلاینت‌ها از طریق سرآیند Accept درخواست JSON دارند،
استثناهای HTTP مربوط به webob به صورت JSON سریال‌سازی می‌شوند، نه در قالب بازنمایی بومی HTML خود.
• 2
رفع باگی که برنامه‌های مشخص‌کننده default_renderer = json را از کار می‌انداخت.
168u
0.5.0
0.0
• 2
این انتشار پشتیبانی رسمی از pypy را اضافه می‌کند.
• 2
افزودن لاگ رنگی درخواست‌ها به دستور pecan serve.
• 2
افزودن اسکلت‌بندی (scaffold) برای تولید آسان یک REST API پایه.
• 2
افزودن امکان ارسال آرگومان‌های کلیدواژه‌ای دلخواه به
pecan.testing.load_test_app.
• 2
رفع یک باگ مرتبط با بازگشت (recursion) در میان‌افزار اسناد خطا.
• 2
رفع باگی در دستور gunicorn_pecan که باعث نشت داده‌های threading.local
بین نخ‌های سبک (green threads) مربوط به eventlet/gevent می‌شد.
• 2
بهبود مستندات از طریق اصلاحات و آموزش‌های گام‌به‌گام برای برنامه‌های نمونه pecan.
168u
0.4.5
0.0
• 2
رفع باگ اسلش پایانی برای RestControllerهایی که متد _lookup دارند.
• 2
پاک‌سازی ارجاع برنامه WSGI از وضعیت threadlocal در هر درخواست
(جهت جلوگیری از نشت حافظه احتمالی، به‌ویژه در هنگام آزمون).
• 2
بهبود مستندات pecan و تصحیح ارجاعات intersphinx.
• 2
‏pecan از Python 3.4 پشتیبانی می‌کند.
0.0
• 2
حذف به‌خاطرسپاری (memoization) برخی از مشخصه‌های controller، که می‌توانست منجر به نشت حافظه در جستجوهای پویای controller شود.
168u
0.4.3
0.0
• 2
رفع چندین باگ در RestController.
• 2
رفع یک باگ در مدیریت امنیت برای controllerهای عمومی.
• 2
رفع باگ در گرداننده‌های _default استفاده‌شده در RestController.
• 2
ماندگاری pecan.request.context در میان تغییرمسیرهای داخلی.
168u
0.4.2
0.0
• 2
حذف بهینه‌سازی مسیریابی‌ای که موجب خرابی افزونهٔ WSME pecan می‌شد.
168u
0.4.1
0.0
• 2
انتقال پروژه به زیرساخت StackForge در http://docs.openstack.org/infra/system-config/stackforge.html، شامل بازبینی کد Gerrit، یکپارچه‌سازی مداوم Jenkins و بازتاب در GitHub.
• 2
افزودن یک افزونهٔ pecan برای کارساز محبوب uwsgi در https://uwsgi-docs.readthedocs.io.
• 2
جایگزینی وابستگی simplegeneric با تابع جدید
functools.singledispatch جهت آماده‌سازی برای پشتیبانی از Python 3.4.
• 2
بهینه‌سازی مسیریابی dispatch در هستهٔ pecan برای دستیابی به زمان‌های پاسخ‌دهی به مراتب سریع‌تر.
168u
0.3.2
0.0
• 2
اعمال تغییراتی جهت ساده‌سازی نحوهٔ ارسال pecan.conf.app به برنامه‌های جدید.
• 2
رفع یک باگ مسیریابی برای برخی پیکربندی‌های controller با _lookup.
• 2
بهبود مستندات مربوط به مدیریت بارگذاری فایل‌ها.
• 2
منسوخ شدن گزینهٔ پیکربندی pecan.conf.requestviewer.
168u
0.3.1
0.0
• 2
قلاب‌های on_error اکنون می‌توانند اشیاء Pecan Response را بازگردانند.
• 2
به‌روزرسانی‌های جزئی در مستندات و ابزارهای انتشار.
168u
0.3.0
0.0
• 2
اکنون Pecan از Python 2.6، 2.7، 3.2 و 3.3 پشتیبانی می‌کند.
168u
0.2.4
0.0
• 2
افزودن پشتیبانی از متدهای _lookup به عنوان راهکار جایگزین (fallback) در RestController.
• 2
بهبودهای گوناگون در مستندات پروژه.
168u
0.2.3
0.0
• 2
افزودن بهینه‌سازی‌های گوناگون به pecan.core که زمان پردازش درخواست
را برای مسیریابی dispatch سادهٔ اشیاء حدود ۳۰٪ بهبود می‌بخشد.
• 2
ذخیرهٔ استثناهای ناشی از abort در WSGI environ تا بعداً در پردازش
درخواست (برای نمونه توسط سایر میان‌افزارها یا قلاب‌های pecan) قابل
دسترس باشند.
• 2
افزایش پایداری TransactionHook تا هنگام بروز استثناها در سایر قلاب‌های
pecan در طول یک درخواست، کمتر در معرض شکست قرار گیرد.
• 2
بازآرایی متن راهنمای quickstart به طوری که کاربران مرحله‌ای ضروری را از دست ندهند.
0.0
• 2
رفع مبهم‌سازی کدهای JavaScript برجسته‌سازی نحو برای بسته‌بندی debian.
• 2
انتقال آزمون‌های ساخت scaffold به tox.
• 2
افزودن پشتیبانی از تعیین فایل پیکربندی pecan از طریق متغیر محیطی
PECAN_CONFIG.
• 2
رفع باگ در متدهای DELETE درون دو (یا چند) RestControllers تو در تو.
• 2
افزودن مستندات برای بازگرداندن کدهای وضعیت خاص HTTP.
168u
0.2.1
0.0
• 2
گنجاندن مجوز، readme و requirements.txt در بسته‌های توزیع.
• 2
بهبود بررسی با dir() برای pecan.request و pecan.response.
• 2
رفع باگی که مانع از اتصال (mount) برنامه‌های pecan در مسیرهای مجازی WSGI می‌شد.
168u
0.2.0
0.0
• 2
به‌روزرسانی آزمون‌های داربست‌بندی (scaffolding) پایه پروژه برای تکرارپذیری بیشتر.
• 2
افزودن یک گزینه پیکربندی در سطح برنامه برای غیرفعال کردن حدس نوع محتوا (content-type) بر اساس URL.
• 2
اصلاح وابستگی نادرست آزمون به Jinja؛ نام درست Jinja2 است.
• 2
رفع باگ مربوط به مسیریابی در RestController. این مورد #156 را برطرف می‌کند.
• 2
افزودن سند صریح CONTRIBUTING.rst.
• 2
بهبود دسترسی و دید مستندات مربوط به استقرار.
• 2
افزودن پشتیبانی از اسکریپت کنسولی gunicorn_pecan.
• 2
حذف و نشانه‌گذاری چند import بدون استفاده (و جایگزین‌های py26).
• 2
رفع باگ: عدم حذف پسوند نقطه‌دار از مسیر مگر اینکه یک mimetype منطبق داشته باشد.
• 2
افزودن آزمونی به فرآیند ساخت پروژه scaffold جهت اطمینان از پاس شدن آزمون pep8.
• 2
اصلاح خروجی گمراه‌کننده دستور $ pecan --version.
168u
0.2.0B
0.0
• 2
رفع باگ در SecureController. رفع مشکل #131.
• 2
استخراج وابستگی‌های فایل‌های ایستا (static) میان‌افزار اشکال‌زدایی به فایل‌های فیزیکی.
• 2
بهبود آزمونی که ممکن بود به دلیل شرایط رقابتی (race condition) ناموفق باشد.
• 2
بهبود مستندات مربوط به قالب پیکربندی و app.py.
• 2
افزودن پشتیبانی از تشخیص نوع محتوا از طریق هدرهای Accept در HTTP.
• 2
تصحیح دستورالعمل‌های نصب از مبدأ (سورس) در README.
• 2
اصلاح یک مثال کد نادرست در مستندات Hooks.
• 2
مستندات: اصلاح اشتباه تایپی جزئی در مثال مسیریابی با *args.
168u
"مجوز (LICENSE)"
فریم‌ورک Pecan و مستندات آن تحت مجوز BSD منتشر شده‌اند:
0.0
3.5
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 <organization> 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 "AS IS" 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 <COPYRIGHT HOLDER> 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.
168u
Jonathan LaCour
"کپی‌رایت و تکثیر (COPYRIGHT)"
2010, Jonathan LaCour
March 20, 2026 1.8.0