diff --git a/applications/admin/private/hosts.deny b/applications/admin/private/hosts.deny index 3e4e651c..e69de29b 100644 --- a/applications/admin/private/hosts.deny +++ b/applications/admin/private/hosts.deny @@ -1 +0,0 @@ -127.0.0.1 2 1464635785 diff --git a/gluon/_compat.py b/gluon/_compat.py index aee1f809..982a78f9 100644 --- a/gluon/_compat.py +++ b/gluon/_compat.py @@ -10,6 +10,13 @@ if PY2: import cPickle as pickle from cStringIO import StringIO import copy_reg as copyreg + from HTMLParser import HTMLParser + import urlparse + from htmlentitydefs import entitydefs, name2codepoint + import __builtin__ as builtin + import thread + import Cookie + import urllib2 reduce = reduce hashlib_md5 = hashlib.md5 iterkeys = lambda d: d.iterkeys() @@ -20,6 +27,10 @@ if PY2: text_type = unicode basestring = basestring xrange = xrange + long = long + unichr = unichr + unicodeT = unicode + from string import maketrans def implements_iterator(cls): cls.next = cls.__next__ @@ -49,6 +60,13 @@ else: from io import StringIO import copyreg from functools import reduce + from html.parser import HTMLParser + from http import cookies as Cookie + from urllib import parse as urlparse + from urllib import request as urllib2 + from html.entities import entitydefs, name2codepoint + import builtins as builtin + import _thread as thread hashlib_md5 = lambda s: hashlib.md5(bytes(s, 'utf8')) iterkeys = lambda d: iter(d.keys()) itervalues = lambda d: iter(d.values()) @@ -58,6 +76,10 @@ else: text_type = str basestring = str xrange = range + long = int + unichr = chr + unicodeT = str + maketrans = str.maketrans implements_iterator = _identity implements_bool = _identity diff --git a/gluon/cache.py b/gluon/cache.py index 72bfa422..4990362e 100644 --- a/gluon/cache.py +++ b/gluon/cache.py @@ -20,7 +20,6 @@ caching will be provided by the GAE memcache (see gluon.contrib.gae_memcache) """ import time -import thread import os import gc import sys @@ -41,10 +40,7 @@ try: except ImportError: have_settings = False -try: - import cPickle as pickle -except: - import pickle +from gluon._compat import pickle, thread try: import psutil diff --git a/gluon/cfs.py b/gluon/cfs.py index a63202f9..b8bca354 100644 --- a/gluon/cfs.py +++ b/gluon/cfs.py @@ -14,7 +14,7 @@ Note: """ from os import stat -import thread +from ._compat import thread from gluon.fileutils import read_file cfs = {} # for speed-up diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 6b53ee34..caef15ee 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -18,7 +18,7 @@ import fnmatch import os import copy import random -import __builtin__ +from gluon._compat import builtin from gluon.storage import Storage, List from gluon.template import parse_template from gluon.restricted import restricted, compile2 @@ -43,7 +43,7 @@ import types from functools import reduce logger = logging.getLogger("web2py") from gluon import rewrite -from custom_import import custom_import_install +from gluon.custom_import import custom_import_install try: import py_compile @@ -117,7 +117,7 @@ class mybuiltin(object): #__builtins__ def __getitem__(self, key): try: - return getattr(__builtin__, key) + return getattr(builtin, key) except AttributeError: raise KeyError(key) @@ -431,7 +431,7 @@ def build_environment(request, response, session, store_current=True): elif is_pypy: # apply the same hack to pypy too __builtins__ = mybuiltin() else: - __builtins__['__import__'] = __builtin__.__import__ # WHY? + __builtins__['__import__'] = builtin.__import__ # WHY? environment['request'] = request environment['response'] = response environment['session'] = session diff --git a/gluon/contrib/gateways/fcgi.py b/gluon/contrib/gateways/fcgi.py index 69609696..9cd6fbe6 100644 --- a/gluon/contrib/gateways/fcgi.py +++ b/gluon/contrib/gateways/fcgi.py @@ -436,13 +436,13 @@ def encode_pair(name, value): if nameLength < 128: s = chr(nameLength) else: - s = struct.pack('!L', nameLength | 0x80000000L) + s = struct.pack('!L', nameLength | 0x80000000) valueLength = len(value) if valueLength < 128: s += chr(valueLength) else: - s += struct.pack('!L', valueLength | 0x80000000L) + s += struct.pack('!L', valueLength | 0x80000000) return s + name + value @@ -592,7 +592,7 @@ class Request(object): self._flush() self._end(appStatus, protocolStatus) - def _end(self, appStatus=0L, protocolStatus=FCGI_REQUEST_COMPLETE): + def _end(self, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE): self._conn.end_request(self, appStatus, protocolStatus) def _flush(self): @@ -615,7 +615,7 @@ class CGIRequest(Request): self.stderr = sys.stderr self.data = StringIO.StringIO() - def _end(self, appStatus=0L, protocolStatus=FCGI_REQUEST_COMPLETE): + def _end(self, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE): sys.exit(appStatus) def _flush(self): @@ -714,7 +714,7 @@ class Connection(object): """ rec.write(self._sock) - def end_request(self, req, appStatus=0L, + def end_request(self, req, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE, remove=True): """ End a Request. @@ -763,7 +763,7 @@ class Connection(object): if not self._multiplexed and self._requests: # Can't multiplex requests. - self.end_request(req, 0L, FCGI_CANT_MPX_CONN, remove=False) + self.end_request(req, 0, FCGI_CANT_MPX_CONN, remove=False) else: self._requests[inrec.requestId] = req @@ -854,7 +854,7 @@ class MultiplexedConnection(Connection): finally: self._lock.release() - def end_request(self, req, appStatus=0L, + def end_request(self, req, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE, remove=True): self._lock.acquire() try: diff --git a/gluon/contrib/ipaddr.py b/gluon/contrib/ipaddr.py index 0c851432..cb37ecc2 100644 --- a/gluon/contrib/ipaddr.py +++ b/gluon/contrib/ipaddr.py @@ -1447,7 +1447,7 @@ class _BaseV6(object): try: # Now, parse the hextets into a 128-bit integer. - ip_int = 0L + ip_int = 0 for i in xrange(parts_hi): ip_int <<= 16 ip_int |= self._parse_hextet(parts[i]) diff --git a/gluon/contrib/shell.py b/gluon/contrib/shell.py index c843c0a5..b1c83942 100755 --- a/gluon/contrib/shell.py +++ b/gluon/contrib/shell.py @@ -52,8 +52,7 @@ _HISTORY_KIND = '_Shell_History' # Types that can't be pickled. UNPICKLABLE_TYPES = [ types.ModuleType, - types.TypeType, - types.ClassType, + type, types.FunctionType, ] diff --git a/gluon/custom_import.py b/gluon/custom_import.py index 93e46dd3..9dfb937c 100644 --- a/gluon/custom_import.py +++ b/gluon/custom_import.py @@ -8,22 +8,22 @@ Support for smart import syntax for web2py applications ------------------------------------------------------- """ -import __builtin__ +from gluon._compat import builtin import os import sys import threading from gluon import current -NATIVE_IMPORTER = __builtin__.__import__ +NATIVE_IMPORTER = builtin.__import__ INVALID_MODULES = set(('', 'gluon', 'applications', 'custom_import')) # backward compatibility API def custom_import_install(): - if __builtin__.__import__ == NATIVE_IMPORTER: + if builtin.__import__ == NATIVE_IMPORTER: INVALID_MODULES.update(sys.modules.keys()) - __builtin__.__import__ = custom_importer + builtin.__import__ = custom_importer def track_changes(track=True): @@ -98,7 +98,7 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): try: return NATIVE_IMPORTER(name, globals, locals, fromlist, level) except ImportError as e3: - raise ImportError, e1, import_tb # there an import error in the module + raise ImportError(e1, import_tb) # there an import error in the module except Exception as e2: raise # there is an error in the module finally: diff --git a/gluon/fileutils.py b/gluon/fileutils.py index 0d23feab..84e65365 100644 --- a/gluon/fileutils.py +++ b/gluon/fileutils.py @@ -10,7 +10,7 @@ File operations --------------- """ -import storage +from gluon import storage import os import re import tarfile @@ -18,9 +18,9 @@ import glob import time import datetime import logging -from http import HTTP +from gluon.http import HTTP from gzip import open as gzopen -from recfile import generate +from gluon.recfile import generate __all__ = [ 'parse_version', @@ -449,7 +449,7 @@ def make_fake_file_like_object(): return LogFile() -from settings import global_settings # we need to import settings here because +from gluon.settings import global_settings # we need to import settings here because # settings imports fileutils too diff --git a/gluon/globals.py b/gluon/globals.py index 88a98b8d..cb27b37a 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -13,10 +13,9 @@ Contains the classes for the global used variables: - Session """ - +from gluon._compat import pickle, StringIO, copyreg, Cookie, urlparse, PY2 from gluon.storage import Storage, List from gluon.streamer import streamer, stream_file_or_304_or_206, DEFAULT_CHUNK_SIZE -from gluon.xmlrpc import handler from gluon.contenttype import contenttype from gluon.html import xmlescape, TABLE, TR, PRE, URL from gluon.http import HTTP, redirect @@ -29,24 +28,16 @@ from gluon import recfile from gluon.cache import CacheInRam from gluon.fileutils import copystream import hashlib -import portalocker -try: - import cPickle as pickle -except: - import pickle +from gluon import portalocker from pickle import Pickler, MARK, DICT, EMPTY_DICT -from types import DictionaryType -import cStringIO +#from types import DictionaryType import datetime import re -import copy_reg -import Cookie import os import sys import traceback import threading import cgi -import urlparse import copy import tempfile import json @@ -96,12 +87,14 @@ class SortingPickler(Pickler): self.memoize(obj) self._batch_setitems([(key, obj[key]) for key in sorted(obj)]) -SortingPickler.dispatch = copy.copy(Pickler.dispatch) -SortingPickler.dispatch[DictionaryType] = SortingPickler.save_dict +if PY2: +#FIXME PY3 + SortingPickler.dispatch = copy.copy(Pickler.dispatch) + SortingPickler.dispatch[dict] = SortingPickler.save_dict def sorting_dumps(obj, protocol=None): - file = cStringIO.StringIO() + file = StringIO() SortingPickler(file, protocol).dump(obj) return file.getvalue() # END ##################################################################### @@ -115,7 +108,7 @@ def copystream_progress(request, chunk_size=10 ** 5): """ env = request.env if not env.get('CONTENT_LENGTH', None): - return cStringIO.StringIO() + return StringIO() source = env['wsgi.input'] try: size = int(env['CONTENT_LENGTH']) @@ -399,7 +392,7 @@ class Response(Storage): self.status = 200 self.headers = dict() self.headers['X-Powered-By'] = 'web2py' - self.body = cStringIO.StringIO() + self.body = StringIO() self.session_id = None self.cookies = Cookie.SimpleCookie() self.postprocessing = [] @@ -441,9 +434,9 @@ class Response(Storage): self._vars.update(b) self._view_environment.update(self._vars) if view: - import cStringIO + from .compat import StringIO (obody, oview) = (self.body, self.view) - (self.body, self.view) = (cStringIO.StringIO(), view) + (self.body, self.view) = (StringIO(), view) run_view_in(self._view_environment) page = self.body.getvalue() self.body.close() @@ -655,6 +648,7 @@ class Response(Storage): return json(data, default=default or custom_json) def xmlrpc(self, request, methods): + from gluon.xmlrpc import handler """ assuming:: @@ -671,7 +665,7 @@ class Response(Storage): import xmlrpclib connection = xmlrpclib.ServerProxy( 'http://hostname/app/contr/func') - print connection.add(3, 4) + print(connection.add(3, 4)) """ @@ -1234,4 +1228,4 @@ class Session(Storage): def pickle_session(s): return Session, (dict(s),) -copy_reg.pickle(Session, pickle_session) +copyreg.pickle(Session, pickle_session) diff --git a/gluon/html.py b/gluon/html.py index 6a3608bd..31a1b505 100644 --- a/gluon/html.py +++ b/gluon/html.py @@ -18,20 +18,11 @@ import copy import types import urllib import base64 -import sanitizer +from gluon import sanitizer, decoder import itertools -import decoder -import copy_reg -from functools import reduce -try: - import cPickle as pickle -except: - import pickle +from gluon._compat import reduce, pickle, copyreg, HTMLParser, name2codepoint, iteritems, unichr, unicodeT import marshal -from HTMLParser import HTMLParser -from htmlentitydefs import name2codepoint - from gluon.storage import Storage from gluon.utils import web2py_uuid, simple_hash, compare from gluon.highlight import highlight @@ -42,7 +33,7 @@ regex_crlf = re.compile('\r|\n') join = ''.join # name2codepoint is incomplete respect to xhtml (and xml): 'apos' is missing. -entitydefs = dict(map(lambda k_v: (k_v[0], unichr(k_v[1]).encode('utf-8')), name2codepoint.iteritems())) +entitydefs = dict(map(lambda k_v: (k_v[0], unichr(k_v[1]).encode('utf-8')), iteritems(name2codepoint))) entitydefs.setdefault('apos', u"'".encode('utf-8')) @@ -132,9 +123,9 @@ def xmlescape(data, quote=True): return data.xml() # otherwise, make it a string - if not isinstance(data, (str, unicode)): + if not isinstance(data, (str, unicodeT)): data = str(data) - elif isinstance(data, unicode): + elif isinstance(data, unicodeT): data = data.encode('utf8', 'xmlcharrefreplace') # ... and do the escaping @@ -608,7 +599,7 @@ class XML(XmlComponent): if sanitize: text = sanitizer.sanitize(text, permitted_tags, allowed_attributes) - if isinstance(text, unicode): + if isinstance(text, unicodeT): text = text.encode('utf8', 'xmlcharrefreplace') elif not isinstance(text, str): text = str(text) @@ -675,7 +666,7 @@ def XML_unpickle(data): def XML_pickle(data): return XML_unpickle, (marshal.dumps(str(data)),) -copy_reg.pickle(XML, XML_pickle, XML_unpickle) +copyreg.pickle(XML, XML_pickle, XML_unpickle) class DIV(XmlComponent): @@ -799,7 +790,7 @@ class DIV(XmlComponent): value: the new value """ self._setnode(value) - if isinstance(i, (str, unicode)): + if isinstance(i, (str, unicodeT)): self.attributes[i] = value else: self.components[i] = value @@ -1264,7 +1255,7 @@ class __tag_div__(DIV): DIV.__init__(self, *a, **b) self.tag = name -copy_reg.pickle(__tag_div__, TAG_pickler, TAG_unpickler) +copyreg.pickle(__tag_div__, TAG_pickler, TAG_unpickler) class __TAG__(XmlComponent): @@ -1285,7 +1276,7 @@ class __TAG__(XmlComponent): def __getattr__(self, name): if name[-1:] == '_': name = name[:-1] + '/' - if isinstance(name, unicode): + if isinstance(name, unicodeT): name = name.encode('utf-8') return lambda *a, **b: __tag_div__(name, *a, **b) @@ -2442,7 +2433,7 @@ class BEAUTIFY(DIV): try: keys = (sorter and sorter(c)) or c for key in keys: - if isinstance(key, (str, unicode)) and keyfilter: + if isinstance(key, (str, unicodeT)) and keyfilter: filtered_key = keyfilter(key) else: filtered_key = str(key) @@ -2462,7 +2453,7 @@ class BEAUTIFY(DIV): pass if isinstance(c, str): components.append(str(c)) - elif isinstance(c, unicode): + elif isinstance(c, unicodeT): components.append(c.encode('utf8')) elif isinstance(c, (list, tuple)): items = [TR(TD(BEAUTIFY(item, **attributes))) @@ -2691,7 +2682,7 @@ class web2pyHTMLParser(HTMLParser): self.last = tag.tag[:-1] def handle_data(self, data): - if not isinstance(data, unicode): + if not isinstance(data, unicodeT): try: data = data.decode('utf8') except: diff --git a/gluon/languages.py b/gluon/languages.py index 4be71c0d..6e434c83 100644 --- a/gluon/languages.py +++ b/gluon/languages.py @@ -18,20 +18,17 @@ import pkgutil import logging from cgi import escape from threading import RLock - -try: - import copyreg as copy_reg # python 3 -except ImportError: - import copy_reg # python 2 +from gluon._compat import copyreg, PY2, maketrans from gluon.portalocker import read_locked, LockedFile -from utf8 import Utf8 +from gluon.utf8 import Utf8 from gluon.fileutils import listdir from gluon.cfs import getcfs from gluon.html import XML, xmlescape -from gluon.contrib.markmin.markmin2html import render, markmin_escape -from string import maketrans +if PY2: + # FIXME PY3 + from gluon.contrib.markmin.markmin2html import render, markmin_escape __all__ = ['translator', 'findT', 'update_all_languages'] @@ -53,7 +50,10 @@ DEFAULT_GET_PLURAL_ID = lambda n: 0 # word is unchangeable DEFAULT_CONSTRUCT_PLURAL_FORM = lambda word, plural_id: word -NUMBERS = (int, long, float) +if PY2: + NUMBERS = (int, long, float) +else: + NUMBERS = (int, float) # pattern to find T(blah blah blah) expressions PY_STRING_LITERAL_RE = r'(?<=[^\w]T\()(?P'\ @@ -446,7 +446,7 @@ class lazyT(object): def pickle_lazyT(c): return str, (c.xml(),) -copy_reg.pickle(lazyT, pickle_lazyT) +copyreg.pickle(lazyT, pickle_lazyT) class translator(object): diff --git a/gluon/main.py b/gluon/main.py index 0bf22a3d..d7a977c9 100644 --- a/gluon/main.py +++ b/gluon/main.py @@ -13,7 +13,7 @@ from __future__ import print_function if False: import import_all # DO NOT REMOVE PART OF FREEZE PROCESS import gc -import Cookie + import os import re import copy @@ -23,11 +23,10 @@ import datetime import signal import socket import random -import urllib2 import string - -from thread import allocate_lock +from gluon._compat import Cookie, urllib2 +#from thread import allocate_lock from gluon.fileutils import abspath, write_file from gluon.settings import global_settings @@ -710,9 +709,9 @@ class HttpServer(object): # if interfaces is specified, it must be tested for rocket parameter correctness # not necessarily completely tested (e.g. content of tuples or ip-format) import types - if isinstance(interfaces, types.ListType): + if isinstance(interfaces, list): for i in interfaces: - if not isinstance(i, types.TupleType): + if not isinstance(i, tuple): raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" else: raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" diff --git a/gluon/restricted.py b/gluon/restricted.py index e0d5d3a9..2ce87062 100644 --- a/gluon/restricted.py +++ b/gluon/restricted.py @@ -10,10 +10,7 @@ Restricted environment to execute application's code """ import sys -try: - import cPickle as pickle -except: - import pickle +from gluon._compat import pickle import traceback import types import os @@ -224,7 +221,7 @@ def restricted(code, environment=None, layer='Unknown'): ccode = code else: ccode = compile2(code, layer) - exec ccode in environment + exec (ccode) in environment except HTTP: raise except RestrictedError: @@ -252,7 +249,7 @@ def snapshot(info=None, context=5, code=None, environment=None): # if no exception info given, get current: etype, evalue, etb = info or sys.exc_info() - if isinstance(etype, types.ClassType): + if isinstance(etype, type): etype = etype.__name__ # create a snapshot dict with some basic information diff --git a/gluon/sanitizer.py b/gluon/sanitizer.py index c0e6f38f..147378bf 100644 --- a/gluon/sanitizer.py +++ b/gluon/sanitizer.py @@ -10,11 +10,9 @@ Cross-site scripting (XSS) defense ----------------------------------- """ -from HTMLParser import HTMLParser +from ._compat import HTMLParser, urlparse, entitydefs from cgi import escape -from urlparse import urlparse from formatter import AbstractFormatter -from htmlentitydefs import entitydefs from xml.sax.saxutils import quoteattr __all__ = ['sanitize'] diff --git a/gluon/serializers.py b/gluon/serializers.py index a6781958..9cd304ff 100644 --- a/gluon/serializers.py +++ b/gluon/serializers.py @@ -120,8 +120,9 @@ def json(value, default=custom_json): value = json_parser.dumps(value, default=default) # replace JavaScript incompatible spacing # http://timelessrepo.com/json-isnt-a-javascript-subset - return value.replace(ur'\u2028', '\\u2028').replace(ur'\2029', '\\u2029') - + # PY3 FIXME + # return value.replace(ur'\u2028', '\\u2028').replace(ur'\2029', '\\u2029') + return value def csv(value): return '' diff --git a/gluon/shell.py b/gluon/shell.py index ae30a4f1..a933fe74 100644 --- a/gluon/shell.py +++ b/gluon/shell.py @@ -86,7 +86,7 @@ def exec_environment( if pyfile: pycfile = pyfile + 'c' if os.path.isfile(pycfile): - exec read_pyc(pycfile) in env + exec (read_pyc(pycfile)) in env else: execfile(pyfile, env) return Storage(env) @@ -243,7 +243,7 @@ def run( "controllers_%s_%s.pyc" % (c, f)) if ((cronjob and os.path.isfile(pycfile)) or not os.path.isfile(pyfile)): - exec read_pyc(pycfile) in _env + exec (read_pyc(pycfile)) in _env elif os.path.isfile(pyfile): execfile(pyfile, _env) else: @@ -259,7 +259,7 @@ def run( ccode = None if startfile.endswith('.pyc'): ccode = read_pyc(startfile) - exec ccode in _env + exec (ccode) in _env else: execfile(startfile, _env) @@ -397,8 +397,7 @@ def test(testpath, import_models=True, verbose=False): def doctest_object(name, obj): """doctest obj and enclosed methods and classes.""" - if type(obj) in (types.FunctionType, types.TypeType, - types.ClassType, types.MethodType, + if type(obj) in (types.FunctionType, type, types.MethodType, types.UnboundMethodType): # Reload environment before each test. @@ -409,7 +408,7 @@ def test(testpath, import_models=True, verbose=False): obj, globs=globs, name='%s: %s' % (os.path.basename(testfile), name), verbose=verbose) - if type(obj) in (types.TypeType, types.ClassType): + if type(obj) in (type): for attr_name in dir(obj): # Execute . operator so decorators are executed. diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 2d983f5f..e8404dda 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -17,9 +17,9 @@ Holds: import datetime import urllib import re -import cStringIO import os +from gluon._compat import StringIO, unichr from gluon.http import HTTP, redirect from gluon.html import XmlComponent, truncate_string from gluon.html import XML, SPAN, TAG, A, DIV, CAT, UL, LI, TEXTAREA, BR, IMG @@ -1654,7 +1654,7 @@ class SQLFORM(FORM): elif isinstance(f, (str, unicode)): # do not know why this happens, it should not (source_file, original_filename) = \ - (cStringIO.StringIO(f), 'file.txt') + (StringIO(f), 'file.txt') else: # this should never happen, why does it happen? # print 'f=', repr(f) @@ -3472,8 +3472,8 @@ class ExporterTSV(ExportClass): ExportClass.__init__(self, rows) def export(self): - out = cStringIO.StringIO() - final = cStringIO.StringIO() + out = StringIO() + final = StringIO() import csv writer = csv.writer(out, delimiter='\t') if self.rows: @@ -3511,7 +3511,7 @@ class ExporterCSV(ExportClass): def export(self): # export CSV with rows.represent if self.rows: - s = cStringIO.StringIO() + s = StringIO() self.rows.export_to_csv_file(s, represent=True) return s.getvalue() else: diff --git a/gluon/storage.py b/gluon/storage.py index 1bb507f5..80cbffd1 100644 --- a/gluon/storage.py +++ b/gluon/storage.py @@ -12,11 +12,7 @@ Provides: - Storage; like dictionary allowing also for `obj.foo` for `obj['foo']` """ -try: - import cPickle as pickle -except: - import pickle -import copy_reg +from gluon._compat import copyreg, pickle, PY2 import gluon.portalocker as portalocker __all__ = ['List', 'Storage', 'Settings', 'Messages', @@ -139,10 +135,11 @@ class Storage(dict): def pickle_storage(s): return Storage, (dict(s),) -copy_reg.pickle(Storage, pickle_storage) - -PICKABLE = (str, int, long, float, bool, list, dict, tuple, set) - +copyreg.pickle(Storage, pickle_storage) +if PY2: + PICKABLE = (str, int, long, float, bool, list, dict, tuple, set) +else: + PICKABLE = (str, int, float, bool, list, dict, tuple, set) class StorageList(Storage): """ diff --git a/gluon/streamer.py b/gluon/streamer.py index 50012ca9..1095b592 100644 --- a/gluon/streamer.py +++ b/gluon/streamer.py @@ -15,7 +15,6 @@ import stat import time import re import errno -import rewrite from gluon.http import HTTP from gluon.contenttype import contenttype diff --git a/gluon/tests/__init__.py b/gluon/tests/__init__.py index cbeae68e..449cfa6f 100644 --- a/gluon/tests/__init__.py +++ b/gluon/tests/__init__.py @@ -1,28 +1,28 @@ import sys -from test_http import * -from test_cache import * -from test_contenttype import * -from test_compileapp import * -from test_fileutils import * -from test_globals import * -from test_html import * -from test_is_url import * -from test_languages import * -from test_router import * -from test_recfile import * -from test_routes import * -from test_storage import * -from test_serializers import * -from test_template import * -from test_validators import * -from test_utils import * -from test_contribs import * -from test_web import * -from test_dal import * -from test_tools import * -from test_appadmin import * -from test_scheduler import * +from .test_http import * +from .test_cache import * +from .test_contenttype import * +from .test_compileapp import * +from .test_fileutils import * +from .test_globals import * +from .test_html import * +from .test_is_url import * +from .test_languages import * +from .test_router import * +from .test_recfile import * +from .test_routes import * +from .test_storage import * +from .test_serializers import * +from .test_template import * +from .test_validators import * +from .test_utils import * +from .test_contribs import * +from .test_web import * +from .test_dal import * +from .test_tools import * +from .test_appadmin import * +from .test_scheduler import * if sys.version[:3] == '2.7': from test_old_doctests import * diff --git a/gluon/tests/test_serializers.py b/gluon/tests/test_serializers.py index c3324238..2e543525 100644 --- a/gluon/tests/test_serializers.py +++ b/gluon/tests/test_serializers.py @@ -43,7 +43,7 @@ class TestSerializers(unittest.TestCase): json_web2pyfied = [json(obj) for obj in iso_objs] self.assertEqual(json_objs, json_web2pyfied) # int or long int()ified - self.assertEqual(json(1), json(1L)) + # self.assertEqual(json(1), json(1)) # decimal stringified obj = {'a': decimal.Decimal('4.312312312312')} self.assertEqual(json(obj), u'{"a": "4.312312312312"}') diff --git a/gluon/tests/test_tools.py b/gluon/tests/test_tools.py index 547a0c95..e5ce5ddc 100644 --- a/gluon/tests/test_tools.py +++ b/gluon/tests/test_tools.py @@ -869,7 +869,7 @@ class TestAuth(unittest.TestCase): # not deleted self.assertFalse(self.auth.del_membership('some_test_group')) self.assertEqual(set(self.db.auth_membership(membership_id).as_dict().items()), - set({'group_id': 2L, 'user_id': 1L, 'id': 2L}.items())) # is not deleted + set({'group_id': 2, 'user_id': 1, 'id': 2}.items())) # is not deleted # deleted bart_id = self.db(self.db.auth_user.username == 'bart').select(self.db.auth_user.id).first().id self.assertTrue(self.auth.del_membership('some_test_group', user_id=bart_id)) diff --git a/gluon/utf8.py b/gluon/utf8.py index 24c90e31..ae592d88 100644 --- a/gluon/utf8.py +++ b/gluon/utf8.py @@ -11,12 +11,14 @@ Utilities and class for UTF8 strings managing ---------------------------------------------- """ from __future__ import print_function -import __builtin__ +from gluon._compat import builtin as __builtin__ + __all__ = ['Utf8'] repr_escape_tab = {} -for i in range(1, 32): - repr_escape_tab[i] = ur'\x%02x' % i +#FIXME PY3 +#for i in range(1, 32): +# repr_escape_tab[i] = ur'\x%02x' % i repr_escape_tab[7] = u'\\a' repr_escape_tab[8] = u'\\b' repr_escape_tab[9] = u'\\t' diff --git a/gluon/utils.py b/gluon/utils.py index 50fd214c..3682c714 100644 --- a/gluon/utils.py +++ b/gluon/utils.py @@ -23,17 +23,11 @@ import logging import socket import base64 import zlib +from gluon._compat import basestring, pickle, PY2, xrange, to_bytes _struct_2_long_long = struct.Struct('=QQ') -python_version = sys.version_info[0] - -if python_version == 2: - import cPickle as pickle -else: - import pickle - -import hashlib +import hashlib, binascii from hashlib import md5, sha1, sha224, sha256, sha384, sha512 try: @@ -46,9 +40,9 @@ import hmac if hasattr(hashlib, "pbkdf2_hmac"): def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None): hashfunc = hashfunc or sha1 - return hashlib.pbkdf2_hmac(hashfunc().name, - data, salt, iterations, - keylen).encode("hex") + hmac = hashlib.pbkdf2_hmac(hashfunc().name, to_bytes(data), + to_bytes(salt), iterations, keylen) + return binascii.hexlify(hmac) HAVE_PBKDF2 = True else: try: @@ -85,7 +79,7 @@ def compare(a, b): return hmac.compare_digest(a, b) result = len(a) ^ len(b) for i in xrange(len(b)): - result |= ord(a[i%len(a)]) ^ ord(b[i]) + result |= ord(a[i%len(a)]) ^ ord(b[i]) return result == 0 @@ -227,7 +221,7 @@ def initialize_urandom(): # try to add process-specific entropy frandom = open('/dev/urandom', 'wb') try: - if python_version == 2: + if PY2: frandom.write(''.join(chr(t) for t in ctokens)) # python 2 else: frandom.write(bytes([]).join(bytes([t]) for t in ctokens)) # python 3 @@ -242,7 +236,7 @@ def initialize_urandom(): """Cryptographically secure session management is not possible on your system because your system does not provide a cryptographically secure entropy source. This is not specific to web2py; consider deploying on a different operating system.""") - if python_version == 2: + if PY2: packed = ''.join(chr(x) for x in ctokens) # python 2 else: packed = bytes([]).join(bytes([x]) for x in ctokens) # python 3 diff --git a/gluon/validators.py b/gluon/validators.py index 012f868d..e2ed96a8 100644 --- a/gluon/validators.py +++ b/gluon/validators.py @@ -21,7 +21,7 @@ import urllib import struct import decimal import unicodedata -from cStringIO import StringIO +from gluon._compat import StringIO, long, unicodeT from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE from pydal.objects import Field, FieldVirtual, FieldMethod from functools import reduce @@ -80,7 +80,7 @@ except ImportError: def translate(text): if text is None: return None - elif isinstance(text, (str, unicode)) and have_current: + elif isinstance(text, (str, unicodeT)) and have_current: if hasattr(current, 'T'): return str(current.T(text)) return str(text) @@ -185,7 +185,7 @@ class IS_MATCH(Validator): if not expression.endswith('$'): expression = '(%s)$' % expression if is_unicode: - if not isinstance(expression, unicode): + if not isinstance(expression, unicodeT): expression = expression.decode('utf8') self.regex = re.compile(expression, re.UNICODE) else: @@ -196,12 +196,12 @@ class IS_MATCH(Validator): def __call__(self, value): if self.is_unicode: - if not isinstance(value, unicode): + if not isinstance(value, unicodeT): match = self.regex.search(str(value).decode('utf8')) else: match = self.regex.search(value) else: - if not isinstance(value, unicode): + if not isinstance(value, unicodeT): match = self.regex.search(str(value)) else: match = self.regex.search(value.encode('utf8')) @@ -267,7 +267,7 @@ class IS_EXPR(Validator): return (value, self.expression(value)) # for backward compatibility self.environment.update(value=value) - exec '__ret__=' + self.expression in self.environment + exec ('__ret__=' + self.expression) in self.environment if self.environment['__ret__']: return (value, None) return (value, translate(self.error_message)) @@ -338,7 +338,7 @@ class IS_LENGTH(Validator): lvalue = len(value) if self.minsize <= lvalue <= self.maxsize: return (value, None) - elif isinstance(value, unicode): + elif isinstance(value, unicodeT): if self.minsize <= len(value) <= self.maxsize: return (value.encode('utf8'), None) elif isinstance(value, (tuple, list)): @@ -717,7 +717,7 @@ class IS_NOT_IN_DB(Validator): self.record_id = id def __call__(self, value): - if isinstance(value, unicode): + if isinstance(value, unicodeT): value = value.encode('utf8') else: value = str(value) @@ -987,7 +987,7 @@ class IS_DECIMAL_IN_RANGE(Validator): def is_empty(value, empty_regex=None): """test empty field""" - if isinstance(value, (str, unicode)): + if isinstance(value, (str, unicodeT)): value = value.strip() if empty_regex is not None and empty_regex.match(value): value = '' @@ -2096,7 +2096,7 @@ class IS_URL(Validator): else: raise SyntaxError("invalid mode '%s' in IS_URL" % self.mode) - if not isinstance(value, unicode): + if not isinstance(value, unicodeT): return subMethod(value) else: try: @@ -2896,13 +2896,13 @@ class CRYPT(object): # entropy calculator for IS_STRONG # -lowerset = frozenset(unicode('abcdefghijklmnopqrstuvwxyz')) -upperset = frozenset(unicode('ABCDEFGHIJKLMNOPQRSTUVWXYZ')) -numberset = frozenset(unicode('0123456789')) -sym1set = frozenset(unicode('!@#$%^&*()')) -sym2set = frozenset(unicode('~`-_=+[]{}\\|;:\'",.<>?/')) +lowerset = frozenset(u'abcdefghijklmnopqrstuvwxyz') +upperset = frozenset(u'ABCDEFGHIJKLMNOPQRSTUVWXYZ') +numberset = frozenset(u'0123456789') +sym1set = frozenset(u'!@#$%^&*()') +sym2set = frozenset(u'~`-_=+[]{}\\|;:\'",.<>?/') otherset = frozenset( - unicode('0123456789abcdefghijklmnopqrstuvwxyz')) # anything else + u'0123456789abcdefghijklmnopqrstuvwxyz') # anything else def calc_entropy(string): @@ -3350,8 +3350,8 @@ class IS_IPV4(Validator): '^(([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.){3}([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])$') numbers = (16777216, 65536, 256, 1) localhost = 2130706433 - private = ((2886729728L, 2886795263L), (3232235520L, 3232301055L)) - automatic = (2851995648L, 2852061183L) + private = ((2886729728, 2886795263), (3232235520, 3232301055)) + automatic = (2851995648, 2852061183) def __init__( self, diff --git a/gluon/widget.py b/gluon/widget.py index 143dff36..6242c280 100644 --- a/gluon/widget.py +++ b/gluon/widget.py @@ -13,9 +13,8 @@ from __future__ import print_function import datetime import sys -import cStringIO +from gluon._compat import StringIO, thread import time -import thread import threading import os import copy @@ -23,14 +22,13 @@ import socket import signal import math import logging -import newcron import getpass -import gluon.main as main +from gluon import main, newcron -from gluon.fileutils import read_file, write_file, create_welcome_w2p -from gluon.settings import global_settings -from gluon.shell import run, test -from gluon.utils import is_valid_ip_address, is_loopback_ip_address, getipaddrinfo +from .fileutils import read_file, write_file, create_welcome_w2p +from .settings import global_settings +from .shell import run, test +from .utils import is_valid_ip_address, is_loopback_ip_address, getipaddrinfo ProgramName = 'web2py Web Framework'