| PECAN(1) | Pecan | PECAN(1) |
نام (NAME)
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
نصب (INSTALLATION)
نسخه پایدار (Stable Version)
توصیه میکنیم 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
نکته:
همچنین میتوانید مستقیماً از GitHub با استفاده از pip نصب کنید:
$ pip install -e git://github.com/pecan/pecan.git#egg=pecan
ایجاد نخستین برنامه PECAN (CREATING YOUR FIRST PECAN APPLICATION)
بیایید یک پروژه نمونه کوچک با Pecan ایجاد کنیم.
نکته:
قالب پایه برنامه (Base Application Template)
برنامه 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 متفاوت باشد، اما ساختار بالا باید دید کلی از آنچه انتظار میرود را به شما بدهد.
بیایید فایلهای ایجاد شده توسط قالب را بررسی کنیم:
- public
- تمام فایلهای ایستا (مانند CSS، Javascript و تصاویر) در اینجا قرار دارند. Pecan با یک سرویسدهنده فایل ساده همراه است که هنگام توسعه، این فایلهای ایستا را ارائه میدهد.
ساختار برنامه Pecan عموماً از الگوی MVC <http://en.wikipedia.org/wiki/Model–view–controller> پیروی میکند. دایرکتوریهای زیر test_project شامل مدلها، کنترلکنندهها و قالبهای شما هستند.
- test_project/controllers
- دایرکتوری دربرگیرنده فایلهای کنترلکننده (controller) شما.
- test_project/templates
- تمام قالبهای (templates) شما در اینجا قرار میگیرند.
- test_project/model
- دربرگیرنده فایلهای مدل (model) شما.
در نهایت، دایرکتوری برای نگهداری آزمونهای واحد (unit) و یکپارچهسازی (integration):
- test_project/tests
- تمام آزمونهای مربوط به برنامه شما.
فایل 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 در پروژه خود پیدا کرد.
استقرار روی یک وبسرور (Deploying to a Web Server)
آماده استقرار برنامه جدید Pecan خود هستید؟ نگاهی به Deploying Pecan in Production <#deployment> بیندازید.
کنترلکنندهها و مسیریابی (CONTROLLERS AND ROUTING)
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 پاسخ خواهد داد.
مسیریابی بر اساس متد درخواست (Routing Based on Request Method)
آرگومان 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
متد ویژهٔ _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
متد _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() را مشخص کند، به شما امکان کنترل کامل را میدهد.
تعامل با شیء درخواست و پاسخ (INTERACTING WITH THE REQUEST AND RESPONSE OBJECT)
برای هر درخواست 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
}
نگاشت آرگومانهای کنترلکننده (Controller)
در 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)
مدیریت بارگذاری فایلها (Handling File Uploads)
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 دسترسی یافت و آن را تغییر داد.
توابع کمکی (Helper Functions)
همچنین Pecan توابع کمکی مفید متعددی را برای جابهجایی میان مسیرهای مختلف فراهم میکند. تابع redirect() <#pecan.core.redirect> به شما اجازه میدهد بازهدایتهای داخلی یا HTTP 302 صادر کنید.
همچنین ببینید:
تعیین نشانی وب برای یک کنترلر (Determining the URL for a Controller)
با توجه به اینکه امکان تغییر چشمگیر مسیریابی در زمان اجرا وجود دارد، همیشه امکان تعیین دقیق یک نگاشت بین متد کنترلر و یک نشانی وب (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 (TEMPLATING IN PECAN)
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>
بازنویسی قالبها (Overriding Templates)
تابع 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')
رندر دستی (Manual Rendering)
تابع 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>
تعریف رندرکنندههای سفارشی (Defining Custom Renderers)
برای تعریف یک رندرکنندهٔ سفارشی، میتوانید کلاسی ایجاد کنید که از پروتکل رندرکننده پیروی کند:
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')
نوشتن وبسرویسهای RESTful با کنترلکنندههای عمومی (WRITING RESTFUL WEB SERVICES WITH GENERIC CONTROLLERS)
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
نگاشت URL (URL Mapping)
بهطور پیشفرض، 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() پشتیبانی میکند.
هشدار:
نمونههای 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) از پیکربندی، یک دیکشنری اختصاص دادهشده به یک نام متغیر در ماژول پیکربندی است.
مقادیر پیشفرض (Default Values)
در زیر فهرست کاملی از مقادیر پیشفرضی که این چارچوب استفاده میکند آمده است:
server = {
'port' : '8080',
'host' : '0.0.0.0'
}
app = {
'root' : None,
'modules' : [],
'static_root' : 'public',
'template_path' : ''
}
پیکربندی برنامه (Application Configuration)
مقادیر پیکربندی 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
}
بیایید به هر مقدار و معنای آن نگاهی بیندازیم:
- modules
- فهرستی از ماژولها که Pecan در آنها به جستجوی برنامهها میپردازد. به طور کلی این باید شامل یک مورد، یعنی نام بسته پایتون پروژه شما باشد. حداقل یکی از ماژولهای فهرستشده باید شامل تابع app.setup_app باشد که برای ایجاد برنامه WSGI فراخوانی میشود. به عبارت دیگر، این بسته باید مکانی باشد که فایل app.py شما در آن قرار دارد، و این فایل باید حاوی یک تابع setup_app باشد.
- root
- کنترلکننده ریشه برنامه شما. به یاد داشته باشید که رشتهای نشاندهنده یک مسیر پایتون به یک شیء قابل فراخوانی (callable) ارائه دهید (مانند "yourapp.controllers.root.RootController").
- static_root
- دایرکتوری که فایلهای ایستای (static) شما در آن یافت میشوند (نسبت به ریشه پروژه). Pecan همراه با یک میانافزار (middleware) ارائه میشود که میتواند برای سرو فایلهای ایستا (مانند فایلهای CSS و Javascript) در طول فرایند توسعه استفاده شود.
- template_path
- به دایرکتوری اشاره میکند که فایلهای قالب شما در آن قرار دارند (نسبت به ریشه پروژه).
- debug
- امکان نمایش ردگیری خطا (traceback) در مرورگر و اشکالزدایی تعاملی در طول فرایند توسعه را فعال میکند.
هشدار:
هشدار:
همچنین ببینید:
- •
- قالب پایه برنامه <#app-template>
Pecan مقادیر پیشفرض معقولی را ارائه میدهد. این مقادیر را تغییر دهید تا میزبان و درگاهی که برنامهٔ WSGI شما روی آن سرویسدهی میشود، دگرگون گردند.
server = {
'port' : '8080',
'host' : '0.0.0.0'
}
پیکربندیهای اضافی (Additional Configuration)
ممکن است برنامهٔ شما در زمان اجرا به مقادیر پیکربندی دیگری (مانند اطلاعات احراز هویت API شخص ثالث) نیاز داشته باشد. این تنظیمات را در بلوکهای اختصاصی خودشان در فایل پیکربندی قرار دهید.
twitter = {
'api_key' : 'FOO',
'api_secret' : 'SECRET'
}
دسترسی به پیکربندی در زمان اجرا (Accessing Configuration at Runtime)
شما میتوانید در زمان اجرا از طریق pecan.conf به هر مقدار پیکربندی دسترسی داشته باشید. این موارد شامل مقادیر سفارشی، مقادیر مربوط به برنامه و مقادیر خاص سرور است.
برای مثال، اگر نیاز به تعیین یک مدیر (administrator) سراسری داشتید، میتوانید این کار را به این صورت در فایل پیکربندی انجام دهید:
administrator = 'foo_bar_user'
و در pecan.conf به این شکل قابل دسترسی خواهد بود:
>>> from pecan import conf >>> conf.administrator 'foo_bar_user'
تبدیل به دیکشنری (Dictionary Conversion)
در شرایط خاصی ممکن است بخواهید با کلیدها و مقادیر دقیقاً در قالب دیکشنری رفتار کنید. شیء 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', [...]
کلیدهای نقطهدار، شناسههای غیرپایتونی و دیکشنریهای بومی (Dotted Keys, Non-Python Identifiers, and Native Dictionaries)
گاهی اوقات میخواهید یک گزینهٔ پیکربندی را مشخص کنید که شامل کلیدهای نقطهدار است یا یک شناسهٔ معتبر در 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)
امنیت و احراز هویت (SECURITY AND AUTHENTICATION)
Pecan هیچ پشتیبانی از پیشآمادهای برای احراز هویت ارائه نمیدهد، اما ابزارهای لازم را فراهم میکند تا بتوانید احراز هویت و مجوزدهی را بر اساس نیاز خود مدیریت کنید.
مبانی دکوراتور secure (secure Decorator Basics)
میتوانید با استفاده از دکوراتور 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> در مثال بالا توجه کنید؛ از این دکوراتور میتوان به شیوهای مشابه برای باز کردن صریح دسترسی همگانی به یک کنترلر بدون هیچگونه بررسی امنیتی استفاده کرد.
نوشتن متدهای احراز هویت/مجوزدهی (Writing Authentication/Authorization Methods)
متد check_permissions() <#pecan.secure.SecureControllerBase.check_permissions> باید برای تعیین وضعیت احراز هویت و مجوزدهی کاربر به کار رود. کدی که در اینجا پیادهسازی میکنید میتواند از بررسیهای سادهٔ نشست (کاربر فعلی به عنوان مدیر سیستم احراز هویت شده است) تا اتصال به یک سرویس LDAP متغیر باشد.
اطلاعات بیشتر دربارهٔ secure (More on secure)
متد 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'
قلابهای PECAN (PECAN HOOKS)
اگرچه استفاده از میانافزار 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>: هنگامی که یک درخواست یک استثنا ایجاد کند، فراخوانی میشود
پیادهسازی قلاب PECAN (Implementating a Pecan Hook)
در مثال زیر، یک قلاب ساده اطلاعاتی درباره درخواست جمعآوری کرده و آن را در 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!
نکته:
هشدار:
Pecan شامل چند قلاب در هستهٔ خود است. این بخش کاربردهای مختلف آنها، نحوهٔ پیکربندی و نمونههایی از سناریوهای رایج را شرح میدهد.
RequestViewerHook
این قلاب برای اهداف اشکالزدایی مفید است. این قلاب به تمام صفتهای شیء response بهعلاوهٔ چند صفت دیگر که مختص این فریمورک هستند دسترسی دارد.
دو روش اصلی وجود دارد که این قلاب میتواند اطلاعات مربوط به یک درخواست را ارائه دهد:
- 1.
- خروجی ترمینال یا ثبت وقایع (از طریق یک جریان شبهفایل مانند stdout)
- 2.
- کلیدهای سفارشی سرایند در پاسخ واقعی.
بهطور پیشفرض، هر دو خروجی فعال هستند.
همچنین ببینید:
- •
- pecan.hooks -- قلابهای Pecan <#pecan-hooks>
پیکربندی RequestViewerHook
چندین روش برای پیکربندی مناسب و اجرای این قلاب وجود دارد. با این حال، دانستن این نکته مفید است که برای راهاندازی و اجرای آن به هیچ پیکربندی اولیهای نیاز نیست.
بهطور پیشفرض، اطلاعات مربوط به این موارد را خروجی میدهد:
- 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 اطلاعاتی را مشخص میکند که هوک بازمیگرداند. گاهی اوقات با توجه به نیاز توسعه، به بخش خاصی از اطلاعات یا دستهای از آنها نیاز خواهید داشت؛ از این رو لازم است مقادیر پیشفرض تغییر کرده و فهرستی از موارد مشخص شود.
نکته:
هوک به تکتک مشخصههای شیء درخواست (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 |