コード例 #1
0
def run(history, statement, env={}):
    """
    Evaluates a python statement in a given history and returns the result.
    """
    history.unpicklables = INITIAL_UNPICKLABLES

    # extract the statement to be run
    if not statement:
        return ''

    # the python compiler doesn't like network line endings
    statement = statement.replace('\r\n', '\n')

    # add a couple newlines at the end of the statement. this makes
    # single-line expressions such as 'class Foo: pass' evaluate happily.
    statement += '\n\n'

    # log and compile the statement up front
    try:
        logging.info('Compiling and evaluating:\n%s' % statement)
        compiled = compile(statement, '<string>', 'single')
    except:
        return str(traceback.format_exc())

    # create a dedicated module to be used as this statement's __main__
    statement_module = new.module('__main__')

    # use this request's __builtin__, since it changes on each request.
    # this is needed for import statements, among other things.
    import __builtin__
    statement_module.__builtins__ = __builtin__

    # load the history from the datastore
    history = History()

    # swap in our custom module for __main__. then unpickle the history
    # globals, run the statement, and re-pickle the history globals, all
    # inside it.
    old_main = sys.modules.get('__main__')
    output = StringIO()
    try:
        sys.modules['__main__'] = statement_module
        statement_module.__name__ = '__main__'
        statement_module.__dict__.update(env)

        # re-evaluate the unpicklables
        for code in history.unpicklables:
            exec(code, statement_module.__dict__)

        # re-initialize the globals
        for name, val in history.globals_dict().items():
            try:
                statement_module.__dict__[name] = val
            except:
                msg = 'Dropping %s since it could not be unpickled.\n' % name
                output.write(msg)
                logging.warning(msg + traceback.format_exc())
                history.remove_global(name)

        # run!
        old_globals = dict((key, represent(value))
                           for key, value in statement_module.__dict__.items())
        try:
            old_stdout, old_stderr = sys.stdout, sys.stderr
            try:
                sys.stderr = sys.stdout = output
                locker.acquire()
                exec(compiled, statement_module.__dict__)
            finally:
                locker.release()
                sys.stdout, sys.stderr = old_stdout, old_stderr
        except:
            output.write(str(traceback.format_exc()))
            return output.getvalue()

        # extract the new globals that this statement added
        new_globals = {}
        for name, val in statement_module.__dict__.items():
            if name not in old_globals or represent(val) != old_globals[name]:
                new_globals[name] = val

        if True in [
                isinstance(val, tuple(UNPICKLABLE_TYPES))
                for val in new_globals.values()
        ]:
            # this statement added an unpicklable global. store the statement and
            # the names of all of the globals it added in the unpicklables.
            history.add_unpicklable(statement, new_globals.keys())
            logging.debug('Storing this statement as an unpicklable.')
        else:
            # this statement didn't add any unpicklables. pickle and store the
            # new globals back into the datastore.
            for name, val in new_globals.items():
                if not name.startswith('__'):
                    try:
                        history.set_global(name, val)
                    except (TypeError, pickle.PicklingError) as ex:
                        UNPICKLABLE_TYPES.append(type(val))
                        history.add_unpicklable(statement, new_globals.keys())

    finally:
        sys.modules['__main__'] = old_main
    return output.getvalue()
コード例 #2
0
ファイル: globals.py プロジェクト: BuhtigithuB/web2py
def sorting_dumps(obj, protocol=None):
    file = StringIO()
    SortingPickler(file, protocol).dump(obj)
    return file.getvalue()
コード例 #3
0
ファイル: globals.py プロジェクト: yuyuyuzxy/web2py
def sorting_dumps(obj, protocol=None):
    file = StringIO()
    SortingPickler(file, protocol).dump(obj)
    return file.getvalue()
コード例 #4
0
ファイル: globals.py プロジェクト: yuyuyuzxy/web2py
class Response(Storage):
    """
    Defines the response object and the default values of its members
    response.write(   ) can be used to write in the output html
    """
    def __init__(self):
        Storage.__init__(self)
        self.status = 200
        self.headers = dict()
        self.headers['X-Powered-By'] = 'web2py'
        self.body = StringIO()
        self.session_id = None
        self.cookies = Cookie.SimpleCookie()
        self.postprocessing = []
        self.flash = ''  # used by the default view layout
        self.meta = Storage()  # used by web2py_ajax.html
        self.menu = []  # used by the default view layout
        self.files = []  # used by web2py_ajax.html
        self._vars = None
        self._caller = lambda f: f()
        self._view_environment = None
        self._custom_commit = None
        self._custom_rollback = None
        self.generic_patterns = ['*']
        self.delimiters = ('{{', '}}')
        self.formstyle = 'table3cols'
        self.form_label_separator = ': '

    def write(self, data, escape=True):
        if not escape:
            self.body.write(str(data))
        else:
            # FIXME PY3:
            self.body.write(to_native(xmlescape(data)))

    def render(self, *a, **b):
        from gluon.compileapp import run_view_in
        if len(a) > 2:
            raise SyntaxError(
                'Response.render can be called with two arguments, at most')
        elif len(a) == 2:
            (view, self._vars) = (a[0], a[1])
        elif len(a) == 1 and isinstance(a[0], str):
            (view, self._vars) = (a[0], {})
        elif len(a) == 1 and hasattr(a[0], 'read') and callable(a[0].read):
            (view, self._vars) = (a[0], {})
        elif len(a) == 1 and isinstance(a[0], dict):
            (view, self._vars) = (None, a[0])
        else:
            (view, self._vars) = (None, {})
        self._vars.update(b)
        self._view_environment.update(self._vars)
        if view:
            from gluon._compat import StringIO
            (obody, oview) = (self.body, self.view)
            (self.body, self.view) = (StringIO(), view)
            run_view_in(self._view_environment)
            page = self.body.getvalue()
            self.body.close()
            (self.body, self.view) = (obody, oview)
        else:
            run_view_in(self._view_environment)
            page = self.body.getvalue()
        return page

    def include_meta(self):
        s = "\n"
        for meta in iteritems((self.meta or {})):
            k, v = meta
            if isinstance(v, dict):
                s += '<meta' + ''.join(
                    ' %s="%s"' % (xmlescape(key), to_native(xmlescape(v[key])))
                    for key in v) + ' />\n'
            else:
                s += '<meta name="%s" content="%s" />\n' % (
                    k, to_native(xmlescape(v)))
        self.write(s, escape=False)

    def include_files(self, extensions=None):
        """
        Includes files (usually in the head).
        Can minify and cache local files
        By default, caches in ram for 5 minutes. To change,
        response.cache_includes = (cache_method, time_expire).
        Example: (cache.disk, 60) # caches to disk for 1 minute.
        """
        files = []
        ext_files = []
        has_js = has_css = False
        for item in self.files:
            if isinstance(item, (list, tuple)):
                ext_files.append(item)
                continue
            if extensions and not item.rpartition('.')[2] in extensions:
                continue
            if item in files:
                continue
            if item.endswith('.js'):
                has_js = True
            if item.endswith('.css'):
                has_css = True
            files.append(item)

        if have_minify and ((self.optimize_css and has_css) or
                            (self.optimize_js and has_js)):
            # cache for 5 minutes by default
            key = hashlib.md5(repr(files)).hexdigest()

            cache = self.cache_includes or (current.cache.ram, 60 * 5)

            def call_minify(files=files):
                return minify.minify(files, URL('static', 'temp'),
                                     current.request.folder, self.optimize_css,
                                     self.optimize_js)

            if cache:
                cache_model, time_expire = cache
                files = cache_model('response.files.minified/' + key,
                                    call_minify, time_expire)
            else:
                files = call_minify()

        files.extend(ext_files)
        s = []
        for item in files:
            if isinstance(item, str):
                f = item.lower().split('?')[0]
                ext = f.rpartition('.')[2]
                # if static_version we need also to check for
                # static_version_urls. In that case, the _.x.x.x
                # bit would have already been added by the URL()
                # function
                if self.static_version and not self.static_version_urls:
                    item = item.replace('/static/',
                                        '/static/_%s/' % self.static_version,
                                        1)
                tmpl = template_mapping.get(ext)
                if tmpl:
                    s.append(tmpl % item)
            elif isinstance(item, (list, tuple)):
                f = item[0]
                tmpl = template_mapping.get(f)
                if tmpl:
                    s.append(tmpl % item[1])
        self.write(''.join(s), escape=False)

    def stream(self,
               stream,
               chunk_size=DEFAULT_CHUNK_SIZE,
               request=None,
               attachment=False,
               filename=None):
        """
        If in a controller function::

            return response.stream(file, 100)

        the file content will be streamed at 100 bytes at the time

        Args:
            stream: filename or read()able content
            chunk_size(int): Buffer size
            request: the request object
            attachment(bool): prepares the correct headers to download the file
                as an attachment. Usually creates a pop-up download window
                on browsers
            filename(str): the name for the attachment

        Note:
            for using the stream name (filename) with attachments
            the option must be explicitly set as function parameter (will
            default to the last request argument otherwise)
        """

        headers = self.headers
        # for attachment settings and backward compatibility
        keys = [item.lower() for item in headers]
        if attachment:
            if filename is None:
                attname = ""
            else:
                attname = filename
            headers["Content-Disposition"] = \
                'attachment;filename="%s"' % attname

        if not request:
            request = current.request
        if isinstance(stream, (str, unicodeT)):
            stream_file_or_304_or_206(stream,
                                      chunk_size=chunk_size,
                                      request=request,
                                      headers=headers,
                                      status=self.status)

        # ## the following is for backward compatibility
        if hasattr(stream, 'name'):
            filename = stream.name

        if filename and not 'content-type' in keys:
            headers['Content-Type'] = contenttype(filename)
        if filename and not 'content-length' in keys:
            try:
                headers['Content-Length'] = \
                    os.path.getsize(filename)
            except OSError:
                pass

        env = request.env
        # Internet Explorer < 9.0 will not allow downloads over SSL unless caching is enabled
        if request.is_https and isinstance(env.http_user_agent, str) and \
                not re.search(r'Opera', env.http_user_agent) and \
                re.search(r'MSIE [5-8][^0-9]', env.http_user_agent):
            headers['Pragma'] = 'cache'
            headers['Cache-Control'] = 'private'

        if request and env.web2py_use_wsgi_file_wrapper:
            wrapped = env.wsgi_file_wrapper(stream, chunk_size)
        else:
            wrapped = streamer(stream, chunk_size=chunk_size)
        return wrapped

    def download(self,
                 request,
                 db,
                 chunk_size=DEFAULT_CHUNK_SIZE,
                 attachment=True,
                 download_filename=None):
        """
        Example of usage in controller::

            def download():
                return response.download(request, db)

        Downloads from http://..../download/filename
        """
        from pydal.exceptions import NotAuthorizedException, NotFoundException

        current.session.forget(current.response)

        if not request.args:
            raise HTTP(404)
        name = request.args[-1]
        items = re.compile('(?P<table>.*?)\.(?P<field>.*?)\..*').match(name)
        if not items:
            raise HTTP(404)
        (t, f) = (items.group('table'), items.group('field'))
        try:
            field = db[t][f]
        except AttributeError:
            raise HTTP(404)
        try:
            (filename, stream) = field.retrieve(name, nameonly=True)
        except NotAuthorizedException:
            raise HTTP(403)
        except NotFoundException:
            raise HTTP(404)
        except IOError:
            raise HTTP(404)
        headers = self.headers
        headers['Content-Type'] = contenttype(name)
        if download_filename is None:
            download_filename = filename
        if attachment:
            headers['Content-Disposition'] = \
                'attachment; filename="%s"' % download_filename.replace('"', '\"')
        return self.stream(stream, chunk_size=chunk_size, request=request)

    def json(self, data, default=None, indent=None):
        if 'Content-Type' not in self.headers:
            self.headers['Content-Type'] = 'application/json'
        return json(data, default=default or custom_json, indent=indent)

    def xmlrpc(self, request, methods):
        from gluon.xmlrpc import handler
        """
        assuming::

            def add(a, b):
                return a+b

        if a controller function \"func\"::

            return response.xmlrpc(request, [add])

        the controller will be able to handle xmlrpc requests for
        the add function. Example::

            import xmlrpclib
            connection = xmlrpclib.ServerProxy(
                'http://hostname/app/contr/func')
            print(connection.add(3, 4))

        """

        return handler(request, self, methods)

    def toolbar(self):
        from gluon.html import DIV, SCRIPT, BEAUTIFY, TAG, A
        BUTTON = TAG.button
        admin = URL("admin",
                    "default",
                    "design",
                    extension='html',
                    args=current.request.application)
        from gluon.dal import DAL
        dbstats = []
        dbtables = {}
        infos = DAL.get_instances()
        for k, v in iteritems(infos):
            dbstats.append(
                TABLE(*[
                    TR(PRE(row[0]), '%.2fms' % (row[1] * 1000))
                    for row in v['dbstats']
                ]))
            dbtables[k] = dict(defined=v['dbtables']['defined']
                               or '[no defined tables]',
                               lazy=v['dbtables']['lazy']
                               or '[no lazy tables]')
        u = web2py_uuid()
        backtotop = A('Back to top', _href="#totop-%s" % u)
        # Convert lazy request.vars from property to Storage so they
        # will be displayed in the toolbar.
        request = copy.copy(current.request)
        request.update(vars=current.request.vars,
                       get_vars=current.request.get_vars,
                       post_vars=current.request.post_vars)
        return DIV(BUTTON('design', _onclick="document.location='%s'" % admin),
                   BUTTON('request',
                          _onclick="jQuery('#request-%s').slideToggle()" % u),
                   BUTTON('response',
                          _onclick="jQuery('#response-%s').slideToggle()" % u),
                   BUTTON('session',
                          _onclick="jQuery('#session-%s').slideToggle()" % u),
                   BUTTON('db tables',
                          _onclick="jQuery('#db-tables-%s').slideToggle()" %
                          u),
                   BUTTON('db stats',
                          _onclick="jQuery('#db-stats-%s').slideToggle()" % u),
                   DIV(BEAUTIFY(request),
                       backtotop,
                       _class="w2p-toolbar-hidden",
                       _id="request-%s" % u),
                   DIV(BEAUTIFY(current.session),
                       backtotop,
                       _class="w2p-toolbar-hidden",
                       _id="session-%s" % u),
                   DIV(BEAUTIFY(current.response),
                       backtotop,
                       _class="w2p-toolbar-hidden",
                       _id="response-%s" % u),
                   DIV(BEAUTIFY(dbtables),
                       backtotop,
                       _class="w2p-toolbar-hidden",
                       _id="db-tables-%s" % u),
                   DIV(BEAUTIFY(dbstats),
                       backtotop,
                       _class="w2p-toolbar-hidden",
                       _id="db-stats-%s" % u),
                   SCRIPT("jQuery('.w2p-toolbar-hidden').hide()"),
                   _id="totop-%s" % u)
コード例 #5
0
ファイル: globals.py プロジェクト: austin-taylor/web2py
class Response(Storage):

    """
    Defines the response object and the default values of its members
    response.write(   ) can be used to write in the output html
    """

    def __init__(self):
        Storage.__init__(self)
        self.status = 200
        self.headers = dict()
        self.headers['X-Powered-By'] = 'web2py'
        self.body = StringIO()
        self.session_id = None
        self.cookies = Cookie.SimpleCookie()
        self.postprocessing = []
        self.flash = ''            # used by the default view layout
        self.meta = Storage()      # used by web2py_ajax.html
        self.menu = []             # used by the default view layout
        self.files = []            # used by web2py_ajax.html
        self._vars = None
        self._caller = lambda f: f()
        self._view_environment = None
        self._custom_commit = None
        self._custom_rollback = None
        self.generic_patterns = ['*']
        self.delimiters = ('{{', '}}')
        self.formstyle = 'table3cols'
        self.form_label_separator = ': '

    def write(self, data, escape=True):
        if not escape:
            self.body.write(str(data))
        else:
            # FIXME PY3:
            self.body.write(to_native(xmlescape(data)))

    def render(self, *a, **b):
        from gluon.compileapp import run_view_in
        if len(a) > 2:
            raise SyntaxError(
                'Response.render can be called with two arguments, at most')
        elif len(a) == 2:
            (view, self._vars) = (a[0], a[1])
        elif len(a) == 1 and isinstance(a[0], str):
            (view, self._vars) = (a[0], {})
        elif len(a) == 1 and hasattr(a[0], 'read') and callable(a[0].read):
            (view, self._vars) = (a[0], {})
        elif len(a) == 1 and isinstance(a[0], dict):
            (view, self._vars) = (None, a[0])
        else:
            (view, self._vars) = (None, {})
        self._vars.update(b)
        self._view_environment.update(self._vars)
        if view:
            from gluon._compat import StringIO
            (obody, oview) = (self.body, self.view)
            (self.body, self.view) = (StringIO(), view)
            run_view_in(self._view_environment)
            page = self.body.getvalue()
            self.body.close()
            (self.body, self.view) = (obody, oview)
        else:
            run_view_in(self._view_environment)
            page = self.body.getvalue()
        return page

    def include_meta(self):
        s = "\n"
        for meta in iteritems((self.meta or {})):
            k, v = meta
            if isinstance(v, dict):
                s += '<meta' + ''.join(' %s="%s"' % (xmlescape(key), to_native(xmlescape(v[key]))) for key in v) +' />\n'
            else:
                s += '<meta name="%s" content="%s" />\n' % (k, to_native(xmlescape(v)))
        self.write(s, escape=False)

    def include_files(self, extensions=None):

        """
        Includes files (usually in the head).
        Can minify and cache local files
        By default, caches in ram for 5 minutes. To change,
        response.cache_includes = (cache_method, time_expire).
        Example: (cache.disk, 60) # caches to disk for 1 minute.
        """
        files = []
        ext_files = []
        has_js = has_css = False
        for item in self.files:
            if isinstance(item, (list, tuple)):
                ext_files.append(item)
                continue
            if extensions and not item.rpartition('.')[2] in extensions:
                continue
            if item in files:
                continue
            if item.endswith('.js'):
                has_js = True
            if item.endswith('.css'):
                has_css = True
            files.append(item)

        if have_minify and ((self.optimize_css and has_css) or (self.optimize_js and has_js)):
            # cache for 5 minutes by default
            key = hashlib.md5(repr(files)).hexdigest()

            cache = self.cache_includes or (current.cache.ram, 60 * 5)

            def call_minify(files=files):
                return minify.minify(files,
                                     URL('static', 'temp'),
                                     current.request.folder,
                                     self.optimize_css,
                                     self.optimize_js)
            if cache:
                cache_model, time_expire = cache
                files = cache_model('response.files.minified/' + key,
                                    call_minify,
                                    time_expire)
            else:
                files = call_minify()

        files.extend(ext_files)
        s = []
        for item in files:
            if isinstance(item, str):
                f = item.lower().split('?')[0]
                ext = f.rpartition('.')[2]
                # if static_version we need also to check for
                # static_version_urls. In that case, the _.x.x.x
                # bit would have already been added by the URL()
                # function
                if self.static_version and not self.static_version_urls:
                    item = item.replace(
                        '/static/', '/static/_%s/' % self.static_version, 1)
                tmpl = template_mapping.get(ext)
                if tmpl:
                    s.append(tmpl % item)
            elif isinstance(item, (list, tuple)):
                f = item[0]
                tmpl = template_mapping.get(f)
                if tmpl:
                    s.append(tmpl % item[1])
        self.write(''.join(s), escape=False)

    def stream(self,
               stream,
               chunk_size=DEFAULT_CHUNK_SIZE,
               request=None,
               attachment=False,
               filename=None
               ):
        """
        If in a controller function::

            return response.stream(file, 100)

        the file content will be streamed at 100 bytes at the time

        Args:
            stream: filename or read()able content
            chunk_size(int): Buffer size
            request: the request object
            attachment(bool): prepares the correct headers to download the file
                as an attachment. Usually creates a pop-up download window
                on browsers
            filename(str): the name for the attachment

        Note:
            for using the stream name (filename) with attachments
            the option must be explicitly set as function parameter (will
            default to the last request argument otherwise)
        """

        headers = self.headers
        # for attachment settings and backward compatibility
        keys = [item.lower() for item in headers]
        if attachment:
            if filename is None:
                attname = ""
            else:
                attname = filename
            headers["Content-Disposition"] = \
                'attachment;filename="%s"' % attname

        if not request:
            request = current.request
        if isinstance(stream, (str, unicodeT)):
            stream_file_or_304_or_206(stream,
                                      chunk_size=chunk_size,
                                      request=request,
                                      headers=headers,
                                      status=self.status)

        # ## the following is for backward compatibility
        if hasattr(stream, 'name'):
            filename = stream.name

        if filename and not 'content-type' in keys:
            headers['Content-Type'] = contenttype(filename)
        if filename and not 'content-length' in keys:
            try:
                headers['Content-Length'] = \
                    os.path.getsize(filename)
            except OSError:
                pass

        env = request.env
        # Internet Explorer < 9.0 will not allow downloads over SSL unless caching is enabled
        if request.is_https and isinstance(env.http_user_agent, str) and \
                not re.search(r'Opera', env.http_user_agent) and \
                re.search(r'MSIE [5-8][^0-9]', env.http_user_agent):
            headers['Pragma'] = 'cache'
            headers['Cache-Control'] = 'private'

        if request and env.web2py_use_wsgi_file_wrapper:
            wrapped = env.wsgi_file_wrapper(stream, chunk_size)
        else:
            wrapped = streamer(stream, chunk_size=chunk_size)
        return wrapped

    def download(self, request, db, chunk_size=DEFAULT_CHUNK_SIZE, attachment=True, download_filename=None):
        """
        Example of usage in controller::

            def download():
                return response.download(request, db)

        Downloads from http://..../download/filename
        """
        from pydal.exceptions import NotAuthorizedException, NotFoundException

        current.session.forget(current.response)

        if not request.args:
            raise HTTP(404)
        name = request.args[-1]
        items = re.compile('(?P<table>.*?)\.(?P<field>.*?)\..*').match(name)
        if not items:
            raise HTTP(404)
        (t, f) = (items.group('table'), items.group('field'))
        try:
            field = db[t][f]
        except AttributeError:
            raise HTTP(404)
        try:
            (filename, stream) = field.retrieve(name, nameonly=True)
        except NotAuthorizedException:
            raise HTTP(403)
        except NotFoundException:
            raise HTTP(404)
        except IOError:
            raise HTTP(404)
        headers = self.headers
        headers['Content-Type'] = contenttype(name)
        if download_filename is None:
            download_filename = filename
        if attachment:
            headers['Content-Disposition'] = \
                'attachment; filename="%s"' % download_filename.replace('"', '\"')
        return self.stream(stream, chunk_size=chunk_size, request=request)

    def json(self, data, default=None, indent=None):
        if 'Content-Type' not in self.headers:
            self.headers['Content-Type'] = 'application/json'
        return json(data, default=default or custom_json, indent=indent)

    def xmlrpc(self, request, methods):
        from gluon.xmlrpc import handler
        """
        assuming::

            def add(a, b):
                return a+b

        if a controller function \"func\"::

            return response.xmlrpc(request, [add])

        the controller will be able to handle xmlrpc requests for
        the add function. Example::

            import xmlrpclib
            connection = xmlrpclib.ServerProxy(
                'http://hostname/app/contr/func')
            print(connection.add(3, 4))

        """

        return handler(request, self, methods)

    def toolbar(self):
        from gluon.html import DIV, SCRIPT, BEAUTIFY, TAG, A
        BUTTON = TAG.button
        admin = URL("admin", "default", "design", extension='html',
                    args=current.request.application)
        from gluon.dal import DAL
        dbstats = []
        dbtables = {}
        infos = DAL.get_instances()
        for k, v in iteritems(infos):
            dbstats.append(TABLE(*[TR(PRE(row[0]), '%.2fms' % (row[1]*1000))
                                   for row in v['dbstats']]))
            dbtables[k] = dict(defined=v['dbtables']['defined'] or '[no defined tables]',
                               lazy=v['dbtables']['lazy'] or '[no lazy tables]')
        u = web2py_uuid()
        backtotop = A('Back to top', _href="#totop-%s" % u)
        # Convert lazy request.vars from property to Storage so they
        # will be displayed in the toolbar.
        request = copy.copy(current.request)
        request.update(vars=current.request.vars,
                       get_vars=current.request.get_vars,
                       post_vars=current.request.post_vars)
        return DIV(
            BUTTON('design', _onclick="document.location='%s'" % admin),
            BUTTON('request',
                   _onclick="jQuery('#request-%s').slideToggle()" % u),
            BUTTON('response',
                   _onclick="jQuery('#response-%s').slideToggle()" % u),
            BUTTON('session',
                   _onclick="jQuery('#session-%s').slideToggle()" % u),
            BUTTON('db tables',
                   _onclick="jQuery('#db-tables-%s').slideToggle()" % u),
            BUTTON('db stats',
                   _onclick="jQuery('#db-stats-%s').slideToggle()" % u),
            DIV(BEAUTIFY(request), backtotop,
                _class="w2p-toolbar-hidden", _id="request-%s" % u),
            DIV(BEAUTIFY(current.session), backtotop,
                _class="w2p-toolbar-hidden", _id="session-%s" % u),
            DIV(BEAUTIFY(current.response), backtotop,
                _class="w2p-toolbar-hidden", _id="response-%s" % u),
            DIV(BEAUTIFY(dbtables), backtotop,
                _class="w2p-toolbar-hidden", _id="db-tables-%s" % u),
            DIV(BEAUTIFY(dbstats), backtotop,
                _class="w2p-toolbar-hidden", _id="db-stats-%s" % u),
            SCRIPT("jQuery('.w2p-toolbar-hidden').hide()"),
            _id="totop-%s" % u
        )
コード例 #6
0
ファイル: shell.py プロジェクト: BuhtigithuB/web2py
def run(history, statement, env={}):
    """
    Evaluates a python statement in a given history and returns the result.
    """
    history.unpicklables = INITIAL_UNPICKLABLES

    # extract the statement to be run
    if not statement:
        return ''

    # the python compiler doesn't like network line endings
    statement = statement.replace('\r\n', '\n')

    # add a couple newlines at the end of the statement. this makes
    # single-line expressions such as 'class Foo: pass' evaluate happily.
    statement += '\n\n'

    # log and compile the statement up front
    try:
        logging.info('Compiling and evaluating:\n%s' % statement)
        compiled = compile(statement, '<string>', 'single')
    except:
        return str(traceback.format_exc())

    # create a dedicated module to be used as this statement's __main__
    statement_module = new.module('__main__')

    # use this request's __builtin__, since it changes on each request.
    # this is needed for import statements, among other things.
    import __builtin__
    statement_module.__builtins__ = __builtin__

    # load the history from the datastore
    history = History()

    # swap in our custom module for __main__. then unpickle the history
    # globals, run the statement, and re-pickle the history globals, all
    # inside it.
    old_main = sys.modules.get('__main__')
    output = StringIO()
    try:
        sys.modules['__main__'] = statement_module
        statement_module.__name__ = '__main__'
        statement_module.__dict__.update(env)

        # re-evaluate the unpicklables
        for code in history.unpicklables:
            exec(code, statement_module.__dict__)

        # re-initialize the globals
        for name, val in history.globals_dict().items():
            try:
                statement_module.__dict__[name] = val
            except:
                msg = 'Dropping %s since it could not be unpickled.\n' % name
                output.write(msg)
                logging.warning(msg + traceback.format_exc())
                history.remove_global(name)

        # run!
        old_globals = dict((key, represent(
            value)) for key, value in statement_module.__dict__.items())
        try:
            old_stdout, old_stderr = sys.stdout, sys.stderr
            try:
                sys.stderr = sys.stdout = output
                locker.acquire()
                exec(compiled, statement_module.__dict__)
            finally:
                locker.release()
                sys.stdout, sys.stderr = old_stdout, old_stderr
        except:
            output.write(str(traceback.format_exc()))
            return output.getvalue()

        # extract the new globals that this statement added
        new_globals = {}
        for name, val in statement_module.__dict__.items():
            if name not in old_globals or represent(val) != old_globals[name]:
                new_globals[name] = val

        if True in [isinstance(val, tuple(UNPICKLABLE_TYPES))
                    for val in new_globals.values()]:
            # this statement added an unpicklable global. store the statement and
            # the names of all of the globals it added in the unpicklables.
            history.add_unpicklable(statement, new_globals.keys())
            logging.debug('Storing this statement as an unpicklable.')
        else:
            # this statement didn't add any unpicklables. pickle and store the
            # new globals back into the datastore.
            for name, val in new_globals.items():
                if not name.startswith('__'):
                    try:
                        history.set_global(name, val)
                    except (TypeError, pickle.PicklingError) as ex:
                        UNPICKLABLE_TYPES.append(type(val))
                        history.add_unpicklable(statement, new_globals.keys())

    finally:
        sys.modules['__main__'] = old_main
    return output.getvalue()