flask v0.1 flask.py

flask 导入的模块

from __future__ import with_statement
import os
import sys

from threading import local
from jinja2 import Environment, PackageLoader, FileSystemLoader
from werkzeug import Request as RequestBase, Response as ResponseBase, \
     LocalStack, LocalProxy, create_environ, cached_property, \
     SharedDataMiddleware
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, InternalServerError
from werkzeug.contrib.securecookie import SecureCookie

# utilities we import from Werkzeug and Jinja2 that are unused
# in the module but are exported as public interface.
from werkzeug import abort, redirect
from jinja2 import Markup, escape

# use pkg_resource if that works, otherwise fall back to cwd.  The
# current working directory is generally not reliable with the notable
# exception of google appengine.
try:
    import pkg_resources
    pkg_resources.resource_stream
except (ImportError, AttributeError):
    pkg_resources = None

1.class Request增加了endpointview_args两个参数,用来接收reuqest的url,父类在werkzeug中实现,用来包装environ,方便我们操作

class Request(RequestBase): # 这里的RequestBase是werkzeug定义的
    def __init__(self, environ):
        RequestBase.__init__(self, environ) # 直接写父类的名称`RequestBase`不推荐,最好用super()代替
        self.endpoint = None
        self.view_args = None

2.class Response增加了返回的默认的mimetype类型

class Response(ResponseBase):
    default_mimetype = 'text/html'

3.class _RequestGlobals

4.class _RequestContext 包含了所有请求的信息
请求进来时被创建,然后加入_request_ctx_stack,请求结束时删除.

class _RequestContext(object): # 使用with语句,拿到栈顶的request进行处理
    def __init__(self, app, environ):
        self.app = app # 当前的app
        self.url_adapter = app.url_map.bind_to_environ(environ) # 主要用来处理URL,因为绑定了environ以后就不需要再往match里传递参数了
        self.request = app.request_class(environ) # 当前的请求信息
        self.session = app.open_session(self.request) # 当前的会话信息
        self.g = _RequestGlobals() # ?
        self.flashes = None

    def __enter__(self): # 使用with语句
        _request_ctx_stack.push(self) # 将当前请求推入栈

    def __exit__(self, exc_type, exc_value, tb):
        # do not pop the request stack if we are in debug mode and an
        # exception happened.  This will allow the debugger to still
        # access the request object in the interactive shell.
        if tb is None or not self.app.debug:
            _request_ctx_stack.pop() # 将往前请求推出栈

5.def url_forendpoint(url的id,一般就是视图函数),

def url_for(endpoint, **values):
    return _request_ctx_stack.top.url_adapter.build(endpoint, values)

6.def flash(message),发送一个message到下一个请求中

def flash(message):
    session['_flashes'] = (session.get('_flashes', [])) + [message

7.def get_flashed_messages

def get_flashed_messages():
    """Pulls all flashed messages from the session and returns them.
    Further calls in the same request to the function will return
    the same messages.
    """
    flashes = _request_ctx_stack.top.flashes
    if flashes is None:
        _request_ctx_stack.top.flashes = flashes = \
            session.pop('_flashes', [])
    return flashes

8.def render_template

def render_template(template_name, **context):
    """Renders a template from the template folder with the given
    context.

    :param template_name: the name of the template to be rendered
    :param context: the variables that should be available in the
                    context of the template.
    """
    current_app.update_template_context(context)
    return current_app.jinja_env.get_template(template_name).render(context

9.def render_template_string

def render_template_string(source, **context):
    """Renders a template from the given template source string
    with the given context.

    :param template_name: the sourcecode of the template to be
                          rendered
    :param context: the variables that should be available in the
                    context of the template.
    """
    current_app.update_template_context(context)
    return current_app.jinja_env.from_string(source).render(context

10.def _default_template_ctx_processor


def _default_template_ctx_processor():
    """Default template context processor.  Injects `request`,
    `session` and `g`.
    """
    reqctx = _request_ctx_stack.top
    return dict(
        request=reqctx.request,
        session=reqctx.session,
        g=reqctx.g
    )

11.def _get_package_path(name)
获得app模块的路径app = Flask(__name__),默认都是使用__main__

def _get_package_path(name):
    """Returns the path to a package or cwd if that cannot be found."""
    try:
        return os.path.abspath(os.path.dirname(sys.modules[name].__file__))
    except (KeyError, AttributeError):
        return os.getcwd()

12.class Flask

class Flask(object):
    request_class = Request
    response_class = Response
    static_path = '/static' # path for the static files
    secret_key = None # cryptographic components can use this to sign cookies and other things
    session_cookie_name = 'session' # name of the session cookie
    jinja_options = dict(  # jinja2 的配置
        autoescape=True,
        extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
    )
    def __init__(self, package_name): # `app = Flask(__name__)`
        self.debug = False
        self.package_name = package_name
        self.root_path = _get_package_path(self.package_name) #: where is the app root located?
        self.view_functions = {} # a dictionary of all view functions registered(`route` decorator)
        self.error_handlers = {} # a dictionary of all registered error handlers,`errorhandler`decorator
        self.before_request_funcs = [] # a list of functions that should be called at the beginning f the request
        self.after_request_funcs = [] # a list of functions that are called at the end of the request.
        self.template_context_processors = [_default_template_ctx_processor] #: to populate the template context.
        self.url_map = Map()

        if self.static_path is not None: # 若果静态文件存在,则通过ShareDatMiddleware设置静态文件夹
            self.url_map.add(Rule(self.static_path + '/<filename>',
                                  build_only=True, endpoint='static')) # 添加静态文件url
            if pkg_resources is not None: # 如果是package不是主程序的话,要从包的路径找`static`
                target = (self.package_name, 'static')
            else:
                target = os.path.join(self.root_path, 'static') # 如果是主程序则拼贴`static`的路径
            self.wsgi_app = SharedDataMiddleware(self.wsgi_app, {
                self.static_path: target
            })

        self.jinja_env = Environment(loader=self.create_jinja_loader(),**self.jinja_options) # 配置jinjia2
        self.jinja_env.globals.update(
            url_for=url_for,
            get_flashed_messages=get_flashed_messages
        )

    def create_jinja_loader(self): # 添加jinja2的载入,默认是`templates`
        if pkg_resources is None:
            return FileSystemLoader(os.path.join(self.root_path, 'templates'))
        return PackageLoader(self.package_name)

    def update_template_context(self, context): #更新template 上下文
        reqctx = _request_ctx_stack.top
        for func in self.template_context_processors:
            context.update(func())

    def run(self, host='localhost', port=5000, **options):
        from werkzeug import run_simple
        if 'debug' in options:
            self.debug = options.pop('debug')
        options.setdefault('use_reloader', self.debug)
        options.setdefault('use_debugger', self.debug)
        return run_simple(host, port, self, **options)

    def test_client(self): # 创建一个客户端,主要用来测试
        from werkzeug import Client
        return Client(self, self.response_class, use_cookies=True)

    def open_resource(self, resource): # 打开一个源文件,主要是用来测试
        if pkg_resources is None:
            return open(os.path.join(self.root_path, resource), 'rb')
        return pkg_resources.resource_stream(self.package_name, resource)

    def open_session(self, request): # 会话,通过cookie来实现
        key = self.secret_key
        if key is not None:
            return SecureCookie.load_cookie(request, self.session_cookie_name,
                                            secret_key=key)
    def save_session(self, session, response):
        if session is not None:
            session.save_cookie(response, self.session_cookie_name)


	# 处理请求
    def add_url_rule(self, rule, endpoint, **options): # 添加URL_RULE
        options['endpoint'] = endpoint
        options.setdefault('methods', ('GET',))
        self.url_map.add(Rule(rule, **options))

    def route(self, rule, **options): # 路由处理
        def decorator(f):
            self.add_url_rule(rule, f.__name__, **options) # 给url起名字
            self.view_functions[f.__name__] = f # 给view_function起相同的名字
            return f
        return decorator

    def errorhandler(self, code):
        def decorator(f):
            self.error_handlers[code] = f
            return f
        return decorator

    def before_request(self, f):
        self.before_request_funcs.append(f)
        return f

    def after_request(self, f):
        self.after_request_funcs.append(f)
        return f

    def context_processor(self, f): # 添加context_processors
        self.template_context_processors.append(f)
        return f

    def match_request(self):
        rv = _request_ctx_stack.top.url_adapter.match() # 通过调用rule.match(path, method))从而返回rule的endpoint
        request.endpoint, request.view_args = rv # 将值赋值给request,request是代买最下面的localproxy
        return rv

    def dispatch_request(self):
        try:
            endpoint, values = self.match_request() # 根据url获得endpoint和values
            return self.view_functions[endpoint](**values) # 调用相应的方法
        except HTTPException, e: # 如果错误则传入handler
            handler = self.error_handlers.get(e.code)
            if handler is None:
                return e
            return handler(e)
        except Exception, e:
            handler = self.error_handlers.get(500)
            if self.debug or handler is None:
                raise
            return handler(e)

    def make_response(self, rv): # 返回内容
        if isinstance(rv, self.response_class):
            return rv
        if isinstance(rv, basestring):
            return self.response_class(rv)
        if isinstance(rv, tuple):
            return self.response_class(*rv)
        return self.response_class.force_type(rv, request.environ)

    def preprocess_request(self): # 对请求进行预处理,如果最后rv不为空,则返回(有可能经过预处理rv就没了,比如说拦截)
        for func in self.before_request_funcs: # 调用预处理函数,是个列表 before_request_funcs
            rv = func()
            if rv is not None:
                return rv

    def process_response(self, response):
        session = _request_ctx_stack.top.session
        if session is not None:
            self.save_session(session, response)
        for handler in self.after_request_funcs:
            response = handler(response)
        return response

    def wsgi_app(self, environ, start_response): # 真实的WSGI application,在__call__中调用
        with self.request_context(environ):
            rv = self.preprocess_request() # 首先调用预处理请求函数
            if rv is None: # 如果预处理后,返回为None,??
                rv = self.dispatch_request() # 这时可能返回字符串,也可能是responseclass
            response = self.make_response(rv) # 进一步处理,比如如果是
            response = self.process_response(response) # 保存session
            return response(environ, start_response)

    def request_context(self, environ):
        return _RequestContext(self, environ)

    def test_request_context(self, *args, **kwargs):
        return self.request_context(create_environ(*args, **kwargs))

    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

# context locals
_request_ctx_stack = LocalStack()
current_app = LocalProxy(lambda: _request_ctx_stack.top.app)
request = LocalProxy(lambda: _request_ctx_stack.top.request)
session = LocalProxy(lambda: _request_ctx_stack.top.session)
g = LocalProxy(lambda: _request_ctx_stack.top.g)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值