.\" Man page generated from reStructuredText .\" by the Docutils 0.22.3 manpage writer. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "FLASK-PRINCIPAL" "1" "Dec 15, 2025" "0.4.0" "Flask Principal" .SH "نام (NAME)" flask-principal \- مستندات Flask-Principal .sp \fI\(dqمن آنم که هستم\(dq\fP .SH "مقدمه (INTRODUCTION)" .sp پکیج Flask\-Principal چارچوبی با پیوند بسیار منعطف و سست (loose) را برای پیوند دادن ارائه‌دهندگان دو نوع سرویس فراهم می‌کند که معمولاً در بخش‌های متفاوتی از یک برنامه وب قرار دارند: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP 1. 3 ارائه‌دهندگان احراز هویت (Authentication providers) .IP 2. 3 ارائه‌دهندگان اطلاعات کاربر (User information providers) .UNINDENT .UNINDENT .UNINDENT .sp به عنوان مثال، یک ارائه‌دهنده احراز هویت می‌تواند OAuth با استفاده از Flask\-OAuth باشد و اطلاعات کاربر نیز ممکن است در یک پایگاه داده رابطه‌ای ذخیره شود. انعطاف‌پذیری و ارتباط سست این چارچوب با استفاده از سیگنال‌ها به عنوان رابط میسر شده است. .sp مؤلفه‌های اصلی عبارتند از Identity، Needs، Permission و IdentityContext. .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP 1. 3 مؤلفه Identity نمایانگر کاربر است و برای هر درخواست از مکان‌های گوناگون (مانند نشست یا session) بارگذاری یا ذخیره می‌شود. Identity در واقع آواتار کاربر در سیستم است که حقوق دسترسی کاربر را در بر دارد. .IP 2. 3 مؤلفه Need کوچک‌ترین واحد در کنترل دسترسی است و پارامتری خاص را برای شرایط موجود بازنمایی می‌کند؛ برای نمونه: «دارای نقش مدیر است» (\(dqhas the admin role\(dq)، «می‌تواند پست‌های وبلاگ را ویرایش کند» (\(dqcan edit blog posts\(dq). .sp هر Need می‌تواند هر تاپل (tuple) یا شیء دلخواهی باشد، اما یک تاپل به بهترین شکل مناسب این کار است. انواع از پیش طراحی‌شدهٔ Need (جهت صرفه‌جویی در کدنویسی) به صورت جفت‌های (method, value) هستند که در آن‌ها method برای تعیین موارد متداول نظیر \fI\(dqrole\(dq\fP، \fI\(dquser\(dq\fP و غیره استفاده می‌شود و value نیز مقدار آن است. نمونه‌ای از این ساختار \fI(\(aqrole\(aq, \(aqadmin\(aq)\fP\& است که نشان‌دهنده Need مربوط به نقش admin خواهد بود؛ یا سه‌تایی‌ها (Triples) برای سناریوهایی نظیر «مجوز ویرایش یک نمونهٔ خاص از یک شیء یا سطر»، که ممکن است به شکل سه‌تایی \fI(\(aqarticle\(aq, \(aqedit\(aq, 46)\fP بازنمایی شود؛ که در آن 46 کلید/شناسهٔ (ID) آن سطر/شیء است. .sp در اصل، ماهیت و چیستی Needs تا حد زیادی بر عهده کاربر است و ساختار آن منعطف طراحی شده تا بتوان با استفاده از نمونه‌های سفارشی به عنوان Need، به هر نیازی پاسخ داد. .sp در حالی که Need مجوزی برای دسترسی به یک منبع است، یک Identity باید مجموعه‌ای از نیازها (Needs) را که به آن‌ها دسترسی دارد ارائه دهد. .IP 3. 3 مؤلفه Permission مجموعه‌ای از نیازمندی‌ها (requirements) است که برای دسترسی به یک منبع، وجود دست‌کم یکی از آن‌ها الزامی است. .IP 4. 3 مؤلفه IdentityContext بستر (context) یک هویت (Identity) خاص در برابر یک Permission معین است. این مؤلفه می‌تواند هم به عنوان context manager و هم به عنوان دکوراتور (decorator) استفاده شود. .UNINDENT .UNINDENT .UNINDENT [نمودار] .SH "پیوندها (LINKS)" .INDENT 0.0 .IP \(bu 2 مستندات \% .IP \(bu 2 کد منبع \% .IP \(bu 2 گزارش تغییرات \%<> .UNINDENT .SH "محافظت از دسترسی به منابع (PROTECTING ACCESS TO RESOURCES)" .sp برای کاربران Flask\-Principal (نه ارائه‌دهندگان احراز هویت)، تعریف محدودیت دسترسی هم به عنوان دکوراتور (decorator) و هم به عنوان مدیر زمینه (context manager) بسیار آسان است. در ادامه یک مثال شروع سریع ساده به همراه توضیحات درون‌کد ارائه شده است: .INDENT 0.0 .INDENT 3.5 .sp .EX from flask import Flask, Response from flask.ext.principal import Principal, Permission, RoleNeed app = Flask(__name__) # load the extension principals = Principal(app) # Create a permission with a single Need, in this case a RoleNeed. admin_permission = Permission(RoleNeed(\(aqadmin\(aq)) # protect a view with a principal for that need @app.route(\(aq/admin\(aq) @admin_permission.require() def do_admin_index(): return Response(\(aqOnly if you are an admin\(aq) # this time protect with a context manager @app.route(\(aq/articles\(aq) def do_articles(): with admin_permission.require(): return Response(\(aqOnly if you are admin\(aq) .EE .UNINDENT .UNINDENT.SH "ارائه‌دهندگان احراز هویت (AUTHENTICATION PROVIDERS)" .sp ارائه‌دهندگان احراز هویت باید از سیگنال \fIidentity\-changed\fP برای مشخص کردن اینکه یک درخواست احراز هویت شده است استفاده کنند. برای نمونه، کد زیر مثالی فرضی از نحوه ترکیب افزونه محبوب Flask\-Login \% با Flask\-Principal است: .INDENT 0.0 .INDENT 3.5 .sp .EX from flask import Flask, current_app, request, session from flask.ext.login import LoginManager, login_user, logout_user, \e login_required, current_user from flask.ext.wtf import Form, TextField, PasswordField, Required, Email from flask.ext.principal import Principal, Identity, AnonymousIdentity, \e identity_changed app = Flask(__name__) Principal(app) login_manager = LoginManager(app) @login_manager.user_loader def load_user(userid): # Return an instance of the User model return datastore.find_user(id=userid) class LoginForm(Form): email = TextField() password = PasswordField() @app.route(\(aq/login\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq]) def login(): # A hypothetical login form that uses Flask\-WTF form = LoginForm() # Validate form input if form.validate_on_submit(): # Retrieve the user from the hypothetical datastore user = datastore.find_user(email=form.email.data) # Compare passwords (use password hashing production) if form.password.data == user.password: # Keep the user info in the session using Flask\-Login login_user(user) # Tell Flask\-Principal the identity changed identity_changed.send(current_app._get_current_object(), identity=Identity(user.id)) return redirect(request.args.get(\(aqnext\(aq) or \(aq/\(aq) return render_template(\(aqlogin.html\(aq, form=form) @app.route(\(aq/logout\(aq) @login_required def logout(): # Remove the user information from the session logout_user() # Remove session keys set by Flask\-Principal for key in (\(aqidentity.name\(aq, \(aqidentity.auth_type\(aq): session.pop(key, None) # Tell Flask\-Principal the user is anonymous identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity()) return redirect(request.args.get(\(aqnext\(aq) or \(aq/\(aq) .EE .UNINDENT .UNINDENT .SH "ارائه‌دهندگان اطلاعات کاربر (USER INFORMATION PROVIDERS)" .sp ارائه‌دهندگان اطلاعات کاربر باید به سیگنال \fIidentity\-loaded\fP متصل شوند تا هرگونه اطلاعات اضافی مانند نقش‌ها (roles) را به نمونه Identity اضافه کنند. در ادامه یک مثال فرضی دیگر با استفاده از Flask\-Login آورده شده است که می‌تواند با مثال پیشین ترکیب شود. این مثال نشان می‌دهد که چگونه می‌توان از یک ساختار مجوز مبتنی بر نقش استفاده کرد: .INDENT 0.0 .INDENT 3.5 .sp .EX from flask.ext.login import current_user from flask.ext.principal import identity_loaded, RoleNeed, UserNeed @identity_loaded.connect_via(app) def on_identity_loaded(sender, identity): # Set the identity user object identity.user = current_user # Add the UserNeed to the identity if hasattr(current_user, \(aqid\(aq): identity.provides.add(UserNeed(current_user.id)) # Assuming the User model has a list of roles, update the # identity with the roles that the user provides if hasattr(current_user, \(aqroles\(aq): for role in current_user.roles: identity.provides.add(RoleNeed(role.name)) .EE .UNINDENT .UNINDENT .SH "حفاظت ریزدانه از منابع (GRANULAR RESOURCE PROTECTION)" .sp حال برای نمونه فرض کنید تنها می‌خواهید نویسنده یک پست وبلاگ قادر به ویرایش مقاله مذکور باشد. این هدف با ساخت اشیاء مورد نیاز \fINeed\fP و \fIPermission\fP، و افزودن منطق بیشتر به پردازشگر سیگنال \fIidentity_loaded\fP قابل دستیابی است. برای مثال: .INDENT 0.0 .INDENT 3.5 .sp .EX from collections import namedtuple from functools import partial from flask.ext.login import current_user from flask.ext.principal import identity_loaded, Permission, RoleNeed, \e UserNeed BlogPostNeed = namedtuple(\(aqblog_post\(aq, [\(aqmethod\(aq, \(aqvalue\(aq]) EditBlogPostNeed = partial(BlogPostNeed, \(aqedit\(aq) class EditBlogPostPermission(Permission): def __init__(self, post_id): need = EditBlogPostNeed(unicode(post_id)) super(EditBlogPostPermission, self).__init__(need) @identity_loaded.connect_via(app) def on_identity_loaded(sender, identity): # Set the identity user object identity.user = current_user # Add the UserNeed to the identity if hasattr(current_user, \(aqid\(aq): identity.provides.add(UserNeed(current_user.id)) # Assuming the User model has a list of roles, update the # identity with the roles that the user provides if hasattr(current_user, \(aqroles\(aq): for role in current_user.roles: identity.provides.add(RoleNeed(role.name)) # Assuming the User model has a list of posts the user # has authored, add the needs to the identity if hasattr(current_user, \(aqposts\(aq): for post in current_user.posts: identity.provides.add(EditBlogPostNeed(unicode(post.id))) .EE .UNINDENT .UNINDENT .sp مرحله بعدی محافظت از نقطه پایانی (endpoint) است که به کاربر اجازه ویرایش یک مقاله را می‌دهد. این کار با ایجاد یک شیء دسترسی به‌صورت پویا در حین اجرا با استفاده از شناسه (ID) منبع (در این مورد، پست وبلاگ) انجام می‌شود: .INDENT 0.0 .INDENT 3.5 .sp .EX @app.route(\(aq/posts/\(aq, methods=[\(aqPUT\(aq, \(aqPATCH\(aq]) def edit_post(post_id): permission = EditBlogPostPermission(post_id) if permission.can(): # Save the edits ... return render_template(\(aqedit_post.html\(aq) abort(403) # HTTP Forbidden .EE .UNINDENT .UNINDENT.SH "راه‌اندازی افزونه (STARTING THE EXTENSION)" .INDENT 0.0 .TP .B class flask_principal.Principal(app=None, use_sessions=True, skip_static=False) افزونهٔ Principal. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBapp\fP \-\- برنامهٔ flask برای توسعه و اعمال افزونه. .IP \(bu 2 \fBuse_sessions\fP \-\- مشخص می‌کند که آیا از نشست‌ها (sessions) برای استخراج و ذخیرهٔ هویت استفاده شود یا خیر. .IP \(bu 2 \fBskip_static\fP \-\- مشخص می‌کند که آیا نقاط پایانی (endpoints) ایستا نادیده گرفته شوند یا خیر. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B identity_loader(f) دکوراتور برای تعریف یک تابع به‌عنوان بارگذار هویت (identity loader). .sp تابع بارگذار هویت پیش از پردازش درخواست فراخوانی می‌شود تا هرگونه هویت ارائه‌شده را پیدا کند. نخستین هویت یافت‌شده برای بارگذاری استفاده خواهد شد. .sp به‌عنوان مثال: .INDENT 7.0 .INDENT 3.5 .sp .EX app = Flask(__name__) principals = Principal(app) @principals.identity_loader def load_identity_from_weird_usecase(): return Identity(\(aqali\(aq) .EE .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B identity_saver(f) دکوراتور برای تعریف یک تابع به‌عنوان ذخیره‌کنندهٔ هویت (identity saver). .sp تابع ذخیره‌کنندهٔ هویت هنگامی که هویت تنظیم می‌شود فراخوانی خواهد شد تا آن را برای درخواست بعدی پایدار (ذخیره) کند. .sp به‌عنوان مثال: .INDENT 7.0 .INDENT 3.5 .sp .EX app = Flask(__name__) principals = Principal(app) @principals.identity_saver def save_identity_to_weird_usecase(identity): my_special_cookie[\(aqidentity\(aq] = identity .EE .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B set_identity(identity) تنظیم هویت جاری. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBidentity\fP \-\- هویتی که باید تنظیم شود. .UNINDENT .UNINDENT .UNINDENT .SH "انواع اصلی (MAIN TYPES)" .INDENT 0.0 .TP .B class flask_principal.Permission(*needs) نمایانگر نیازمندی‌ها (needs) است که وجود هر یک از آن‌ها برای دسترسی به یک منبع الزامی است. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBneeds\fP \-\- نیازمندی‌های این مجوز. .UNINDENT .INDENT 7.0 .TP .B allows(identity) مشخص می‌کند که آیا هویت موردنظر به این مجوز دسترسی دارد یا خیر. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBidentity\fP \-\- هویت موردنظر. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B can() مشخص می‌کند که آیا بافتار (context) موردنیاز برای این مجوز دسترسی دارد یا خیر. .sp این متد یک بافتار هویت ایجاد می‌کند و دسترسی داشتن آن به این مجوز را می‌سنجد. .UNINDENT .INDENT 7.0 .TP .B difference(other) مجوز جدیدی شامل نیازمندی‌هایی که در این مجوز وجود دارند و در دیگری نیستند ایجاد می‌کند (تفاضل). .UNINDENT .INDENT 7.0 .TP .B issubset(other) مشخص می‌کند که آیا نیازمندی‌های این مجوز زیرمجموعه‌ای از مجوز دیگر است یا خیر. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBother\fP \-\- مجوز دیگر. .UNINDENT .UNINDENT .INDENT 7.0 .TP .B require(http_exception=None) یک principal برای این مجوز ایجاد می‌کند. .sp این principal می‌تواند به‌عنوان یک مدیر بافتار (context manager) یا یک دکوراتور استفاده شود. .sp در صورت ارسال \fBhttp_exception\fP، تابع \fBabort()\fP با کد استثنای HTTP فراخوانی خواهد شد. در غیر این صورت، چنانچه هویت نیازمندی‌ها را برآورده نکند، یک استثنای \fBPermissionDenied\fP صادر خواهد شد. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBhttp_exception\fP \-\- کد استثنای HTTP (مانند 403، 401 و غیره). .UNINDENT .UNINDENT .INDENT 7.0 .TP .B reverse() معکوس وضعیت جاری را بازمی‌گرداند (needs\->excludes، excludes\->needs). .UNINDENT .INDENT 7.0 .TP .B test(http_exception=None) بررسی می‌کند که آیا مجوز در دسترس است یا خیر و در صورت عدم دسترسی، استثنای مربوطه را صادر می‌کند. این روش زمانی کاربرد دارد که تنها بخواهید بدون قرار دادن همه‌چیز در یک بلوک ()require، مجوز را بررسی کنید. .sp این معادل است با: .INDENT 7.0 .INDENT 3.5 .sp .EX with permission.require(): pass .EE .UNINDENT .UNINDENT .UNINDENT .INDENT 7.0 .TP .B union(other) مجوز جدیدی با اجتماع نیازمندی‌های این مجوز و دیگری ایجاد می‌کند. .INDENT 7.0 .TP .B پارامترها (Parameters) \fBother\fP \-\- مجوز دیگر. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class flask_principal.Identity(id, auth_type=None) نمایانگر هویت کاربر است. .INDENT 7.0 .TP .B پارامترها (Parameters) .INDENT 7.0 .IP \(bu 2 \fBid\fP \-\- شناسهٔ کاربر (user id). .IP \(bu 2 \fBauth_type\fP \-\- نوع احراز هویت استفاده‌شده برای تأیید هویت کاربر. .UNINDENT .UNINDENT .sp هویت برای نشان دادن هویت کاربر در سامانه به کار می‌رود. این شیء در هنگام ورود به سیستم (login)، یا در ابتدای درخواست بر اساس داده‌های بارگذاری‌شده از نشست (session) کاربر ایجاد می‌شود. .sp پس از بارگذاری، این شیء با استفاده از سیگنال \fIidentity\-loaded\fP ارسال می‌گردد و باید با اطلاعات موردنیاز تکمیلی مقداردهی شود. .sp نیازمندی‌هایی (Needs) که توسط این هویت برآورده می‌شوند، باید پس از بارگذاری به مجموعهٔ \fIprovides\fP اضافه شوند. .INDENT 7.0 .TP .B can(permission) مشخص می‌کند که آیا هویت به این مجوز دسترسی دارد یا خیر. .INDENT 7.0.TP .B پارامترها (Parameters) \fBpermission\fP \-\- مجوزی که فراهم بودن آن بررسی می‌شود. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B class flask_principal.AnonymousIdentity یک هویت ناشناس .UNINDENT .INDENT 0.0 .TP .B class flask_principal.IdentityContext(permission, http_exception=None) زمینهٔ (context) یک هویت برای یک مجوز. .sp \fBنکته:\fP .INDENT 7.0 .INDENT 3.5 در سناریوهای معمول، principal معمولاً با فراخوانی متد flaskext.Permission.require ایجاد می‌شود. .UNINDENT .UNINDENT .sp این principal هم به عنوان یک مدیر زمینه (context manager) و هم به عنوان یک دکوراتور (decorator) عمل می‌کند. فراهم بودن مجوز در هویت بررسی می‌شود، و در صورت موجود بودن، روند ادامه می‌یابد (context manager) یا تابع اجرا می‌شود (decorator). .INDENT 7.0 .TP .B can() این‌که آیا هویت به این مجوز دسترسی دارد یا خیر .UNINDENT .INDENT 7.0 .TP .B http_exception مجوز مربوط به این principal .UNINDENT .INDENT 7.0 .TP .B property identity هویت مربوط به این principal .UNINDENT .UNINDENT .SH "انواع پیش‌تعریف‌شده NEED (PREDEFINED NEED TYPES)" .INDENT 0.0 .TP .B class flask_principal.Need(method, value) یک نیاز (need) الزامی .sp این صرفاً یک تاپل نام‌دار (named tuple) است و عملاً هر تاپلی کار خواهد کرد. .sp از ویژگی \fBmethod\fP می‌توان برای جستجوی عنصر ۰ و از ویژگی \fBvalue\fP برای جستجوی عنصر ۱ استفاده کرد. .UNINDENT .INDENT 0.0 .TP .B flask_principal.RoleNeed نام مستعار (alias) برای functools.partial(, \(aqrole\(aq) .UNINDENT .INDENT 0.0 .TP .B flask_principal.UserNeed نام مستعار (alias) برای functools.partial(, \(aqid\(aq) .UNINDENT .INDENT 0.0 .TP .B class flask_principal.ItemNeed(method, value, type) یک نیاز به آیتم (item need) الزامی .sp یک item need صرفاً یک تاپل نام‌دار است و عملاً هر تاپلی کار خواهد کرد. علاوه بر دیگر Needها، یک نوع (type) نیز وجود دارد؛ به عنوان مثال می‌تواند به این شکل مشخص شود: .INDENT 7.0 .INDENT 3.5 .sp .EX ItemNeed(\(aqupdate\(aq, 27, \(aqposts\(aq) (\(aqupdate\(aq, 27, \(aqposts\(aq) # or like this .EE .UNINDENT .UNINDENT .sp و این ممکن است مجوزی را برای به‌روزرسانی یک پست وبلاگ خاص توصیف کند. در عمل، توسعه‌دهنده در انتخاب هر قراردادی برای مجوزها آزاد است. .UNINDENT .SH "سیگنال‌ها (SIGNALS)" .INDENT 0.0 .TP .B identity_changed سیگنالی که هنگام تغییر هویت برای یک درخواست ارسال می‌شود. .UNINDENT .INDENT 0.0 .TP .B identity_loaded سیگنالی که پس از مقداردهی اولیه هویت برای یک درخواست ارسال می‌شود. .UNINDENT .SH "تغییرات FLASK-PRINCIPAL (FLASK-PRINCIPAL CHANGELOG)" .sp در اینجا می‌توانید فهرست کامل تغییرات میان هر نسخه از Flask\-Principal را مشاهده کنید. .SS "نسخه 0.4.0 (Version 0.4.0)" .sp منتشر شده در ۱۴ ژوئن ۲۰۱۳ .INDENT 0.0 .IP \(bu 2 افزوده شدن پشتیبانی از Python 3 .IP \(bu 2 حذف پشتیبانی از Python 2.5 .UNINDENT .SS "نسخه 0.3.5 (Version 0.3.5)" .sp منتشر شده در ۳ آوریل ۲۰۱۳ .INDENT 0.0 .IP \(bu 2 رفع باگ احتمالی در ارسال \(dqanon\(dq به عنوان نام کاربری توسط \fBAnonymousIdentity\fP .IP \(bu 2 تغییر ویژگی \fBname\fP در Identity به \fBid\fP به منظور عمومی‌تر شدن .UNINDENT .SS "نسخه 0.3.4 (Version 0.3.4)" .sp منتشر شده در ۱ فوریه ۲۰۱۳ .INDENT 0.0 .IP \(bu 2 افزودن متد \fB__repr__\fP به کلاس‌های Identity و Permission .IP \(bu 2 بهینه‌سازی متد \fB_is_static_resource\fP .UNINDENT.SS "نسخه 0.3.3" .sp منتشر شده در ۴ سپتامبر ۲۰۱۲ .INDENT 0.0 .IP \(bu 2 افزودن متد \fBinit_app\fP برای استفاده به همراه الگوی کارخانه (factory pattern). .UNINDENT .SS "نسخه 0.3.2" .sp منتشر شده در ۲۵ اوت ۲۰۱۲ .INDENT 0.0 .IP \(bu 2 به‌روزرسانی برای بررسی \fBstatic_url_path\fP در Flask 0.9 .UNINDENT .SS "نسخه 0.3.1" .sp منتشر شده در ۱۶ اوت ۲۰۱۲ .INDENT 0.0 .IP \(bu 2 رفع باگ مربوط به پرتاب مجدد (re\-raising) استثناها/ردیابی‌ها (tracebacks) .UNINDENT .SS "نسخه 0.3" .sp منتشر شده در ۲۰ ژوئن ۲۰۱۲ .INDENT 0.0 .IP \(bu 2 پشتیبانی از Python 2.5/GAE .IP \(bu 2 ساختار جدید افزونه .IP \(bu 2 افزودن گزینه ignore_static .IP \(bu 2 به‌روزرسانی مستندات .UNINDENT .SS "نسخه 0.2" .sp توسعه اولیه توسط Ali Asfshar. مخزن اصلی \% .INDENT 0.0 .IP \(bu 2 نمایه \%<> .IP \(bu 2 نمایه ماژول‌ها \%<> .IP \(bu 2 صفحه جستجو \%<> .UNINDENT .SH "نویسندگان (AUTHORS)" Matt Wright .SH "کپی‌رایت و تکثیر (COPYRIGHT)" 2012, Ali Afshar .\" End of generated man page.