[Python-modules-commits] [webpy] 01/07: Import webpy_0.38+20170615.orig.tar.gz

Wolfgang Borgert debacle at moszumanska.debian.org
Mon Aug 21 22:07:18 UTC 2017


This is an automated email from the git hooks/post-receive script.

debacle pushed a commit to branch master
in repository webpy.

commit 8e5f710ea392ce595b2075b4420f6379da0cefe8
Author: W. Martin Borgert <debacle at debian.org>
Date:   Mon Aug 21 20:53:42 2017 +0200

    Import webpy_0.38+20170615.orig.tar.gz
---
 .gitignore                                     |    7 +-
 .travis.yml                                    |    9 +-
 setup.py                                       |    4 +-
 test/{README => README.md}                     |    0
 test/alltests.py                               |    2 +-
 test/application.py                            |   80 +-
 test/db.py                                     |   32 +-
 test/requirements.txt                          |    4 +-
 test/requirements2.txt                         |    3 +-
 test/session.py                                |   20 +-
 test/template.py                               |   50 +
 test/wsgi.py                                   |   52 +
 tools/makedoc.py                               |    8 +-
 web/__init__.py                                |   30 +-
 web/application.py                             |  143 +-
 web/browser.py                                 |   86 +-
 web/db.py                                      |  161 +-
 web/debugerror.py                              |   28 +-
 web/form.py                                    |   41 +-
 web/http.py                                    |   19 +-
 web/httpserver.py                              |   66 +-
 web/net.py                                     |   80 +-
 web/py3helpers.py                              |   42 +
 web/python23.py                                |   46 -
 web/session.py                                 |   37 +-
 web/template.py                                |  302 ++--
 web/test.py                                    |   25 +-
 web/utils.py                                   |  260 ++-
 web/webapi.py                                  |   41 +-
 web/wsgi.py                                    |   22 +-
 web/wsgiserver/__init__.py                     | 2226 +-----------------------
 web/wsgiserver/ssl_builtin.py                  |   69 +-
 web/wsgiserver/ssl_pyopenssl.py                |  101 +-
 web/wsgiserver/{__init__.py => wsgiserver2.py} | 1208 ++++++++-----
 web/wsgiserver/{__init__.py => wsgiserver3.py} | 1605 +++++++++--------
 35 files changed, 2654 insertions(+), 4255 deletions(-)

diff --git a/.gitignore b/.gitignore
index d0a113f..5a92924 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,7 @@
 *.pyc
-.DS_Store
\ No newline at end of file
+.DS_Store
+build/
+dist/
+docs/_build/
+*.egg-info
+
diff --git a/.travis.yml b/.travis.yml
index f76de70..6053812 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,9 +2,12 @@ language: python
 python:
   - "2.6"
   - "2.7"
-#  - "3.1"
-#  - "3.2"
-install: pip install -r test/requirements.txt --use-mirrors; if [ $TRAVIS_PYTHON_VERSION == 2* ] ; then pip install -r test/requirements2.txt --use-mirrors; fi
+  - "3.5"
+  - "3.6"
+  - "3.7-dev"
+install:
+    - pip install -r test/requirements.txt
+    - if [[ $TRAVIS_PYTHON_VERSION = 2* ]] ; then pip install -r test/requirements2.txt; fi
 script: python test/alltests.py
 before_install:
   - "sudo mkdir -p /usr/include/postgresql/8.4/server"
diff --git a/setup.py b/setup.py
index 62fd74d..5b57043 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,6 @@
 #!/usr/bin/env python
 
-# ...
-
-from distutils.core import setup
+from setuptools import setup
 from web import __version__
 
 setup(name='web.py',
diff --git a/test/README b/test/README.md
similarity index 100%
rename from test/README
rename to test/README.md
diff --git a/test/alltests.py b/test/alltests.py
index 9e2ad75..f0b7d57 100644
--- a/test/alltests.py
+++ b/test/alltests.py
@@ -1,7 +1,7 @@
 import webtest
 
 def suite():
-    modules = ["doctests", "db", "application", "session"]
+    modules = ["doctests", "db", "application", "session", "template", "wsgi"]
     return webtest.suite(modules)
     
 if __name__ == "__main__":
diff --git a/test/application.py b/test/application.py
index e0a7231..bcf3272 100644
--- a/test/application.py
+++ b/test/application.py
@@ -5,6 +5,13 @@ import threading
 import web
 import urllib
 
+try:
+    from urllib.parse import urlencode
+except ImportError:
+    from urllib import urlencode
+
+from web.py3helpers import PY2
+
 data = """
 import web
 
@@ -40,17 +47,17 @@ class ApplicationTest(webtest.TestCase):
         import foo
         app = foo.app
         
-        self.assertEquals(app.request('/').data, 'a')
+        self.assertEquals(app.request('/').data, b'a')
         
         # test class change
         time.sleep(1)
         write('foo.py', data % dict(classname='a', output='b'))
-        self.assertEquals(app.request('/').data, 'b')
+        self.assertEquals(app.request('/').data, b'b')
 
         # test urls change
         time.sleep(1)
         write('foo.py', data % dict(classname='c', output='c'))
-        self.assertEquals(app.request('/').data, 'c')
+        self.assertEquals(app.request('/').data, b'c')
         
     def testUppercaseMethods(self):
         urls = ("/", "hello")
@@ -85,6 +92,20 @@ class ApplicationTest(webtest.TestCase):
         response = app.request('/b/foo?x=2')
         self.assertEquals(response.status, '301 Moved Permanently')
         self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/hello/foo?x=2')
+
+    def test_routing(self):
+        urls = (
+            "/foo", "foo"
+        )
+
+        class foo:
+            def GET(self):
+                return "foo"
+
+        app = web.application(urls, {"foo": foo})
+
+        self.assertEquals(app.request('/foo\n').data, b'not found')
+        self.assertEquals(app.request('/foo').data, b'foo')
         
     def test_subdirs(self):
         urls = (
@@ -104,13 +125,13 @@ class ApplicationTest(webtest.TestCase):
                 return "hello " + path
         app = web.application(urls, locals())
         
-        self.assertEquals(app.request('/blog/foo').data, 'blog foo')
-        self.assertEquals(app.request('/foo').data, 'hello foo')
+        self.assertEquals(app.request('/blog/foo').data, b'blog foo')
+        self.assertEquals(app.request('/foo').data, b'hello foo')
         
         def processor(handler):
             return web.ctx.path + ":" + handler()
         app.add_processor(processor)
-        self.assertEquals(app.request('/blog/foo').data, '/blog/foo:blog foo')
+        self.assertEquals(app.request('/blog/foo').data, b'/blog/foo:blog foo')
     
     def test_subdomains(self):
         def create_app(name):
@@ -131,10 +152,10 @@ class ApplicationTest(webtest.TestCase):
             result = app.request('/', host=host)
             self.assertEquals(result.data, expected_result)
             
-        test('a.example.com', 'a')
-        test('b.example.com', 'b')
-        test('c.example.com', '*')
-        test('d.example.com', '*')
+        test('a.example.com', b'a')
+        test('b.example.com', b'b')
+        test('c.example.com', b'*')
+        test('d.example.com', b'*')
         
     def test_redirect(self):
         urls = (
@@ -216,24 +237,29 @@ class ApplicationTest(webtest.TestCase):
                     return i.file.value
                 else:
                     i = web.input()
-                    return repr(dict(i))
+                    return repr(dict(i)).replace('u','')
                 
         app = web.application(urls, locals())
         
         def f(name):
-            path = '/?' + urllib.urlencode({"name": name.encode('utf-8')})
-            self.assertEquals(app.request(path).data, repr(name))
+            path = '/?' + urlencode({"name": name.encode('utf-8')})
+            self.assertEquals(app.request(path).data.decode('utf-8'), repr(name))
             
         f(u'\u1234')
         f(u'foo')
 
         response = app.request('/', method='POST', data=dict(name='foo'))
-        self.assertEquals(response.data, "{'name': u'foo'}")
+
+        self.assertEquals(response.data, b"{'name': 'foo'}")
+
         
-        data = '--boundary\r\nContent-Disposition: form-data; name="x"\r\nfoo\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="a.txt"\r\nContent-Type: text/plain\r\n\r\na\r\n--boundary--\r\n'
+        data = '--boundary\r\nContent-Disposition: form-data; name="x"\r\n\r\nfoo\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="a.txt"\r\nContent-Type: text/plain\r\n\r\na\r\n--boundary--\r\n'
         headers = {'Content-Type': 'multipart/form-data; boundary=boundary'}
         response = app.request('/multipart', method="POST", data=data, headers=headers)
-        self.assertEquals(response.data, 'a')
+
+
+        self.assertEquals(response.data, b'a')
+
         
     def testCustomNotFound(self):
         urls_a = ("/", "a")
@@ -255,19 +281,19 @@ class ApplicationTest(webtest.TestCase):
             self.assertEquals(response.status.split()[0], "404")
             self.assertEquals(response.data, message)
             
-        assert_notfound("/a/foo", "not found 1")
-        assert_notfound("/b/foo", "not found")
+        assert_notfound("/a/foo", b"not found 1")
+        assert_notfound("/b/foo", b"not found")
         
         app.notfound = lambda: web.HTTPError("404 Not Found", {}, "not found 2")
-        assert_notfound("/a/foo", "not found 1")
-        assert_notfound("/b/foo", "not found 2")
+        assert_notfound("/a/foo", b"not found 1")
+        assert_notfound("/b/foo", b"not found 2")
 
     def testIter(self):
-        self.assertEquals(app.request('/iter').data, 'hello, world')
-        self.assertEquals(app.request('/iter?name=web').data, 'hello, web')
+        self.assertEquals(app.request('/iter').data, b'hello, world')
+        self.assertEquals(app.request('/iter?name=web').data, b'hello, web')
 
-        self.assertEquals(app.request('/iter', method='POST').data, 'hello, world')
-        self.assertEquals(app.request('/iter', method='POST', data='name=web').data, 'hello, web')
+        self.assertEquals(app.request('/iter', method='POST').data, b'hello, world')
+        self.assertEquals(app.request('/iter', method='POST', data='name=web').data, b'hello, web')
 
     def testUnload(self):
         x = web.storage(a=0)
@@ -306,8 +332,10 @@ class ApplicationTest(webtest.TestCase):
         def f(path):
             return app.request(path).data
                 
-        self.assertEquals(f('/?x=2'), '/?x=1')
-        self.assertEquals(f('/?y=1&y=2&x=2'), '/?y=1&y=2&x=1')
+        self.assertEquals(f('/?x=2'), b'/?x=1')
+
+        p = f('/?y=1&y=2&x=2')
+        self.assertTrue(p == b'/?y=1&y=2&x=1' or p == b'/?x=1&y=1&y=2')
         
     def test_setcookie(self):
         urls = (
diff --git a/test/db.py b/test/db.py
index 5fb631c..b480218 100644
--- a/test/db.py
+++ b/test/db.py
@@ -1,7 +1,12 @@
 """DB test"""
+from __future__ import print_function
+
 import webtest
 import web
 
+from web.py3helpers import PY2
+
+
 class DBTest(webtest.TestCase):
     dbname = 'postgres'
     driver = None
@@ -18,9 +23,10 @@ class DBTest(webtest.TestCase):
     def _testable(self):
         try:
             webtest.setup_database(self.dbname, driver=self.driver)
+            print("Running tests for %s" % self.__class__.__name__, file=web.debug)
             return True
-        except ImportError, e:
-            print >> web.debug, str(e), "(ignoring %s)" % self.__class__.__name__
+        except ImportError as e:
+            print(str(e), "(ignoring %s)" % self.__class__.__name__, file=web.debug)
             return False
     
     def testUnicode(self):
@@ -58,12 +64,12 @@ class DBTest(webtest.TestCase):
         except:
             pass
         self.db.select('person')
-        
+
     def testNestedTransactions(self):
         t1 = self.db.transaction()
         self.db.insert('person', False, name='user1')
-        self.assertRows(1)        
-        
+        self.assertRows(1)
+
         t2 = self.db.transaction()
         self.db.insert('person', False, name='user2')
         self.assertRows(2)  
@@ -94,10 +100,11 @@ class DBTest(webtest.TestCase):
         assert db.select("person", where="name='b'").list()
 
     def test_result_is_unicode(self):
+        #TODO : not sure this test has still meaning with Py3
         db = webtest.setup_database(self.dbname)
         self.db.insert('person', False, name='user')
         name = db.select('person')[0].name
-        self.assertEquals(type(name), unicode)
+        self.assertEquals(type(name), unicode if PY2 else str)
 
     def test_result_is_true(self):
         db = webtest.setup_database(self.dbname)
@@ -150,8 +157,9 @@ class SqliteTest(DBTest):
 class SqliteTest_pysqlite2(SqliteTest):
     driver = "pysqlite2.dbapi2"
 
-class MySQLTest(DBTest):
+class MySQLTest_MySQLdb(DBTest):
     dbname = "mysql"
+    driver = "MySQLdb"
     
     def setUp(self):
         self.db = webtest.setup_database(self.dbname)
@@ -162,6 +170,10 @@ class MySQLTest(DBTest):
         # boolean datatype is not suppoted in MySQL (at least until v5.0)
         pass
 
+class MySQLTest_PyMySQL(MySQLTest_MySQLdb):
+    driver="pymysql"
+class MySQLTest_MySQLConnector(MySQLTest_MySQLdb):
+    driver="mysql.connector"
 del DBTest
 
 def is_test(cls):
@@ -169,15 +181,15 @@ def is_test(cls):
     return inspect.isclass(cls) and webtest.TestCase in inspect.getmro(cls)
 
 # ignore db tests when the required db adapter is not found.
-for t in globals().values():
+for t in list(globals().values()):
     if is_test(t) and not t('_testable')._testable():
         del globals()[t.__name__]
 del t
 
 try:
     import DBUtils
-except ImportError, e:
-    print >> web.debug, str(e) + "(ignoring testPooling)"
+except ImportError as e:
+    print(str(e) + "(ignoring testPooling)", file=web.debug)
 
 if __name__ == '__main__':
     webtest.main()
diff --git a/test/requirements.txt b/test/requirements.txt
index 8eae619..0d8de54 100644
--- a/test/requirements.txt
+++ b/test/requirements.txt
@@ -1,4 +1,4 @@
 psycopg2
-MySQL-python
-PyGreSQL
+PyMySQL
+mysql-connector==2.1.4
 DBUtils
diff --git a/test/requirements2.txt b/test/requirements2.txt
index cd3e80b..5c0a295 100644
--- a/test/requirements2.txt
+++ b/test/requirements2.txt
@@ -1,2 +1,3 @@
-pysqlite
+pysqlite; python_version >= '2.7'
 MySQL-python
+PyGreSQL
diff --git a/test/session.py b/test/session.py
index 8e0e92b..7afb6b8 100644
--- a/test/session.py
+++ b/test/session.py
@@ -36,11 +36,11 @@ class SessionTest(webtest.TestCase):
         
     def testSession(self):
         b = self.app.browser() 
-        self.assertEquals(b.open('/count').read(), '1')
-        self.assertEquals(b.open('/count').read(), '2')
-        self.assertEquals(b.open('/count').read(), '3')
+        self.assertEquals(b.open('/count').read(), b'1')
+        self.assertEquals(b.open('/count').read(), b'2')
+        self.assertEquals(b.open('/count').read(), b'3')
         b.open('/reset')
-        self.assertEquals(b.open('/count').read(), '1')
+        self.assertEquals(b.open('/count').read(), b'1')
 
     def testParallelSessions(self):
         b1 = self.app.browser()
@@ -49,23 +49,23 @@ class SessionTest(webtest.TestCase):
         b1.open('/count')
         
         for i in range(1, 10):
-            self.assertEquals(b1.open('/count').read(), str(i+1))
-            self.assertEquals(b2.open('/count').read(), str(i))
+            self.assertEquals(b1.open('/count').read(), str(i+1).encode('utf8'))
+            self.assertEquals(b2.open('/count').read(), str(i).encode('utf8'))
 
     def testBadSessionId(self):
         b = self.app.browser()
-        self.assertEquals(b.open('/count').read(), '1')
-        self.assertEquals(b.open('/count').read(), '2')
+        self.assertEquals(b.open('/count').read(), b'1')
+        self.assertEquals(b.open('/count').read(), b'2')
         
         cookie = b.cookiejar._cookies['0.0.0.0']['/']['webpy_session_id']
         cookie.value = '/etc/password'
-        self.assertEquals(b.open('/count').read(), '1')
+        self.assertEquals(b.open('/count').read(), b'1')
 
     def testRedirect(self):
         b = self.app.browser()
         b.open("/redirect")
         b.open("/session/request_token")
-        assert b.data == '123'
+        self.assertEquals(b.data, b'123')
 
 class DBSessionTest(SessionTest):
     """Session test with db store."""
diff --git a/test/template.py b/test/template.py
new file mode 100644
index 0000000..6fd5352
--- /dev/null
+++ b/test/template.py
@@ -0,0 +1,50 @@
+import webtest
+import web
+from web.template import SecurityError, Template
+from web.py3helpers import PY2
+
+class TestResult:
+    def __init__(self, t):
+        self.t = t
+
+    def __getattr__(self, name):
+        return getattr(self.t, name)
+
+    def __repr__(self):
+        return repr(unicode(self.t) if PY2 else str(self.t))
+
+def t(code, **keywords):
+    tmpl = Template(code, **keywords)
+    return lambda *a, **kw: TestResult(tmpl(*a, **kw))
+
+class TemplateTest(webtest.TestCase):
+    """Tests for the template security feature."""
+
+    def testPrint(self):
+        if PY2:
+            tpl = "$code:\n    print 'blah'"
+            #print_function has been imported from __future__ so the print statement doesn't exist anymore
+            self.assertRaises(SyntaxError, t, tpl) 
+        else:
+            tpl = "$code:\n    print('blah')"
+            self.assertRaises(NameError, t(tpl))
+
+    def testRepr(self):
+        if PY2: #this feature doesn't exist in Py3 anymore
+            tpl = "$code:\n    `1`"
+            self.assertRaises(SecurityError, t, tpl)
+
+    def testAttr(self):
+        tpl = '$code:\n    (lambda x: x+1).func_code'
+        self.assertRaises(SecurityError, t, tpl)
+        
+        tpl = '$def with (a)\n$code:\n    a.b = 3'
+        self.assertRaises(SecurityError, t, tpl)
+
+        #these two should execute themselves flawlessly
+        t("$code:\n    foo = {'a': 1}.items()")()
+        if not PY2:
+            t("$code:\n    bar = {k:0 for k in [1,2,3]}")()
+
+if __name__ == "__main__":
+    webtest.main()
diff --git a/test/wsgi.py b/test/wsgi.py
new file mode 100644
index 0000000..e719159
--- /dev/null
+++ b/test/wsgi.py
@@ -0,0 +1,52 @@
+import webtest, web
+import threading, time
+
+class WSGITest(webtest.TestCase):
+    def test_layers_unicode(self):
+        urls = (
+            '/', 'uni',
+        )
+
+        class uni:
+            def GET(self):
+                return u"\u0C05\u0C06"
+
+        app = web.application(urls, locals())
+
+        thread = threading.Thread(target=app.run)
+        thread.start()
+        time.sleep(0.5)
+
+        b = web.browser.Browser()
+        r = b.open('/').read()
+        s = r.decode('utf8')
+        self.assertEqual(s, u"\u0C05\u0C06")
+
+        app.stop()
+        thread.join()
+
+
+    def test_layers_bytes(self):
+        urls = (
+            '/', 'bytes',
+        )
+
+        class bytes:
+            def GET(self):
+                return b'abcdef'
+
+        app = web.application(urls, locals())
+
+        thread = threading.Thread(target=app.run)
+        thread.start()
+        time.sleep(0.5)
+
+        b = web.browser.Browser()
+        r = b.open('/')
+        self.assertEqual(r.read(), b'abcdef')
+
+        app.stop()
+        thread.join()
+
+if __name__ == '__main__':
+    webtest.main()
diff --git a/tools/makedoc.py b/tools/makedoc.py
index 8573ead..6d002cd 100644
--- a/tools/makedoc.py
+++ b/tools/makedoc.py
@@ -164,8 +164,12 @@ def main(modules=None):
         print '<li><a href="#%(name)s">%(name)s</a></li>' % dict(name=name)
     print '</ul>' 
     for name in modules:
-        mod = __import__(name, {}, {}, 'x')
-        recurse_over(mod, name)
+        try:
+            mod = __import__(name, {}, {}, 'x')
+            recurse_over(mod, name)
+        except ImportError as e:
+            print >> sys.stderr, "Unable to import module %s (Error: %s)" % (name, e)
+            pass
     print '</div>'
         
 if __name__ == '__main__':
diff --git a/web/__init__.py b/web/__init__.py
index 670dacb..2d2f1b6 100644
--- a/web/__init__.py
+++ b/web/__init__.py
@@ -3,7 +3,7 @@
 
 from __future__ import generators
 
-__version__ = "0.38"
+__version__ = "0.40-dev0"
 __author__ = [
     "Aaron Swartz <me at aaronsw.com>",
     "Anand Chitipothu <anandology at gmail.com>"
@@ -11,23 +11,23 @@ __author__ = [
 __license__ = "public domain"
 __contributors__ = "see http://webpy.org/changes"
 
-import utils, db, net, wsgi, http, webapi, httpserver, debugerror
-import template, form
+from . import utils, db, net, wsgi, http, webapi, httpserver, debugerror
+from . import template, form
 
-import session
+from . import session
 
-from utils import *
-from db import *
-from net import *
-from wsgi import *
-from http import *
-from webapi import *
-from httpserver import *
-from debugerror import *
-from application import *
-from browser import *
+from .utils import *
+from .db import *
+from .net import *
+from .wsgi import *
+from .http import *
+from .webapi import *
+from .httpserver import *
+from .debugerror import *
+from .application import *
+#from browser import *
 try:
-    import webopenid as openid
+    from . import webopenid as openid
 except ImportError:
     pass # requires openid module
 
diff --git a/web/application.py b/web/application.py
index f30d322..a85b031 100644
--- a/web/application.py
+++ b/web/application.py
@@ -2,12 +2,14 @@
 Web application
 (from web.py)
 """
-import webapi as web
-import webapi, wsgi, utils
-import debugerror
-import httpserver
-
-from utils import lstrips, safeunicode
+from __future__ import print_function
+
+from . import webapi as web
+from . import webapi, wsgi, utils, browser
+from .debugerror import debugerror
+from . import httpserver
+from .utils import lstrips, safeunicode
+from .py3helpers import iteritems, string_types, is_iter, PY2, text_type
 import sys
 
 import urllib
@@ -15,12 +17,25 @@ import traceback
 import itertools
 import os
 import types
-from exceptions import SystemExit
+from inspect import isclass
+
+import wsgiref.handlers
+
+try:
+    from urllib.parse import splitquery, urlencode, quote, unquote
+except ImportError:
+    from urllib import splitquery, urlencode, quote, unquote
 
 try:
-    import wsgiref.handlers
+    from importlib import reload #Since Py 3.4 reload is in importlib
 except ImportError:
-    pass # don't break people with old Pythons
+    try:
+        from imp import reload #Since Py 3.0 and before 3.4 reload is in imp
+    except ImportError:
+        pass #Before Py 3.0 reload is a global function
+
+from io import BytesIO
+
 
 __all__ = [
     "application", "auto_application",
@@ -39,7 +54,7 @@ class application:
         ...     def GET(self): return "hello"
         >>>
         >>> app.request("/hello").data
-        'hello'
+        b'hello'
     """
     def __init__(self, mapping=(), fvars={}, autoreload=None):
         if autoreload is None:
@@ -131,7 +146,7 @@ class application:
             ...
             >>> app.add_processor(hello)
             >>> app.request("/web.py").data
-            'hello, web.py'
+            b'hello, web.py'
         """
         self.processors.append(processor)
 
@@ -149,7 +164,7 @@ class application:
             ...
             >>> response = app.request("/hello")
             >>> response.data
-            'hello'
+            b'hello'
             >>> response.status
             '200 OK'
             >>> response.headers['Content-Type']
@@ -181,10 +196,10 @@ class application:
             >>> app.request('/ua', headers = {
             ...      'User-Agent': 'a small jumping bean/1.0 (compatible)'
             ... }).data
-            'your user-agent is a small jumping bean/1.0 (compatible)'
+            b'your user-agent is a small jumping bean/1.0 (compatible)'
 
         """
-        path, maybe_query = urllib.splitquery(localpart)
+        path, maybe_query = splitquery(localpart)
         query = maybe_query or ""
         
         if 'env' in kw:
@@ -205,24 +220,27 @@ class application:
 
         if method not in ["HEAD", "GET"]:
             data = data or ''
-            import StringIO
+
             if isinstance(data, dict):
-                q = urllib.urlencode(data)
+                q = urlencode(data)
             else:
                 q = data
-            env['wsgi.input'] = StringIO.StringIO(q)
-            if not env.get('CONTENT_TYPE', '').lower().startswith('multipart/') and 'CONTENT_LENGTH' not in env:
+
+            env['wsgi.input'] = BytesIO(q.encode('utf-8'))
+            if 'CONTENT_LENGTH' not in env:
+            #if not env.get('CONTENT_TYPE', '').lower().startswith('multipart/') and 'CONTENT_LENGTH' not in env:
                 env['CONTENT_LENGTH'] = len(q)
         response = web.storage()
         def start_response(status, headers):
             response.status = status
             response.headers = dict(headers)
             response.header_items = headers
-        response.data = "".join(self.wsgifunc()(env, start_response))
+
+        data = self.wsgifunc()(env, start_response)
+        response.data = b"".join(data)
         return response
 
     def browser(self):
-        import browser
         return browser.AppBrowser(self)
 
     def handle(self):
@@ -242,7 +260,7 @@ class application:
             except (KeyboardInterrupt, SystemExit):
                 raise
             except:
-                print >> web.debug, traceback.format_exc()
+                print(traceback.format_exc(), file=web.debug)
                 raise self.internalerror()
         
         # processors must be applied in the resvere order. (??)
@@ -258,14 +276,12 @@ class application:
             # so we need to do an iteration
             # and save the result for later
             try:
-                firstchunk = iterator.next()
+                firstchunk = next(iterator)
             except StopIteration:
                 firstchunk = ''
 
             return itertools.chain([firstchunk], iterator)    
                                 
-        def is_generator(x): return x and hasattr(x, 'next')
-        
         def wsgi(env, start_resp):
             # clear threadlocal to avoid inteference of previous requests
             self._cleanup()
@@ -277,21 +293,33 @@ class application:
                     raise web.nomethod()
 
                 result = self.handle_with_processors()
-                if is_generator(result):
+                if is_iter(result):
                     result = peep(result)
                 else:
                     result = [result]
-            except web.HTTPError, e:
+            except web.HTTPError as e:
                 result = [e.data]
 
-            result = web.safestr(iter(result))
+            def build_result(result):
+                for r in result:
+                    if PY2:
+                        yield utils.safestr(r)
+                    else:
+                        if isinstance(r, bytes):
+                            yield r
+                        elif isinstance(r, string_types):
+                            yield r.encode('utf-8')
+                        else:
+                            yield str(r).encode('utf-8')
+
+            result = build_result(result)
 
             status, headers = web.ctx.status, web.ctx.headers
             start_resp(status, headers)
             
             def cleanup():
                 self._cleanup()
-                yield '' # force this function to be a generator
+                yield b'' # force this function to be a generator
                             
             return itertools.chain(result, cleanup())
 
@@ -407,7 +435,7 @@ class application:
             ctx.path = lstrips(env.get('REQUEST_URI').split('?')[0], ctx.homepath)
             # Apache and CherryPy webservers unquote the url but lighttpd doesn't. 
             # unquote explicitly for lighttpd to make ctx.path uniform across all servers.
-            ctx.path = urllib.unquote(ctx.path)
+            ctx.path = unquote(ctx.path)
 
         if env.get('QUERY_STRING'):
             ctx.query = '?' + env.get('QUERY_STRING', '')
@@ -416,11 +444,11 @@ class application:
 
         ctx.fullpath = ctx.path + ctx.query
         
-        for k, v in ctx.iteritems():
+        for k, v in iteritems(ctx):
             # convert all string values to unicode values and replace 
             # malformed data with a suitable replacement marker.
-            if isinstance(v, str):
-                ctx[k] = v.decode('utf-8', 'replace') 
+            if isinstance(v, bytes):
+                ctx[k] = v.decode('utf-8', 'replace')
 
         # status must always be str
         ctx.status = '200 OK'
@@ -437,15 +465,13 @@ class application:
             tocall = getattr(cls(), meth)
             return tocall(*args)
             
-        def is_class(o): return isinstance(o, (types.ClassType, type))
-            
         if f is None:
             raise web.notfound()
         elif isinstance(f, application):
             return f.handle_with_processors()
-        elif is_class(f):
+        elif isclass(f):
             return handle_class(f)
-        elif isinstance(f, basestring):
+        elif isinstance(f, string_types):
             if f.startswith('redirect '):
                 url = f.split(' ', 1)[1]
                 if web.ctx.method == "GET":
@@ -473,10 +499,10 @@ class application:
                     return f, None
                 else:
                     continue
-            elif isinstance(what, basestring):
-                what, result = utils.re_subm('^' + pat + '$', what, value)
+            elif isinstance(what, string_types):
+                what, result = utils.re_subm(r'^%s\Z' % (pat,), what, value)
             else:
-                result = utils.re_compile('^' + pat + '$').match(value)
+                result = utils.re_compile(r'^%s\Z' % (pat,)).match(value)
                 
             if result: # it's a match
                 return what, [x for x in result.groups()]
@@ -516,14 +542,22 @@ class application:
         if parent:
             return parent.internalerror()
         elif web.config.get('debug'):
-            import debugerror
-            return debugerror.debugerror()
+            return debugerror()
         else:
             return web._InternalError()
 
+def with_metaclass(mcls):
+    def decorator(cls):
+        body = vars(cls).copy()
+        # clean out class body
+        body.pop('__dict__', None)
+        body.pop('__weakref__', None)
+        return mcls(cls.__name__, cls.__bases__, body)
+    return decorator
+
 class auto_application(application):
     """Application similar to `application` but urls are constructed 
-    automatiacally using metaclass.
+    automatically using metaclass.
 
         >>> app = auto_application()
         >>> class hello(app.page):
@@ -533,9 +567,9 @@ class auto_application(application):
         ...     path = '/foo/.*'
         ...     def GET(self): return "foo"
         >>> app.request("/hello").data
-        'hello, world'
+        b'hello, world'
         >>> app.request('/foo/bar').data
-        'foo'
+        b'foo'
     """
     def __init__(self):
         application.__init__(self)
@@ -550,9 +584,10 @@ class auto_application(application):
                 if path is not None:
                     self.add_mapping(path, klass)
 
-        class page:
+
+        @with_metaclass(metapage) #little hack needed or Py2 and Py3 compatibility
+        class page():
             path = None
-            __metaclass__ = metapage
 
         self.page = page
 
@@ -571,12 +606,12 @@ class subdomain_application(application):
         >>> mapping = (r"hello\.example\.com", app)
         >>> app2 = subdomain_application(mapping)
         >>> app2.request("/hello", host="hello.example.com").data
-        'hello'
+        b'hello'
         >>> response = app2.request("/hello", host="something.example.com")
         >>> response.status
         '404 Not Found'
         >>> response.data
-        'not found'
+        b'not found'
     """
     def handle(self):
         host = web.ctx.host.split(':')[0] #strip port
@@ -585,7 +620,7 @@ class subdomain_application(application):
         
     def _match(self, mapping, value):
         for pat, what in mapping:
-            if isinstance(what, basestring):
+            if isinstance(what, string_types):
                 what, result = utils.re_subm('^' + pat + '$', what, value)
             else:
                 result = utils.re_compile('^' + pat + '$').match(value)
@@ -621,22 +656,22 @@ def unloadhook(h):
     def processor(handler):
         try:
             result = handler()
-            is_generator = result and hasattr(result, 'next')
+            is_gen = is_iter(result)
         except:
             # run the hook even when handler raises some exception
             h()
             raise
 
-        if is_generator:
+        if is_gen:
             return wrap(result)
         else:
             h()
             return result
             
     def wrap(result):
-        def next():
+        def next_hook():
             try:
-                return result.next()
+                return next(result)
             except:
                 # call the hook at the and of iterator
                 h()
@@ -644,7 +679,7 @@ def unloadhook(h):
 
         result = iter(result)
         while True:
-            yield next()
+            yield next_hook()
             
     return processor
 
diff --git a/web/browser.py b/web/browser.py
index 66d859e..18158fb 100644
--- a/web/browser.py
+++ b/web/browser.py
@@ -1,12 +1,41 @@
 """Browser to test web applications.
 (from web.py)
 """
-from utils import re_compile
-from net import htmlunquote
+from .utils import re_compile
... 10719 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/webpy.git



More information about the Python-modules-commits mailing list