Merge pull request #2088 from vinyldarkscratch/python-3
Introduce better Python 3 compatibility across all files
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@
|
||||
Utility functions for the Admin application
|
||||
-------------------------------------------
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
+1
-1
@@ -988,7 +988,7 @@ class AuthAPI(object):
|
||||
requires = table_user[passfield].requires
|
||||
if not isinstance(requires, (list, tuple)):
|
||||
requires = [requires]
|
||||
requires = list(filter(lambda t: isinstance(t, CRYPT), requires))
|
||||
requires = [t for t in requires if isinstance(t, CRYPT)]
|
||||
if requires:
|
||||
requires[0] = CRYPT(**requires[0].__dict__) # Copy the existing CRYPT attributes
|
||||
requires[0].min_length = 0 # But do not enforce minimum length for the old password
|
||||
|
||||
+1
-1
@@ -619,7 +619,7 @@ class Cache(object):
|
||||
if user_agent_ is True:
|
||||
cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent())
|
||||
else:
|
||||
cache_key.append(str(user_agent_.items()))
|
||||
cache_key.append(str(list(user_agent_.items())))
|
||||
if vars_:
|
||||
cache_key.append(current.request.env.query_string)
|
||||
if lang_:
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ import fnmatch
|
||||
import os, sys
|
||||
import copy
|
||||
import random
|
||||
from gluon._compat import builtin, PY2, unicodeT, to_native, to_bytes, iteritems, basestring, reduce, xrange, long, reload
|
||||
from gluon._compat import builtin, PY2, unicodeT, to_native, to_bytes, iteritems, integer_types, basestring, reduce, xrange, long, reload
|
||||
from gluon.storage import Storage, List
|
||||
from gluon.template import parse_template
|
||||
from gluon.restricted import restricted, compile2
|
||||
@@ -177,7 +177,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
||||
else:
|
||||
raise TypeError("Unsupported times argument type %s" % type(times))
|
||||
if timeout is not None:
|
||||
if not isinstance(timeout, (int, long)):
|
||||
if not isinstance(timeout, integer_types):
|
||||
raise ValueError("Timeout argument must be an integer or None")
|
||||
elif timeout <= 0:
|
||||
raise ValueError(
|
||||
@@ -261,7 +261,7 @@ class LoadFactory(object):
|
||||
if args is None:
|
||||
args = []
|
||||
vars = Storage(vars or {})
|
||||
import globals
|
||||
from . import globals
|
||||
target = target or 'c' + str(random.random())[2:]
|
||||
attr['_id'] = target
|
||||
request = current.request
|
||||
@@ -631,7 +631,7 @@ def run_controller_in(controller, function, environment):
|
||||
raise HTTP(404,
|
||||
rewrite.THREAD_LOCAL.routes.error_message % badc,
|
||||
web2py_error=badc)
|
||||
environment['__symbols__'] = environment.keys()
|
||||
environment['__symbols__'] = list(environment.keys())
|
||||
code = read_file(filename)
|
||||
code += TEST_CODE
|
||||
ccode = compile2(code, filename)
|
||||
|
||||
@@ -108,8 +108,8 @@ def saml2_handler(session, request, config_filename = None, entityid = None):
|
||||
config_filename = config_filename or os.path.join(request.folder,'private','sp_conf')
|
||||
client = Saml2Client(config_file = config_filename)
|
||||
if not entityid:
|
||||
idps = client.metadata.with_descriptor("idpsso")
|
||||
entityid = idps.keys()[0]
|
||||
idps = client.metadata.with_descriptor("idpsso")
|
||||
entityid = idps.keys()[0]
|
||||
bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
|
||||
binding, destination = client.pick_binding(
|
||||
"single_sign_on_service", bindings, "idpsso", entity_id=entityid)
|
||||
@@ -120,7 +120,7 @@ def saml2_handler(session, request, config_filename = None, entityid = None):
|
||||
if not request.vars.SAMLResponse:
|
||||
req_id, req = client.create_authn_request(destination, binding=binding)
|
||||
relay_state = web2py_uuid().replace('-','')
|
||||
session.saml_outstanding_queries = {req_id: request.url}
|
||||
session.saml_outstanding_queries = {req_id: request.url}
|
||||
session.saml_req_id = req_id
|
||||
http_args = client.apply_binding(binding, str(req), destination,
|
||||
relay_state=relay_state)
|
||||
@@ -150,14 +150,14 @@ class Saml2Auth(object):
|
||||
self.config_file = config_file
|
||||
self.maps = maps
|
||||
|
||||
# URL for redirecting users to when they sign out
|
||||
# URL for redirecting users to when they sign out
|
||||
self.saml_logout_url = logout_url
|
||||
|
||||
# URL to let users change their password in the IDP system
|
||||
self.saml_change_password_url = change_password_url
|
||||
|
||||
# URL to specify an IDP if using federation metadata or an MDQ
|
||||
self.entityid = entityid
|
||||
|
||||
# URL to specify an IDP if using federation metadata or an MDQ
|
||||
self.entityid = entityid
|
||||
|
||||
def login_url(self, next="/"):
|
||||
d = saml2_handler(current.session, current.request, entityid=self.entityid)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from .markdown2 import *
|
||||
from gluon.html import XML
|
||||
from gluon._compat import to_unicode
|
||||
|
||||
def WIKI(text, encoding="utf8", safe_mode='escape', html4tags=False, **attributes):
|
||||
if not text:
|
||||
@@ -9,7 +10,7 @@ def WIKI(text, encoding="utf8", safe_mode='escape', html4tags=False, **attribute
|
||||
del attributes['extras']
|
||||
else:
|
||||
extras=None
|
||||
text = text.decode(encoding,'replace')
|
||||
text = to_unicode(text, encoding, 'replace')
|
||||
|
||||
return XML(markdown(text,extras=extras,
|
||||
safe_mode=safe_mode, html4tags=html4tags)\
|
||||
|
||||
@@ -82,14 +82,14 @@ def test():
|
||||
def check(data, salt, iterations, keylen, expected):
|
||||
rv = pbkdf2_hex(data, salt, iterations, keylen)
|
||||
if rv != expected:
|
||||
print 'Test failed:'
|
||||
print ' Expected: %s' % expected
|
||||
print ' Got: %s' % rv
|
||||
print ' Parameters:'
|
||||
print ' data=%s' % data
|
||||
print ' salt=%s' % salt
|
||||
print ' iterations=%d' % iterations
|
||||
print
|
||||
print('Test failed:')
|
||||
print(' Expected: %s' % expected)
|
||||
print(' Got: %s' % rv)
|
||||
print(' Parameters:')
|
||||
print(' data=%s' % data)
|
||||
print(' salt=%s' % salt)
|
||||
print(' iterations=%d' % iterations)
|
||||
print()
|
||||
failed.append(1)
|
||||
|
||||
# From RFC 6070
|
||||
|
||||
+2
-2
@@ -57,8 +57,8 @@ def autoDetectXMLEncoding(buffer):
|
||||
secret_decoder_ring = codecs.lookup(encoding)[1]
|
||||
(decoded, length) = secret_decoder_ring(buffer)
|
||||
first_line = decoded.split("\n")[0]
|
||||
if first_line and first_line.startswith(u"<?xml"):
|
||||
encoding_pos = first_line.find(u"encoding")
|
||||
if first_line and first_line.startswith("<?xml"):
|
||||
encoding_pos = first_line.find("encoding")
|
||||
if encoding_pos != -1:
|
||||
# look for double quote
|
||||
quote_pos = first_line.find('"', encoding_pos)
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from gluon._compat import xrange
|
||||
from gluon.utils import local_html_escape
|
||||
import re
|
||||
@@ -325,7 +325,7 @@ color: #A0A0A0;
|
||||
fa = ' '.join([key[1:].lower() for (key, value) in items if key[:1]
|
||||
== '_' and value is None] + ['%s="%s"'
|
||||
% (key[1:].lower(), str(value).replace('"', "'"))
|
||||
for (key, value) in attributes.items() if key[:1]
|
||||
for (key, value) in items if key[:1]
|
||||
== '_' and value])
|
||||
if fa:
|
||||
fa = ' ' + fa
|
||||
|
||||
+2
-3
@@ -9,7 +9,6 @@
|
||||
Template helpers
|
||||
--------------------------------------------
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import cgi
|
||||
import os
|
||||
@@ -35,8 +34,8 @@ 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')), iteritems(name2codepoint)))
|
||||
entitydefs.setdefault('apos', u"'".encode('utf-8'))
|
||||
entitydefs = dict([(k_v[0], to_bytes(unichr(k_v[1]))) for k_v in iteritems(name2codepoint)])
|
||||
entitydefs.setdefault('apos', to_bytes("'"))
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
+1
-3
@@ -326,9 +326,7 @@ def write_plural_dict(filename, contents):
|
||||
|
||||
|
||||
def sort_function(x):
|
||||
if sys.version_info.major == 3: # python 3 compatibility
|
||||
unicode = str
|
||||
return unicode(x, 'utf-8').lower()
|
||||
return to_unicode(x, 'utf-8').lower()
|
||||
|
||||
|
||||
def write_dict(filename, contents):
|
||||
|
||||
+6
-7
@@ -9,10 +9,9 @@
|
||||
The gluon wsgi application
|
||||
---------------------------
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
if False:
|
||||
import import_all # DO NOT REMOVE PART OF FREEZE PROCESS
|
||||
from . import import_all # DO NOT REMOVE PART OF FREEZE PROCESS
|
||||
import gc
|
||||
|
||||
import os
|
||||
@@ -249,7 +248,7 @@ class LazyWSGI(object):
|
||||
def app(environ, start_response):
|
||||
data = f()
|
||||
start_response(self.response.status,
|
||||
self.response.headers.items())
|
||||
list(self.response.headers.items()))
|
||||
if isinstance(data, list):
|
||||
return data
|
||||
return [data]
|
||||
@@ -486,10 +485,10 @@ def wsgibase(environ, responder):
|
||||
if request.ajax:
|
||||
if response.flash:
|
||||
http_response.headers['web2py-component-flash'] = \
|
||||
urllib2.quote(xmlescape(response.flash).replace(b'\n', b''))
|
||||
urllib_quote(xmlescape(response.flash).replace(b'\n', b''))
|
||||
if response.js:
|
||||
http_response.headers['web2py-component-command'] = \
|
||||
urllib2.quote(response.js.replace('\n', ''))
|
||||
urllib_quote(response.js.replace('\n', ''))
|
||||
|
||||
# ##################################################
|
||||
# store cookies in headers
|
||||
@@ -717,9 +716,9 @@ class HttpServer(object):
|
||||
if isinstance(interfaces, list):
|
||||
for i in interfaces:
|
||||
if not isinstance(i, tuple):
|
||||
raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/"
|
||||
raise AttributeError("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/"
|
||||
raise AttributeError("Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/")
|
||||
|
||||
if path:
|
||||
# if a path is specified change the global variables so that web2py
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import Tkinter
|
||||
except:
|
||||
if sys.version_info[0] == 2:
|
||||
import Tkinter as tkinter
|
||||
else:
|
||||
import tkinter
|
||||
except ImportError:
|
||||
Tkinter = None
|
||||
|
||||
|
||||
@@ -12,15 +16,15 @@ class MessageBoxHandler(logging.Handler):
|
||||
logging.Handler.__init__(self)
|
||||
|
||||
def emit(self, record):
|
||||
if Tkinter:
|
||||
if tkinter:
|
||||
msg = self.format(record)
|
||||
root = Tkinter.Tk()
|
||||
root = tkinter.Tk()
|
||||
root.wm_title("web2py logger message")
|
||||
text = Tkinter.Text()
|
||||
text = tkinter.Text()
|
||||
text["height"] = 12
|
||||
text.insert(0.1, msg)
|
||||
text.pack()
|
||||
button = Tkinter.Button(root, text="OK", command=root.destroy)
|
||||
button = tkinter.Button(root, text="OK", command=root.destroy)
|
||||
button.pack()
|
||||
root.mainloop()
|
||||
|
||||
@@ -30,6 +34,6 @@ class NotifySendHandler(logging.Handler):
|
||||
logging.Handler.__init__(self)
|
||||
|
||||
def emit(self, record):
|
||||
if Tkinter:
|
||||
if tkinter:
|
||||
msg = self.format(record)
|
||||
os.system("notify-send '%s'" % msg)
|
||||
|
||||
+1
-5
@@ -20,13 +20,9 @@ import re
|
||||
import datetime
|
||||
import platform
|
||||
from functools import reduce
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except:
|
||||
import pickle
|
||||
from gluon.settings import global_settings
|
||||
from gluon import fileutils
|
||||
from gluon._compat import to_bytes
|
||||
from gluon._compat import to_bytes, pickle
|
||||
from pydal.contrib import portalocker
|
||||
|
||||
logger = logging.getLogger("web2py.cron")
|
||||
|
||||
@@ -15,7 +15,6 @@ routes.py supports two styles of URL rewriting, depending on whether 'routers' i
|
||||
Refer to router.example.py and routes.example.py for additional documentation.
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
+8
-39
@@ -5,14 +5,14 @@
|
||||
# Modified by Massimo Di Pierro
|
||||
|
||||
# Import System Modules
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import errno
|
||||
import socket
|
||||
import logging
|
||||
import platform
|
||||
from gluon._compat import iteritems, to_bytes, StringIO
|
||||
from gluon._compat import urllib_unquote, to_native
|
||||
from gluon._compat import iteritems, to_bytes, to_unicode, StringIO
|
||||
from gluon._compat import urllib_unquote, to_native, PY2
|
||||
|
||||
# Define Constants
|
||||
VERSION = '1.2.6'
|
||||
@@ -32,7 +32,7 @@ DEFAULTS = dict(LISTEN_QUEUE_SIZE=DEFAULT_LISTEN_QUEUE_SIZE,
|
||||
MIN_THREADS=DEFAULT_MIN_THREADS,
|
||||
MAX_THREADS=DEFAULT_MAX_THREADS)
|
||||
|
||||
PY3K = sys.version_info[0] > 2
|
||||
PY3K = not PY2
|
||||
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
@@ -40,39 +40,8 @@ class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
|
||||
if PY3K:
|
||||
def b(val):
|
||||
""" Convert string/unicode/bytes literals into bytes. This allows for
|
||||
the same code to run on Python 2.x and 3.x. """
|
||||
if isinstance(val, str):
|
||||
return val.encode()
|
||||
else:
|
||||
return val
|
||||
|
||||
def u(val, encoding="us-ascii"):
|
||||
""" Convert bytes into string/unicode. This allows for the
|
||||
same code to run on Python 2.x and 3.x. """
|
||||
if isinstance(val, bytes):
|
||||
return val.decode(encoding)
|
||||
else:
|
||||
return val
|
||||
|
||||
else:
|
||||
def b(val):
|
||||
""" Convert string/unicode/bytes literals into bytes. This allows for
|
||||
the same code to run on Python 2.x and 3.x. """
|
||||
if isinstance(val, unicode):
|
||||
return val.encode()
|
||||
else:
|
||||
return val
|
||||
|
||||
def u(val, encoding="us-ascii"):
|
||||
""" Convert bytes into string/unicode. This allows for the
|
||||
same code to run on Python 2.x and 3.x. """
|
||||
if isinstance(val, str):
|
||||
return val.decode(encoding)
|
||||
else:
|
||||
return val
|
||||
b = to_bytes
|
||||
u = to_unicode
|
||||
|
||||
# Import Package Modules
|
||||
# package imports removed in monolithic build
|
||||
@@ -613,9 +582,9 @@ import socket
|
||||
import logging
|
||||
import traceback
|
||||
from threading import Lock
|
||||
try:
|
||||
if PY3K:
|
||||
from queue import Queue
|
||||
except ImportError:
|
||||
else:
|
||||
from Queue import Queue
|
||||
|
||||
# Import Package Modules
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from __future__ import print_function
|
||||
# The following code is not part of Rocket but was added to
|
||||
# web2py for testing purposes.
|
||||
|
||||
|
||||
+9
-11
@@ -8,7 +8,6 @@
|
||||
Background processes made simple
|
||||
---------------------------------
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -29,7 +28,7 @@ from json import loads, dumps
|
||||
from gluon import DAL, Field, IS_NOT_EMPTY, IS_IN_SET, IS_NOT_IN_DB, IS_EMPTY_OR
|
||||
from gluon import IS_INT_IN_RANGE, IS_DATETIME, IS_IN_DB
|
||||
from gluon.utils import web2py_uuid
|
||||
from gluon._compat import Queue, long, iteritems, PY2
|
||||
from gluon._compat import Queue, long, iteritems, PY2, to_bytes, string_types, integer_types
|
||||
from gluon.storage import Storage
|
||||
|
||||
USAGE = """
|
||||
@@ -417,8 +416,8 @@ def _decode_list(lst):
|
||||
return lst
|
||||
newlist = []
|
||||
for i in lst:
|
||||
if isinstance(i, unicode):
|
||||
i = i.encode('utf-8')
|
||||
if isinstance(i, string_types):
|
||||
i = to_bytes(i)
|
||||
elif isinstance(i, list):
|
||||
i = _decode_list(i)
|
||||
newlist.append(i)
|
||||
@@ -430,10 +429,9 @@ def _decode_dict(dct):
|
||||
return dct
|
||||
newdict = {}
|
||||
for k, v in iteritems(dct):
|
||||
if isinstance(k, unicode):
|
||||
k = k.encode('utf-8')
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode('utf-8')
|
||||
k = to_bytes(k)
|
||||
if isinstance(v, string_types):
|
||||
v = to_bytes(v)
|
||||
elif isinstance(v, list):
|
||||
v = _decode_list(v)
|
||||
newdict[k] = v
|
||||
@@ -1572,7 +1570,7 @@ class Scheduler(MetaScheduler):
|
||||
"""
|
||||
from pydal.objects import Query
|
||||
sr, st = self.db.scheduler_run, self.db.scheduler_task
|
||||
if isinstance(ref, (int, long)):
|
||||
if isinstance(ref, integer_types):
|
||||
q = st.id == ref
|
||||
elif isinstance(ref, str):
|
||||
q = st.uuid == ref
|
||||
@@ -1623,7 +1621,7 @@ class Scheduler(MetaScheduler):
|
||||
Experimental
|
||||
"""
|
||||
st, sw = self.db.scheduler_task, self.db.scheduler_worker
|
||||
if isinstance(ref, (int, long)):
|
||||
if isinstance(ref, integer_types):
|
||||
q = st.id == ref
|
||||
elif isinstance(ref, str):
|
||||
q = st.uuid == ref
|
||||
@@ -1723,7 +1721,7 @@ def main():
|
||||
sys.path.append(path)
|
||||
print('importing tasks...')
|
||||
tasks = __import__(filename, globals(), locals(), [], -1).tasks
|
||||
print('tasks found: ' + ', '.join(tasks.keys()))
|
||||
print('tasks found: ' + ', '.join(list(tasks.keys())))
|
||||
else:
|
||||
tasks = {}
|
||||
group_names = [x.strip() for x in options.group_names.split(',')]
|
||||
|
||||
@@ -10,7 +10,7 @@ from gluon.html import TAG, XmlComponent, xmlescape
|
||||
from gluon.languages import lazyT
|
||||
import gluon.contrib.rss2 as rss2
|
||||
import json as json_parser
|
||||
from gluon._compat import long, to_native, unicodeT
|
||||
from gluon._compat import long, to_native, unicodeT, integer_types
|
||||
|
||||
have_yaml = True
|
||||
try:
|
||||
@@ -79,7 +79,7 @@ def custom_json(o):
|
||||
datetime.datetime,
|
||||
datetime.time)):
|
||||
return o.isoformat()[:19].replace('T', ' ')
|
||||
elif isinstance(o, (int, long)):
|
||||
elif isinstance(o, integer_types):
|
||||
return int(o)
|
||||
elif isinstance(o, decimal.Decimal):
|
||||
return str(o)
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@
|
||||
Web2py environment in the shell
|
||||
--------------------------------
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
@@ -95,7 +96,7 @@ def exec_environment(
|
||||
if pyfile:
|
||||
pycfile = pyfile + 'c'
|
||||
if os.path.isfile(pycfile):
|
||||
exec (read_pyc(pycfile), env)
|
||||
exec(read_pyc(pycfile), env)
|
||||
else:
|
||||
execfile(pyfile, env)
|
||||
return Storage(env)
|
||||
|
||||
+8
-8
@@ -717,7 +717,7 @@ class AutocompleteWidget(object):
|
||||
compact=table_rows.compact)
|
||||
elif settings and settings.global_settings.web2py_runtime_gae:
|
||||
rows = self.db(field.__ge__(kword) &
|
||||
field.__lt__(kword + u'\ufffd')
|
||||
field.__lt__(kword + '\ufffd')
|
||||
).select(orderby=self.orderby,
|
||||
limitby=self.limitby,
|
||||
*(self.fields + self.help_fields))
|
||||
@@ -1966,7 +1966,7 @@ class SQLFORM(FORM):
|
||||
|
||||
AUTOTYPES = {
|
||||
type(''): ('string', None),
|
||||
type(u''): ('string',None),
|
||||
type(''): ('string',None),
|
||||
type(True): ('boolean', None),
|
||||
type(1): ('integer', IS_INT_IN_RANGE(-1e12, +1e12)),
|
||||
type(1.0): ('double', IS_FLOAT_IN_RANGE()),
|
||||
@@ -2462,8 +2462,8 @@ class SQLFORM(FORM):
|
||||
filter1 = lambda f: isinstance(f, Field) and (f.type!='blob' or showblobs)
|
||||
filter2 = lambda f: isinstance(f, Field) and f.readable and f.listable
|
||||
for table in tables:
|
||||
fields += filter(filter1, table)
|
||||
columns += filter(filter2, table)
|
||||
fields += list(filter(filter1, table))
|
||||
columns += list(filter(filter2, table))
|
||||
for k, f in iteritems(table):
|
||||
if not k.startswith('_'):
|
||||
if isinstance(f, Field.Virtual) and f.readable:
|
||||
@@ -2549,7 +2549,7 @@ class SQLFORM(FORM):
|
||||
table = db[request.args[-2]]
|
||||
record = table(request.args[-1]) or redirect(referrer)
|
||||
if represent_none is not None:
|
||||
for field in record.iterkeys():
|
||||
for field in record.keys():
|
||||
if record[field] is None:
|
||||
record[field] = represent_none
|
||||
sqlformargs = dict(upload=upload, ignore_rw=ignore_rw,
|
||||
@@ -2676,7 +2676,7 @@ class SQLFORM(FORM):
|
||||
# the query should be constructed using searchable
|
||||
# fields but not virtual fields
|
||||
is_searchable = lambda f: f.readable and not isinstance(f, Field.Virtual) and f.searchable
|
||||
sfields = reduce(lambda a, b: a + b, [filter(is_searchable, t) for t in tables])
|
||||
sfields = reduce(lambda a, b: a + b, [list(filter(is_searchable, t)) for t in tables])
|
||||
# use custom_query using searchable
|
||||
if callable(searchable):
|
||||
dbset = dbset(searchable(sfields, keywords))
|
||||
@@ -2937,7 +2937,7 @@ class SQLFORM(FORM):
|
||||
paginator.append(LI(self_link('<<', 0)))
|
||||
if page > NPAGES:
|
||||
paginator.append(LI(self_link('<', page - 1)))
|
||||
pages = range(max(0, page - NPAGES), min(page + NPAGES, npages))
|
||||
pages = list(range(max(0, page - NPAGES), min(page + NPAGES, npages)))
|
||||
for p in pages:
|
||||
if p == page:
|
||||
paginator.append(LI(A(p + 1, _onclick='return false'),
|
||||
@@ -3426,7 +3426,7 @@ class SQLTABLE(TABLE):
|
||||
if not sqlrows:
|
||||
return
|
||||
REGEX_TABLE_DOT_FIELD = sqlrows.db._adapter.REGEX_TABLE_DOT_FIELD
|
||||
fieldmap = dict(zip(sqlrows.colnames, sqlrows.fields))
|
||||
fieldmap = dict(list(zip(sqlrows.colnames, sqlrows.fields)))
|
||||
tablemap = dict(((f.tablename, f.table) if isinstance(f, Field) else (f._table._tablename, f._table) for f in fieldmap.values()))
|
||||
for table in tablemap.values():
|
||||
pref = table._tablename + '.'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"""
|
||||
Unit tests for gluon.sqlhtml
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
@@ -56,7 +56,7 @@ def _prepare_exec_for_file(filename):
|
||||
elif os.path.split(filename)[1] == '__init__.py':
|
||||
filename = os.path.dirname(filename)
|
||||
else:
|
||||
raise 'The file provided (%s) does is not a valid Python file.'
|
||||
raise IOError('The file provided (%s) is not a valid Python file.')
|
||||
filename = os.path.realpath(filename)
|
||||
dirpath = filename
|
||||
while True:
|
||||
|
||||
@@ -252,11 +252,11 @@ class testResponse(unittest.TestCase):
|
||||
|
||||
def test_include_meta(self):
|
||||
response = Response()
|
||||
response.meta[u'web2py'] = 'web2py'
|
||||
response.meta['web2py'] = 'web2py'
|
||||
response.include_meta()
|
||||
self.assertEqual(response.body.getvalue(), '\n<meta name="web2py" content="web2py" />\n')
|
||||
response = Response()
|
||||
response.meta[u'meta_dict'] = {u'tag_name':'tag_value'}
|
||||
response.meta['meta_dict'] = {'tag_name':'tag_value'}
|
||||
response.include_meta()
|
||||
self.assertEqual(response.body.getvalue(), '\n<meta tag_name="tag_value" />\n')
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Unit tests for rewrite.py routers option"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import tempfile
|
||||
|
||||
@@ -551,12 +551,12 @@ class TestsForSchedulerAPIs(BaseTestScheduler):
|
||||
def isnotqueued(result):
|
||||
self.assertEqual(result.id, None)
|
||||
self.assertEqual(result.uuid, None)
|
||||
self.assertEqual(len(result.errors.keys()) > 0, True)
|
||||
self.assertEqual(len(list(result.errors.keys())) > 0, True)
|
||||
|
||||
def isqueued(result):
|
||||
self.assertNotEqual(result.id, None)
|
||||
self.assertNotEqual(result.uuid, None)
|
||||
self.assertEqual(len(result.errors.keys()), 0)
|
||||
self.assertEqual(len(list(result.errors.keys())), 0)
|
||||
|
||||
s = Scheduler(self.db)
|
||||
fname = 'foo'
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"""
|
||||
Unit tests for running web2py
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
|
||||
+27
-27
@@ -15,8 +15,9 @@ from functools import reduce
|
||||
from gluon._compat import pickle, thread, urllib2, Cookie, StringIO, urlencode
|
||||
from gluon._compat import configparser, MIMEBase, MIMEMultipart, MIMEText, Header
|
||||
from gluon._compat import Encoders, Charset, long, urllib_quote, iteritems
|
||||
from gluon._compat import to_bytes, to_native, add_charset
|
||||
from gluon._compat import to_bytes, to_native, add_charset, string_types
|
||||
from gluon._compat import charset_QP, basestring, unicodeT, to_unicode
|
||||
from gluon._compat import urllib2, urlopen
|
||||
import datetime
|
||||
import logging
|
||||
import sys
|
||||
@@ -902,13 +903,13 @@ class Recaptcha2(DIV):
|
||||
'secret': self.private_key,
|
||||
'remoteip': remoteip,
|
||||
'response': recaptcha_response_field,
|
||||
})
|
||||
}).encode('utf-8')
|
||||
request = urllib2.Request(
|
||||
url=self.VERIFY_SERVER,
|
||||
data=to_bytes(params),
|
||||
headers={'Content-type': 'application/x-www-form-urlencoded',
|
||||
'User-agent': 'reCAPTCHA Python'})
|
||||
httpresp = urllib2.urlopen(request)
|
||||
httpresp = urlopen(request)
|
||||
content = httpresp.read()
|
||||
httpresp.close()
|
||||
try:
|
||||
@@ -1037,7 +1038,7 @@ class AuthJWT(object):
|
||||
Example:
|
||||
def mybefore_authorization(tokend):
|
||||
if not tokend['my_name_is'] == 'bond,james bond':
|
||||
raise HTTP(400, u'Invalid JWT my_name_is claim')
|
||||
raise HTTP(400, 'Invalid JWT my_name_is claim')
|
||||
- max_header_length: check max length to avoid load()ing unusually large tokens (could mean crafted, e.g. in a DDoS.)
|
||||
|
||||
Basic Usage:
|
||||
@@ -1161,7 +1162,7 @@ class AuthJWT(object):
|
||||
b64h, b64b = body.split(b'.', 1)
|
||||
if b64h != self.cached_b64h:
|
||||
# header not the same
|
||||
raise HTTP(400, u'Invalid JWT Header')
|
||||
raise HTTP(400, 'Invalid JWT Header')
|
||||
secret = self.secret_key
|
||||
tokend = serializers.loads_json(to_native(self.jwt_b64d(b64b)))
|
||||
if self.salt:
|
||||
@@ -1172,11 +1173,11 @@ class AuthJWT(object):
|
||||
secret = to_bytes(secret, 'ascii', 'ignore')
|
||||
if not self.verify_signature(body, sig, secret):
|
||||
# signature verification failed
|
||||
raise HTTP(400, u'Token signature is invalid')
|
||||
raise HTTP(400, 'Token signature is invalid')
|
||||
if self.verify_expiration:
|
||||
now = time.mktime(datetime.datetime.utcnow().timetuple())
|
||||
if tokend['exp'] + self.leeway < now:
|
||||
raise HTTP(400, u'Token is expired')
|
||||
raise HTTP(400, 'Token is expired')
|
||||
if callable(self.before_authorization):
|
||||
self.before_authorization(tokend)
|
||||
return tokend
|
||||
@@ -1209,11 +1210,11 @@ class AuthJWT(object):
|
||||
orig_exp = orig_payload['exp']
|
||||
if orig_exp + self.leeway < now:
|
||||
# token already expired, can't be used for refresh
|
||||
raise HTTP(400, u'Token already expired')
|
||||
raise HTTP(400, 'Token already expired')
|
||||
orig_iat = orig_payload.get('orig_iat') or orig_payload['iat']
|
||||
if orig_iat + self.refresh_expiration_delta < now:
|
||||
# refreshed too long ago
|
||||
raise HTTP(400, u'Token issued too long ago')
|
||||
raise HTTP(400, 'Token issued too long ago')
|
||||
expires = now + self.expiration
|
||||
orig_payload.update(
|
||||
orig_iat=orig_iat,
|
||||
@@ -1259,7 +1260,7 @@ class AuthJWT(object):
|
||||
pass
|
||||
if token:
|
||||
if not self.allow_refresh:
|
||||
raise HTTP(403, u'Refreshing token is not allowed')
|
||||
raise HTTP(403, 'Refreshing token is not allowed')
|
||||
tokend = self.load_token(token)
|
||||
# verification can fail here
|
||||
refreshed = self.refresh_token(tokend)
|
||||
@@ -1277,9 +1278,9 @@ class AuthJWT(object):
|
||||
ret = {'token': self.generate_token(payload)}
|
||||
elif ret is None:
|
||||
raise HTTP(401,
|
||||
u'Not Authorized - need to be logged in, to pass a token '
|
||||
u'for refresh or username and password for login',
|
||||
**{'WWW-Authenticate': u'JWT realm="%s"' % self.realm})
|
||||
'Not Authorized - need to be logged in, to pass a token '
|
||||
'for refresh or username and password for login',
|
||||
**{'WWW-Authenticate': 'JWT realm="%s"' % self.realm})
|
||||
response.headers['Content-Type'] = 'application/json'
|
||||
return serializers.json(ret)
|
||||
|
||||
@@ -1303,9 +1304,9 @@ class AuthJWT(object):
|
||||
if token_in_header:
|
||||
parts = token_in_header.split()
|
||||
if parts[0].lower() != self.header_prefix.lower():
|
||||
raise HTTP(400, u'Invalid JWT header')
|
||||
raise HTTP(400, 'Invalid JWT header')
|
||||
elif len(parts) == 1:
|
||||
raise HTTP(400, u'Invalid JWT header, missing token')
|
||||
raise HTTP(400, 'Invalid JWT header, missing token')
|
||||
elif len(parts) > 2:
|
||||
raise HTTP(400, 'Invalid JWT header, token contains spaces')
|
||||
token = parts[1]
|
||||
@@ -2243,11 +2244,11 @@ class Auth(AuthAPI):
|
||||
if basic_auth_realm:
|
||||
if callable(basic_auth_realm):
|
||||
basic_auth_realm = basic_auth_realm()
|
||||
elif isinstance(basic_auth_realm, (unicode, str)):
|
||||
basic_realm = unicode(basic_auth_realm) # Warning python 3.5 does not have method unicod
|
||||
elif isinstance(basic_auth_realm, string_types):
|
||||
basic_realm = to_unicode(basic_auth_realm)
|
||||
elif basic_auth_realm is True:
|
||||
basic_realm = u'' + current.request.application
|
||||
http_401 = HTTP(401, u'Not Authorized', **{'WWW-Authenticate': u'Basic realm="' + basic_realm + '"'})
|
||||
basic_realm = '' + current.request.application
|
||||
http_401 = HTTP(401, 'Not Authorized', **{'WWW-Authenticate': 'Basic realm="' + basic_realm + '"'})
|
||||
if not basic or not basic[:6].lower() == 'basic ':
|
||||
if basic_auth_realm:
|
||||
raise http_401
|
||||
@@ -3576,7 +3577,7 @@ class Auth(AuthAPI):
|
||||
requires = table_user[passfield].requires
|
||||
if not isinstance(requires, (list, tuple)):
|
||||
requires = [requires]
|
||||
requires = list(filter(lambda t: isinstance(t, CRYPT), requires))
|
||||
requires = [t for t in requires if isinstance(t, CRYPT)]
|
||||
if requires:
|
||||
requires[0] = CRYPT(**requires[0].__dict__) # Copy the existing CRYPT attributes
|
||||
requires[0].min_length = 0 # But do not enforce minimum length for the old password
|
||||
@@ -4616,7 +4617,6 @@ class Crud(object): # pragma: no cover
|
||||
results = None
|
||||
return form, results
|
||||
|
||||
|
||||
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPCookieProcessor()))
|
||||
|
||||
|
||||
@@ -4634,7 +4634,7 @@ def fetch(url, data=None, headers=None,
|
||||
from google.appengine.api import urlfetch
|
||||
except ImportError:
|
||||
req = urllib2.Request(url, data, headers)
|
||||
html = urllib2.urlopen(req).read()
|
||||
html = urlopen(req).read()
|
||||
else:
|
||||
method = ((data is None) and urlfetch.GET) or urlfetch.POST
|
||||
while url is not None:
|
||||
@@ -5002,7 +5002,7 @@ class Service(object):
|
||||
elif r and not isinstance(r, types.GeneratorType) and isinstance(r[0], (dict, Storage)):
|
||||
import csv
|
||||
writer = csv.writer(s)
|
||||
writer.writerow(r[0].keys())
|
||||
writer.writerow(list(r[0].keys()))
|
||||
for line in r:
|
||||
writer.writerow([none_exception(v)
|
||||
for v in line.values()])
|
||||
@@ -5219,7 +5219,7 @@ class Service(object):
|
||||
def serve_xmlrpc(self):
|
||||
request = current.request
|
||||
response = current.response
|
||||
services = self.xmlrpc_procedures.values()
|
||||
services = list(self.xmlrpc_procedures.values())
|
||||
return response.xmlrpc(request, services)
|
||||
|
||||
def serve_amfrpc(self, version=0):
|
||||
@@ -5574,7 +5574,7 @@ class PluginManager(object):
|
||||
return self.__dict__[key]
|
||||
|
||||
def keys(self):
|
||||
return self.__dict__.keys()
|
||||
return list(self.__dict__.keys())
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.__dict__
|
||||
@@ -5820,7 +5820,7 @@ class Wiki(object):
|
||||
settings.templates = templates
|
||||
settings.controller = controller
|
||||
settings.function = function
|
||||
settings.groups = auth.user_groups.values() \
|
||||
settings.groups = list(auth.user_groups.values()) \
|
||||
if groups is None else groups
|
||||
|
||||
db = auth.db
|
||||
@@ -5916,7 +5916,7 @@ class Wiki(object):
|
||||
if (auth.user and
|
||||
check_credentials(current.request, gae_login=False) and
|
||||
'wiki_editor' not in auth.user_groups.values() and
|
||||
self.settings.groups == auth.user_groups.values()):
|
||||
self.settings.groups == list(auth.user_groups.values())):
|
||||
group = db.auth_group(role='wiki_editor')
|
||||
gid = group.id if group else db.auth_group.insert(
|
||||
role='wiki_editor')
|
||||
|
||||
+4
-5
@@ -16,7 +16,6 @@ import datetime
|
||||
import time
|
||||
import cgi
|
||||
import json
|
||||
import urllib
|
||||
import struct
|
||||
import decimal
|
||||
import unicodedata
|
||||
@@ -437,7 +436,7 @@ class IS_IN_SET(Validator):
|
||||
self.multiple = multiple
|
||||
if isinstance(theset, dict):
|
||||
self.theset = [str(item) for item in theset]
|
||||
self.labels = theset.values()
|
||||
self.labels = list(theset.values())
|
||||
elif theset and isinstance(theset, (tuple, list)) \
|
||||
and isinstance(theset[0], (tuple, list)) and len(theset[0]) == 2:
|
||||
self.theset = [str(item) for item, label in theset]
|
||||
@@ -575,7 +574,7 @@ class IS_IN_DB(Validator):
|
||||
else:
|
||||
fields = [table[k] for k in self.fieldnames]
|
||||
ignore = (FieldVirtual, FieldMethod)
|
||||
fields = filter(lambda f: not isinstance(f, ignore), fields)
|
||||
fields = [f for f in fields if not isinstance(f, ignore)]
|
||||
if self.dbset.db._dbname != 'gae':
|
||||
orderby = self.orderby or reduce(lambda a, b: a | b, fields)
|
||||
groupby = self.groupby
|
||||
@@ -649,7 +648,7 @@ class IS_IN_DB(Validator):
|
||||
return (values, None)
|
||||
else:
|
||||
def count(values, s=self.dbset, f=field):
|
||||
return s(f.belongs(map(int, values))).count()
|
||||
return s(f.belongs(list(map(int, values)))).count()
|
||||
|
||||
if self.dbset.db._adapter.dbengine == "google:datastore":
|
||||
range_ids = range(0, len(values), 30)
|
||||
@@ -3533,7 +3532,7 @@ class IS_IPV4(Validator):
|
||||
if isinstance(value, str):
|
||||
temp.append(value.split('.'))
|
||||
elif isinstance(value, (list, tuple)):
|
||||
if len(value) == len(list(filter(lambda item: isinstance(item, int), value))) == 4:
|
||||
if len(value) == len([item for item in value if isinstance(item, int)]) == 4:
|
||||
temp.append(value)
|
||||
else:
|
||||
for item in value:
|
||||
|
||||
+4
-2
@@ -9,7 +9,6 @@
|
||||
The widget is called from web2py
|
||||
----------------------------------
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import datetime
|
||||
import sys
|
||||
@@ -31,6 +30,9 @@ 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
|
||||
|
||||
if PY2:
|
||||
input = raw_input
|
||||
|
||||
|
||||
ProgramName = 'web2py Web Framework'
|
||||
ProgramAuthor = 'Created by Massimo Di Pierro, Copyright 2007-' + str(
|
||||
@@ -952,7 +954,7 @@ def console():
|
||||
|
||||
if options.gae:
|
||||
if not os.path.exists('app.yaml'):
|
||||
name = raw_input("Your GAE app name: ")
|
||||
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:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
echo "This script will:
|
||||
1) Install modules needed to run web2py on Fedora and CentOS/RHEL
|
||||
2) Install Python 2.6 to /opt and recompile wsgi if not provided
|
||||
2) Install Python 3.7 to /opt and recompile wsgi if not provided
|
||||
2) Install web2py in /opt/web-apps/
|
||||
3) Configure SELinux and iptables
|
||||
5) Create a self signed ssl certificate
|
||||
@@ -56,7 +56,7 @@ echo
|
||||
yum update
|
||||
|
||||
# Install required packages
|
||||
yum install httpd mod_ssl mod_wsgi wget python unzip
|
||||
yum install httpd mod_ssl mod_wsgi wget python3 unzip
|
||||
|
||||
###
|
||||
### Phase 2 - Install web2py
|
||||
|
||||
@@ -38,8 +38,8 @@ apt-get -y install libapache2-mod-wsgi
|
||||
apt-get -y install python-psycopg2
|
||||
apt-get -y install postfix
|
||||
apt-get -y install wget
|
||||
apt-get -y install python-matplotlib
|
||||
apt-get -y install python-reportlab
|
||||
apt-get -y install python3-matplotlib
|
||||
apt-get -y install python3-reportlab
|
||||
apt-get -y install mercurial
|
||||
/etc/init.d/postgresql restart
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
echo "This script will:
|
||||
1) Install modules needed to run web2py on Fedora and CentOS/RHEL
|
||||
2) Install Python 2.6 to /opt and recompile wsgi if not provided
|
||||
2) Install Python 3.7 to /opt and recompile wsgi if not provided
|
||||
2) Install web2py in /opt/web-apps/
|
||||
3) Configure SELinux and iptables
|
||||
5) Create a self signed ssl certificate
|
||||
@@ -54,7 +54,7 @@ echo
|
||||
yum update
|
||||
|
||||
# Install required packages
|
||||
yum install httpd mod_ssl mod_wsgi wget python
|
||||
yum install httpd mod_ssl mod_wsgi wget python3
|
||||
|
||||
# Verify we have at least Python 2.5
|
||||
typeset -i version_major
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
echo "This script will:
|
||||
1) Install modules needed to run web2py on Fedora and CentOS/RHEL
|
||||
2) Install Python 2.6 to /opt and recompile wsgi if not provided
|
||||
2) Install Python 3.7 to /opt and recompile wsgi if not provided
|
||||
2) Install web2py in /opt/web-apps/
|
||||
3) Configure SELinux and iptables
|
||||
5) Create a self signed ssl certificate
|
||||
@@ -55,7 +55,7 @@ echo
|
||||
yum update
|
||||
|
||||
# Install required packages
|
||||
yum install httpd mod_ssl mod_wsgi wget python
|
||||
yum install httpd mod_ssl mod_wsgi wget python3
|
||||
|
||||
# Verify we have at least Python 2.5
|
||||
typeset -i version_major
|
||||
|
||||
@@ -31,18 +31,17 @@ apt-get -y install zip unzip
|
||||
apt-get -y install tar
|
||||
apt-get -y install openssh-server
|
||||
apt-get -y install build-essential
|
||||
apt-get -y install python
|
||||
#apt-get -y install python2.5
|
||||
apt-get -y install ipython
|
||||
apt-get -y install python-dev
|
||||
apt-get -y install python3
|
||||
apt-get -y install ipython3
|
||||
apt-get -y install python3-dev
|
||||
apt-get -y install postgresql
|
||||
apt-get -y install apache2
|
||||
apt-get -y install libapache2-mod-wsgi
|
||||
apt-get -y install python2.5-psycopg2
|
||||
apt-get -y install python3-psycopg2
|
||||
apt-get -y install postfix
|
||||
apt-get -y install wget
|
||||
apt-get -y install python-matplotlib
|
||||
apt-get -y install python-reportlab
|
||||
apt-get -y install python3-matplotlib
|
||||
apt-get -y install python3-reportlab
|
||||
apt-get -y install mercurial
|
||||
/etc/init.d/postgresql restart
|
||||
|
||||
|
||||
@@ -14,15 +14,14 @@ parentdir = os.path.dirname(currentdir)
|
||||
sys.path.insert(0, parentdir)
|
||||
|
||||
from gluon.cfs import getcfs
|
||||
from gluon.utf8 import Utf8
|
||||
from gluon._compat import copyreg, PY2, maketrans, iterkeys, unicodeT, to_unicode, to_bytes, iteritems, to_native, pjoin
|
||||
from gluon.languages import findT
|
||||
from gluon.languages import findT, sort_function
|
||||
|
||||
# This script can be run with no arguments (which sets the application folder to the current working directory, and default language to English), one argument (which sets the default language), or two arguments (application folder path and default language).
|
||||
# When run, it will update the default language, as well as strip all of the strings found in the non-default languages but not in the default language, and add the strings found in the default language to the non-default languages it is not, making sure translators don't do additional work that will never be used.
|
||||
|
||||
def read_dict_aux(filename):
|
||||
lang_text = open(filename, 'r').read().replace(b'\r\n', b'\n')
|
||||
lang_text = open(filename, 'r').read().replace('\r\n', '\n')
|
||||
try:
|
||||
return safe_eval(to_native(lang_text)) or {}
|
||||
except Exception:
|
||||
@@ -41,14 +40,11 @@ def safe_eval(text):
|
||||
return eval(text, {}, {})
|
||||
return None
|
||||
|
||||
def sort_function(x, y):
|
||||
return cmp(unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower())
|
||||
|
||||
def write_file(file, contents):
|
||||
file.write('# -*- coding: utf-8 -*-\n{\n')
|
||||
for key in sorted(contents, sort_function):
|
||||
file.write('%s: %s,\n' % (repr(Utf8(key)),
|
||||
repr(Utf8(contents[key]))))
|
||||
for key in sorted(contents, key = sort_function):
|
||||
file.write('%s: %s,\n' % (repr(to_unicode(key)),
|
||||
repr(to_unicode(contents[key]))))
|
||||
file.write('}\n')
|
||||
file.close()
|
||||
|
||||
@@ -67,7 +63,7 @@ def update_languages(cwd, default_lang):
|
||||
if phrase in default:
|
||||
new_dict[phrase] = i18n[phrase]
|
||||
write_file(open(os.path.join(cwd, "languages", lang), 'w'), new_dict)
|
||||
print lang
|
||||
print(lang)
|
||||
|
||||
if __name__ == "__main__":
|
||||
cwd = os.getcwd()
|
||||
|
||||
Reference in New Issue
Block a user