Esempio n. 1
0
class IO(object):
    """   """
    def __init__(self):
        """   """

        self.buffer = StringIO()

    def write(self, data):
        """   """

        sys.__stdout__.write(data)
        if hasattr(self, 'callback'):
            self.callback(data)
        else:
            self.buffer.write(data)
Esempio n. 2
0
 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
Esempio n. 3
0
class IO(object):
    """   """

    def __init__(self):
        """   """

        self.buffer = StringIO()

    def write(self, data):
        """   """

        sys.__stdout__.write(data)
        if hasattr(self, 'callback'):
            self.callback(data)
        else:
            self.buffer.write(data)
Esempio n. 4
0
def install(app_name, filename, data, overwrite=True):
    f = StringIO(base64.b64decode(data))
    installed = app_install(app_name,
                            f,
                            request,
                            filename,
                            overwrite=overwrite)

    return installed
Esempio n. 5
0
 def dummy_open(path, mode):
     if path == pjoin('views', 'layout.html'):
         return StringIO("{{block left_sidebar}}left{{end}}"
                         "{{include}}"
                         "{{block right_sidebar}}right{{end}}")
     elif path == pjoin('views', 'layoutbrackets.html'):
         return StringIO("[[block left_sidebar]]left[[end]]"
                         "[[include]]"
                         "[[block right_sidebar]]right[[end]]")
     elif path == pjoin('views', 'default', 'index.html'):
         return StringIO("{{extend 'layout.html'}}"
                         "{{block left_sidebar}}{{super}} {{end}}"
                         "to"
                         "{{block right_sidebar}} {{super}}{{end}}")
     elif path == pjoin('views', 'default', 'indexbrackets.html'):
         return StringIO("[[extend 'layoutbrackets.html']]"
                         "[[block left_sidebar]][[super]] [[end]]"
                         "to"
                         "[[block right_sidebar]] [[super]][[end]]")
     elif path == pjoin('views', 'default', 'missing.html'):
         return StringIO("{{extend 'wut'}}"
                         "{{block left_sidebar}}{{super}} {{end}}"
                         "to"
                         "{{block right_sidebar}} {{super}}{{end}}")
     elif path == pjoin('views', 'default', 'noescape.html'):
         return StringIO("""{{=NOESCAPE('<script></script>')}}""")
     raise IOError
Esempio n. 6
0
 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 = ': '
Esempio n. 7
0
 def b64pack(app):
     """
     Given an app's name, return the base64 representation of its packed version.
     """
     folder = apath(app, r=request)
     tmpfile = StringIO()
     tar = tarfile.TarFile(fileobj=tmpfile, mode='w')
     try:
         filenames = listdir(
             folder,
             '^[\w\.\-]+$',
             add_dirs=True,
             exclude_content_from=['cache', 'sessions', 'errors'])
         for fname in filenames:
             tar.add(os.path.join(folder, fname), fname, False)
     finally:
         tar.close()
     tmpfile.seek(0)
     gzfile = StringIO()
     w2pfp = gzip.GzipFile(fileobj=gzfile, mode='wb')
     w2pfp.write(tmpfile.read())
     w2pfp.close()
     gzfile.seek(0)
     return base64.b64encode(gzfile.read())
Esempio n. 8
0
def copystream_progress(request, chunk_size=10**5):
    """
    Copies request.env.wsgi_input into request.body
    and stores progress upload status in cache_ram
    X-Progress-ID:length and X-Progress-ID:uploaded
    """
    env = request.env
    if not env.get('CONTENT_LENGTH', None):
        return StringIO()
    source = env['wsgi.input']
    try:
        size = int(env['CONTENT_LENGTH'])
    except ValueError:
        raise HTTP(400, "Invalid Content-Length header")
    try:  # Android requires this
        dest = tempfile.NamedTemporaryFile()
    except NotImplementedError:  # and GAE this
        dest = tempfile.TemporaryFile()
    if not 'X-Progress-ID' in request.get_vars:
        copystream(source, dest, size, chunk_size)
        return dest
    cache_key = 'X-Progress-ID:' + request.get_vars['X-Progress-ID']
    cache_ram = CacheInRam(request)  # same as cache.ram because meta_storage
    cache_ram(cache_key + ':length', lambda: size, 0)
    cache_ram(cache_key + ':uploaded', lambda: 0, 0)
    while size > 0:
        if size < chunk_size:
            data = source.read(size)
            cache_ram.increment(cache_key + ':uploaded', size)
        else:
            data = source.read(chunk_size)
            cache_ram.increment(cache_key + ':uploaded', chunk_size)
        length = len(data)
        if length > size:
            (data, length) = (data[:size], size)
        size -= length
        if length == 0:
            break
        dest.write(data)
        if length < chunk_size:
            break
    dest.seek(0)
    cache_ram(cache_key + ':length', None)
    cache_ram(cache_key + ':uploaded', None)
    return dest
Esempio n. 9
0
 def b64pack(app):
     """
     Given an app's name, return the base64 representation of its packed version.
     """
     folder = apath(app, r=request)
     tmpfile = StringIO()
     tar = tarfile.TarFile(fileobj=tmpfile, mode='w')
     try:
         filenames = listdir(folder, '^[\w\.\-]+$', add_dirs=True, 
                             exclude_content_from=['cache', 'sessions', 'errors'])
         for fname in filenames:
             tar.add(os.path.join(folder, fname), fname, False)
     finally:
         tar.close()
     tmpfile.seek(0)
     gzfile = StringIO()
     w2pfp = gzip.GzipFile(fileobj=gzfile, mode='wb')
     w2pfp.write(tmpfile.read())
     w2pfp.close()
     gzfile.seek(0)
     return base64.b64encode(gzfile.read())
Esempio n. 10
0
 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 = ': '
Esempio n. 11
0
class DummyResponse():
    def __init__(self):
        self.body = StringIO()

    def write(self, data, escape=True):
        if not escape:
            self.body.write(str(data))
        elif hasattr(data, 'xml') and callable(data.xml):
            self.body.write(data.xml())
        else:
            # make it a string
            if not isinstance(data, (str, unicodeT)):
                data = str(data)
            elif isinstance(data, unicodeT):
                data = data.encode('utf8', 'xmlcharrefreplace')
            data = cgi.escape(data, True).replace("'", "&#x27;")
            self.body.write(data)
Esempio n. 12
0
class DummyResponse():
    def __init__(self):
        self.body = StringIO()

    def write(self, data, escape=True):
        if not escape:
            self.body.write(str(data))
        elif hasattr(data, 'xml') and callable(data.xml):
            self.body.write(data.xml())
        else:
            # make it a string
            if not isinstance(data, (str, unicodeT)):
                data = str(data)
            elif isinstance(data, unicodeT):
                data = data.encode('utf8', 'xmlcharrefreplace')
            data = cgi.escape(data, True).replace("'", "&#x27;")
            self.body.write(data)
Esempio n. 13
0
def render(content="hello world",
           stream=None,
           filename=None,
           path=None,
           context={},
           lexers={},
           delimiters=('{{', '}}'),
           writer='response.write'):
    """
    Generic render function

    Args:
        content: default content
        stream: file-like obj to read template from
        filename: where to find template
        path: base path for templates
        context: env
        lexers: custom lexers to use
        delimiters: opening and closing tags
        writer: where to inject the resulting stream

    Example::
        >>> render()
        'hello world'
        >>> render(content='abc')
        'abc'
        >>> render(content="abc'")
        "abc'"
        >>> render(content=''''a"'bc''')
        'a"'bc'
        >>> render(content='a\\nbc')
        'a\\nbc'
        >>> render(content='a"bcd"e')
        'a"bcd"e'
        >>> render(content="'''a\\nc'''")
        "'''a\\nc'''"
        >>> render(content="'''a\\'c'''")
        "'''a\'c'''"
        >>> render(content='{{for i in range(a):}}{{=i}}<br />{{pass}}', context=dict(a=5))
        '0<br />1<br />2<br />3<br />4<br />'
        >>> render(content='{%for i in range(a):%}{%=i%}<br />{%pass%}', context=dict(a=5),delimiters=('{%','%}'))
        '0<br />1<br />2<br />3<br />4<br />'
        >>> render(content="{{='''hello\\nworld'''}}")
        'hello\\nworld'
        >>> render(content='{{for i in range(3):\\n=i\\npass}}')
        '012'

    """
    # here to avoid circular Imports
    try:
        from gluon.globals import Response
    except ImportError:
        # Working standalone. Build a mock Response object.
        Response = DummyResponse

        # Add it to the context so we can use it.
        if not 'NOESCAPE' in context:
            context['NOESCAPE'] = NOESCAPE

    if isinstance(content, unicodeT):
        content = content.encode('utf8')

    # save current response class
    if context and 'response' in context:
        old_response_body = context['response'].body
        context['response'].body = StringIO()
    else:
        old_response_body = None
        context['response'] = Response()

    # If we don't have anything to render, why bother?
    if not content and not stream and not filename:
        raise SyntaxError("Must specify a stream or filename or content")

    # Here for legacy purposes, probably can be reduced to
    # something more simple.
    close_stream = False
    if not stream:
        if filename:
            stream = open(filename, 'rb')
            close_stream = True
        elif content:
            stream = StringIO(to_native(content))

    # Execute the template.
    code = str(
        TemplateParser(stream.read(),
                       context=context,
                       path=path,
                       lexers=lexers,
                       delimiters=delimiters,
                       writer=writer))

    try:
        exec(code, context)
    except Exception:
        # for i,line in enumerate(code.split('\n')): print i,line
        raise

    if close_stream:
        stream.close()

    # Returned the rendered content.
    text = context['response'].body.getvalue()
    if old_response_body is not None:
        context['response'].body = old_response_body
    return text
Esempio n. 14
0
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)
Esempio n. 15
0
    def __init__(self):
        """   """

        self.buffer = StringIO()
Esempio n. 16
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()
Esempio n. 17
0
def sorting_dumps(obj, protocol=None):
    file = StringIO()
    SortingPickler(file, protocol).dump(obj)
    return file.getvalue()
Esempio n. 18
0
 def __init__(self):
     self.body = StringIO()
Esempio n. 19
0
 def __init__(self):
     self.body = StringIO()
Esempio n. 20
0
def render(content="hello world",
           stream=None,
           filename=None,
           path=None,
           context={},
           lexers={},
           delimiters=('{{', '}}'),
           writer='response.write'
           ):
    """
    Generic render function

    Args:
        content: default content
        stream: file-like obj to read template from
        filename: where to find template
        path: base path for templates
        context: env
        lexers: custom lexers to use
        delimiters: opening and closing tags
        writer: where to inject the resulting stream

    Example::
        >>> render()
        'hello world'
        >>> render(content='abc')
        'abc'
        >>> render(content="abc'")
        "abc'"
        >>> render(content=''''a"'bc''')
        'a"'bc'
        >>> render(content='a\\nbc')
        'a\\nbc'
        >>> render(content='a"bcd"e')
        'a"bcd"e'
        >>> render(content="'''a\\nc'''")
        "'''a\\nc'''"
        >>> render(content="'''a\\'c'''")
        "'''a\'c'''"
        >>> render(content='{{for i in range(a):}}{{=i}}<br />{{pass}}', context=dict(a=5))
        '0<br />1<br />2<br />3<br />4<br />'
        >>> render(content='{%for i in range(a):%}{%=i%}<br />{%pass%}', context=dict(a=5),delimiters=('{%','%}'))
        '0<br />1<br />2<br />3<br />4<br />'
        >>> render(content="{{='''hello\\nworld'''}}")
        'hello\\nworld'
        >>> render(content='{{for i in range(3):\\n=i\\npass}}')
        '012'

    """
    # here to avoid circular Imports
    try:
        from gluon.globals import Response
    except ImportError:
        # Working standalone. Build a mock Response object.
        Response = DummyResponse

        # Add it to the context so we can use it.
        if 'NOESCAPE' not in context:
            context['NOESCAPE'] = NOESCAPE

    if isinstance(content, unicodeT):
        content = content.encode('utf8')

    # save current response class
    if context and 'response' in context:
        old_response_body = context['response'].body
        context['response'].body = StringIO()
    else:
        old_response_body = None
        context['response'] = Response()

    # If we don't have anything to render, why bother?
    if not content and not stream and not filename:
        raise SyntaxError("Must specify a stream or filename or content")

    # Here for legacy purposes, probably can be reduced to
    # something more simple.
    close_stream = False
    if not stream:
        if filename:
            stream = open(filename, 'rb')
            close_stream = True
        elif content:
            stream = StringIO(to_native(content))

    # Execute the template.
    code = str(TemplateParser(stream.read(
    ), context=context, path=path, lexers=lexers, delimiters=delimiters, writer=writer))

    try:
        exec(code, context)
    except Exception:
        # for i,line in enumerate(code.split('\n')): print i,line
        raise

    if close_stream:
        stream.close()

    # Returned the rendered content.
    text = context['response'].body.getvalue()
    if old_response_body is not None:
        context['response'].body = old_response_body
    return text
Esempio n. 21
0
def sorting_dumps(obj, protocol=None):
    file = StringIO()
    SortingPickler(file, protocol).dump(obj)
    return file.getvalue()
Esempio n. 22
0
    def __init__(self):
        """   """

        self.buffer = StringIO()
Esempio n. 23
0
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:
            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)
            page = run_view_in(self._view_environment)
            self.body.close()
            (self.body, self.view) = (obody, oview)
        else:
            page = run_view_in(self._view_environment)
        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"' % (to_native(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.
        """
        app = current.request.application

        # We start by building a files list in which adjacent files internal to
        # the application are placed in a list inside the files list.
        #
        # We will only minify and concat adjacent internal files as there's
        # no way to know if changing the order with which the files are apppended
        # will break things since the order matters in both CSS and JS and 
        # internal files may be interleaved with external ones.
        files = []
        # For the adjacent list we're going to use storage List to both distinguish
        # from the regular list and so we can add attributes
        internal = List()  
        internal.has_js = False
        internal.has_css = False
        done = set() # to remove duplicates
        for item in self.files:
            if not isinstance(item, list):
                if item in done:
                    continue
                done.add(item)
            if isinstance(item, (list, tuple)) or not item.startswith('/' + app): # also consider items in other web2py applications to be external
                if internal:
                    files.append(internal)
                    internal = List()
                    internal.has_js = False
                    internal.has_css = False
                files.append(item)
                continue
            if extensions and not item.rpartition('.')[2] in extensions:
                continue
            internal.append(item)
            if item.endswith('.js'):
                internal.has_js = True
            if item.endswith('.css'):
                internal.has_css = True            
        if internal:
            files.append(internal)

        # We're done we can now minify
        if have_minify:
            for i, f in enumerate(files):
                if isinstance(f, List) and ((self.optimize_css and f.has_css) or (self.optimize_js and f.has_js)):
                    # cache for 5 minutes by default
                    key = hashlib_md5(repr(f)).hexdigest()
                    cache = self.cache_includes or (current.cache.ram, 60 * 5)
                    def call_minify(files=f):
                        return List(minify.minify(files,
                                             URL('static', 'temp'),
                                             current.request.folder,
                                             self.optimize_css,
                                             self.optimize_js))
                    if cache:
                        cache_model, time_expire = cache
                        files[i] = cache_model('response.files.minified/' + key,
                                            call_minify,
                                            time_expire)
                    else:
                        files[i] = call_minify()
        
        def static_map(s, item):
            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])

        s = []
        for item in files:
            if isinstance(item, List):
                for f in item:
                    static_map(s, f)
            else:
                static_map(s, item)
        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 'content-type' not in keys:
            headers['Content-Type'] = contenttype(filename)
        if filename and 'content-length' not 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:
            # Browsers still don't have a simple uniform way to have non ascii
            # characters in the filename so for now we are percent encoding it
            if isinstance(download_filename, unicodeT):
                download_filename = download_filename.encode('utf-8')
            download_filename = urllib_quote(download_filename)
            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
        )
Esempio n. 24
0
def console():
    """ Defines the behavior of the console web2py execution """
    import optparse
    import textwrap

    usage = "python web2py.py"

    description = """\
    web2py Web Framework startup script.
    ATTENTION: unless a password is specified (-a 'passwd') web2py will
    attempt to run a GUI. In this case command line options are ignored."""

    description = textwrap.dedent(description)

    parser = optparse.OptionParser(usage, None, optparse.Option,
                                   ProgramVersion)

    parser.description = description

    msg = ('IP address of the server (e.g., 127.0.0.1 or ::1); '
           'Note: This value is ignored when using the \'interfaces\' option.')
    parser.add_option('-i', '--ip', default='127.0.0.1', dest='ip', help=msg)

    parser.add_option('-p',
                      '--port',
                      default='8000',
                      dest='port',
                      type='int',
                      help='port of server (8000)')

    parser.add_option(
        '-G',
        '--GAE',
        default=None,
        dest='gae',
        help="'-G configure' will create app.yaml and gaehandler.py")

    msg = ('password to be used for administration '
           '(use -a "<recycle>" to reuse the last password))')
    parser.add_option('-a',
                      '--password',
                      default='<ask>',
                      dest='password',
                      help=msg)

    parser.add_option('-c',
                      '--ssl_certificate',
                      default='',
                      dest='ssl_certificate',
                      help='file that contains ssl certificate')

    parser.add_option('-k',
                      '--ssl_private_key',
                      default='',
                      dest='ssl_private_key',
                      help='file that contains ssl private key')

    msg = ('Use this file containing the CA certificate to validate X509 '
           'certificates from clients')
    parser.add_option('--ca-cert',
                      action='store',
                      dest='ssl_ca_certificate',
                      default=None,
                      help=msg)

    parser.add_option('-d',
                      '--pid_filename',
                      default='httpserver.pid',
                      dest='pid_filename',
                      help='file to store the pid of the server')

    parser.add_option('-l',
                      '--log_filename',
                      default='httpserver.log',
                      dest='log_filename',
                      help='file to log connections')

    parser.add_option('-n',
                      '--numthreads',
                      default=None,
                      type='int',
                      dest='numthreads',
                      help='number of threads (deprecated)')

    parser.add_option('--minthreads',
                      default=None,
                      type='int',
                      dest='minthreads',
                      help='minimum number of server threads')

    parser.add_option('--maxthreads',
                      default=None,
                      type='int',
                      dest='maxthreads',
                      help='maximum number of server threads')

    parser.add_option('-s',
                      '--server_name',
                      default=socket.gethostname(),
                      dest='server_name',
                      help='server name for the web server')

    msg = 'max number of queued requests when server unavailable'
    parser.add_option('-q',
                      '--request_queue_size',
                      default='5',
                      type='int',
                      dest='request_queue_size',
                      help=msg)

    parser.add_option('-o',
                      '--timeout',
                      default='10',
                      type='int',
                      dest='timeout',
                      help='timeout for individual request (10 seconds)')

    parser.add_option('-z',
                      '--shutdown_timeout',
                      default='5',
                      type='int',
                      dest='shutdown_timeout',
                      help='timeout on shutdown of server (5 seconds)')

    parser.add_option('--socket-timeout',
                      default=5,
                      type='int',
                      dest='socket_timeout',
                      help='timeout for socket (5 second)')

    parser.add_option('-f',
                      '--folder',
                      default=os.getcwd(),
                      dest='folder',
                      help='folder from which to run web2py')

    parser.add_option('-v',
                      '--verbose',
                      action='store_true',
                      dest='verbose',
                      default=False,
                      help='increase --test verbosity')

    parser.add_option('-Q',
                      '--quiet',
                      action='store_true',
                      dest='quiet',
                      default=False,
                      help='disable all output')

    parser.add_option('-e',
                      '--errors_to_console',
                      action='store_true',
                      dest='print_errors',
                      default=False,
                      help='log all errors to console')

    msg = ('set debug output level (0-100, 0 means all, 100 means none; '
           'default is 30)')
    parser.add_option('-D',
                      '--debug',
                      dest='debuglevel',
                      default=30,
                      type='int',
                      help=msg)

    msg = ('run web2py in interactive shell or IPython (if installed) with '
           'specified appname (if app does not exist it will be created). '
           'APPNAME like a/c/f (c,f optional)')
    parser.add_option('-S',
                      '--shell',
                      dest='shell',
                      metavar='APPNAME',
                      help=msg)

    msg = ('run web2py in interactive shell or bpython (if installed) with '
           'specified appname (if app does not exist it will be created).\n'
           'Use combined with --shell')
    parser.add_option('-B',
                      '--bpython',
                      action='store_true',
                      default=False,
                      dest='bpython',
                      help=msg)

    msg = 'only use plain python shell; should be used with --shell option'
    parser.add_option('-P',
                      '--plain',
                      action='store_true',
                      default=False,
                      dest='plain',
                      help=msg)

    msg = ('auto import model files; default is False; should be used '
           'with --shell option')
    parser.add_option('-M',
                      '--import_models',
                      action='store_true',
                      default=False,
                      dest='import_models',
                      help=msg)

    msg = ('run PYTHON_FILE in web2py environment; '
           'should be used with --shell option')
    parser.add_option('-R',
                      '--run',
                      dest='run',
                      metavar='PYTHON_FILE',
                      default='',
                      help=msg)

    msg = ('run scheduled tasks for the specified apps: expects a list of '
           'app names as -K app1,app2,app3 '
           'or a list of app:groups as -K app1:group1:group2,app2:group1 '
           'to override specific group_names. (only strings, no spaces '
           'allowed. Requires a scheduler defined in the models')
    parser.add_option('-K',
                      '--scheduler',
                      dest='scheduler',
                      default=None,
                      help=msg)

    msg = 'run schedulers alongside webserver, needs -K app1 and -a too'
    parser.add_option('-X',
                      '--with-scheduler',
                      action='store_true',
                      default=False,
                      dest='with_scheduler',
                      help=msg)

    msg = ('run doctests in web2py environment; '
           'TEST_PATH like a/c/f (c,f optional)')
    parser.add_option('-T',
                      '--test',
                      dest='test',
                      metavar='TEST_PATH',
                      default=None,
                      help=msg)

    msg = 'trigger a cron run manually; usually invoked from a system crontab'
    parser.add_option('-C',
                      '--cron',
                      action='store_true',
                      dest='extcron',
                      default=False,
                      help=msg)

    msg = 'triggers the use of softcron'
    parser.add_option('--softcron',
                      action='store_true',
                      dest='softcron',
                      default=False,
                      help=msg)

    parser.add_option('-Y',
                      '--run-cron',
                      action='store_true',
                      dest='runcron',
                      default=False,
                      help='start the background cron process')

    parser.add_option('-J',
                      '--cronjob',
                      action='store_true',
                      dest='cronjob',
                      default=False,
                      help='identify cron-initiated command')

    parser.add_option('-L',
                      '--config',
                      dest='config',
                      default='',
                      help='config file')

    parser.add_option('-F',
                      '--profiler',
                      dest='profiler_dir',
                      default=None,
                      help='profiler dir')

    parser.add_option('-t',
                      '--taskbar',
                      action='store_true',
                      dest='taskbar',
                      default=False,
                      help='use web2py gui and run in taskbar (system tray)')

    parser.add_option('',
                      '--nogui',
                      action='store_true',
                      default=False,
                      dest='nogui',
                      help='text-only, no GUI')

    msg = ('should be followed by a list of arguments to be passed to script, '
           'to be used with -S, -A must be the last option')
    parser.add_option('-A',
                      '--args',
                      action='store',
                      dest='args',
                      default=None,
                      help=msg)

    parser.add_option('--no-banner',
                      action='store_true',
                      default=False,
                      dest='nobanner',
                      help='Do not print header banner')

    msg = ('listen on multiple addresses: '
           '"ip1:port1:key1:cert1:ca_cert1;ip2:port2:key2:cert2:ca_cert2;..." '
           '(:key:cert:ca_cert optional; no spaces; IPv6 addresses must be in '
           'square [] brackets)')
    parser.add_option('--interfaces',
                      action='store',
                      dest='interfaces',
                      default=None,
                      help=msg)

    msg = 'runs web2py tests'
    parser.add_option('--run_system_tests',
                      action='store_true',
                      dest='run_system_tests',
                      default=False,
                      help=msg)

    msg = ('adds coverage reporting (needs --run_system_tests), '
           'python 2.7 and the coverage module installed. '
           'You can alter the default path setting the environmental '
           'var "COVERAGE_PROCESS_START". '
           'By default it takes gluon/tests/coverage.ini')
    parser.add_option('--with_coverage',
                      action='store_true',
                      dest='with_coverage',
                      default=False,
                      help=msg)

    if '-A' in sys.argv:
        k = sys.argv.index('-A')
    elif '--args' in sys.argv:
        k = sys.argv.index('--args')
    else:
        k = len(sys.argv)
    sys.argv, other_args = sys.argv[:k], sys.argv[k + 1:]
    (options, args) = parser.parse_args()
    options.args = [options.run] + other_args

    copy_options = copy.deepcopy(options)
    copy_options.password = '******'
    global_settings.cmd_options = copy_options
    global_settings.cmd_args = args

    if options.gae:
        if not os.path.exists('app.yaml'):
            name = raw_input("Your GAE app name: ")
            content = open(os.path.join('examples', 'app.example.yaml'),
                           'rb').read()
            open('app.yaml', 'wb').write(content.replace("yourappname", name))
        else:
            print("app.yaml alreday exists in the web2py folder")
        if not os.path.exists('gaehandler.py'):
            content = open(os.path.join('handlers', 'gaehandler.py'),
                           'rb').read()
            open('gaehandler.py', 'wb').write(content)
        else:
            print("gaehandler.py alreday exists in the web2py folder")
        sys.exit(0)

    try:
        options.ips = list(
            set(  # no duplicates
                [
                    addrinfo[4][0]
                    for addrinfo in getipaddrinfo(socket.getfqdn())
                    if not is_loopback_ip_address(addrinfo=addrinfo)
                ]))
    except socket.gaierror:
        options.ips = []

    if options.run_system_tests:
        run_system_tests(options)

    if options.quiet:
        capture = StringIO()
        sys.stdout = capture
        logger.setLevel(logging.CRITICAL + 1)
    else:
        logger.setLevel(options.debuglevel)

    if options.config[-3:] == '.py':
        options.config = options.config[:-3]

    if options.cronjob:
        global_settings.cronjob = True  # tell the world
        options.plain = True  # cronjobs use a plain shell
        options.nobanner = True
        options.nogui = True

    options.folder = os.path.abspath(options.folder)

    #  accept --interfaces in the form
    #  "ip1:port1:key1:cert1:ca_cert1;[ip2]:port2;ip3:port3:key3:cert3"
    #  (no spaces; optional key:cert indicate SSL)
    if isinstance(options.interfaces, str):
        interfaces = options.interfaces.split(';')
        options.interfaces = []
        for interface in interfaces:
            if interface.startswith('['):  # IPv6
                ip, if_remainder = interface.split(']', 1)
                ip = ip[1:]
                if_remainder = if_remainder[1:].split(':')
                if_remainder[0] = int(if_remainder[0])  # numeric port
                options.interfaces.append(tuple([ip] + if_remainder))
            else:  # IPv4
                interface = interface.split(':')
                interface[1] = int(interface[1])  # numeric port
                options.interfaces.append(tuple(interface))

    #  accepts --scheduler in the form
    #  "app:group1,group2,app2:group1"
    scheduler = []
    options.scheduler_groups = None
    if isinstance(options.scheduler, str):
        if ':' in options.scheduler:
            for opt in options.scheduler.split(','):
                scheduler.append(opt.split(':'))
            options.scheduler = ','.join([app[0] for app in scheduler])
            options.scheduler_groups = scheduler

    if options.numthreads is not None and options.minthreads is None:
        options.minthreads = options.numthreads  # legacy

    create_welcome_w2p()

    if not options.cronjob:
        # If we have the applications package or if we should upgrade
        if not os.path.exists('applications/__init__.py'):
            write_file('applications/__init__.py', '')

    return options, args
Esempio n. 25
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()
Esempio n. 26
0
def start(cron=True):
    """ Starts server and other services """

    # get command line arguments
    (options, args) = console()

    if options.gae:
        # write app.yaml, gaehandler.py, and exit
        if not os.path.exists('app.yaml'):
            name = options.gae
            # for backward compatibility
            if name == 'configure':
                if PY2: input = raw_input
                name = input("Your GAE app name: ")
            content = open(os.path.join('examples', 'app.example.yaml'),
                           'rb').read()
            open('app.yaml', 'wb').write(content.replace("yourappname", name))
        else:
            print("app.yaml alreday exists in the web2py folder")
        if not os.path.exists('gaehandler.py'):
            content = open(os.path.join('handlers', 'gaehandler.py'),
                           'rb').read()
            open('gaehandler.py', 'wb').write(content)
        else:
            print("gaehandler.py alreday exists in the web2py folder")
        return

    create_welcome_w2p()

    if options.run_system_tests:
        # run system test and exit
        run_system_tests(options)

    if options.quiet:
        capture = StringIO()
        sys.stdout = capture
        logger.setLevel(logging.CRITICAL + 1)
    else:
        logger.setLevel(options.debuglevel)

    if not options.nobanner:
        # banner
        print(ProgramName)
        print(ProgramAuthor)
        print(ProgramVersion)
        from pydal.drivers import DRIVERS
        print('Database drivers available: %s' % ', '.join(DRIVERS))

    if options.test:
        # run doctests and exit
        test(options.test, verbose=options.verbose)
        return

    if options.shell:
        # run interactive shell and exit
        if options.folder:
            os.chdir(options.folder)
        sys.argv = [options.run] + options.args
        run(options.shell,
            plain=options.plain,
            bpython=options.bpython,
            import_models=options.import_models,
            startfile=options.run,
            cronjob=options.cronjob)
        return

    if options.extcron:
        # run cron (extcron) and exit
        logger.debug('Starting extcron...')
        global_settings.web2py_crontype = 'external'
        if options.scheduler:
            # run cron for applications listed with --scheduler (-K)
            apps = [
                app.strip() for app in options.scheduler.split(',')
                if check_existent_app(options, app.strip())
            ]
        else:
            apps = None
        extcron = newcron.extcron(options.folder, apps=apps)
        extcron.start()
        extcron.join()
        return

    if options.scheduler and not options.with_scheduler:
        # run schedulers and exit
        try:
            start_schedulers(options)
        except KeyboardInterrupt:
            pass
        return

    if cron and options.runcron:
        if options.softcron:
            print('Using softcron (but this is not very efficient)')
            global_settings.web2py_crontype = 'soft'
        else:
            # start hardcron thread
            logger.debug('Starting hardcron...')
            global_settings.web2py_crontype = 'hard'
            newcron.hardcron(options.folder).start()

    # if no password provided and have Tk library start GUI (when not
    # explicitly disabled), we also need a GUI to put in taskbar (system tray)
    # when requested

    # FIXME: this check should be done first
    if options.taskbar and os.name != 'nt':
        die('taskbar not supported on this platform')

    root = None

    if (not options.nogui and options.password == '<ask>') or options.taskbar:
        try:
            if PY2:
                import Tkinter as tkinter
            else:
                import tkinter
            root = tkinter.Tk()
        except (ImportError, OSError):
            logger.warn(
                'GUI not available because Tk library is not installed')
            options.nogui = True
        except:
            logger.exception('cannot get Tk root window, GUI disabled')
            options.nogui = True

    if root:
        # run GUI and exit
        root.focus_force()

        # Mac OS X - make the GUI window rise to the top
        if os.path.exists("/usr/bin/osascript"):
            applescript = """
tell application "System Events"
    set proc to first process whose unix id is %d
    set frontmost of proc to true
end tell
""" % (os.getpid())
            os.system("/usr/bin/osascript -e '%s'" % applescript)

        # web2pyDialog takes care of schedulers
        master = web2pyDialog(root, options)
        signal.signal(signal.SIGTERM, lambda a, b: master.quit())

        try:
            root.mainloop()
        except:
            master.quit()

        sys.exit()

    if options.password == '<ask>':
        options.password = getpass.getpass('choose a password:'******'no password, disable admin interface')

    spt = None

    if options.scheduler and options.with_scheduler:
        # start schedulers in a separate thread
        spt = threading.Thread(target=start_schedulers, args=(options, ))
        spt.start()

    # start server

    # Use first interface IP and port if interfaces specified, since the
    # interfaces option overrides the IP (and related) options.
    if not options.interfaces:
        ip = options.ip
        port = options.port
    else:
        first_if = options.interfaces[0]
        ip = first_if[0]
        port = first_if[1]

    if options.ssl_certificate or options.ssl_private_key:
        proto = 'https'
    else:
        proto = 'http'

    url = get_url(ip, proto=proto, port=port)

    if not options.nobanner:
        message = '\nplease visit:\n\t%s\n'
        if sys.platform.startswith('win'):
            message += 'use "taskkill /f /pid %i" to shutdown the web2py server\n\n'
        else:
            message += 'use "kill -SIGTERM %i" to shutdown the web2py server\n\n'
        print(message % (url, os.getpid()))

    # enhance linecache.getline (used by debugger) to look at the source file
    # if the line was not found (under py2exe & when file was modified)
    import linecache
    py2exe_getline = linecache.getline

    def getline(filename, lineno, *args, **kwargs):
        line = py2exe_getline(filename, lineno, *args, **kwargs)
        if not line:
            try:
                with open(filename, "rb") as f:
                    for i, line in enumerate(f):
                        line = line.decode('utf-8')
                        if lineno == i + 1:
                            break
                    else:
                        line = ''
            except (IOError, OSError):
                line = ''
        return line

    linecache.getline = getline

    server = main.HttpServer(ip=ip,
                             port=port,
                             password=options.password,
                             pid_filename=options.pid_filename,
                             log_filename=options.log_filename,
                             profiler_dir=options.profiler_dir,
                             ssl_certificate=options.ssl_certificate,
                             ssl_private_key=options.ssl_private_key,
                             ssl_ca_certificate=options.ssl_ca_certificate,
                             min_threads=options.minthreads,
                             max_threads=options.maxthreads,
                             server_name=options.server_name,
                             request_queue_size=options.request_queue_size,
                             timeout=options.timeout,
                             socket_timeout=options.socket_timeout,
                             shutdown_timeout=options.shutdown_timeout,
                             path=options.folder,
                             interfaces=options.interfaces)

    try:
        server.start()
    except KeyboardInterrupt:
        server.stop()
        if spt is not None:
            try:
                spt.join()
            except:
                logger.exception('error terminating schedulers')
                pass
    logging.shutdown()