merged conflicts

This commit is contained in:
mdipierro
2016-06-12 19:59:58 -05:00
110 changed files with 2504 additions and 2053 deletions
+1
View File
@@ -48,6 +48,7 @@ applications/*/sessions/*
applications/*/errors/* applications/*/errors/*
applications/*/cache/* applications/*/cache/*
applications/*/uploads/* applications/*/uploads/*
applications/*/private/*
applications/*/*.py[oc] applications/*/*.py[oc]
applications/*/static/temp applications/*/static/temp
applications/*/progress.log applications/*/progress.log
+4 -3
View File
@@ -9,6 +9,7 @@ cache:
python: python:
- '2.7' - '2.7'
- 'pypy' - 'pypy'
- '3.5'
install: install:
- | - |
@@ -24,8 +25,8 @@ install:
virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION"
source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
fi fi
- pip install -e . - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then pip install --download-cache $HOME/.pip-cache pycrypto; fi;
- if [[ $TRAVIS_PYTHON_VERSION != '3.5' ]]; then pip install -e .; fi;
before_script: before_script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache coverage; fi; - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache coverage; fi;
@@ -39,7 +40,7 @@ before_script:
script: export COVERAGE_PROCESS_START=gluon/tests/coverage.ini; ./web2py.py --run_system_tests --with_coverage script: export COVERAGE_PROCESS_START=gluon/tests/coverage.ini; ./web2py.py --run_system_tests --with_coverage
after_success: after_success:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coverage combine; fi - coverage combine;
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then codecov; fi - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then codecov; fi
notifications: notifications:
+25 -10
View File
@@ -15,7 +15,7 @@ label, strong {font-weight:bold}
ul {list-style-type:none; padding-left:20px} ul {list-style-type:none; padding-left:20px}
a {text-decoration:none; color:#26a69a; white-space:nowrap} a {text-decoration:none; color:#26a69a; white-space:nowrap}
a:hover {cursor:pointer} a:hover {cursor:pointer}
h1,h2,h3,h4,h5,h6{font-weight:bold; text-transform:uppercase} h1,h2,h3,h4,h5,h6{font-weight:bold}
h1{font-size:4em; margin:1.0em 0 0.25em 0} h1{font-size:4em; margin:1.0em 0 0.25em 0}
h2{font-size:2.4em; margin:0.9em 0 0.25em 0} h2{font-size:2.4em; margin:0.9em 0 0.25em 0}
h3{font-size:1.8em; margin:0.8em 0 0.25em 0} h3{font-size:1.8em; margin:0.8em 0 0.25em 0}
@@ -44,7 +44,7 @@ header, main, footer {display:block; with:100%} /* IE fix */
.btn:hover, button:hover, [type=button]:hover, [type=submit]:hover {box-shadow:0 0 10px #666; text-decoration:none; cursor:pointer} .btn:hover, button:hover, [type=button]:hover, [type=submit]:hover {box-shadow:0 0 10px #666; text-decoration:none; cursor:pointer}
.btn.small, table .btn {padding:0.25em 0.5em; font-size:0.8em} .btn.small, table .btn {padding:0.25em 0.5em; font-size:0.8em}
.btn.large {padding:1em 2em; font-size:1.2em} .btn.large {padding:1em 2em; font-size:1.2em}
.btn.oval {border-radius:50%} .oval {border-radius:50%}
/*** helpers ***/ /*** helpers ***/
.rounded {-moz-border-radius:5px; border-radius:5px} .rounded {-moz-border-radius:5px; border-radius:5px}
@@ -62,7 +62,7 @@ header, main, footer {display:block; with:100%} /* IE fix */
.relative {position:relative} .relative {position:relative}
.relative>div {position:absolute} .relative>div {position:absolute}
.spaced {margin-bottom:20px; margin-top:20px} .spaced {margin-bottom:20px; margin-top:20px}
.hidden {display:none} .hidden {display:none !important}
/*** forms ***/ /*** forms ***/
input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]), [type=file]:before {outline:none; padding:0.5em 1em; margin:0.5px; border-bottom:1px solid #ddd; width:100%} input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]), [type=file]:before {outline:none; padding:0.5em 1em; margin:0.5px; border-bottom:1px solid #ddd; width:100%}
@@ -70,7 +70,7 @@ textarea {width:100%; border:1px solid #ddd; padding:4px 8px; outline:none; outl
select {-webkit-appearance:none; outline:none; padding:0.5em 1em; border-radius:0; margin:0.5px; border-bottom:1px solid #ddd; width:100%;background-color:transparent} select {-webkit-appearance:none; outline:none; padding:0.5em 1em; border-radius:0; margin:0.5px; border-bottom:1px solid #ddd; width:100%;background-color:transparent}
input, textarea, select, button, .btn {font-size:12px} input, textarea, select, button, .btn {font-size:12px}
input:not([type]):hover, input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):hover, select:hover, textarea:hover {background-color:#fbf6d9; transition:background-color 1s ease} input:not([type]):hover, input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):hover, select:hover, textarea:hover {background-color:#fbf6d9; transition:background-color 1s ease}
input:invalid, input.error {background:#cc1f00;color:white} input:invalid, input.error, textarea:invalid, textarea.error {background: #ffdfdf}
/*** grid ***/ /*** grid ***/
.container {margin-right:-20px} .container {margin-right:-20px}
@@ -108,14 +108,10 @@ input:invalid, input.error {background:#cc1f00;color:white}
/*** progress bar from http://codepen.io/holdencreative/details/pvxGxy ***/ /*** progress bar from http://codepen.io/holdencreative/details/pvxGxy ***/
.progress { .progress {
margin-left:-15px;
margin-right:-15px;
position:relative; position:relative;
height:8px; height:8px;
display:block; display:block;
width:120%;
background-color:#acece6; background-color:#acece6;
border-radius:0;
background-clip:padding-box; background-clip:padding-box;
overflow:hidden; overflow:hidden;
} }
@@ -189,7 +185,7 @@ input:invalid, input.error {background:#cc1f00;color:white}
.menu li {position:relative; float:left; margin:0; padding:0} .menu li {position:relative; float:left; margin:0; padding:0}
.menu ul {background:white; border:1px solid #e1e1e1; visibility:hidden; opacity:0; position:absolute; top:110%; padding:0; z-index:1000; transition:all 0.2s ease-out; list-style-type:none; box-shadow:5px 5px 10px #666} .menu ul {background:white; border:1px solid #e1e1e1; visibility:hidden; opacity:0; position:absolute; top:110%; padding:0; z-index:1000; transition:all 0.2s ease-out; list-style-type:none; box-shadow:5px 5px 10px #666}
.menu ul a {padding:10px 15px; color:#333; font-weight:700; font-size:12px; line-height:16px; display: block} .menu ul a {padding:10px 15px; color:#333; font-weight:700; font-size:12px; line-height:16px; display: block}
.menu ul li {float:none; width:200px} .menu ul li {float:none}
.menu ul ul {top:0; left:80%; z-index:1100} .menu ul ul {top:0; left:80%; z-index:1100}
.menu li:hover > ul {visibility:visible; opacity:1} .menu li:hover > ul {visibility:visible; opacity:1}
.menu>li>ul>li:first-child:before{content:''; position:absolute; width:1px; height:1px; border:10px solid transparent; left:50px; top:-20px; margin-left:-10px; border-bottom-color:white} .menu>li>ul>li:first-child:before{content:''; position:absolute; width:1px; height:1px; border:10px solid transparent; left:50px; top:-20px; margin-left:-10px; border-bottom-color:white}
@@ -208,6 +204,24 @@ input:invalid, input.error {background:#cc1f00;color:white}
.burger.accordion * {max-height:1000px; overflow:visible} .burger.accordion * {max-height:1000px; overflow:visible}
} }
/*** sliding sidebar ***/
.sidebar {
position:fixed;
z-index:1000;
-webkit-transition:all 0.5s, -webkit-transform 0.5s;
transition:all 0.5s, transform 0.5s;
left:0;
top:0;
height:100vh;
box-shadow:0 0 10px #666;
width:220px;
padding:0 10px 0 10px;
margin-left:-210px;
}
.sidebar:hover {margin-left:0}
.sidebar.right {text-align: left; left: auto; right: 0; margin-right: -210px}
.sidebar.right:hover {margin-right:0}
/*** pulsating ring from https://jsfiddle.net/mandynicole/7xrKP/ *******/ /*** pulsating ring from https://jsfiddle.net/mandynicole/7xrKP/ *******/
.pulse:after { .pulse:after {
content:""; content:"";
@@ -292,10 +306,11 @@ a:not(.btn):not(.noeffect):after {
margin-top:1.5em; margin-top:1.5em;
padding:5px 15px; padding:5px 15px;
white-space:pre-wrap; white-space:pre-wrap;
width:100px; min-width:100px;
} }
/*** accordion ***/ /*** accordion ***/
.accordion>label{cursor:pointer}
.accordion>input ~ label:before {content:"▲ "; color:#ddd} .accordion>input ~ label:before {content:"▲ "; color:#ddd}
.accordion>input:checked ~ label:before {content:"▼ "; color:#ddd} .accordion>input:checked ~ label:before {content:"▼ "; color:#ddd}
.accordion>input {display:none} .accordion>input {display:none}
+2 -2
View File
@@ -267,7 +267,7 @@ def select():
else: else:
rows = db(query, ignore_common_filters=True).select( rows = db(query, ignore_common_filters=True).select(
*fields, limitby=(start, stop)) *fields, limitby=(start, stop))
except Exception, e: except Exception as e:
import traceback import traceback
tb = traceback.format_exc() tb = traceback.format_exc()
(rows, nrows) = ([], 0) (rows, nrows) = ([], 0)
@@ -286,7 +286,7 @@ def select():
import_csv(db[request.vars.table], import_csv(db[request.vars.table],
request.vars.csvfile.file) request.vars.csvfile.file)
response.flash = T('data uploaded') response.flash = T('data uploaded')
except Exception, e: except Exception as e:
response.flash = DIV(T('unable to parse csv file'), PRE(str(e))) response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
# end handle upload csv # end handle upload csv
+11 -11
View File
@@ -29,20 +29,20 @@ except ImportError:
"You can also download a complete copy from http://www.web2py.com." "You can also download a complete copy from http://www.web2py.com."
) )
from globals import current from .globals import current
from html import * from .html import *
from validators import * from .validators import *
from http import redirect, HTTP from .http import redirect, HTTP
from dal import DAL, Field from .dal import DAL, Field
from sqlhtml import SQLFORM, SQLTABLE from .sqlhtml import SQLFORM, SQLTABLE
from compileapp import LOAD from .compileapp import LOAD
# Dummy code to enable code completion in IDE's. # Dummy code to enable code completion in IDE's.
if 0: if 0:
from globals import Request, Response, Session from .globals import Request, Response, Session
from cache import Cache from .cache import Cache
from languages import translator from .languages import translator
from tools import Auth, Crud, Mail, Service, PluginManager from .tools import Auth, Crud, Mail, Service, PluginManager
# API objects # API objects
request = Request() request = Request()
+172
View File
@@ -0,0 +1,172 @@
import sys
import hashlib
import os
PY2 = sys.version_info[0] == 2
_identity = lambda x: x
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
import Queue
import ConfigParser as configparser
from email.MIMEBase import MIMEBase
from email.Header import Header
from email import MIMEMultipart, MIMEText, Encoders, Charset
from urllib import FancyURLopener, urlencode, urlopen
from urllib import quote as urllib_quote, unquote as urllib_unquote
from string import maketrans
from types import ClassType
import cgi
reduce = reduce
hashlib_md5 = hashlib.md5
iterkeys = lambda d: d.iterkeys()
itervalues = lambda d: d.itervalues()
iteritems = lambda d: d.iteritems()
integer_types = (int, long)
string_types = (str, unicode)
text_type = unicode
basestring = basestring
xrange = xrange
long = long
unichr = unichr
unicodeT = unicode
def implements_iterator(cls):
cls.next = cls.__next__
del cls.__next__
return cls
def implements_bool(cls):
cls.__nonzero__ = cls.__bool__
del cls.__bool__
return cls
def to_bytes(obj, charset='utf-8', errors='strict'):
if obj is None:
return None
if isinstance(obj, (bytes, bytearray, buffer)):
return bytes(obj)
if isinstance(obj, unicode):
return obj.encode(charset, errors)
raise TypeError('Expected bytes')
def to_native(obj, charset='utf8', errors='strict'):
if obj is None or isinstance(obj, str):
return obj
return obj.encode(charset, errors)
def _local_html_escape(data, quote=False):
s = cgi.escape(data, quote)
return s.replace("'", "'") if quote else s
else:
import pickle
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
import configparser
import queue as Queue
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import encoders as Encoders
from email.header import Header
from email.charset import Charset
from urllib.request import FancyURLopener, urlopen
from urllib.parse import quote as urllib_quote, unquote as urllib_unquote, urlencode
import html
hashlib_md5 = lambda s: hashlib.md5(bytes(s, 'utf8'))
iterkeys = lambda d: iter(d.keys())
itervalues = lambda d: iter(d.values())
iteritems = lambda d: iter(d.items())
integer_types = (int,)
string_types = (str,)
text_type = str
basestring = str
xrange = range
long = int
unichr = chr
unicodeT = str
maketrans = str.maketrans
ClassType = type
implements_iterator = _identity
implements_bool = _identity
def to_bytes(obj, charset='utf-8', errors='strict'):
if obj is None:
return None
if isinstance(obj, (bytes, bytearray, memoryview)):
return bytes(obj)
if isinstance(obj, str):
return obj.encode(charset, errors)
raise TypeError('Expected bytes')
def to_native(obj, charset='utf8', errors='strict'):
if obj is None or isinstance(obj, str):
return obj
return obj.decode(charset, errors)
def _local_html_escape(s, quote=True):
"""
Works with bytes.
Replace special characters "&", "<" and ">" to HTML-safe sequences.
If the optional flag quote is true (the default), the quotation mark
characters, both double quote (") and single quote (') characters are also
translated.
"""
if isinstance(s, str):
return html.escape(s, quote=quote)
s = s.replace(b"&", b"&amp;") # Must be done first!
s = s.replace(b"<", b"&lt;")
s = s.replace(b">", b"&gt;")
if quote:
s = s.replace(b'"', b"&quot;")
s = s.replace(b'\'', b"&#x27;")
return s
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__
def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})
def to_unicode(obj, charset='utf-8', errors='strict'):
if obj is None:
return None
if not isinstance(obj, bytes):
return text_type(obj)
return obj.decode(charset, errors)
# shortcuts
pjoin = os.path.join
exists = os.path.exists
+7 -6
View File
@@ -9,6 +9,7 @@
Utility functions for the Admin application Utility functions for the Admin application
------------------------------------------- -------------------------------------------
""" """
from __future__ import print_function
import os import os
import sys import sys
import traceback import traceback
@@ -58,9 +59,9 @@ def app_pack(app, request, raise_ex=False, filenames=None):
filename = apath('../deposit/web2py.app.%s.w2p' % app, request) filename = apath('../deposit/web2py.app.%s.w2p' % app, request)
w2p_pack(filename, apath(app, request), filenames=filenames) w2p_pack(filename, apath(app, request), filenames=filenames)
return filename return filename
except Exception, e: except Exception as e:
import traceback import traceback
print traceback.format_exc() print(traceback.format_exc())
if raise_ex: if raise_ex:
raise raise
return False return False
@@ -82,7 +83,7 @@ def app_pack_compiled(app, request, raise_ex=False):
filename = apath('../deposit/%s.w2p' % app, request) filename = apath('../deposit/%s.w2p' % app, request)
w2p_pack(filename, apath(app, request), compiled=True) w2p_pack(filename, apath(app, request), compiled=True)
return filename return filename
except Exception, e: except Exception as e:
if raise_ex: if raise_ex:
raise raise
return None return None
@@ -343,7 +344,7 @@ def check_new_version(myversion, version_url):
pmyversion = parse_version(myversion) pmyversion = parse_version(myversion)
except IOError: except IOError:
import traceback import traceback
print traceback.format_exc() print(traceback.format_exc())
return -1, myversion return -1, myversion
if pversion[:3]+pversion[-6:] > pmyversion[:3]+pmyversion[-6:]: if pversion[:3]+pversion[-6:] > pmyversion[:3]+pmyversion[-6:]:
@@ -423,12 +424,12 @@ def upgrade(request, url='http://web2py.com'):
filename = abspath('web2py_%s_downloaded.zip' % version_type) filename = abspath('web2py_%s_downloaded.zip' % version_type)
try: try:
write_file(filename, urllib.urlopen(full_url).read(), 'wb') write_file(filename, urllib.urlopen(full_url).read(), 'wb')
except Exception, e: except Exception as e:
return False, e return False, e
try: try:
unzip(filename, destination, subfolder) unzip(filename, destination, subfolder)
return True, None return True, None
except Exception, e: except Exception as e:
return False, e return False, e
+5 -9
View File
@@ -20,7 +20,6 @@ caching will be provided by the GAE memcache
(see gluon.contrib.gae_memcache) (see gluon.contrib.gae_memcache)
""" """
import time import time
import thread
import os import os
import gc import gc
import sys import sys
@@ -41,10 +40,7 @@ try:
except ImportError: except ImportError:
have_settings = False have_settings = False
try: from gluon._compat import pickle, thread
import cPickle as pickle
except:
import pickle
try: try:
import psutil import psutil
@@ -159,7 +155,7 @@ class CacheAbstract(object):
Auxiliary function called by `clear` to search and clear cache entries Auxiliary function called by `clear` to search and clear cache entries
""" """
r = re.compile(regex) r = re.compile(regex)
for key in storage.keys(): for key in list(storage.keys()):
if r.match(str(key)): if r.match(str(key)):
del storage[key] del storage[key]
return return
@@ -265,7 +261,7 @@ class CacheInRam(CacheAbstract):
if key in self.storage: if key in self.storage:
value = self.storage[key][1] + value value = self.storage[key][1] + value
self.storage[key] = (time.time(), value) self.storage[key] = (time.time(), value)
except BaseException, e: except BaseException as e:
self.locker.release() self.locker.release()
raise e raise e
self.locker.release() self.locker.release()
@@ -635,7 +631,7 @@ class Cache(object):
# action returns something # action returns something
rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire) rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire)
http, status = None, current.response.status http, status = None, current.response.status
except HTTP, e: except HTTP as e:
# action raises HTTP (can still be valid) # action raises HTTP (can still be valid)
rtn = cache_model(cache_key, lambda: e.body, time_expire=time_expire) rtn = cache_model(cache_key, lambda: e.body, time_expire=time_expire)
http, status = HTTP(e.status, rtn, **e.headers), e.status http, status = HTTP(e.status, rtn, **e.headers), e.status
@@ -648,7 +644,7 @@ class Cache(object):
# action returns something # action returns something
rtn = func() rtn = func()
http, status = None, current.response.status http, status = None, current.response.status
except HTTP, e: except HTTP as e:
# action raises HTTP (can still be valid) # action raises HTTP (can still be valid)
status = e.status status = e.status
http = HTTP(e.status, e.body, **e.headers) http = HTTP(e.status, e.body, **e.headers)
+1 -1
View File
@@ -14,7 +14,7 @@ Note:
""" """
from os import stat from os import stat
import thread from ._compat import thread
from gluon.fileutils import read_file from gluon.fileutils import read_file
cfs = {} # for speed-up cfs = {} # for speed-up
+17 -9
View File
@@ -18,7 +18,7 @@ import fnmatch
import os import os
import copy import copy
import random import random
import __builtin__ from gluon._compat import builtin, PY2
from gluon.storage import Storage, List from gluon.storage import Storage, List
from gluon.template import parse_template from gluon.template import parse_template
from gluon.restricted import restricted, compile2 from gluon.restricted import restricted, compile2
@@ -40,9 +40,10 @@ import shutil
import imp import imp
import logging import logging
import types import types
from functools import reduce
logger = logging.getLogger("web2py") logger = logging.getLogger("web2py")
from gluon import rewrite from gluon import rewrite
from custom_import import custom_import_install from gluon.custom_import import custom_import_install
try: try:
import py_compile import py_compile
@@ -116,7 +117,7 @@ class mybuiltin(object):
#__builtins__ #__builtins__
def __getitem__(self, key): def __getitem__(self, key):
try: try:
return getattr(__builtin__, key) return getattr(builtin, key)
except AttributeError: except AttributeError:
raise KeyError(key) raise KeyError(key)
@@ -213,7 +214,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
request.env.path_info request.env.path_info
other_request.cid = target other_request.cid = target
other_request.env.http_web2py_component_element = target other_request.env.http_web2py_component_element = target
other_request.restful = types.MethodType(request.restful.im_func, other_request) # A bit nasty but needed to use LOAD on action decorates with @request.restful() other_request.restful = types.MethodType(request.restful.__func__, other_request) # A bit nasty but needed to use LOAD on action decorates with @request.restful()
other_response.view = '%s/%s.%s' % (c, f, other_request.extension) other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
other_environment = copy.copy(current.globalenv) # NASTY other_environment = copy.copy(current.globalenv) # NASTY
@@ -430,7 +431,7 @@ def build_environment(request, response, session, store_current=True):
elif is_pypy: # apply the same hack to pypy too elif is_pypy: # apply the same hack to pypy too
__builtins__ = mybuiltin() __builtins__ = mybuiltin()
else: else:
__builtins__['__import__'] = __builtin__.__import__ # WHY? __builtins__['__import__'] = builtin.__import__ # WHY?
environment['request'] = request environment['request'] = request
environment['response'] = response environment['response'] = response
environment['session'] = session environment['session'] = session
@@ -474,7 +475,7 @@ def compile_views(folder, skip_failed_views=False):
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'): for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
try: try:
data = parse_template(fname, path) data = parse_template(fname, path)
except Exception, e: except Exception as e:
if skip_failed_views: if skip_failed_views:
failed_views.append(fname) failed_views.append(fname)
else: else:
@@ -547,10 +548,17 @@ def run_models_in(environment):
path = pjoin(folder, 'models') path = pjoin(folder, 'models')
cpath = pjoin(folder, 'compiled') cpath = pjoin(folder, 'compiled')
compiled = os.path.exists(cpath) compiled = os.path.exists(cpath)
if compiled: if PY2:
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), model_cmp) if compiled:
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), model_cmp)
else:
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), model_cmp_sep)
else: else:
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), model_cmp_sep) if compiled:
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), key=lambda f: '{0:03d}'.format(f.count('.')) + f)
else:
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), key=lambda f: '{0:03d}'.format(f.count(os.path.sep)) + f)
models_to_run = None models_to_run = None
for model in models: for model in models:
if response.models_to_run != models_to_run: if response.models_to_run != models_to_run:
+15 -14
View File
@@ -13,6 +13,7 @@ Modifed by Massimo Di Pierro
- namedtuple from http://code.activestate.com/recipes/500261/ - namedtuple from http://code.activestate.com/recipes/500261/
""" """
from __future__ import print_function
__all__ = ['AIM'] __all__ = ['AIM']
@@ -248,23 +249,23 @@ def test():
payment.setParameter('x_email_customer', False) payment.setParameter('x_email_customer', False)
payment.process() payment.process()
if payment.isApproved(): if payment.isApproved():
print 'Response Code: ', payment.response.ResponseCode print('Response Code: ', payment.response.ResponseCode)
print 'Response Text: ', payment.response.ResponseText print('Response Text: ', payment.response.ResponseText)
print 'Response: ', payment.getResultResponseFull() print('Response: ', payment.getResultResponseFull())
print 'Transaction ID: ', payment.response.TransactionID print('Transaction ID: ', payment.response.TransactionID)
print 'CVV Result: ', payment.response.CVVResponse print('CVV Result: ', payment.response.CVVResponse)
print 'Approval Code: ', payment.response.AuthCode print('Approval Code: ', payment.response.AuthCode)
print 'AVS Result: ', payment.response.AVSResponse print('AVS Result: ', payment.response.AVSResponse)
elif payment.isDeclined(): elif payment.isDeclined():
print 'Your credit card was declined by your bank' print('Your credit card was declined by your bank')
elif payment.isError(): elif payment.isError():
raise AIM.AIMError('An uncaught error occurred') raise AIM.AIMError('An uncaught error occurred')
except AIM.AIMError, e: except AIM.AIMError as e:
print "Exception thrown:", e print("Exception thrown:", e)
print 'An error occured' print('An error occured')
print 'approved', payment.isApproved() print('approved', payment.isApproved())
print 'declined', payment.isDeclined() print('declined', payment.isDeclined())
print 'error', payment.isError() print('error', payment.isError())
if __name__ == '__main__': if __name__ == '__main__':
test() test()
+10 -9
View File
@@ -9,6 +9,7 @@ Modifed by Dave Stoll dave.stoll@gmail.com
- modifed to support Dow Commerce API - modifed to support Dow Commerce API
""" """
from __future__ import print_function
__all__ = ['DowCommerce'] __all__ = ['DowCommerce']
@@ -227,18 +228,18 @@ def test():
payment.process() payment.process()
if payment.isApproved(): if payment.isApproved():
print 'Payment approved!' print('Payment approved!')
print payment.getFullResponse() print(payment.getFullResponse())
elif payment.isDeclined(): elif payment.isDeclined():
print 'Your credit card was declined by your bank' print('Your credit card was declined by your bank')
elif payment.isError(): elif payment.isError():
raise DowCommerce.DowCommerceError('An uncaught error occurred') raise DowCommerce.DowCommerceError('An uncaught error occurred')
except DowCommerce.DowCommerceError, e: except DowCommerce.DowCommerceError as e:
print "Exception thrown:", e print("Exception thrown:", e)
print 'An error occured' print('An error occured')
print 'approved', payment.isApproved() print('approved', payment.isApproved())
print 'declined', payment.isDeclined() print('declined', payment.isDeclined())
print 'error', payment.isError() print('error', payment.isError())
if __name__ == '__main__': if __name__ == '__main__':
test() test()
+3 -4
View File
@@ -27,11 +27,10 @@ Once the value has been fetched (and casted) it won't change until the process
is restarted (or reload=True is passed). is restarted (or reload=True is passed).
""" """
import thread
import os import os
from ConfigParser import SafeConfigParser
from gluon import current
import json import json
from gluon._compat import thread, configparser
from gluon.globals import current
locker = thread.allocate_lock() locker = thread.allocate_lock()
@@ -121,7 +120,7 @@ class AppConfigLoader(object):
self.read_config() self.read_config()
def read_config_ini(self): def read_config_ini(self):
config = SafeConfigParser() config = configparser.SafeConfigParser()
config.read(self.file) config.read(self.file)
settings = {} settings = {}
for section in config.sections(): for section in config.sections():
+6 -4
View File
@@ -41,6 +41,8 @@ wordpress.com
revision3.com revision3.com
viddler.com viddler.com
""" """
from __future__ import print_function
from gluon._compat import FancyURLopener, urllib_quote
import re import re
import cgi import cgi
@@ -93,7 +95,7 @@ def video(url):
def googledoc_viewer(url): def googledoc_viewer(url):
return '<iframe src="https://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url) return '<iframe src="https://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib_quote(url)
def web2py_component(url): def web2py_component(url):
@@ -135,7 +137,7 @@ EXTENSION_MAPS = {
} }
class VimeoURLOpener(urllib.FancyURLopener): class VimeoURLOpener(FancyURLopener):
"Vimeo blocks the urllib user agent for some reason" "Vimeo blocks the urllib user agent for some reason"
version = "Mozilla/4.0" version = "Mozilla/4.0"
urllib._urlopener = VimeoURLOpener() urllib._urlopener = VimeoURLOpener()
@@ -215,6 +217,6 @@ laoreet tortor.</p>
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) > 1: if len(sys.argv) > 1:
print expand_html(open(sys.argv[1]).read()) print(expand_html(open(sys.argv[1]).read()))
else: else:
print test() print(test())
+4 -4
View File
@@ -4,13 +4,13 @@
"FPDF for python" "FPDF for python"
__license__ = "LGPL 3.0" __license__ = "LGPL 3.0"
__version__ = "1.7" __version__ = "1.7.2"
from fpdf import * from .fpdf import FPDF, FPDF_FONT_DIR, FPDF_VERSION, SYSTEM_TTFONTS, set_global, FPDF_CACHE_MODE, FPDF_CACHE_DIR
try: try:
from html import HTMLMixin from .html import HTMLMixin
except ImportError: except ImportError:
import warnings import warnings
warnings.warn("web2py gluon package not installed, required for html2pdf") warnings.warn("web2py gluon package not installed, required for html2pdf")
from template import Template from .template import Template
+1 -1
View File
@@ -7,7 +7,7 @@ fpdf_charwidths = {}
fpdf_charwidths['courier']={} fpdf_charwidths['courier']={}
for i in xrange(0,256): for i in range(0,256):
fpdf_charwidths['courier'][chr(i)]=600 fpdf_charwidths['courier'][chr(i)]=600
fpdf_charwidths['courierB']=fpdf_charwidths['courier'] fpdf_charwidths['courierB']=fpdf_charwidths['courier']
fpdf_charwidths['courierI']=fpdf_charwidths['courier'] fpdf_charwidths['courierI']=fpdf_charwidths['courier']
+537 -398
View File
File diff suppressed because it is too large Load Diff
+21 -17
View File
@@ -8,8 +8,8 @@ __license__ = "LGPL 3.0"
# Inspired by tuto5.py and several examples from fpdf.org, html2fpdf, etc. # Inspired by tuto5.py and several examples from fpdf.org, html2fpdf, etc.
from fpdf import FPDF from .fpdf import FPDF
from HTMLParser import HTMLParser from .py3k import PY3K, basestring, unicode, HTMLParser
DEBUG = False DEBUG = False
@@ -78,8 +78,8 @@ class HTML2FPDF(HTMLParser):
l = self.table_col_width[i:i+colspan] l = self.table_col_width[i:i+colspan]
else: else:
l = [self.td.get('width','240')] l = [self.td.get('width','240')]
w = sum([self.width2mm(lenght) for lenght in l]) w = sum([self.width2mm(length) for length in l])
h = int(self.td.get('height', 0)) / 4 or self.h*1.30 h = int(self.td.get('height', 0)) // 4 or self.h*1.30
self.table_h = h self.table_h = h
border = int(self.table.get('border', 0)) border = int(self.table.get('border', 0))
if not self.th: if not self.th:
@@ -99,30 +99,30 @@ class HTML2FPDF(HTMLParser):
height = h + (self.tfooter and self.tfooter[0][0][1] or 0) height = h + (self.tfooter and self.tfooter[0][0][1] or 0)
if self.pdf.y+height>self.pdf.page_break_trigger and not self.th: if self.pdf.y+height>self.pdf.page_break_trigger and not self.th:
self.output_table_footer() self.output_table_footer()
self.pdf.add_page() self.pdf.add_page(same = True)
self.theader_out = self.tfooter_out = False self.theader_out = self.tfooter_out = False
if self.tfoot is None and self.thead is None: if self.tfoot is None and self.thead is None:
if not self.theader_out: if not self.theader_out:
self.output_table_header() self.output_table_header()
self.box_shadow(w, h, bgcolor) self.box_shadow(w, h, bgcolor)
if DEBUG: print "td cell", self.pdf.x, w, txt, "*" if DEBUG: print("td cell", self.pdf.x, w, txt, "*")
self.pdf.cell(w,h,txt,border,0,align) self.pdf.cell(w,h,txt,border,0,align)
elif self.table is not None: elif self.table is not None:
# ignore anything else than td inside a table # ignore anything else than td inside a table
pass pass
elif self.align: elif self.align:
if DEBUG: print "cell", txt, "*" if DEBUG: print("cell", txt, "*")
self.pdf.cell(0,self.h,txt,0,1,self.align[0].upper(), self.href) self.pdf.cell(0,self.h,txt,0,1,self.align[0].upper(), self.href)
else: else:
txt = txt.replace("\n"," ") txt = txt.replace("\n"," ")
if self.href: if self.href:
self.put_link(self.href,txt) self.put_link(self.href,txt)
else: else:
if DEBUG: print "write", txt, "*" if DEBUG: print("write", txt, "*")
self.pdf.write(self.h,txt) self.pdf.write(self.h,txt)
def box_shadow(self, w, h, bgcolor): def box_shadow(self, w, h, bgcolor):
if DEBUG: print "box_shadow", w, h, bgcolor if DEBUG: print("box_shadow", w, h, bgcolor)
if bgcolor: if bgcolor:
fill_color = self.pdf.fill_color fill_color = self.pdf.fill_color
self.pdf.set_fill_color(*bgcolor) self.pdf.set_fill_color(*bgcolor)
@@ -168,7 +168,7 @@ class HTML2FPDF(HTMLParser):
def handle_starttag(self, tag, attrs): def handle_starttag(self, tag, attrs):
attrs = dict(attrs) attrs = dict(attrs)
if DEBUG: print "STARTTAG", tag, attrs if DEBUG: print("STARTTAG", tag, attrs)
if tag=='b' or tag=='i' or tag=='u': if tag=='b' or tag=='i' or tag=='u':
self.set_style(tag,1) self.set_style(tag,1)
if tag=='a': if tag=='a':
@@ -216,13 +216,16 @@ class HTML2FPDF(HTMLParser):
# save previous font state: # save previous font state:
self.font_stack.append((self.font_face, self.font_size, self.color)) self.font_stack.append((self.font_face, self.font_size, self.color))
if 'color' in attrs: if 'color' in attrs:
self.color = hex2dec(attrs['color']) color = hex2dec(attrs['color'])
self.set_text_color(*color) self.set_text_color(*color)
self.color = color self.color = color
if 'face' in attrs: if 'face' in attrs:
face = attrs.get('face').lower() face = attrs.get('face').lower()
self.pdf.set_font(face) try:
self.font_face = face self.pdf.set_font(face)
self.font_face = face
except RuntimeError:
pass # font not found, ignore
if 'size' in attrs: if 'size' in attrs:
size = int(attrs.get('size')) size = int(attrs.get('size'))
self.pdf.set_font(self.font_face, size=int(size)) self.pdf.set_font(self.font_face, size=int(size))
@@ -277,7 +280,7 @@ class HTML2FPDF(HTMLParser):
def handle_endtag(self, tag): def handle_endtag(self, tag):
#Closing tag #Closing tag
if DEBUG: print "ENDTAG", tag if DEBUG: print("ENDTAG", tag)
if tag=='h1' or tag=='h2' or tag=='h3' or tag=='h4': if tag=='h1' or tag=='h2' or tag=='h3' or tag=='h4':
self.pdf.ln(6) self.pdf.ln(6)
self.set_font() self.set_font()
@@ -326,7 +329,7 @@ class HTML2FPDF(HTMLParser):
self.tr = None self.tr = None
if tag=='td' or tag=='th': if tag=='td' or tag=='th':
if self.th: if self.th:
if DEBUG: print "revert style" if DEBUG: print("revert style")
self.set_style('B', False) # revert style self.set_style('B', False) # revert style
self.table_col_index += int(self.td.get('colspan','1')) self.table_col_index += int(self.td.get('colspan','1'))
self.td = None self.td = None
@@ -348,7 +351,7 @@ class HTML2FPDF(HTMLParser):
if size: if size:
self.font_size = size self.font_size = size
self.h = size / 72.0*25.4 self.h = size / 72.0*25.4
if DEBUG: print "H", self.h if DEBUG: print("H", self.h)
self.pdf.set_font(self.font_face or 'times','',12) self.pdf.set_font(self.font_face or 'times','',12)
self.pdf.set_font_size(self.font_size or 12) self.pdf.set_font_size(self.font_size or 12)
self.set_style('u', False) self.set_style('u', False)
@@ -365,7 +368,7 @@ class HTML2FPDF(HTMLParser):
for s in ('b','i','u'): for s in ('b','i','u'):
if self.style.get(s): if self.style.get(s):
style+=s style+=s
if DEBUG: print "SET_FONT_STYLE", style if DEBUG: print("SET_FONT_STYLE", style)
self.pdf.set_font('',style) self.pdf.set_font('',style)
def set_text_color(self, r=None, g=0, b=0): def set_text_color(self, r=None, g=0, b=0):
@@ -394,5 +397,6 @@ class HTMLMixin(object):
def write_html(self, text, image_map=None): def write_html(self, text, image_map=None):
"Parse HTML and convert it to PDF" "Parse HTML and convert it to PDF"
h2p = HTML2FPDF(self, image_map) h2p = HTML2FPDF(self, image_map)
text = h2p.unescape(text) # To deal with HTML entities
h2p.feed(text) h2p.feed(text)
+9 -4
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: latin-1 -*- # -*- coding: latin-1 -*-
from .py3k import PY3K, basestring, unicode
# fpdf php helpers: # fpdf php helpers:
def substr(s, start, length=-1): def substr(s, start, length=-1):
@@ -14,16 +16,19 @@ def print_r(array):
if not isinstance(array, dict): if not isinstance(array, dict):
array = dict([(k, k) for k in array]) array = dict([(k, k) for k in array])
for k, v in array.items(): for k, v in array.items():
print "[%s] => %s" % (k, v), print("[%s] => %s " % (k, v))
def UTF8ToUTF16BE(instr, setbom=True): def UTF8ToUTF16BE(instr, setbom=True):
"Converts UTF-8 strings to UTF16-BE." "Converts UTF-8 strings to UTF16-BE."
outstr = "" outstr = "".encode()
if (setbom): if (setbom):
outstr += "\xFE\xFF"; outstr += "\xFE\xFF".encode("latin1")
if not isinstance(instr, unicode): if not isinstance(instr, unicode):
instr = instr.decode('UTF-8') instr = instr.decode('UTF-8')
outstr += instr.encode('UTF-16BE') outstr += instr.encode('UTF-16BE')
# convert bytes back to fake unicode string until PEP461-like is implemented
if PY3K:
outstr = outstr.decode("latin1")
return outstr return outstr
def UTF8StringToArray(instr): def UTF8StringToArray(instr):
@@ -46,4 +51,4 @@ def str_pad(s, pad_length=0, pad_char= " ", pad_type= +1 ):
else: # pad both else: # pad both
return s.center(pad_length, pad_char) return s.center(pad_length, pad_char)
strlen = count = lambda s: len(s) strlen = count = lambda s: len(s)
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"Special module to handle differences between Python 2 and 3 versions"
import sys
PY3K = sys.version_info >= (3, 0)
try:
import cPickle as pickle
except ImportError:
import pickle
try:
from urllib import urlopen
except ImportError:
from urllib.request import urlopen
try:
from io import BytesIO
except ImportError:
try:
from cStringIO import StringIO as BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
try:
from hashlib import md5
except ImportError:
try:
from md5 import md5
except ImportError:
md5 = None
def hashpath(fn):
h = md5()
if PY3K:
h.update(fn.encode("UTF-8"))
else:
h.update(fn)
return h.hexdigest()
# Check if PIL is available (tries importing both pypi version and corrected or manually installed versions).
# Necessary for JPEG and GIF support.
# TODO: Pillow support
try:
from PIL import Image
except ImportError:
try:
import Image
except ImportError:
Image = None
try:
from HTMLParser import HTMLParser
except ImportError:
from html.parser import HTMLParser
if PY3K:
basestring = str
unicode = str
ord = lambda x: x
else:
basestring = basestring
unicode = unicode
ord = ord
# shortcut to bytes conversion (b prefix)
def b(s):
if isinstance(s, basestring):
return s.encode("latin1")
elif isinstance(s, int):
if PY3K:
return bytes([s]) # http://bugs.python.org/issue4588
else:
return chr(s)
def exception():
"Return the current the exception instance currently being handled"
# this is needed to support Python 2.5 that lacks "as" syntax
return sys.exc_info()[1]
+66 -138
View File
@@ -2,12 +2,15 @@
"PDF Template Helper for FPDF.py" "PDF Template Helper for FPDF.py"
from __future__ import with_statement
__author__ = "Mariano Reingart <reingart@gmail.com>" __author__ = "Mariano Reingart <reingart@gmail.com>"
__copyright__ = "Copyright (C) 2010 Mariano Reingart" __copyright__ = "Copyright (C) 2010 Mariano Reingart"
__license__ = "LGPL 3.0" __license__ = "LGPL 3.0"
import sys,os,csv import sys,os,csv
from fpdf import FPDF from .fpdf import FPDF
from .py3k import PY3K, basestring, unicode
def rgb(col): def rgb(col):
return (col // 65536), (col // 256 % 256), (col% 256) return (col // 65536), (col // 256 % 256), (col% 256)
@@ -16,11 +19,9 @@ class Template:
def __init__(self, infile=None, elements=None, format='A4', orientation='portrait', def __init__(self, infile=None, elements=None, format='A4', orientation='portrait',
title='', author='', subject='', creator='', keywords=''): title='', author='', subject='', creator='', keywords=''):
if elements: if elements:
self.elements = elements self.load_elements(elements)
self.keys = [v['name'].lower() for v in self.elements]
self.handlers = {'T': self.text, 'L': self.line, 'I': self.image, self.handlers = {'T': self.text, 'L': self.line, 'I': self.image,
'B': self.rect, 'BC': self.barcode, } 'B': self.rect, 'BC': self.barcode, 'W': self.write, }
self.pg_no = 0
self.texts = {} self.texts = {}
pdf = self.pdf = FPDF(format=format,orientation=orientation, unit="mm") pdf = self.pdf = FPDF(format=format,orientation=orientation, unit="mm")
pdf.set_title(title) pdf.set_title(title)
@@ -29,25 +30,37 @@ class Template:
pdf.set_subject(subject) pdf.set_subject(subject)
pdf.set_keywords(keywords) pdf.set_keywords(keywords)
def load_elements(self, elements):
"Initialize the internal element structures"
self.pg_no = 0
self.elements = elements
self.keys = [v['name'].lower() for v in self.elements]
def parse_csv(self, infile, delimiter=",", decimal_sep="."): def parse_csv(self, infile, delimiter=",", decimal_sep="."):
"Parse template format csv file and create elements dict" "Parse template format csv file and create elements dict"
keys = ('name','type','x1','y1','x2','y2','font','size', keys = ('name','type','x1','y1','x2','y2','font','size',
'bold','italic','underline','foreground','background', 'bold','italic','underline','foreground','background',
'align','text','priority', 'multiline') 'align','text','priority', 'multiline')
self.elements = [] self.elements = []
for row in csv.reader(open(infile, 'rb'), delimiter=delimiter): self.pg_no = 0
kargs = {} if not PY3K:
for i,v in enumerate(row): f = open(infile, 'rb')
if not v.startswith("'") and decimal_sep!=".": else:
v = v.replace(decimal_sep,".") f = open(infile)
else: with f:
v = v for row in csv.reader(f, delimiter=delimiter):
if v=='': kargs = {}
v = None for i,v in enumerate(row):
else: if not v.startswith("'") and decimal_sep!=".":
v = eval(v.strip()) v = v.replace(decimal_sep,".")
kargs[keys[i]] = v else:
self.elements.append(kargs) v = v
if v=='':
v = None
else:
v = eval(v.strip())
kargs[keys[i]] = v
self.elements.append(kargs)
self.keys = [v['name'].lower() for v in self.elements] self.keys = [v['name'].lower() for v in self.elements]
def add_page(self): def add_page(self):
@@ -55,8 +68,8 @@ class Template:
self.texts[self.pg_no] = {} self.texts[self.pg_no] = {}
def __setitem__(self, name, value): def __setitem__(self, name, value):
if self.has_key(name): if name.lower() in self.keys:
if isinstance(value,unicode): if not PY3K and isinstance(value, unicode):
value = value.encode("latin1","ignore") value = value.encode("latin1","ignore")
elif value is None: elif value is None:
value = "" value = ""
@@ -71,7 +84,7 @@ class Template:
return name.lower() in self.keys return name.lower() in self.keys
def __getitem__(self, name): def __getitem__(self, name):
if self.has_key(name): if name in self.keys:
key = name.lower() key = name.lower()
if key in self.texts: if key in self.texts:
# text for this page: # text for this page:
@@ -94,7 +107,7 @@ class Template:
if element['underline']: style += "U" if element['underline']: style += "U"
pdf.set_font(element['font'],style,element['size']) pdf.set_font(element['font'],style,element['size'])
align = {'L':'L','R':'R','I':'L','D':'R','C':'C','':''}.get(element['align']) # D/I in spanish align = {'L':'L','R':'R','I':'L','D':'R','C':'C','':''}.get(element['align']) # D/I in spanish
if isinstance(text, unicode): if isinstance(text, unicode) and not PY3K:
text = text.encode("latin1","ignore") text = text.encode("latin1","ignore")
else: else:
text = str(text) text = str(text)
@@ -110,16 +123,17 @@ class Template:
pdf.set_auto_page_break(False,margin=0) pdf.set_auto_page_break(False,margin=0)
for element in sorted(self.elements,key=lambda x: x['priority']): for element in sorted(self.elements,key=lambda x: x['priority']):
# make a copy of the element: #print "dib",element['type'], element['name'], element['x1'], element['y1'], element['x2'], element['y2']
element = dict(element) element = element.copy()
element['text'] = self.texts[pg].get(element['name'].lower(), element['text']) element['text'] = self.texts[pg].get(element['name'].lower(), element['text'])
if 'rotate' in element: if 'rotate' in element:
pdf.rotate(element['rotate'], element['x1'], element['y1']) pdf.rotate(element['rotate'], element['x1'], element['y1'])
self.handlers[element['type'].upper()](pdf, **element) self.handlers[element['type'].upper()](pdf, **element)
if 'rotate' in element: if 'rotate' in element:
pdf.rotate(0) pdf.rotate(0)
return pdf.output(outfile, dest) if dest:
return pdf.output(outfile, dest)
def text(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=10, def text(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=10,
bold=False, italic=False, underline=False, align="", bold=False, italic=False, underline=False, align="",
@@ -157,7 +171,7 @@ class Template:
# multiline==False: trim to fit exactly the space defined # multiline==False: trim to fit exactly the space defined
text = pdf.multi_cell(w=x2-x1, h=y2-y1, text = pdf.multi_cell(w=x2-x1, h=y2-y1,
txt=text, align=align, split_only=True)[0] txt=text, align=align, split_only=True)[0]
print "trimming: *%s*" % text print("trimming: *%s*" % text)
pdf.cell(w=x2-x1,h=y2-y1,txt=text,border=0,ln=0,align=align) pdf.cell(w=x2-x1,h=y2-y1,txt=text,border=0,ln=0,align=align)
#pdf.Text(x=x1,y=y1,txt=text) #pdf.Text(x=x1,y=y1,txt=text)
@@ -179,7 +193,8 @@ class Template:
pdf.rect(x1, y1, x2-x1, y2-y1) pdf.rect(x1, y1, x2-x1, y2-y1)
def image(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', *args,**kwargs): def image(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', *args,**kwargs):
pdf.image(text,x1,y1,w=x2-x1,h=y2-y1,type='',link='') if text:
pdf.image(text,x1,y1,w=x2-x1,h=y2-y1,type='',link='')
def barcode(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=1, def barcode(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=1,
foreground=0, *args, **kwargs): foreground=0, *args, **kwargs):
@@ -189,113 +204,26 @@ class Template:
if font == 'interleaved 2of5 nt': if font == 'interleaved 2of5 nt':
pdf.interleaved2of5(text,x1,y1,w=size,h=y2-y1) pdf.interleaved2of5(text,x1,y1,w=size,h=y2-y1)
# Added by Derek Schwalenberg Schwalenberg1013@gmail.com to allow (url) links in templates (using write method) 2014-02-22
if __name__ == "__main__": def write(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=1,
bold=False, italic=False, underline=False, align="", link='http://example.com',
# generate sample invoice (according Argentina's regulations) foreground=0, *args, **kwargs):
if pdf.text_color!=rgb(foreground):
import random pdf.set_text_color(*rgb(foreground))
from decimal import Decimal font = font.strip().lower()
if font == 'arial black':
f = Template(format="A4", font = 'arial'
title="Sample Invoice", author="Sample Company", style = ""
subject="Sample Customer", keywords="Electronic TAX Invoice") for tag in 'B', 'I', 'U':
f.parse_csv(infile="invoice.csv", delimiter=";", decimal_sep=",") if (text.startswith("<%s>" % tag) and text.endswith("</%s>" %tag)):
text = text[3:-4]
detail = "Lorem ipsum dolor sit amet, consectetur. " * 30 style += tag
items = [] if bold: style += "B"
for i in range(1, 30): if italic: style += "I"
ds = "Sample product %s" % i if underline: style += "U"
qty = random.randint(1,10) align = {'L':'L','R':'R','I':'L','D':'R','C':'C','':''}.get(align) # D/I in spanish
price = round(random.random()*100,3) pdf.set_font(font,style,size)
code = "%s%s%02d" % (chr(random.randint(65,90)), chr(random.randint(65,90)),i) ##m_k = 72 / 2.54
items.append(dict(code=code, unit='u', ##h = (size/m_k)
qty=qty, price=price, pdf.set_xy(x1,y1)
amount=qty*price, pdf.write(5,text,link)
ds="%s: %s" % (i,ds)))
# divide and count lines
lines = 0
li_items = []
for it in items:
qty = it['qty']
code = it['code']
unit = it['unit']
for ds in f.split_multicell(it['ds'], 'item_description01'):
# add item description line (without price nor amount)
li_items.append(dict(code=code, ds=ds, qty=qty, unit=unit, price=None, amount=None))
# clean qty and code (show only at first)
unit = qty = code = None
# set last item line price and amount
li_items[-1].update(amount = it['amount'],
price = it['price'])
obs="\n<U>Detail:</U>\n\n" + detail
for ds in f.split_multicell(obs, 'item_description01'):
li_items.append(dict(code=code, ds=ds, qty=qty, unit=unit, price=None, amount=None))
# calculate pages:
lines = len(li_items)
max_lines_per_page = 24
pages = lines / (max_lines_per_page - 1)
if lines % (max_lines_per_page - 1): pages = pages + 1
# completo campos y hojas
for page in range(1, pages+1):
f.add_page()
f['page'] = 'Page %s of %s' % (page, pages)
if pages>1 and page<pages:
s = 'Continues on page %s' % (page+1)
else:
s = ''
f['item_description%02d' % (max_lines_per_page+1)] = s
f["company_name"] = "Sample Company"
f["company_logo"] = "tutorial/logo.png"
f["company_header1"] = "Some Address - somewhere -"
f["company_header2"] = "http://www.example.com"
f["company_footer1"] = "Tax Code ..."
f["company_footer2"] = "Tax/VAT ID ..."
f['number'] = '0001-00001234'
f['issue_date'] = '2010-09-10'
f['due_date'] = '2099-09-10'
f['customer_name'] = "Sample Client"
f['customer_address'] = "Siempreviva 1234"
# print line item...
li = 0
k = 0
total = Decimal("0.00")
for it in li_items:
k = k + 1
if k > page * (max_lines_per_page - 1):
break
if it['amount']:
total += Decimal("%.6f" % it['amount'])
if k > (page - 1) * (max_lines_per_page - 1):
li += 1
if it['qty'] is not None:
f['item_quantity%02d' % li] = it['qty']
if it['code'] is not None:
f['item_code%02d' % li] = it['code']
if it['unit'] is not None:
f['item_unit%02d' % li] = it['unit']
f['item_description%02d' % li] = it['ds']
if it['price'] is not None:
f['item_price%02d' % li] = "%0.3f" % it['price']
if it['amount'] is not None:
f['item_amount%02d' % li] = "%0.2f" % it['amount']
if pages == page:
f['net'] = "%0.2f" % (total/Decimal("1.21"))
f['vat'] = "%0.2f" % (total*(1-1/Decimal("1.21")))
f['total_label'] = 'Total:'
else:
f['total_label'] = 'SubTotal:'
f['total'] = "%0.2f" % total
f.render("./invoice.pdf")
if sys.platform.startswith("linux"):
os.system("evince ./invoice.pdf")
else:
os.system("./invoice.pdf")
+358 -366
View File
@@ -16,10 +16,13 @@
# #
#****************************************************************************** #******************************************************************************
from __future__ import with_statement
from struct import pack, unpack, unpack_from from struct import pack, unpack, unpack_from
import re import re
import warnings import warnings
from php import die, substr, str_repeat, str_pad, strlen, count from .php import die, substr, str_repeat, str_pad, strlen, count
from .py3k import b, ord
# Define the value used in the "head" table of a created TTF file # Define the value used in the "head" table of a created TTF file
@@ -55,7 +58,7 @@ def sub32(x, y):
def calcChecksum(data): def calcChecksum(data):
if (strlen(data) % 4): if (strlen(data) % 4):
data += str_repeat("\0", (4-(len(data) % 4))) data += str_repeat(b("\0"), (4-(len(data) % 4)))
hi=0x0000 hi=0x0000
lo=0x0000 lo=0x0000
for i in range(0, len(data), 4): for i in range(0, len(data), 4):
@@ -74,26 +77,25 @@ class TTFontFile:
def getMetrics(self, file): def getMetrics(self, file):
self.filename = file self.filename = file
self.fh = open(file,'rb') with open(file,'rb') as self.fh:
self._pos = 0 self._pos = 0
self.charWidths = [] self.charWidths = []
self.glyphPos = {} self.glyphPos = {}
self.charToGlyph = {} self.charToGlyph = {}
self.tables = {} self.tables = {}
self.otables = {} self.otables = {}
self.ascent = 0 self.ascent = 0
self.descent = 0 self.descent = 0
self.TTCFonts = {} self.TTCFonts = {}
self.version = version = self.read_ulong() self.version = version = self.read_ulong()
if (version==0x4F54544F): if (version==0x4F54544F):
die("Postscript outlines are not supported") die("Postscript outlines are not supported")
if (version==0x74746366): if (version==0x74746366):
die("ERROR - TrueType Fonts Collections not supported") die("ERROR - TrueType Fonts Collections not supported")
if (version not in (0x00010000,0x74727565)): if (version not in (0x00010000,0x74727565)):
die("Not a TrueType font: version=" + version) die("Not a TrueType font: version=" + str(version))
self.readTableDirectory() self.readTableDirectory()
self.extractInfo() self.extractInfo()
self.fh.close()
def readTableDirectory(self, ): def readTableDirectory(self, ):
self.numTables = self.read_ushort() self.numTables = self.read_ushort()
@@ -130,7 +132,7 @@ class TTFontFile:
def read_tag(self): def read_tag(self):
self._pos += 4 self._pos += 4
return self.fh.read(4) return self.fh.read(4).decode("latin1")
def read_short(self): def read_short(self):
self._pos += 2 self._pos += 2
@@ -204,7 +206,7 @@ class TTFontFile:
def add(self, tag, data): def add(self, tag, data):
if (tag == 'head') : if (tag == 'head') :
data = self.splice(data, 8, "\0\0\0\0") data = self.splice(data, 8, b("\0\0\0\0"))
self.otables[tag] = data self.otables[tag] = data
############################################/ ############################################/
@@ -226,7 +228,7 @@ class TTFontFile:
numRecords = self.read_ushort() numRecords = self.read_ushort()
string_data_offset = name_offset + self.read_ushort() string_data_offset = name_offset + self.read_ushort()
names = {1:'',2:'',3:'',4:'',6:''} names = {1:'',2:'',3:'',4:'',6:''}
K = names.keys() K = list(names.keys())
nameCount = len(names) nameCount = len(names)
for i in range(numRecords): for i in range(numRecords):
platformId = self.read_ushort() platformId = self.read_ushort()
@@ -242,7 +244,7 @@ class TTFontFile:
self.seek(string_data_offset + offset) self.seek(string_data_offset + offset)
if (length % 2 != 0): if (length % 2 != 0):
die("PostScript name is UTF-16BE string of odd length") die("PostScript name is UTF-16BE string of odd length")
length /= 2 length //= 2
N = '' N = ''
while (length > 0): while (length > 0):
char = self.read_ushort() char = self.read_ushort()
@@ -253,7 +255,7 @@ class TTFontFile:
elif (platformId == 1 and encodingId == 0 and languageId == 0): # Macintosh, Roman, English, PS Name elif (platformId == 1 and encodingId == 0 and languageId == 0): # Macintosh, Roman, English, PS Name
opos = self._pos opos = self._pos
N = self.get_chunk(string_data_offset + offset, length) N = self.get_chunk(string_data_offset + offset, length).decode("latin1")
self._pos = opos self._pos = opos
self.seek(opos) self.seek(opos)
@@ -455,346 +457,344 @@ class TTFontFile:
def makeSubset(self, file, subset): def makeSubset(self, file, subset):
self.filename = file self.filename = file
self.fh = open(file ,'rb') with open(file ,'rb') as self.fh:
self._pos = 0 self._pos = 0
self.charWidths = [] self.charWidths = []
self.glyphPos = {} self.glyphPos = {}
self.charToGlyph = {} self.charToGlyph = {}
self.tables = {} self.tables = {}
self.otables = {} self.otables = {}
self.ascent = 0 self.ascent = 0
self.descent = 0 self.descent = 0
self.skip(4) self.skip(4)
self.maxUni = 0 self.maxUni = 0
self.readTableDirectory() self.readTableDirectory()
#################/ #################/
# head - Font header table # head - Font header table
#################/ #################/
self.seek_table("head") self.seek_table("head")
self.skip(50) self.skip(50)
indexToLocFormat = self.read_ushort() indexToLocFormat = self.read_ushort()
glyphDataFormat = self.read_ushort() glyphDataFormat = self.read_ushort()
#################/ #################/
# hhea - Horizontal header table # hhea - Horizontal header table
#################/ #################/
self.seek_table("hhea") self.seek_table("hhea")
self.skip(32) self.skip(32)
metricDataFormat = self.read_ushort() metricDataFormat = self.read_ushort()
orignHmetrics = numberOfHMetrics = self.read_ushort() orignHmetrics = numberOfHMetrics = self.read_ushort()
#################/ #################/
# maxp - Maximum profile table # maxp - Maximum profile table
#################/ #################/
self.seek_table("maxp") self.seek_table("maxp")
self.skip(4) self.skip(4)
numGlyphs = self.read_ushort() numGlyphs = self.read_ushort()
#################/ #################/
# cmap - Character to glyph index mapping table # cmap - Character to glyph index mapping table
#################/ #################/
cmap_offset = self.seek_table("cmap") cmap_offset = self.seek_table("cmap")
self.skip(2) self.skip(2)
cmapTableCount = self.read_ushort() cmapTableCount = self.read_ushort()
unicode_cmap_offset = 0 unicode_cmap_offset = 0
unicode_cmap_offset12 = 0 unicode_cmap_offset12 = 0
for i in range(cmapTableCount): for i in range(cmapTableCount):
platformID = self.read_ushort() platformID = self.read_ushort()
encodingID = self.read_ushort() encodingID = self.read_ushort()
offset = self.read_ulong() offset = self.read_ulong()
save_pos = self._pos save_pos = self._pos
if platformID == 3 and encodingID == 10: # Microsoft, UCS-4 if platformID == 3 and encodingID == 10: # Microsoft, UCS-4
format = self.get_ushort(cmap_offset + offset) format = self.get_ushort(cmap_offset + offset)
if (format == 12): if (format == 12):
if not unicode_cmap_offset12: if not unicode_cmap_offset12:
unicode_cmap_offset12 = cmap_offset + offset unicode_cmap_offset12 = cmap_offset + offset
break break
if ((platformID == 3 and encodingID == 1) or platformID == 0): # Microsoft, Unicode if ((platformID == 3 and encodingID == 1) or platformID == 0): # Microsoft, Unicode
format = self.get_ushort(cmap_offset + offset) format = self.get_ushort(cmap_offset + offset)
if (format == 4): if (format == 4):
unicode_cmap_offset = cmap_offset + offset unicode_cmap_offset = cmap_offset + offset
break break
self.seek(save_pos ) self.seek(save_pos )
if not unicode_cmap_offset and not unicode_cmap_offset12: if not unicode_cmap_offset and not unicode_cmap_offset12:
die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 3, encoding 10, format 12, or platform 0, any encoding, format 4)') die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 3, encoding 10, format 12, or platform 0, any encoding, format 4)')
glyphToChar = {} glyphToChar = {}
charToGlyph = {} charToGlyph = {}
if unicode_cmap_offset12: if unicode_cmap_offset12:
self.getCMAP12(unicode_cmap_offset12, glyphToChar, charToGlyph) self.getCMAP12(unicode_cmap_offset12, glyphToChar, charToGlyph)
else: else:
self.getCMAP4(unicode_cmap_offset, glyphToChar, charToGlyph) self.getCMAP4(unicode_cmap_offset, glyphToChar, charToGlyph)
self.charToGlyph = charToGlyph self.charToGlyph = charToGlyph
#################/ #################/
# hmtx - Horizontal metrics table # hmtx - Horizontal metrics table
#################/ #################/
scale = 1 # not used scale = 1 # not used
self.getHMTX(numberOfHMetrics, numGlyphs, glyphToChar, scale) self.getHMTX(numberOfHMetrics, numGlyphs, glyphToChar, scale)
#################/ #################/
# loca - Index to location # loca - Index to location
#################/ #################/
self.getLOCA(indexToLocFormat, numGlyphs) self.getLOCA(indexToLocFormat, numGlyphs)
subsetglyphs = [(0, 0)] # special "sorted dict"! subsetglyphs = [(0, 0)] # special "sorted dict"!
subsetCharToGlyph = {} subsetCharToGlyph = {}
for code in subset: for code in subset:
if (code in self.charToGlyph): if (code in self.charToGlyph):
if (self.charToGlyph[code], code) not in subsetglyphs: if (self.charToGlyph[code], code) not in subsetglyphs:
subsetglyphs.append((self.charToGlyph[code], code)) # Old Glyph ID => Unicode subsetglyphs.append((self.charToGlyph[code], code)) # Old Glyph ID => Unicode
subsetCharToGlyph[code] = self.charToGlyph[code] # Unicode to old GlyphID subsetCharToGlyph[code] = self.charToGlyph[code] # Unicode to old GlyphID
self.maxUni = max(self.maxUni, code) self.maxUni = max(self.maxUni, code)
(start,dummy) = self.get_table_pos('glyf') (start,dummy) = self.get_table_pos('glyf')
subsetglyphs.sort() subsetglyphs.sort()
glyphSet = {} glyphSet = {}
n = 0 n = 0
fsLastCharIndex = 0 # maximum Unicode index (character code) in this font, according to the cmap subtable for platform ID 3 and platform- specific encoding ID 0 or 1. fsLastCharIndex = 0 # maximum Unicode index (character code) in this font, according to the cmap subtable for platform ID 3 and platform- specific encoding ID 0 or 1.
for originalGlyphIdx, uni in subsetglyphs: for originalGlyphIdx, uni in subsetglyphs:
fsLastCharIndex = max(fsLastCharIndex , uni) fsLastCharIndex = max(fsLastCharIndex , uni)
glyphSet[originalGlyphIdx] = n # old glyphID to new glyphID glyphSet[originalGlyphIdx] = n # old glyphID to new glyphID
n += 1 n += 1
codeToGlyph = {} codeToGlyph = {}
for uni, originalGlyphIdx in sorted(subsetCharToGlyph.items()): for uni, originalGlyphIdx in sorted(subsetCharToGlyph.items()):
codeToGlyph[uni] = glyphSet[originalGlyphIdx] codeToGlyph[uni] = glyphSet[originalGlyphIdx]
self.codeToGlyph = codeToGlyph self.codeToGlyph = codeToGlyph
for originalGlyphIdx, uni in subsetglyphs: for originalGlyphIdx, uni in subsetglyphs:
nonlocals = {'start': start, 'glyphSet': glyphSet, nonlocals = {'start': start, 'glyphSet': glyphSet,
'subsetglyphs': subsetglyphs} 'subsetglyphs': subsetglyphs}
self.getGlyphs(originalGlyphIdx, nonlocals) self.getGlyphs(originalGlyphIdx, nonlocals)
numGlyphs = numberOfHMetrics = len(subsetglyphs) numGlyphs = numberOfHMetrics = len(subsetglyphs)
#tables copied from the original #tables copied from the original
tags = ['name'] tags = ['name']
for tag in tags: for tag in tags:
self.add(tag, self.get_table(tag)) self.add(tag, self.get_table(tag))
tags = ['cvt ', 'fpgm', 'prep', 'gasp'] tags = ['cvt ', 'fpgm', 'prep', 'gasp']
for tag in tags: for tag in tags:
if (tag in self.tables): if (tag in self.tables):
self.add(tag, self.get_table(tag)) self.add(tag, self.get_table(tag))
# post - PostScript # post - PostScript
opost = self.get_table('post') opost = self.get_table('post')
post = "\x00\x03\x00\x00" + substr(opost,4,12) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" post = b("\x00\x03\x00\x00") + substr(opost,4,12) + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
self.add('post', post) self.add('post', post)
# Sort CID2GID map into segments of contiguous codes # Sort CID2GID map into segments of contiguous codes
if 0 in codeToGlyph: if 0 in codeToGlyph:
del codeToGlyph[0] del codeToGlyph[0]
#unset(codeToGlyph[65535]) #unset(codeToGlyph[65535])
rangeid = 0 rangeid = 0
range_ = {} range_ = {}
prevcid = -2 prevcid = -2
prevglidx = -1 prevglidx = -1
# for each character # for each character
for cid, glidx in sorted(codeToGlyph.items()): for cid, glidx in sorted(codeToGlyph.items()):
if (cid == (prevcid + 1) and glidx == (prevglidx + 1)): if (cid == (prevcid + 1) and glidx == (prevglidx + 1)):
range_[rangeid].append(glidx) range_[rangeid].append(glidx)
else: else:
# new range # new range
rangeid = cid rangeid = cid
range_[rangeid] = [] range_[rangeid] = []
range_[rangeid].append(glidx) range_[rangeid].append(glidx)
prevcid = cid prevcid = cid
prevglidx = glidx prevglidx = glidx
# cmap - Character to glyph mapping - Format 4 (MS / ) # cmap - Character to glyph mapping - Format 4 (MS / )
segCount = len(range_) + 1 # + 1 Last segment has missing character 0xFFFF segCount = len(range_) + 1 # + 1 Last segment has missing character 0xFFFF
searchRange = 1 searchRange = 1
entrySelector = 0 entrySelector = 0
while (searchRange * 2 <= segCount ): while (searchRange * 2 <= segCount ):
searchRange = searchRange * 2
entrySelector = entrySelector + 1
searchRange = searchRange * 2 searchRange = searchRange * 2
entrySelector = entrySelector + 1 rangeShift = segCount * 2 - searchRange
length = 16 + (8*segCount ) + (numGlyphs+1)
searchRange = searchRange * 2 cmap = [0, 1, # Index : version, number of encoding subtables
rangeShift = segCount * 2 - searchRange 3, 1, # Encoding Subtable : platform (MS=3), encoding (Unicode)
length = 16 + (8*segCount ) + (numGlyphs+1) 0, 12, # Encoding Subtable : offset (hi,lo)
cmap = [0, 1, # Index : version, number of encoding subtables 4, length, 0, # Format 4 Mapping subtable: format, length, language
3, 1, # Encoding Subtable : platform (MS=3), encoding (Unicode) segCount*2,
0, 12, # Encoding Subtable : offset (hi,lo) searchRange,
4, length, 0, # Format 4 Mapping subtable: format, length, language entrySelector,
segCount*2, rangeShift]
searchRange,
entrySelector,
rangeShift]
range_ = sorted(range_.items()) range_ = sorted(range_.items())
# endCode(s) # endCode(s)
for start, subrange in range_: for start, subrange in range_:
endCode = start + (len(subrange)-1) endCode = start + (len(subrange)-1)
cmap.append(endCode) # endCode(s) cmap.append(endCode) # endCode(s)
cmap.append(0xFFFF) # endCode of last Segment cmap.append(0xFFFF) # endCode of last Segment
cmap.append(0) # reservedPad cmap.append(0) # reservedPad
# startCode(s) # startCode(s)
for start, subrange in range_: for start, subrange in range_:
cmap.append(start) # startCode(s) cmap.append(start) # startCode(s)
cmap.append(0xFFFF) # startCode of last Segment cmap.append(0xFFFF) # startCode of last Segment
# idDelta(s) # idDelta(s)
for start, subrange in range_: for start, subrange in range_:
idDelta = -(start-subrange[0]) idDelta = -(start-subrange[0])
n += count(subrange) n += count(subrange)
cmap.append(idDelta) # idDelta(s) cmap.append(idDelta) # idDelta(s)
cmap.append(1) # idDelta of last Segment cmap.append(1) # idDelta of last Segment
# idRangeOffset(s) # idRangeOffset(s)
for subrange in range_: for subrange in range_:
cmap.append(0) # idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0 cmap.append(0) # idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0
cmap.append(0) # idRangeOffset of last Segment cmap.append(0) # idRangeOffset of last Segment
for subrange, glidx in range_: for subrange, glidx in range_:
cmap.extend(glidx) cmap.extend(glidx)
cmap.append(0) # Mapping for last character cmap.append(0) # Mapping for last character
cmapstr = '' cmapstr = b('')
for cm in cmap: for cm in cmap:
if cm >= 0: if cm >= 0:
cmapstr += pack(">H", cm) cmapstr += pack(">H", cm)
else: else:
try:
cmapstr += pack(">h", cm)
except:
warnings.warn("cmap value too big/small: %s" % cm)
cmapstr += pack(">H", -cm)
self.add('cmap', cmapstr)
# glyf - Glyph data
(glyfOffset,glyfLength) = self.get_table_pos('glyf')
if (glyfLength < self.maxStrLenRead):
glyphData = self.get_table('glyf')
offsets = []
glyf = b('')
pos = 0
hmtxstr = b('')
xMinT = 0
yMinT = 0
xMaxT = 0
yMaxT = 0
advanceWidthMax = 0
minLeftSideBearing = 0
minRightSideBearing = 0
xMaxExtent = 0
maxPoints = 0 # points in non-compound glyph
maxContours = 0 # contours in non-compound glyph
maxComponentPoints = 0 # points in compound glyph
maxComponentContours = 0 # contours in compound glyph
maxComponentElements = 0 # number of glyphs referenced at top level
maxComponentDepth = 0 # levels of recursion, set to 0 if font has only simple glyphs
self.glyphdata = {}
for originalGlyphIdx, uni in subsetglyphs:
# hmtx - Horizontal Metrics
hm = self.getHMetric(orignHmetrics, originalGlyphIdx)
hmtxstr += hm
offsets.append(pos)
try: try:
cmapstr += pack(">h", cm) glyphPos = self.glyphPos[originalGlyphIdx]
except: glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos
warnings.warn("cmap value too big/small: %s" % cm) except IndexError:
cmapstr += pack(">H", -cm) warnings.warn("missing glyph %s" % (originalGlyphIdx))
self.add('cmap', cmapstr) glyphLen = 0
# glyf - Glyph data if (glyfLength < self.maxStrLenRead):
(glyfOffset,glyfLength) = self.get_table_pos('glyf') data = substr(glyphData,glyphPos,glyphLen)
if (glyfLength < self.maxStrLenRead): else:
glyphData = self.get_table('glyf') if (glyphLen > 0):
data = self.get_chunk(glyfOffset+glyphPos,glyphLen)
offsets = [] else:
glyf = '' data = b('')
pos = 0
if (glyphLen > 0):
hmtxstr = '' up = unpack(">H", substr(data,0,2))[0]
xMinT = 0 if (glyphLen > 2 and (up & (1 << 15)) ): # If number of contours <= -1 i.e. composite glyph
yMinT = 0 pos_in_glyph = 10
xMaxT = 0 flags = GF_MORE
yMaxT = 0 nComponentElements = 0
advanceWidthMax = 0 while (flags & GF_MORE):
minLeftSideBearing = 0 nComponentElements += 1 # number of glyphs referenced at top level
minRightSideBearing = 0 up = unpack(">H", substr(data,pos_in_glyph,2))
xMaxExtent = 0 flags = up[0]
maxPoints = 0 # points in non-compound glyph up = unpack(">H", substr(data,pos_in_glyph+2,2))
maxContours = 0 # contours in non-compound glyph glyphIdx = up[0]
maxComponentPoints = 0 # points in compound glyph self.glyphdata.setdefault(originalGlyphIdx, {}).setdefault('compGlyphs', []).append(glyphIdx)
maxComponentContours = 0 # contours in compound glyph try:
maxComponentElements = 0 # number of glyphs referenced at top level data = self._set_ushort(data, pos_in_glyph + 2, glyphSet[glyphIdx])
maxComponentDepth = 0 # levels of recursion, set to 0 if font has only simple glyphs except KeyError:
self.glyphdata = {} data = 0
warnings.warn("missing glyph data %s" % glyphIdx)
for originalGlyphIdx, uni in subsetglyphs: pos_in_glyph += 4
# hmtx - Horizontal Metrics if (flags & GF_WORDS):
hm = self.getHMetric(orignHmetrics, originalGlyphIdx) pos_in_glyph += 4
hmtxstr += hm else:
pos_in_glyph += 2
if (flags & GF_SCALE):
pos_in_glyph += 2
elif (flags & GF_XYSCALE):
pos_in_glyph += 4
elif (flags & GF_TWOBYTWO):
pos_in_glyph += 8
maxComponentElements = max(maxComponentElements, nComponentElements)
glyf += data
pos += glyphLen
if (pos % 4 != 0):
padding = 4 - (pos % 4)
glyf += str_repeat(b("\0"),padding)
pos += padding
offsets.append(pos) offsets.append(pos)
try: self.add('glyf', glyf)
glyphPos = self.glyphPos[originalGlyphIdx]
glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos
except IndexError:
warnings.warn("missing glyph %s" % (originalGlyphIdx))
glyphLen = 0
if (glyfLength < self.maxStrLenRead): # hmtx - Horizontal Metrics
data = substr(glyphData,glyphPos,glyphLen) self.add('hmtx', hmtxstr)
# loca - Index to location
locastr = b('')
if (((pos + 1) >> 1) > 0xFFFF):
indexToLocFormat = 1 # long format
for offset in offsets:
locastr += pack(">L",offset)
else: else:
if (glyphLen > 0): indexToLocFormat = 0 # short format
data = self.get_chunk(glyfOffset+glyphPos,glyphLen) for offset in offsets:
else: locastr += pack(">H",offset//2)
data = ''
if (glyphLen > 0): self.add('loca', locastr)
up = unpack(">H", substr(data,0,2))[0]
if (glyphLen > 2 and (up & (1 << 15)) ): # If number of contours <= -1 i.e. composiste glyph
pos_in_glyph = 10
flags = GF_MORE
nComponentElements = 0
while (flags & GF_MORE):
nComponentElements += 1 # number of glyphs referenced at top level
up = unpack(">H", substr(data,pos_in_glyph,2))
flags = up[0]
up = unpack(">H", substr(data,pos_in_glyph+2,2))
glyphIdx = up[0]
self.glyphdata.setdefault(originalGlyphIdx, {}).setdefault('compGlyphs', []).append(glyphIdx)
try:
data = self._set_ushort(data, pos_in_glyph + 2, glyphSet[glyphIdx])
except KeyError:
data = 0
warnings.warn("missing glyph data %s" % glyphIdx)
pos_in_glyph += 4
if (flags & GF_WORDS):
pos_in_glyph += 4
else:
pos_in_glyph += 2
if (flags & GF_SCALE):
pos_in_glyph += 2
elif (flags & GF_XYSCALE):
pos_in_glyph += 4
elif (flags & GF_TWOBYTWO):
pos_in_glyph += 8
maxComponentElements = max(maxComponentElements, nComponentElements)
glyf += data
pos += glyphLen
if (pos % 4 != 0):
padding = 4 - (pos % 4)
glyf += str_repeat("\0",padding)
pos += padding
offsets.append(pos) # head - Font header
self.add('glyf', glyf) head = self.get_table('head')
head = self._set_ushort(head, 50, indexToLocFormat)
self.add('head', head)
# hmtx - Horizontal Metrics # hhea - Horizontal Header
self.add('hmtx', hmtxstr) hhea = self.get_table('hhea')
hhea = self._set_ushort(hhea, 34, numberOfHMetrics)
self.add('hhea', hhea)
# loca - Index to location # maxp - Maximum Profile
locastr = '' maxp = self.get_table('maxp')
if (((pos + 1) >> 1) > 0xFFFF): maxp = self._set_ushort(maxp, 4, numGlyphs)
indexToLocFormat = 1 # long format self.add('maxp', maxp)
for offset in offsets:
locastr += pack(">L",offset)
else:
indexToLocFormat = 0 # short format
for offset in offsets:
locastr += pack(">H",(offset/2))
self.add('loca', locastr)
# head - Font header # OS/2 - OS/2
head = self.get_table('head') os2 = self.get_table('OS/2')
head = self._set_ushort(head, 50, indexToLocFormat) self.add('OS/2', os2 )
self.add('head', head)
# hhea - Horizontal Header
hhea = self.get_table('hhea')
hhea = self._set_ushort(hhea, 34, numberOfHMetrics)
self.add('hhea', hhea)
# maxp - Maximum Profile
maxp = self.get_table('maxp')
maxp = self._set_ushort(maxp, 4, numGlyphs)
self.add('maxp', maxp)
# OS/2 - OS/2
os2 = self.get_table('OS/2')
self.add('OS/2', os2 )
self.fh.close()
# Put the TTF file together # Put the TTF file together
stm = self.endTTFile('') stm = self.endTTFile('')
@@ -864,11 +864,16 @@ class TTFontFile:
def getHMTX(self, numberOfHMetrics, numGlyphs, glyphToChar, scale): def getHMTX(self, numberOfHMetrics, numGlyphs, glyphToChar, scale):
start = self.seek_table("hmtx") start = self.seek_table("hmtx")
aw = 0 aw = 0
self.charWidths = [0] * 256*256*2 self.charWidths = []
def resize_cw(size, default):
size = (((size + 1) // 1024) + 1) * 1024
delta = size - len(self.charWidths)
if delta > 0:
self.charWidths += [default] * delta
nCharWidths = 0 nCharWidths = 0
if ((numberOfHMetrics*4) < self.maxStrLenRead): if ((numberOfHMetrics*4) < self.maxStrLenRead):
data = self.get_chunk(start,(numberOfHMetrics*4)) data = self.get_chunk(start,(numberOfHMetrics*4))
arr = unpack(">" + "H" * (len(data)/2), data) arr = unpack(">%dH" % (len(data)//2), data)
else: else:
self.seek(start) self.seek(start)
for glyph in range(numberOfHMetrics): for glyph in range(numberOfHMetrics):
@@ -886,26 +891,30 @@ class TTFontFile:
self.defaultWidth = scale*aw self.defaultWidth = scale*aw
continue continue
for char in glyphToChar[glyph]: for char in glyphToChar[glyph]:
if (char != 0 and char != 65535): if (char != 0 and char != 65535):
w = int(round(scale*aw)) w = int(round(scale*aw+0.001)) # ROUND_HALF_UP in PY3K (like php)
if (w == 0): w = 65535 if (w == 0): w = 65535
if (char < 196608): if (char < 196608):
if char >= len(self.charWidths):
resize_cw(char, self.defaultWidth)
self.charWidths[char] = w self.charWidths[char] = w
nCharWidths += 1 nCharWidths += 1
data = self.get_chunk((start+numberOfHMetrics*4),(numGlyphs*2)) data = self.get_chunk((start+numberOfHMetrics*4),(numGlyphs*2))
arr = unpack(">" + "H" * (len(data)/2), data) arr = unpack(">%dH" % (len(data)//2), data)
diff = numGlyphs-numberOfHMetrics diff = numGlyphs-numberOfHMetrics
for pos in range(diff): for pos in range(diff):
glyph = pos + numberOfHMetrics glyph = pos + numberOfHMetrics
if (glyph in glyphToChar): if (glyph in glyphToChar):
for char in glyphToChar[glyph]: for char in glyphToChar[glyph]:
if (char != 0 and char != 65535): if (char != 0 and char != 65535):
w = int(round(scale*aw)) w = int(round(scale*aw+0.001)) # ROUND_HALF_UP in PY3K (like php)
if (w == 0): w = 65535 if (w == 0): w = 65535
if (char < 196608): if (char < 196608):
if char >= len(self.charWidths):
resize_cw(char, self.defaultWidth)
self.charWidths[char] = w self.charWidths[char] = w
nCharWidths += 1 nCharWidths += 1
@@ -933,12 +942,12 @@ class TTFontFile:
self.glyphPos = [] self.glyphPos = []
if (indexToLocFormat == 0): if (indexToLocFormat == 0):
data = self.get_chunk(start,(numGlyphs*2)+2) data = self.get_chunk(start,(numGlyphs*2)+2)
arr = unpack(">" + "H" * (len(data)/2), data) arr = unpack(">%dH" % (len(data)//2), data)
for n in range(numGlyphs): for n in range(numGlyphs):
self.glyphPos.append((arr[n] * 2)) # n+1 !? self.glyphPos.append((arr[n] * 2)) # n+1 !?
elif (indexToLocFormat == 1): elif (indexToLocFormat == 1):
data = self.get_chunk(start,(numGlyphs*4)+4) data = self.get_chunk(start,(numGlyphs*4)+4)
arr = unpack(">" + "L" * (len(data)/4), data) arr = unpack(">%dL" % (len(data)//4), data)
for n in range(numGlyphs): for n in range(numGlyphs):
self.glyphPos.append((arr[n])) # n+1 !? self.glyphPos.append((arr[n])) # n+1 !?
else: else:
@@ -952,7 +961,7 @@ class TTFontFile:
limit = unicode_cmap_offset + length limit = unicode_cmap_offset + length
self.skip(2) self.skip(2)
segCount = self.read_ushort() / 2 segCount = self.read_ushort() // 2
self.skip(6) self.skip(6)
endCount = [] endCount = []
for i in range(segCount): for i in range(segCount):
@@ -1020,7 +1029,7 @@ class TTFontFile:
# Put the TTF file together # Put the TTF file together
def endTTFile(self, stm): def endTTFile(self, stm):
stm = '' stm = b('')
numTables = count(self.otables) numTables = count(self.otables)
searchRange = 1 searchRange = 1
entrySelector = 0 entrySelector = 0
@@ -1046,7 +1055,7 @@ class TTFontFile:
for tag, data in sorted_tables: for tag, data in sorted_tables:
if (tag == 'head'): if (tag == 'head'):
head_start = offset head_start = offset
stm += tag stm += tag.encode("latin1")
checksum = calcChecksum(data) checksum = calcChecksum(data)
stm += pack(">HH", checksum[0],checksum[1]) stm += pack(">HH", checksum[0],checksum[1])
stm += pack(">LL", offset, strlen(data)) stm += pack(">LL", offset, strlen(data))
@@ -1055,7 +1064,7 @@ class TTFontFile:
# Table data # Table data
for tag, data in sorted_tables: for tag, data in sorted_tables:
data += "\0\0\0" data += b("\0\0\0")
stm += substr(data,0,(strlen(data)&~3)) stm += substr(data,0,(strlen(data)&~3))
checksum = calcChecksum(stm) checksum = calcChecksum(stm)
@@ -1064,20 +1073,3 @@ class TTFontFile:
stm = self.splice(stm,(head_start + 8),chk) stm = self.splice(stm,(head_start + 8),chk)
return stm return stm
if __name__ == '__main__':
ttf = TTFontFile()
ttffile = 'DejaVuSansCondensed.ttf';
ttf.getMetrics(ttffile)
# test basic metrics:
assert round(ttf.descent, 0) == -236
assert round(ttf.capHeight, 0) == 928
assert ttf.flags == 4
assert [round(i, 0) for i in ttf.bbox] == [-918, -415, 1513, 1167]
assert ttf.italicAngle == 0
assert ttf.stemV == 87
assert round(ttf.defaultWidth, 0) == 540
assert round(ttf.underlinePosition, 0) == -63
assert round(ttf.underlineThickness, 0) == 44
# test char widths 8(against binary file generated by tfpdf.php):
assert ''.join(ttf.charWidths) == open("dejavusanscondensed.cw.dat").read()
+1 -1
View File
@@ -69,7 +69,7 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
while True: while True:
try: try:
return wrapped(*args, **kwargs) return wrapped(*args, **kwargs)
except apiproxy_errors.ApplicationError, err: except apiproxy_errors.ApplicationError as err:
errno = err.application_error errno = err.application_error
if errno not in errors: if errno not in errors:
raise raise
+3 -3
View File
@@ -14,11 +14,11 @@ def wrapper(f):
try: try:
output = f(data) output = f(data)
return XML(ouput) return XML(ouput)
except (TypeError, ValueError), e: except (TypeError, ValueError) as e:
raise HTTP(405, '%s serialization error' % e) raise HTTP(405, '%s serialization error' % e)
except ImportError, e: except ImportError as e:
raise HTTP(405, '%s not available' % e) raise HTTP(405, '%s not available' % e)
except Exception, e: except Exception as e:
raise HTTP(405, '%s error' % e) raise HTTP(405, '%s error' % e)
return g return g
+4 -3
View File
@@ -1,6 +1,7 @@
import json import json
from collections import OrderedDict from collections import OrderedDict
from gluon import URL, IS_SLUG from gluon import URL, IS_SLUG
from functools import reduce
# compliant with https://github.com/collection-json/spec # compliant with https://github.com/collection-json/spec
# also compliant with http://code.ge/media-types/collection-next-json/ # also compliant with http://code.ge/media-types/collection-next-json/
@@ -282,7 +283,7 @@ class Collection(object):
# ADD validate fields and return error # ADD validate fields and return error
try: try:
(query, limitby, orderby) = self.request2query(table, request.get_vars) (query, limitby, orderby) = self.request2query(table, request.get_vars)
fields = filter(lambda (fn,value):table[fn].writable,data.items()) fields = filter(lambda fn_value:table[fn_value[0]].writable,data.items())
res = db(query).validate_and_update(**dict(fields)) # MAY FAIL res = db(query).validate_and_update(**dict(fields)) # MAY FAIL
if res.errors: if res.errors:
return self.error(400,'BAD REQUEST','Validation Error',res.errors) return self.error(400,'BAD REQUEST','Validation Error',res.errors)
@@ -295,7 +296,7 @@ class Collection(object):
else: # create else: # create
# ADD validate fields and return error # ADD validate fields and return error
try: try:
fields = filter(lambda (fn,value):table[fn].writable,data.items()) fields = filter(lambda fn_value1:table[fn_value1[0]].writable,data.items())
res = table.validate_and_insert(**dict(fields)) # MAY FAIL res = table.validate_and_insert(**dict(fields)) # MAY FAIL
if res.errors: if res.errors:
return self.error(400,'BAD REQUEST','Validation Error',res.errors) return self.error(400,'BAD REQUEST','Validation Error',res.errors)
@@ -304,7 +305,7 @@ class Collection(object):
response.headers['location'] = \ response.headers['location'] = \
URL(args=(tablename,res.id),scheme=True) URL(args=(tablename,res.id),scheme=True)
return '' return ''
except SyntaxError,e: #Exception,e: except SyntaxError as e: #Exception,e:
db.rollback() db.rollback()
return self.error(400,'BAD REQUEST','Invalid Query:'+e) return self.error(400,'BAD REQUEST','Invalid Query:'+e)
+144 -86
View File
@@ -22,7 +22,7 @@ and networks.
""" """
__version__ = '2.1.11' __version__ = 'trunk'
import struct import struct
@@ -156,16 +156,19 @@ def _find_address_range(addresses):
addresses: a list of IPv4 or IPv6 addresses. addresses: a list of IPv4 or IPv6 addresses.
Returns: Returns:
A tuple containing the first and last IP addresses in the sequence. A tuple containing the first and last IP addresses in the sequence,
and the index of the last IP address in the sequence.
""" """
first = last = addresses[0] first = last = addresses[0]
last_index = 0
for ip in addresses[1:]: for ip in addresses[1:]:
if ip._ip == last._ip + 1: if ip._ip == last._ip + 1:
last = ip last = ip
last_index += 1
else: else:
break break
return (first, last) return (first, last, last_index)
def _get_prefix_length(number1, number2, bits): def _get_prefix_length(number1, number2, bits):
"""Get the number of leading bits that are same for two numbers. """Get the number of leading bits that are same for two numbers.
@@ -358,8 +361,8 @@ def collapse_address_list(addresses):
nets = sorted(set(nets)) nets = sorted(set(nets))
while i < len(ips): while i < len(ips):
(first, last) = _find_address_range(ips[i:]) (first, last, last_index) = _find_address_range(ips[i:])
i = ips.index(last) + 1 i += last_index + 1
addrs.extend(summarize_address_range(first, last)) addrs.extend(summarize_address_range(first, last))
return _collapse_address_list_recursive(sorted( return _collapse_address_list_recursive(sorted(
@@ -876,6 +879,26 @@ class _BaseNet(_IPAddrBase):
else: else:
raise NetmaskValueError('Bit pattern does not match /1*0*/') raise NetmaskValueError('Bit pattern does not match /1*0*/')
def _prefix_from_prefix_int(self, prefixlen):
"""Validate and return a prefix length integer.
Args:
prefixlen: An integer containing the prefix length.
Returns:
The input, possibly converted from long to int.
Raises:
NetmaskValueError: If the input is not an integer, or out of range.
"""
if not isinstance(prefixlen, (int, long)):
raise NetmaskValueError('%r is not an integer' % prefixlen)
prefixlen = int(prefixlen)
if not (0 <= prefixlen <= self._max_prefixlen):
raise NetmaskValueError('%d is not a valid prefix length' %
prefixlen)
return prefixlen
def _prefix_from_prefix_string(self, prefixlen_str): def _prefix_from_prefix_string(self, prefixlen_str):
"""Turn a prefix length string into an integer. """Turn a prefix length string into an integer.
@@ -893,12 +916,10 @@ class _BaseNet(_IPAddrBase):
if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str): if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str):
raise ValueError raise ValueError
prefixlen = int(prefixlen_str) prefixlen = int(prefixlen_str)
if not (0 <= prefixlen <= self._max_prefixlen):
raise ValueError
except ValueError: except ValueError:
raise NetmaskValueError('%s is not a valid prefix length' % raise NetmaskValueError('%s is not a valid prefix length' %
prefixlen_str) prefixlen_str)
return prefixlen return self._prefix_from_prefix_int(prefixlen)
def _prefix_from_ip_string(self, ip_str): def _prefix_from_ip_string(self, ip_str):
"""Turn a netmask/hostmask string into a prefix length. """Turn a netmask/hostmask string into a prefix length.
@@ -1239,6 +1260,11 @@ class IPv4Address(_BaseV4, _BaseIP):
""" """
_BaseV4.__init__(self, address) _BaseV4.__init__(self, address)
# Efficient copy constructor.
if isinstance(address, IPv4Address):
self._ip = address._ip
return
# Efficient constructor from integer. # Efficient constructor from integer.
if isinstance(address, (int, long)): if isinstance(address, (int, long)):
self._ip = address self._ip = address
@@ -1279,29 +1305,32 @@ class IPv4Network(_BaseV4, _BaseNet):
"""Instantiate a new IPv4 network object. """Instantiate a new IPv4 network object.
Args: Args:
address: A string or integer representing the IP [& network]. address: The IPv4 network as a string, 2-tuple, or any format
'192.168.1.1/24' supported by the IPv4Address constructor.
'192.168.1.1/255.255.255.0'
'192.168.1.1/0.0.0.255'
are all functionally the same in IPv4. Similarly,
'192.168.1.1'
'192.168.1.1/255.255.255.255'
'192.168.1.1/32'
are also functionaly equivalent. That is to say, failing to
provide a subnetmask will create an object with a mask of /32.
If the mask (portion after the / in the argument) is given in Strings typically use CIDR format, such as '192.0.2.0/24'.
dotted quad form, it is treated as a netmask if it starts with a If a dotted-quad is provided after the '/', it is treated as
non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it a netmask if it starts with a nonzero bit (e.g. 255.0.0.0 == /8)
starts with a zero field (e.g. 0.255.255.255 == /8), with the or a hostmask if it starts with a zero bit
single exception of an all-zero mask which is treated as a (e.g. /0.0.0.255 == /8), with the single exception of an all-zero
netmask == /0. If no mask is given, a default of /32 is used. mask which is treated as /0.
Additionally, an integer can be passed, so The 2-tuple format consists of an (ip, prefixlen), where ip is any
IPv4Network('192.168.1.1') == IPv4Network(3232235777). format recognized by the IPv4Address constructor, and prefixlen is
or, more generally an integer from 0 through 32.
IPv4Network(int(IPv4Network('192.168.1.1'))) ==
IPv4Network('192.168.1.1') A plain IPv4 address (in any format) will be forwarded to the
IPv4Address constructor, with an implied prefixlen of 32.
For example, the following inputs are equivalent:
IPv4Network('192.0.2.1/32')
IPv4Network('192.0.2.1/255.255.255.255')
IPv4Network('192.0.2.1')
IPv4Network(0xc0000201)
IPv4Network(IPv4Address('192.0.2.1'))
IPv4Network(('192.0.2.1', 32))
IPv4Network((0xc0000201, 32))
IPv4Network((IPv4Address('192.0.2.1'), 32))
strict: A boolean. If true, ensure that we have been passed strict: A boolean. If true, ensure that we have been passed
A true network address, eg, 192.168.1.0/24 and not an A true network address, eg, 192.168.1.0/24 and not an
@@ -1318,41 +1347,51 @@ class IPv4Network(_BaseV4, _BaseNet):
_BaseNet.__init__(self, address) _BaseNet.__init__(self, address)
_BaseV4.__init__(self, address) _BaseV4.__init__(self, address)
# Constructing from an integer or packed bytes. # Constructing from a single IP address.
if isinstance(address, (int, long, Bytes)): if isinstance(address, (int, long, Bytes, IPv4Address)):
self.ip = IPv4Address(address) self.ip = IPv4Address(address)
self._ip = self.ip._ip self._ip = self.ip._ip
self._prefixlen = self._max_prefixlen self._prefixlen = self._max_prefixlen
self.netmask = IPv4Address(self._ALL_ONES) self.netmask = IPv4Address(self._ALL_ONES)
return return
# Assume input argument to be string or any object representation # Constructing from an (ip, prefixlen) tuple.
# which converts into a formatted IP prefix string. if isinstance(address, tuple):
addr = str(address).split('/')
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv4Address(self._ip)
if len(addr) == 2:
try: try:
# Check for a netmask in prefix length form. ip, prefixlen = address
self._prefixlen = self._prefix_from_prefix_string(addr[1]) except ValueError:
except NetmaskValueError: raise AddressValueError(address)
# Check for a netmask or hostmask in dotted-quad form. self.ip = IPv4Address(ip)
# This may raise NetmaskValueError. self._ip = self.ip._ip
self._prefixlen = self._prefix_from_ip_string(addr[1]) self._prefixlen = self._prefix_from_prefix_int(prefixlen)
else: else:
self._prefixlen = self._max_prefixlen # Assume input argument to be string or any object representation
# which converts into a formatted IP prefix string.
addr = str(address).split('/')
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv4Address(self._ip)
if len(addr) == 2:
try:
# Check for a netmask in prefix length form.
self._prefixlen = self._prefix_from_prefix_string(addr[1])
except NetmaskValueError:
# Check for a netmask or hostmask in dotted-quad form.
# This may raise NetmaskValueError.
self._prefixlen = self._prefix_from_ip_string(addr[1])
else:
self._prefixlen = self._max_prefixlen
self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen)) self.netmask = IPv4Address(self._ip_int_from_prefix(self._prefixlen))
if strict: if strict:
if self.ip != self.network: if self.ip != self.network:
raise ValueError('%s has host bits set' % raise ValueError('%s has host bits set' % self.ip)
self.ip)
if self._prefixlen == (self._max_prefixlen - 1): if self._prefixlen == (self._max_prefixlen - 1):
self.iterhosts = self.__iter__ self.iterhosts = self.__iter__
@@ -1752,6 +1791,11 @@ class IPv6Address(_BaseV6, _BaseIP):
""" """
_BaseV6.__init__(self, address) _BaseV6.__init__(self, address)
# Efficient copy constructor.
if isinstance(address, IPv6Address):
self._ip = address._ip
return
# Efficient constructor from integer. # Efficient constructor from integer.
if isinstance(address, (int, long)): if isinstance(address, (int, long)):
self._ip = address self._ip = address
@@ -1771,9 +1815,6 @@ class IPv6Address(_BaseV6, _BaseIP):
# Assume input argument to be string or any object representation # Assume input argument to be string or any object representation
# which converts into a formatted IP string. # which converts into a formatted IP string.
addr_str = str(address) addr_str = str(address)
if not addr_str:
raise AddressValueError('')
self._ip = self._ip_int_from_string(addr_str) self._ip = self._ip_int_from_string(addr_str)
@@ -1793,28 +1834,34 @@ class IPv6Network(_BaseV6, _BaseNet):
def __init__(self, address, strict=False): def __init__(self, address, strict=False):
"""Instantiate a new IPv6 Network object. """Instantiate a new IPv6 network object.
Args: Args:
address: A string or integer representing the IPv6 network or the IP address: The IPv6 network as a string, 2-tuple, or any format
and prefix/netmask. supported by the IPv6Address constructor.
'2001:4860::/128'
'2001:4860:0000:0000:0000:0000:0000:0000/128'
'2001:4860::'
are all functionally the same in IPv6. That is to say,
failing to provide a subnetmask will create an object with
a mask of /128.
Additionally, an integer can be passed, so Strings should be in CIDR format, such as '2001:db8::/32'.
IPv6Network('2001:4860::') ==
IPv6Network(42541956101370907050197289607612071936L). The 2-tuple format consists of an (ip, prefixlen), where ip is any
or, more generally format recognized by the IPv6Address constructor, and prefixlen is
IPv6Network(IPv6Network('2001:4860::')._ip) == an integer from 0 through 128.
IPv6Network('2001:4860::')
A plain IPv6 address (in any format) will be forwarded to the
IPv6Address constructor, with an implied prefixlen of 128.
For example, the following inputs are equivalent:
IPv6Network('2001:db8::/128')
IPv6Network('2001:db8:0:0:0:0:0:0/128')
IPv6Network('2001:db8::')
IPv6Network(0x20010db8 << 96)
IPv6Network(IPv6Address('2001:db8::'))
IPv6Network(('2001:db8::', 128))
IPv6Network((0x20010db8 << 96, 128))
IPv6Network((IPv6Address('2001:db8::'), 128))
strict: A boolean. If true, ensure that we have been passed strict: A boolean. If true, ensure that we have been passed
A true network address, eg, 192.168.1.0/24 and not an A true network address, eg, 2001:db8::/32 and not an
IP address on a network, eg, 192.168.1.1/24. IP address on a network, eg, 2001:db8::1/32.
Raises: Raises:
AddressValueError: If address isn't a valid IPv6 address. AddressValueError: If address isn't a valid IPv6 address.
@@ -1827,29 +1874,40 @@ class IPv6Network(_BaseV6, _BaseNet):
_BaseNet.__init__(self, address) _BaseNet.__init__(self, address)
_BaseV6.__init__(self, address) _BaseV6.__init__(self, address)
# Constructing from an integer or packed bytes. # Constructing from a single IP address.
if isinstance(address, (int, long, Bytes)): if isinstance(address, (int, long, Bytes, IPv6Address)):
self.ip = IPv6Address(address) self.ip = IPv6Address(address)
self._ip = self.ip._ip self._ip = self.ip._ip
self._prefixlen = self._max_prefixlen self._prefixlen = self._max_prefixlen
self.netmask = IPv6Address(self._ALL_ONES) self.netmask = IPv6Address(self._ALL_ONES)
return return
# Assume input argument to be string or any object representation # Constructing from an (ip, prefixlen) tuple.
# which converts into a formatted IP prefix string. if isinstance(address, tuple):
addr = str(address).split('/') try:
ip, prefixlen = address
except ValueError:
raise AddressValueError(address)
self.ip = IPv6Address(ip)
self._ip = self.ip._ip
self._prefixlen = self._prefix_from_prefix_int(prefixlen)
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv6Address(self._ip)
if len(addr) == 2:
# This may raise NetmaskValueError
self._prefixlen = self._prefix_from_prefix_string(addr[1])
else: else:
self._prefixlen = self._max_prefixlen # Assume input argument to be string or any object representation
# which converts into a formatted IP prefix string.
addr = str(address).split('/')
if len(addr) > 2:
raise AddressValueError(address)
self._ip = self._ip_int_from_string(addr[0])
self.ip = IPv6Address(self._ip)
if len(addr) == 2:
# This may raise NetmaskValueError
self._prefixlen = self._prefix_from_prefix_string(addr[1])
else:
self._prefixlen = self._max_prefixlen
self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen)) self.netmask = IPv6Address(self._ip_int_from_prefix(self._prefixlen))
+13 -13
View File
@@ -9,7 +9,7 @@ try:
import ldap import ldap
import ldap.filter import ldap.filter
ldap.set_option(ldap.OPT_REFERRALS, 0) ldap.set_option(ldap.OPT_REFERRALS, 0)
except Exception, e: except Exception as e:
logging.error('missing ldap, try "easy_install python-ldap"') logging.error('missing ldap, try "easy_install python-ldap"')
raise e raise e
@@ -357,7 +357,7 @@ def ldap_auth(server='ldap',
con.simple_bind_s(user_dn, password) con.simple_bind_s(user_dn, password)
found = True found = True
break break
except ldap.LDAPError, detail: except ldap.LDAPError as detail:
(exc_type, exc_value) = sys.exc_info()[:2] (exc_type, exc_value) = sys.exc_info()[:2]
logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn, logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn,
filter, filter,
@@ -392,7 +392,7 @@ def ldap_auth(server='ldap',
con.simple_bind_s(user_dn, password) con.simple_bind_s(user_dn, password)
found = True found = True
break break
except ldap.LDAPError, detail: except ldap.LDAPError as detail:
(exc_type, exc_value) = sys.exc_info()[:2] (exc_type, exc_value) = sys.exc_info()[:2]
logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn, logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn,
filter, filter,
@@ -410,18 +410,18 @@ def ldap_auth(server='ldap',
store_user_firstname = result[user_firstname_attrib][0].split(' ', 1)[user_firstname_part] store_user_firstname = result[user_firstname_attrib][0].split(' ', 1)[user_firstname_part]
else: else:
store_user_firstname = result[user_firstname_attrib][0] store_user_firstname = result[user_firstname_attrib][0]
except KeyError, e: except KeyError as e:
store_user_firstname = None store_user_firstname = None
try: try:
if user_lastname_part is not None: if user_lastname_part is not None:
store_user_lastname = result[user_lastname_attrib][0].split(' ', 1)[user_lastname_part] store_user_lastname = result[user_lastname_attrib][0].split(' ', 1)[user_lastname_part]
else: else:
store_user_lastname = result[user_lastname_attrib][0] store_user_lastname = result[user_lastname_attrib][0]
except KeyError, e: except KeyError as e:
store_user_lastname = None store_user_lastname = None
try: try:
store_user_mail = result[user_mail_attrib][0] store_user_mail = result[user_mail_attrib][0]
except KeyError, e: except KeyError as e:
store_user_mail = None store_user_mail = None
update_or_insert_values = {'first_name': store_user_firstname, update_or_insert_values = {'first_name': store_user_firstname,
'last_name': store_user_lastname, 'last_name': store_user_lastname,
@@ -451,14 +451,14 @@ def ldap_auth(server='ldap',
if not do_manage_groups(username, password, group_mapping): if not do_manage_groups(username, password, group_mapping):
return False return False
return True return True
except ldap.INVALID_CREDENTIALS, e: except ldap.INVALID_CREDENTIALS as e:
return False return False
except ldap.LDAPError, e: except ldap.LDAPError as e:
import traceback import traceback
logger.warning('[%s] Error in ldap processing' % str(username)) logger.warning('[%s] Error in ldap processing' % str(username))
logger.debug(traceback.format_exc()) logger.debug(traceback.format_exc())
return False return False
except IndexError, ex: # for AD membership test except IndexError as ex: # for AD membership test
import traceback import traceback
logger.warning('[%s] Ldap result indexing error' % str(username)) logger.warning('[%s] Ldap result indexing error' % str(username))
logger.debug(traceback.format_exc()) logger.debug(traceback.format_exc())
@@ -477,7 +477,7 @@ def ldap_auth(server='ldap',
ldap_groups_of_the_user = get_user_groups_from_ldap(username, password) ldap_groups_of_the_user = get_user_groups_from_ldap(username, password)
# search for allowed group names # search for allowed group names
if type(allowed_groups) != type(list()): if not isinstance(allowed_groups, list):
allowed_groups = [allowed_groups] allowed_groups = [allowed_groups]
for group in allowed_groups: for group in allowed_groups:
if ldap_groups_of_the_user.count(group) > 0: if ldap_groups_of_the_user.count(group) > 0:
@@ -518,14 +518,14 @@ def ldap_auth(server='ldap',
except: except:
try: try:
db_user_id = db(db.auth_user.email == username).select(db.auth_user.id).first().id db_user_id = db(db.auth_user.email == username).select(db.auth_user.id).first().id
except AttributeError, e: except AttributeError as e:
# #
# There is no user in local db # There is no user in local db
# We create one # We create one
# ############################## # ##############################
try: try:
db_user_id = db.auth_user.insert(username=username, first_name=username) db_user_id = db.auth_user.insert(username=username, first_name=username)
except AttributeError, e: except AttributeError as e:
db_user_id = db.auth_user.insert(email=username, first_name=username) db_user_id = db.auth_user.insert(email=username, first_name=username)
if not db_user_id: if not db_user_id:
logging.error( logging.error(
@@ -695,7 +695,7 @@ def ldap_auth(server='ldap',
ldap_groups_of_the_user = list() ldap_groups_of_the_user = list()
for group_row in group_search_result: for group_row in group_search_result:
group = group_row[1] group = group_row[1]
if type(group) == dict and group_name_attrib in group: if isinstance(group, dict) and group_name_attrib in group:
ldap_groups_of_the_user.extend(group[group_name_attrib]) ldap_groups_of_the_user.extend(group[group_name_attrib])
con.unbind() con.unbind()
@@ -174,7 +174,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
opener = self.__build_url_opener(self.token_url) opener = self.__build_url_opener(self.token_url)
try: try:
open_url = opener.open(self.token_url, urlencode(data), self.socket_timeout) open_url = opener.open(self.token_url, urlencode(data), self.socket_timeout)
except urllib2.HTTPError, e: except urllib2.HTTPError as e:
tmp = e.read() tmp = e.read()
raise Exception(tmp) raise Exception(tmp)
finally: finally:
@@ -190,7 +190,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
try: try:
tokendata = json.loads(data) tokendata = json.loads(data)
current.session.token = tokendata current.session.token = tokendata
except Exception, e: except Exception as e:
raise Exception("Cannot parse oauth server response %s %s" % (data, e)) raise Exception("Cannot parse oauth server response %s %s" % (data, e))
else: # try facebook style first with x-www-form-encoded else: # try facebook style first with x-www-form-encoded
tokendata = cgi.parse_qs(data) tokendata = cgi.parse_qs(data)
+1 -1
View File
@@ -44,7 +44,7 @@ try:
from openid.extensions.sreg import SRegRequest, SRegResponse from openid.extensions.sreg import SRegRequest, SRegResponse
from openid.store import nonce from openid.store import nonce
from openid.consumer.discover import DiscoveryFailure from openid.consumer.discover import DiscoveryFailure
except ImportError, err: except ImportError as err:
raise ImportError("OpenIDAuth requires python-openid package") raise ImportError("OpenIDAuth requires python-openid package")
DEFAULT = lambda: None DEFAULT = lambda: None
+1 -1
View File
@@ -133,7 +133,7 @@ def saml2_handler(session, request, config_filename = None):
data = client.parse_authn_request_response( data = client.parse_authn_request_response(
unquoted_response, binding, session.saml_outstanding_queries) unquoted_response, binding, session.saml_outstanding_queries)
res['response'] = data if data else {} res['response'] = data if data else {}
except Exception, e: except Exception as e:
import traceback import traceback
res['error'] = traceback.format_exc() res['error'] = traceback.format_exc()
return res return res
+1
View File
@@ -15,6 +15,7 @@ from gluon.http import HTTP, redirect
#requires M2Crypto #requires M2Crypto
from M2Crypto import X509 from M2Crypto import X509
from functools import reduce
class X509Auth(object): class X509Auth(object):
+1 -1
View File
@@ -4,7 +4,7 @@ from gluon.html import XML
def WIKI(text, encoding="utf8", safe_mode='escape', html4tags=False, **attributes): def WIKI(text, encoding="utf8", safe_mode='escape', html4tags=False, **attributes):
if not text: if not text:
test = '' test = ''
if attributes.has_key('extras'): if 'extras' in attributes:
extras = attributes['extras'] extras = attributes['extras']
del attributes['extras'] del attributes['extras']
else: else:
+1
View File
@@ -35,6 +35,7 @@ This implementation of Markdown implements the full "core" syntax plus a
number of extras (e.g., code syntax coloring, footnotes) as described on number of extras (e.g., code syntax coloring, footnotes) as described on
<https://github.com/trentm/python-markdown2/wiki/Extras>. <https://github.com/trentm/python-markdown2/wiki/Extras>.
""" """
from __future__ import print_function
cmdln_desc = """A fast and complete Python implementation of Markdown, a cmdln_desc = """A fast and complete Python implementation of Markdown, a
text-to-HTML conversion tool for web writers. text-to-HTML conversion tool for web writers.
+20 -19
View File
@@ -3,10 +3,11 @@
# created by Massimo Di Pierro # created by Massimo Di Pierro
# recreated by Vladyslav Kozlovskyy # recreated by Vladyslav Kozlovskyy
# license MIT/BSD/GPL # license MIT/BSD/GPL
from __future__ import print_function
import re import re
import urllib import urllib
from cgi import escape from cgi import escape
from string import maketrans from gluon._compat import maketrans, urllib_quote, unicodeT, _local_html_escape, to_bytes
try: try:
from ast import parse as ast_parse from ast import parse as ast_parse
@@ -45,11 +46,11 @@ Example of usage:
`` ``
m = "Hello **world** [[link http://web2py.com]]" m = "Hello **world** [[link http://web2py.com]]"
from markmin2html import markmin2html from markmin2html import markmin2html
print markmin2html(m) print(markmin2html(m))
from markmin2latex import markmin2latex from markmin2latex import markmin2latex
print markmin2latex(m) print(markmin2latex(m))
from markmin2pdf import markmin2pdf # requires pdflatex from markmin2pdf import markmin2pdf # requires pdflatex
print markmin2pdf(m) print(markmin2pdf(m))
`` ``
==================== ====================
# This is a test block # This is a test block
@@ -650,7 +651,7 @@ def replace_components(text, env):
pass pass
try: try:
f = f(**b) if isinstance(b, dict) else f(b) f = f(**b) if isinstance(b, dict) else f(b)
except Exception, e: except Exception as e:
f = 'ERROR: %s' % e f = 'ERROR: %s' % e
return str(f) return str(f)
@@ -803,7 +804,7 @@ def render(text,
>>> render("``aaa``:custom", extra=dict(custom=lambda text: 'x'+text+'x')) >>> render("``aaa``:custom", extra=dict(custom=lambda text: 'x'+text+'x'))
'xaaax' 'xaaax'
>>> print render(r"$$\int_a^b sin(x)dx$$") >>> print(render(r"$$\int_a^b sin(x)dx$$"))
<img src="http://chart.apis.google.com/chart?cht=tx&chl=%5Cint_a%5Eb%20sin%28x%29dx" /> <img src="http://chart.apis.google.com/chart?cht=tx&chl=%5Cint_a%5Eb%20sin%28x%29dx" />
>>> markmin2html(r"use backslash: \[\[[[mess\[[ag\]]e link]]\]]") >>> markmin2html(r"use backslash: \[\[[[mess\[[ag\]]e link]]\]]")
@@ -949,7 +950,7 @@ def render(text,
if protolinks == "default": if protolinks == "default":
protolinks = protolinks_simple protolinks = protolinks_simple
pp = '\n' if pretty_print else '' pp = '\n' if pretty_print else ''
if isinstance(text, unicode): if isinstance(text, unicodeT):
text = text.encode('utf8') text = text.encode('utf8')
text = str(text or '') text = str(text or '')
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text) text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
@@ -1417,7 +1418,7 @@ def render(text,
return '[' + ','.join('<a href="#%s" class="%s">%s</a>' % return '[' + ','.join('<a href="#%s" class="%s">%s</a>' %
(id_prefix + d, b, d) for d in escape(code).split(',')) + ']' (id_prefix + d, b, d) for d in escape(code).split(',')) + ']'
elif b == 'latex': elif b == 'latex':
return LATEX % urllib.quote(code) return LATEX % urllib_quote(code)
elif b in html_colors: elif b in html_colors:
return '<span style="color: %s">%s</span>' \ return '<span style="color: %s">%s</span>' \
% (b, render(code, {}, {}, 'br', URL, environment, latex, % (b, render(code, {}, {}, 'br', URL, environment, latex,
@@ -1494,17 +1495,17 @@ if __name__ == '__main__':
pre { background-color: #E0E0E0; padding: 5px; } pre { background-color: #E0E0E0; padding: 5px; }
</style>""")[1:] </style>""")[1:]
print html % dict(title="Markmin markup language", print(html % dict(title="Markmin markup language",
style=style, style=style,
body=markmin2html(__doc__, pretty_print=True)) body=markmin2html(__doc__, pretty_print=True)))
elif sys.argv[1:2] == ['-t']: elif sys.argv[1:2] == ['-t']:
from timeit import Timer from timeit import Timer
loops = 1000 loops = 1000
ts = Timer("markmin2html(__doc__)", "from markmin2html import markmin2html") ts = Timer("markmin2html(__doc__)", "from markmin2html import markmin2html")
print 'timeit "markmin2html(__doc__)":' print('timeit "markmin2html(__doc__)":')
t = min([ts.timeit(loops) for i in range(3)]) t = min([ts.timeit(loops) for i in range(3)])
print "%s loops, best of 3: %.3f ms per loop" % (loops, t / 1000 * loops) print("%s loops, best of 3: %.3f ms per loop" % (loops, t / 1000 * loops))
elif len(sys.argv) > 1: elif len(sys.argv) > 1:
fargv = open(sys.argv[1], 'r') fargv = open(sys.argv[1], 'r')
try: try:
@@ -1523,15 +1524,15 @@ if __name__ == '__main__':
else: else:
markmin_style = "" markmin_style = ""
print html % dict(title=sys.argv[1], style=markmin_style, print(html % dict(title=sys.argv[1], style=markmin_style,
body=markmin2html(markmin_text, pretty_print=True)) body=markmin2html(markmin_text, pretty_print=True)))
finally: finally:
fargv.close() fargv.close()
else: else:
print "Usage: " + sys.argv[0] + " -h | -t | file.markmin [file.css|@path_to/css]" print("Usage: " + sys.argv[0] + " -h | -t | file.markmin [file.css|@path_to/css]")
print "where: -h - print __doc__" print("where: -h - print __doc__")
print " -t - timeit __doc__ (for testing purpuse only)" print(" -t - timeit __doc__ (for testing purpuse only)")
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)" print(" file.markmin [file.css] - process file.markmin + built in file.css (optional)")
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)" print(" file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)")
run_doctests() run_doctests()
+2 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# created my Massimo Di Pierro # created my Massimo Di Pierro
# license MIT/BSD/GPL # license MIT/BSD/GPL
from __future__ import print_function
import re import re
import cgi import cgi
import sys import sys
@@ -309,4 +310,4 @@ if __name__ == '__main__':
output = markmin2latex(content, output = markmin2latex(content,
wrapper=wrapper, wrapper=wrapper,
chapters=options.chapters) chapters=options.chapters)
print output print(output)
+10 -8
View File
@@ -2,6 +2,7 @@
Created by Massimo Di Pierro Created by Massimo Di Pierro
License BSD License BSD
""" """
from __future__ import print_function
import subprocess import subprocess
import os import os
@@ -20,8 +21,9 @@ def removeall(path):
def rmgeneric(path, __func__): def rmgeneric(path, __func__):
try: try:
__func__(path) __func__(path)
except OSError, (errno, strerror): except OSError as xxx_todo_changeme:
print ERROR_STR % {'path': path, 'error': strerror} (errno, strerror) = xxx_todo_changeme.args
print(ERROR_STR % {'path': path, 'error': strerror})
files = [path] files = [path]
@@ -112,10 +114,10 @@ if __name__ == '__main__':
if sys.argv[1:2] == ['-h']: if sys.argv[1:2] == ['-h']:
data, warnings, errors = markmin2pdf(markmin2html.__doc__) data, warnings, errors = markmin2pdf(markmin2html.__doc__)
if errors: if errors:
print 'ERRORS:' + '\n'.join(errors) print('ERRORS:' + '\n'.join(errors))
print 'WARNGINS:' + '\n'.join(warnings) print('WARNGINS:' + '\n'.join(warnings))
else: else:
print data print(data)
elif len(sys.argv) > 1: elif len(sys.argv) > 1:
fargv = open(sys.argv[1], 'rb') fargv = open(sys.argv[1], 'rb')
try: try:
@@ -123,9 +125,9 @@ if __name__ == '__main__':
finally: finally:
fargv.close() fargv.close()
if errors: if errors:
print 'ERRORS:' + '\n'.join(errors) print('ERRORS:' + '\n'.join(errors))
print 'WARNGINS:' + '\n'.join(warnings) print('WARNGINS:' + '\n'.join(warnings))
else: else:
print data print(data)
else: else:
doctest.testmod() doctest.testmod()
+2 -1
View File
@@ -9,6 +9,7 @@ a user against the Pluggable Authentication Modules (PAM) on the system.
Implemented using ctypes, so no compilation is necessary. Implemented using ctypes, so no compilation is necessary.
""" """
from __future__ import print_function
__all__ = ['authenticate'] __all__ = ['authenticate']
from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, pointer, sizeof from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, pointer, sizeof
@@ -125,4 +126,4 @@ def authenticate(username, password, service='login'):
if __name__ == "__main__": if __name__ == "__main__":
import getpass import getpass
print authenticate(getpass.getuser(), getpass.getpass()) print(authenticate(getpass.getuser(), getpass.getpass()))
+9 -8
View File
@@ -40,6 +40,7 @@
:copyright: (c) Copyright 2011 by Armin Ronacher. :copyright: (c) Copyright 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import print_function
import hmac import hmac
try: try:
from hashlib import sha1 from hashlib import sha1
@@ -92,14 +93,14 @@ def test():
def check(data, salt, iterations, keylen, expected): def check(data, salt, iterations, keylen, expected):
rv = pbkdf2_hex(data, salt, iterations, keylen) rv = pbkdf2_hex(data, salt, iterations, keylen)
if rv != expected: if rv != expected:
print 'Test failed:' print('Test failed:')
print ' Expected: %s' % expected print(' Expected: %s' % expected)
print ' Got: %s' % rv print(' Got: %s' % rv)
print ' Parameters:' print(' Parameters:')
print ' data=%s' % data print(' data=%s' % data)
print ' salt=%s' % salt print(' salt=%s' % salt)
print ' iterations=%d' % iterations print(' iterations=%d' % iterations)
print print()
failed.append(1) failed.append(1)
# From RFC 6070 # From RFC 6070
+1
View File
@@ -18,6 +18,7 @@
:license: LGPLv3 :license: LGPLv3
""" """
from __future__ import print_function
import ctypes import ctypes
import ctypes.util import ctypes.util
+2 -1
View File
@@ -1,6 +1,7 @@
""" """
BSD license - created by Massimo Di Pierro BSD license - created by Massimo Di Pierro
""" """
from __future__ import print_function
from reportlab.pdfgen.canvas import Canvas from reportlab.pdfgen.canvas import Canvas
from reportlab.platypus import Table from reportlab.platypus import Table
from reportlab.lib.pagesizes import A4 from reportlab.lib.pagesizes import A4
@@ -158,4 +159,4 @@ if __name__=='__main__':
['000001','Chairs',600.0], ['000001','Chairs',600.0],
['','Tax',50.0]], ['','Tax',50.0]],
} }
print PDF().draw(invoice,items_page=20) print(PDF().draw(invoice,items_page=20))
+2 -1
View File
@@ -1,3 +1,4 @@
from __future__ import print_function
import re import re
import cPickle import cPickle
import random import random
@@ -267,4 +268,4 @@ def populate_generator(table, default=True, compute=False, contents={}):
if __name__ == '__main__': if __name__ == '__main__':
ell = Learner() ell = Learner()
ell.loadd(IUP) ell.loadd(IUP)
print ell.generate(1000, prefix=None) print(ell.generate(1000, prefix=None))
+1 -1
View File
@@ -5,7 +5,7 @@
# Read more about this http://code.google.com/p/pyfpdf # Read more about this http://code.google.com/p/pyfpdf
# Please note that new package name is fpdf (to avoid some naming conflicts) # Please note that new package name is fpdf (to avoid some naming conflicts)
# import fpdf into pyfpdf for backward compatibility (prior web2py 2.0): # import fpdf into pyfpdf for backward compatibility (prior web2py 2.0):
from fpdf import * from gluon.contrib.fpdf import *
# import warnings # import warnings
# warnings.warn("pyfpdf package name is deprecated, please use fpdf instead") # warnings.warn("pyfpdf package name is deprecated, please use fpdf instead")
+8 -8
View File
@@ -1,3 +1,4 @@
from __future__ import print_function
from types import IntType, FloatType, LongType, StringTypes from types import IntType, FloatType, LongType, StringTypes
from copy import deepcopy from copy import deepcopy
from binascii import hexlify from binascii import hexlify
@@ -384,10 +385,9 @@ def _get_emf_dimensions( fin ):
header.HeightDevMM = get_LONG() # Height of reference device in millimeters header.HeightDevMM = get_LONG() # Height of reference device in millimeters
if 0: if 0:
klist = header.__dict__.keys() klist = sorted(header.__dict__.keys())
klist.sort()
for k in klist: for k in klist:
print "%20s:%s" % (k,header.__dict__[k]) print("%20s:%s" % (k,header.__dict__[k]))
dw = header.FrameRight-header.FrameLeft dw = header.FrameRight-header.FrameLeft
dh = header.FrameBottom-header.FrameTop dh = header.FrameBottom-header.FrameTop
@@ -416,7 +416,7 @@ class Image( RawCode ) :
fin = infile fin = infile
if 'datatype' not in kwargs.keys(): if 'datatype' not in kwargs.keys():
msg = "If passing in a file object, you must also specify type='xxx' where xxx is one of %s" % self.PICT_TYPES.keys() msg = "If passing in a file object, you must also specify type='xxx' where xxx is one of %s" % self.PICT_TYPES.keys()
raise ValueError,msg raise ValueError(msg)
file_name = kwargs.pop('datatype') file_name = kwargs.pop('datatype')
else: else:
fin = file( infile, 'rb' ) fin = file( infile, 'rb' )
@@ -722,7 +722,7 @@ def TEXT( *params, **kwargs ) :
return Text( params[ 0 ], text_props ) return Text( params[ 0 ], text_props )
result = Inline( text_props ) result = Inline( text_props )
apply( result.append, params ) result.append(*params)
return result return result
def B( *params ) : def B( *params ) :
@@ -732,7 +732,7 @@ def B( *params ) :
return Text( params[ 0 ], text_props ) return Text( params[ 0 ], text_props )
result = Inline( text_props ) result = Inline( text_props )
apply( result.append, params ) result.append(*params)
return result return result
def I( *params ) : def I( *params ) :
@@ -742,7 +742,7 @@ def I( *params ) :
return Text( params[ 0 ], text_props ) return Text( params[ 0 ], text_props )
result = Inline( text_props ) result = Inline( text_props )
apply( result.append, params ) result.append(*params)
return result return result
def U( *params ) : def U( *params ) :
@@ -752,6 +752,6 @@ def U( *params ) :
return Text( params[ 0 ], text_props ) return Text( params[ 0 ], text_props )
result = Inline( text_props ) result = Inline( text_props )
apply( result.append, params ) result.append(*params)
return result return result
+2 -2
View File
@@ -17,7 +17,7 @@ from copy import deepcopy
# We need some basic Type like fonts, colours and paper definitions # We need some basic Type like fonts, colours and paper definitions
# #
def MakeAttributeName( value ) : def MakeAttributeName( value ) :
assert value and type( value ) is StringType assert value and isinstance(value, StringType)
value = value.replace( ' ', '' ) value = value.replace( ' ', '' )
return value return value
@@ -427,7 +427,7 @@ class ParagraphPropertySet :
self.SetSpaceAfter ( space_after ) self.SetSpaceAfter ( space_after )
self.Tabs = [] self.Tabs = []
if tabs : apply( self.SetTabs, tabs ) if tabs : self.SetTabs(*tabs)
self.SetFirstLineIndent( first_line_indent or None ) self.SetFirstLineIndent( first_line_indent or None )
self.SetLeftIndent ( left_indent or None ) self.SetLeftIndent ( left_indent or None )
+53 -52
View File
@@ -2,6 +2,7 @@
# coding:utf-8 # coding:utf-8
"Queues(Pipe)-based independent remote client-server Python Debugger" "Queues(Pipe)-based independent remote client-server Python Debugger"
from __future__ import print_function
__author__ = "Mariano Reingart (reingart@gmail.com)" __author__ = "Mariano Reingart (reingart@gmail.com)"
__copyright__ = "Copyright (C) 2011 Mariano Reingart" __copyright__ = "Copyright (C) 2011 Mariano Reingart"
@@ -69,7 +70,7 @@ class Qdb(bdb.Bdb):
method = getattr(self, request['method']) method = getattr(self, request['method'])
response['result'] = method.__call__(*request['args'], response['result'] = method.__call__(*request['args'],
**request.get('kwargs', {})) **request.get('kwargs', {}))
except Exception, e: except Exception as e:
response['error'] = {'code': 0, 'message': str(e)} response['error'] = {'code': 0, 'message': str(e)}
# send the result for normal method calls, not for notifications # send the result for normal method calls, not for notifications
if request.get('id'): if request.get('id'):
@@ -259,8 +260,8 @@ class Qdb(bdb.Bdb):
try: try:
self.frame.f_lineno = arg self.frame.f_lineno = arg
return arg return arg
except ValueError, e: except ValueError as e:
print '*** Jump failed:', e print('*** Jump failed:', e)
return False return False
def do_list(self, arg): def do_list(self, arg):
@@ -317,7 +318,7 @@ class Qdb(bdb.Bdb):
# required by BDB to remove temp breakpoints! # required by BDB to remove temp breakpoints!
err = self.clear_bpbynumber(arg) err = self.clear_bpbynumber(arg)
if err: if err:
print '*** DO_CLEAR failed', err print('*** DO_CLEAR failed', err)
def do_eval(self, arg, safe=True): def do_eval(self, arg, safe=True):
ret = eval(arg, self.frame.f_globals, ret = eval(arg, self.frame.f_globals,
@@ -375,7 +376,7 @@ class Qdb(bdb.Bdb):
"Return list of auto-completion options for expression" "Return list of auto-completion options for expression"
try: try:
obj = self.do_eval(expression) obj = self.do_eval(expression)
except Exception, e: except Exception as e:
return ('', '', str(e)) return ('', '', str(e))
else: else:
name = '' name = ''
@@ -391,16 +392,16 @@ class Qdb(bdb.Bdb):
pass pass
elif inspect.ismethod(obj): elif inspect.ismethod(obj):
# Get the function from the object # Get the function from the object
f = obj.im_func f = obj.__func__
drop_self = 1 drop_self = 1
elif inspect.isclass(obj): elif inspect.isclass(obj):
# Get the __init__ method function for the class. # Get the __init__ method function for the class.
if hasattr(obj, '__init__'): if hasattr(obj, '__init__'):
f = obj.__init__.im_func f = obj.__init__.__func__
else: else:
for base in object.__bases__: for base in object.__bases__:
if hasattr(base, '__init__'): if hasattr(base, '__init__'):
f = base.__init__.im_func f = base.__init__.__func__
break break
if f is not None: if f is not None:
drop_self = 1 drop_self = 1
@@ -408,12 +409,12 @@ class Qdb(bdb.Bdb):
# use the obj as a function by default # use the obj as a function by default
f = obj f = obj
# Get the __call__ method instead. # Get the __call__ method instead.
f = obj.__call__.im_func f = obj.__call__.__func__
drop_self = 0 drop_self = 0
except AttributeError: except AttributeError:
pass pass
if f: if f:
argspec = apply(inspect.formatargspec, inspect.getargspec(f)) argspec = inspect.formatargspec(*inspect.getargspec(f))
doc = '' doc = ''
if callable(obj): if callable(obj):
try: try:
@@ -602,7 +603,7 @@ class Frontend(object):
req = {'method': method, 'args': args, 'id': self.i} req = {'method': method, 'args': args, 'id': self.i}
self.send(req) self.send(req)
self.i += 1 # increment the id self.i += 1 # increment the id
while 1: while True:
# wait until command acknowledge (response id match the request) # wait until command acknowledge (response id match the request)
res = self.recv() res = self.recv()
if 'id' not in res or not res['id']: if 'id' not in res or not res['id']:
@@ -612,8 +613,8 @@ class Frontend(object):
# nested request received (i.e. readline)! process it! # nested request received (i.e. readline)! process it!
self.process_message(res) self.process_message(res)
elif long(req['id']) != long(res['id']): elif long(req['id']) != long(res['id']):
print "DEBUGGER wrong packet received: expecting id", req[ print("DEBUGGER wrong packet received: expecting id", req[
'id'], res['id'] 'id'], res['id'])
# protocol state is unknown # protocol state is unknown
elif 'error' in res and res['error']: elif 'error' in res and res['error']:
raise RPCError(res['error']['message']) raise RPCError(res['error']['message'])
@@ -639,7 +640,7 @@ class Frontend(object):
def do_jump(self, arg): def do_jump(self, arg):
"Set the next line that will be executed." "Set the next line that will be executed."
res = self.call('do_jump', arg) res = self.call('do_jump', arg)
print res print(res)
def do_where(self, arg=None): def do_where(self, arg=None):
"Print a stack trace, with the most recent frame at the bottom." "Print a stack trace, with the most recent frame at the bottom."
@@ -715,26 +716,26 @@ class Cli(Frontend, cmd.Cmd):
# redefine Frontend methods: # redefine Frontend methods:
def run(self): def run(self):
while 1: while True:
try: try:
Frontend.run(self) Frontend.run(self)
except KeyboardInterrupt: except KeyboardInterrupt:
print "Interupting..." print("Interupting...")
self.interrupt() self.interrupt()
def interaction(self, filename, lineno, line): def interaction(self, filename, lineno, line):
print "> %s(%d)\n-> %s" % (filename, lineno, line), print("> %s(%d)\n-> %s" % (filename, lineno, line), end=' ')
self.filename = filename self.filename = filename
self.cmdloop() self.cmdloop()
def exception(self, title, extype, exvalue, trace, request): def exception(self, title, extype, exvalue, trace, request):
print "=" * 80 print("=" * 80)
print "Exception", title print("Exception", title)
print request print(request)
print "-" * 80 print("-" * 80)
def write(self, text): def write(self, text):
print text, print(text, end=' ')
def readline(self): def readline(self):
return raw_input() return raw_input()
@@ -753,7 +754,7 @@ class Cli(Frontend, cmd.Cmd):
def do_eval(self, args): def do_eval(self, args):
"Inspect the value of the expression" "Inspect the value of the expression"
print Frontend.do_eval(self, args) print(Frontend.do_eval(self, args))
def do_list(self, args): def do_list(self, args):
"List source code for the current file" "List source code for the current file"
@@ -768,19 +769,19 @@ class Cli(Frontend, cmd.Cmd):
def do_environment(self, args=None): def do_environment(self, args=None):
env = Frontend.do_environment(self) env = Frontend.do_environment(self)
for key in env: for key in env:
print "=" * 78 print("=" * 78)
print key.capitalize() print(key.capitalize())
print "-" * 78 print("-" * 78)
for name, value in env[key].items(): for name, value in env[key].items():
print "%-12s = %s" % (name, value) print("%-12s = %s" % (name, value))
def do_list_breakpoint(self, arg=None): def do_list_breakpoint(self, arg=None):
"List all breakpoints" "List all breakpoints"
breaks = Frontend.do_list_breakpoint(self) breaks = Frontend.do_list_breakpoint(self)
print "Num File Line Temp Enab Hits Cond" print("Num File Line Temp Enab Hits Cond")
for bp in breaks: for bp in breaks:
print '%-4d%-30s%4d %4s %4s %4d %s' % bp print('%-4d%-30s%4d %4s %4s %4d %s' % bp)
print print()
def do_set_breakpoint(self, arg): def do_set_breakpoint(self, arg):
"Set a breakpoint at filename:breakpoint" "Set a breakpoint at filename:breakpoint"
@@ -802,26 +803,26 @@ class Cli(Frontend, cmd.Cmd):
def default(self, line): def default(self, line):
"Default command" "Default command"
if line[:1] == '!': if line[:1] == '!':
print self.do_exec(line[1:]) print(self.do_exec(line[1:]))
else: else:
print "*** Unknown command: ", line print("*** Unknown command: ", line)
def print_lines(self, lines): def print_lines(self, lines):
for filename, lineno, bp, current, source in lines: for filename, lineno, bp, current, source in lines:
print "%s:%4d%s%s\t%s" % (filename, lineno, bp, current, source), print("%s:%4d%s%s\t%s" % (filename, lineno, bp, current, source), end=' ')
print print()
def test(): def test():
def f(pipe): def f(pipe):
print "creating debugger" print("creating debugger")
qdb = Qdb(pipe=pipe, redirect_stdio=False) qdb = Qdb(pipe=pipe, redirect_stdio=False)
print "set trace" print("set trace")
my_var = "Mariano!" my_var = "Mariano!"
qdb.set_trace() qdb.set_trace()
print "hello world!" print("hello world!")
print "good by!" print("good by!")
saraza saraza
if '--process' in sys.argv: if '--process' in sys.argv:
@@ -841,20 +842,20 @@ def test():
class Test(Frontend): class Test(Frontend):
def interaction(self, *args): def interaction(self, *args):
print "interaction!", args print("interaction!", args)
def exception(self, *args): def exception(self, *args):
print "exception", args print("exception", args)
#raise RuntimeError("exception %s" % repr(args)) #raise RuntimeError("exception %s" % repr(args))
qdb = Test(front_conn) qdb = Test(front_conn)
time.sleep(5) time.sleep(5)
while 1: while True:
print "running..." print("running...")
Frontend.run(qdb) Frontend.run(qdb)
time.sleep(1) time.sleep(1)
print "do_next" print("do_next")
qdb.do_next() qdb.do_next()
p.join() p.join()
@@ -865,7 +866,7 @@ def connect(host="localhost", port=6000, authkey='secret password'):
address = (host, port) address = (host, port)
from multiprocessing.connection import Client from multiprocessing.connection import Client
print "qdb debugger fronted: waiting for connection to", address print("qdb debugger fronted: waiting for connection to", address)
conn = Client(address, authkey=authkey) conn = Client(address, authkey=authkey)
try: try:
Cli(conn).run() Cli(conn).run()
@@ -879,12 +880,12 @@ def main(host='localhost', port=6000, authkey='secret password'):
"Debug a script and accept a remote frontend" "Debug a script and accept a remote frontend"
if not sys.argv[1:] or sys.argv[1] in ("--help", "-h"): if not sys.argv[1:] or sys.argv[1] in ("--help", "-h"):
print "usage: pdb.py scriptfile [arg] ..." print("usage: pdb.py scriptfile [arg] ...")
sys.exit(2) sys.exit(2)
mainpyfile = sys.argv[1] # Get script filename mainpyfile = sys.argv[1] # Get script filename
if not os.path.exists(mainpyfile): if not os.path.exists(mainpyfile):
print 'Error:', mainpyfile, 'does not exist' print('Error:', mainpyfile, 'does not exist')
sys.exit(1) sys.exit(1)
del sys.argv[0] # Hide "pdb.py" from argument list del sys.argv[0] # Hide "pdb.py" from argument list
@@ -895,20 +896,20 @@ def main(host='localhost', port=6000, authkey='secret password'):
from multiprocessing.connection import Listener from multiprocessing.connection import Listener
address = (host, port) # family is deduced to be 'AF_INET' address = (host, port) # family is deduced to be 'AF_INET'
listener = Listener(address, authkey=authkey) listener = Listener(address, authkey=authkey)
print "qdb debugger backend: waiting for connection at", address print("qdb debugger backend: waiting for connection at", address)
conn = listener.accept() conn = listener.accept()
print 'qdb debugger backend: connected to', listener.last_accepted print('qdb debugger backend: connected to', listener.last_accepted)
# create the backend # create the backend
qdb = Qdb(conn, redirect_stdio=True, allow_interruptions=True) qdb = Qdb(conn, redirect_stdio=True, allow_interruptions=True)
try: try:
print "running", mainpyfile print("running", mainpyfile)
qdb._runscript(mainpyfile) qdb._runscript(mainpyfile)
print "The program finished" print("The program finished")
except SystemExit: except SystemExit:
# In most cases SystemExit does not warrant a post-mortem session. # In most cases SystemExit does not warrant a post-mortem session.
print "The program exited via sys.exit(). Exit status: ", print("The program exited via sys.exit(). Exit status: ", end=' ')
print sys.exc_info()[1] print(sys.exc_info()[1])
raise raise
except: except:
raise raise
+2 -2
View File
@@ -31,7 +31,7 @@ from gluon.contrib.redis_utils import RConn
from gluon.contrib.redis_scheduler import RScheduler from gluon.contrib.redis_scheduler import RScheduler
def demo1(*args,**vars): def demo1(*args,**vars):
print 'you passed args=%s and vars=%s' % (args, vars) print('you passed args=%s and vars=%s' % (args, vars))
return 'done!' return 'done!'
def demo2(): def demo2():
@@ -317,7 +317,7 @@ class RScheduler(Scheduler):
now = self.now() now = self.now()
status_keyset = self._nkey('worker_statuses') status_keyset = self._nkey('worker_statuses')
with r_server.pipeline() as pipe: with r_server.pipeline() as pipe:
while 1: while True:
try: try:
# making sure we're the only one doing the job # making sure we're the only one doing the job
pipe.watch('ASSIGN_TASKS') pipe.watch('ASSIGN_TASKS')
+9 -13
View File
@@ -28,17 +28,13 @@
""" """
An interactive, stateful AJAX shell that runs Python code on the server. An interactive, stateful AJAX shell that runs Python code on the server.
""" """
from __future__ import print_function
from gluon._compat import ClassType, pickle, StringIO
import logging import logging
import new import new
try:
import cPickle as pickle
except:
import pickle
import sys import sys
import traceback import traceback
import types import types
import StringIO
import threading import threading
locker = threading.RLock() locker = threading.RLock()
@@ -51,8 +47,8 @@ _HISTORY_KIND = '_Shell_History'
# Types that can't be pickled. # Types that can't be pickled.
UNPICKLABLE_TYPES = [ UNPICKLABLE_TYPES = [
types.ModuleType, types.ModuleType,
types.TypeType, type,
types.ClassType, ClassType
types.FunctionType, types.FunctionType,
] ]
@@ -204,7 +200,7 @@ def run(history, statement, env={}):
# globals, run the statement, and re-pickle the history globals, all # globals, run the statement, and re-pickle the history globals, all
# inside it. # inside it.
old_main = sys.modules.get('__main__') old_main = sys.modules.get('__main__')
output = StringIO.StringIO() output = StringIO()
try: try:
sys.modules['__main__'] = statement_module sys.modules['__main__'] = statement_module
statement_module.__name__ = '__main__' statement_module.__name__ = '__main__'
@@ -212,7 +208,7 @@ def run(history, statement, env={}):
# re-evaluate the unpicklables # re-evaluate the unpicklables
for code in history.unpicklables: for code in history.unpicklables:
exec code in statement_module.__dict__ exec(code, statement_module.__dict__)
# re-initialize the globals # re-initialize the globals
for name, val in history.globals_dict().items(): for name, val in history.globals_dict().items():
@@ -232,7 +228,7 @@ def run(history, statement, env={}):
try: try:
sys.stderr = sys.stdout = output sys.stderr = sys.stdout = output
locker.acquire() locker.acquire()
exec compiled in statement_module.__dict__ exec(compiled, statement_module.__dict__)
finally: finally:
locker.release() locker.release()
sys.stdout, sys.stderr = old_stdout, old_stderr sys.stdout, sys.stderr = old_stdout, old_stderr
@@ -259,7 +255,7 @@ def run(history, statement, env={}):
if not name.startswith('__'): if not name.startswith('__'):
try: try:
history.set_global(name, val) history.set_global(name, val)
except (TypeError, pickle.PicklingError), ex: except (TypeError, pickle.PicklingError) as ex:
UNPICKLABLE_TYPES.append(type(val)) UNPICKLABLE_TYPES.append(type(val))
history.add_unpicklable(statement, new_globals.keys()) history.add_unpicklable(statement, new_globals.keys())
@@ -270,4 +266,4 @@ def run(history, statement, env={}):
if __name__ == '__main__': if __name__ == '__main__':
history = History() history = History()
while True: while True:
print run(history, raw_input('>>> ')).rstrip() print(run(history, raw_input('>>> ')).rstrip())
+3 -2
View File
@@ -10,6 +10,7 @@
# for more details. # for more details.
"Pythonic simple JSON RPC Client implementation" "Pythonic simple JSON RPC Client implementation"
from __future__ import print_function
__author__ = "Mariano Reingart (reingart@gmail.com)" __author__ = "Mariano Reingart (reingart@gmail.com)"
__copyright__ = "Copyright (C) 2011 Mariano Reingart" __copyright__ = "Copyright (C) 2011 Mariano Reingart"
@@ -105,7 +106,7 @@ class ServerProxy(object):
"JSON RPC communication (method invocation)" "JSON RPC communication (method invocation)"
# build data sent to the service # build data sent to the service
request_id = random.randint(0, sys.maxint) request_id = random.randint(0, sys.maxsize)
data = {'id': request_id, 'method': method, 'params': args, } data = {'id': request_id, 'method': method, 'params': args, }
if self.version: if self.version:
data['jsonrpc'] = self.version #mandatory key/value for jsonrpc2 validation else err -32600 data['jsonrpc'] = self.version #mandatory key/value for jsonrpc2 validation else err -32600
@@ -145,4 +146,4 @@ if __name__ == "__main__":
# basic tests: # basic tests:
location = "http://www.web2py.com.ar/webservices/sample/call/jsonrpc" location = "http://www.web2py.com.ar/webservices/sample/call/jsonrpc"
client = ServerProxy(location, verbose='--verbose' in sys.argv,) client = ServerProxy(location, verbose='--verbose' in sys.argv,)
print client.add(1, 2) print(client.add(1, 2))
+5 -4
View File
@@ -3,6 +3,7 @@
""" """
Developed by Massimo Di Pierro, optional component of web2py, BSDv3 license. Developed by Massimo Di Pierro, optional component of web2py, BSDv3 license.
""" """
from __future__ import print_function
import re import re
import pickle import pickle
@@ -255,7 +256,7 @@ class Sheet:
try: try:
r, c = Sheet.pregex.findall(key) r, c = Sheet.pregex.findall(key)
r, c = int(r), int(c) r, c = int(r), int(c)
except (ValueError, IndexError, TypeError), e: except (ValueError, IndexError, TypeError) as e:
error = "%s. %s" % \ error = "%s. %s" % \
("Unexpected position parameter", ("Unexpected position parameter",
"Must be a key of type 'rncn'") "Must be a key of type 'rncn'")
@@ -529,7 +530,7 @@ class Sheet:
""" """
if not self.regex.match(key): if not self.regex.match(key):
raise SyntaxError, "Invalid cell name: %s" % key raise SyntaxError("Invalid cell name: %s" % key)
else: else:
attributes = self.get_attributes(kwarg) attributes = self.get_attributes(kwarg)
if attributes is not None: if attributes is not None:
@@ -742,7 +743,7 @@ class Sheet:
exec('__value__=' + node.value[1:], {}, self.environment) exec('__value__=' + node.value[1:], {}, self.environment)
node.computed_value = self.environment['__value__'] node.computed_value = self.environment['__value__']
del self.environment['__value__'] del self.environment['__value__']
except Exception, e: except Exception as e:
node.computed_value = self.error % dict(error=str(e)) node.computed_value = self.error % dict(error=str(e))
self.environment[node.name] = node.computed_value self.environment[node.name] = node.computed_value
if node.onchange: if node.onchange:
@@ -900,4 +901,4 @@ if __name__ == '__main__':
s.cell('a', value="2") s.cell('a', value="2")
s.cell('b', value="=sin(a)") s.cell('b', value="=sin(a)")
s.cell('c', value="=cos(a)**2+b*b") s.cell('c', value="=cos(a)**2+b*b")
print s['c'].computed_value print(s['c'].computed_value)
+4 -3
View File
@@ -1,3 +1,4 @@
from __future__ import print_function
import urllib import urllib
import json import json
from hashlib import sha1 from hashlib import sha1
@@ -244,8 +245,8 @@ jQuery(function(){
if __name__ == '__main__': if __name__ == '__main__':
key = raw_input('user>') key = raw_input('user>')
d = Stripe(key).charge(100) d = Stripe(key).charge(100)
print 'charged', d['paid'] print('charged', d['paid'])
s = Stripe(key).check(d[u'id']) s = Stripe(key).check(d[u'id'])
print 'paid', s['paid'], s['amount'], s['currency'] print('paid', s['paid'], s['amount'], s['currency'])
s = Stripe(key).refund(d[u'id']) s = Stripe(key).refund(d[u'id'])
print 'refunded', s['refunded'] print('refunded', s['refunded'])
+4 -3
View File
@@ -6,6 +6,7 @@
# # 11/7/08 # # 11/7/08
# dual licensed under the web2py license (LGPL) and the Python license. # dual licensed under the web2py license (LGPL) and the Python license.
from __future__ import print_function
import os import os
import sys import sys
import base64 import base64
@@ -78,7 +79,7 @@ class TaskBarIcon:
hicon = self.__loadFromFile(fp) hicon = self.__loadFromFile(fp)
os.unlink(fp) os.unlink(fp)
except: except:
print "Can't load web2py icons - using default" print("Can't load web2py icons - using default")
hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION) hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)
flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE\ flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE\
@@ -101,7 +102,7 @@ class TaskBarIcon:
# This is common when windows is starting, and this code is hit # This is common when windows is starting, and this code is hit
# before the taskbar has been created. # before the taskbar has been created.
print 'Failed to add the taskbar icon - is explorer running?' print('Failed to add the taskbar icon - is explorer running?')
# but keep running anyway - when explorer starts, we get the # but keep running anyway - when explorer starts, we get the
@@ -197,7 +198,7 @@ class TaskBarIcon:
self.status.append(self.EnumStatus.QUIT) self.status.append(self.EnumStatus.QUIT)
self.Destroy() self.Destroy()
else: else:
print 'Unknown command -', id print('Unknown command -', id)
def Destroy(self): def Destroy(self):
win32gui.DestroyWindow(self.hwnd) win32gui.DestroyWindow(self.hwnd)
+1
View File
@@ -1,3 +1,4 @@
from __future__ import print_function
# Only Python 2.6 and up, because of NamedTuple. # Only Python 2.6 and up, because of NamedTuple.
import time import time
from collections import namedtuple from collections import namedtuple
+9 -8
View File
@@ -15,6 +15,7 @@ mostly for testing purposes
Some examples at the bottom. Some examples at the bottom.
""" """
from __future__ import print_function
import re import re
import time import time
import urllib import urllib
@@ -126,7 +127,7 @@ class WebClient(object):
t0 = time.time() t0 = time.time()
self.response = opener.open(self.url, data) self.response = opener.open(self.url, data)
self.time = time.time() - t0 self.time = time.time() - t0
except urllib2.HTTPError, error: except urllib2.HTTPError as error:
# catch HTTP errors # catch HTTP errors
self.time = time.time() - t0 self.time = time.time() - t0
self.response = error self.response = error
@@ -160,7 +161,7 @@ class WebClient(object):
if match: if match:
name = match.group('name') name = match.group('name')
if name in self.sessions and self.sessions[name] != value: if name in self.sessions and self.sessions[name] != value:
print RuntimeError('Changed session ID %s' % name) print(RuntimeError('Changed session ID %s' % name))
self.sessions[name] = value self.sessions[name] = value
# find all forms and formkeys in page # find all forms and formkeys in page
@@ -202,13 +203,13 @@ def test_web2py_registration_and_login():
assert 'Welcome Homer' in client.text assert 'Welcome Homer' in client.text
# print some variables # print some variables
print '\nsessions:\n', client.sessions print('\nsessions:\n', client.sessions)
print '\nheaders:\n', client.headers print('\nheaders:\n', client.headers)
print '\ncookies:\n', client.cookies print('\ncookies:\n', client.cookies)
print '\nforms:\n', client.forms print('\nforms:\n', client.forms)
print print()
for method, url, status, t in client.history: for method, url, status, t in client.history:
print method, url, status, t print(method, url, status, t)
if __name__ == '__main__': if __name__ == '__main__':
test_web2py_registration_and_login() test_web2py_registration_and_login()
+4 -3
View File
@@ -83,6 +83,7 @@ Acknowledgements:
Tornado code inspired by http://thomas.pelletier.im/2010/08/websocket-tornado-redis/ Tornado code inspired by http://thomas.pelletier.im/2010/08/websocket-tornado-redis/
""" """
from __future__ import print_function
import tornado.httpserver import tornado.httpserver
import tornado.websocket import tornado.websocket
@@ -117,7 +118,7 @@ class PostHandler(tornado.web.RequestHandler):
if 'message' in self.request.arguments: if 'message' in self.request.arguments:
message = self.request.arguments['message'][0] message = self.request.arguments['message'][0]
group = self.request.arguments.get('group', ['default'])[0] group = self.request.arguments.get('group', ['default'])[0]
print '%s:MESSAGE to %s:%s' % (time.time(), group, message) print('%s:MESSAGE to %s:%s' % (time.time(), group, message))
if hmac_key: if hmac_key:
signature = self.request.arguments['signature'][0] signature = self.request.arguments['signature'][0]
if not hmac.new(hmac_key, message).hexdigest() == signature: if not hmac.new(hmac_key, message).hexdigest() == signature:
@@ -167,7 +168,7 @@ class DistributeHandler(tornado.websocket.WebSocketHandler):
client.write_message('+' + self.name) client.write_message('+' + self.name)
listeners[self.group].append(self) listeners[self.group].append(self)
names[self] = self.name names[self] = self.name
print '%s:CONNECT to %s' % (time.time(), self.group) print('%s:CONNECT to %s' % (time.time(), self.group))
def on_message(self, message): def on_message(self, message):
pass pass
@@ -179,7 +180,7 @@ class DistributeHandler(tornado.websocket.WebSocketHandler):
# notify clients that a member has left the groups # notify clients that a member has left the groups
for client in listeners.get(self.group, []): for client in listeners.get(self.group, []):
client.write_message('-' + self.name) client.write_message('-' + self.name)
print '%s:DISCONNECT from %s' % (time.time(), self.group) print('%s:DISCONNECT from %s' % (time.time(), self.group))
# if your webserver is different from tornado server uncomment this # if your webserver is different from tornado server uncomment this
# or override using something more restrictive: # or override using something more restrictive:
+11 -11
View File
@@ -8,22 +8,22 @@
Support for smart import syntax for web2py applications Support for smart import syntax for web2py applications
------------------------------------------------------- -------------------------------------------------------
""" """
import __builtin__ from gluon._compat import builtin
import os import os
import sys import sys
import threading import threading
from gluon import current from gluon import current
NATIVE_IMPORTER = __builtin__.__import__ NATIVE_IMPORTER = builtin.__import__
INVALID_MODULES = set(('', 'gluon', 'applications', 'custom_import')) INVALID_MODULES = set(('', 'gluon', 'applications', 'custom_import'))
# backward compatibility API # backward compatibility API
def custom_import_install(): def custom_import_install():
if __builtin__.__import__ == NATIVE_IMPORTER: if builtin.__import__ == NATIVE_IMPORTER:
INVALID_MODULES.update(sys.modules.keys()) INVALID_MODULES.update(sys.modules.keys())
__builtin__.__import__ = custom_importer builtin.__import__ = custom_importer
def track_changes(track=True): def track_changes(track=True):
@@ -85,21 +85,21 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1):
modules_prefix, globals, locals, [itemname], level) modules_prefix, globals, locals, [itemname], level)
try: try:
result = result or sys.modules[modules_prefix+'.'+itemname] result = result or sys.modules[modules_prefix+'.'+itemname]
except KeyError, e: except KeyError as e:
raise ImportError, 'Cannot import module %s' % str(e) raise ImportError('Cannot import module %s' % str(e))
modules_prefix += "." + itemname modules_prefix += "." + itemname
return result return result
else: else:
# import like "from x import a, b, ..." # import like "from x import a, b, ..."
pname = modules_prefix + "." + name pname = modules_prefix + "." + name
return base_importer(pname, globals, locals, fromlist, level) return base_importer(pname, globals, locals, fromlist, level)
except ImportError, e1: except ImportError as e1:
import_tb = sys.exc_info()[2] import_tb = sys.exc_info()[2]
try: try:
return NATIVE_IMPORTER(name, globals, locals, fromlist, level) return NATIVE_IMPORTER(name, globals, locals, fromlist, level)
except ImportError, e3: 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, e2: except Exception as e2:
raise # there is an error in the module raise # there is an error in the module
finally: finally:
if import_tb: if import_tb:
@@ -135,7 +135,7 @@ class TrackImporter(object):
# Module maybe loaded for the 1st time so we need to set the date # Module maybe loaded for the 1st time so we need to set the date
self._update_dates(name, globals, locals, fromlist, level) self._update_dates(name, globals, locals, fromlist, level)
return result return result
except Exception, e: except Exception as e:
raise # Don't hide something that went wrong raise # Don't hide something that went wrong
def _update_dates(self, name, globals, locals, fromlist, level): def _update_dates(self, name, globals, locals, fromlist, level):
+5 -5
View File
@@ -10,7 +10,7 @@ File operations
--------------- ---------------
""" """
import storage from gluon import storage
import os import os
import re import re
import tarfile import tarfile
@@ -18,9 +18,9 @@ import glob
import time import time
import datetime import datetime
import logging import logging
from http import HTTP from gluon.http import HTTP
from gzip import open as gzopen from gzip import open as gzopen
from recfile import generate from gluon.recfile import generate
__all__ = [ __all__ = [
'parse_version', 'parse_version',
@@ -362,7 +362,7 @@ def get_session(request, other_application='admin'):
if not os.path.exists(session_filename): if not os.path.exists(session_filename):
session_filename = generate(session_filename) session_filename = generate(session_filename)
osession = storage.load_storage(session_filename) osession = storage.load_storage(session_filename)
except Exception, e: except Exception as e:
osession = storage.Storage() osession = storage.Storage()
return osession return osession
@@ -449,7 +449,7 @@ def make_fake_file_like_object():
return LogFile() 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 # settings imports fileutils too
+24 -28
View File
@@ -13,10 +13,9 @@ Contains the classes for the global used variables:
- Session - Session
""" """
from gluon._compat import pickle, StringIO, copyreg, Cookie, urlparse, PY2, iteritems, to_unicode, to_native
from gluon.storage import Storage, List from gluon.storage import Storage, List
from gluon.streamer import streamer, stream_file_or_304_or_206, DEFAULT_CHUNK_SIZE 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.contenttype import contenttype
from gluon.html import xmlescape, TABLE, TR, PRE, URL from gluon.html import xmlescape, TABLE, TR, PRE, URL
from gluon.http import HTTP, redirect from gluon.http import HTTP, redirect
@@ -29,24 +28,16 @@ from gluon import recfile
from gluon.cache import CacheInRam from gluon.cache import CacheInRam
from gluon.fileutils import copystream from gluon.fileutils import copystream
import hashlib import hashlib
import portalocker from gluon import portalocker
try:
import cPickle as pickle
except:
import pickle
from pickle import Pickler, MARK, DICT, EMPTY_DICT from pickle import Pickler, MARK, DICT, EMPTY_DICT
from types import DictionaryType #from types import DictionaryType
import cStringIO
import datetime import datetime
import re import re
import copy_reg
import Cookie
import os import os
import sys import sys
import traceback import traceback
import threading import threading
import cgi import cgi
import urlparse
import copy import copy
import tempfile import tempfile
import json import json
@@ -57,6 +48,7 @@ PAST = 'Sat, 1-Jan-1971 00:00:00'
FUTURE = 'Tue, 1-Dec-2999 23:59:59' FUTURE = 'Tue, 1-Dec-2999 23:59:59'
try: try:
#FIXME PY3
from gluon.contrib.minify import minify from gluon.contrib.minify import minify
have_minify = True have_minify = True
except ImportError: except ImportError:
@@ -96,12 +88,14 @@ class SortingPickler(Pickler):
self.memoize(obj) self.memoize(obj)
self._batch_setitems([(key, obj[key]) for key in sorted(obj)]) self._batch_setitems([(key, obj[key]) for key in sorted(obj)])
SortingPickler.dispatch = copy.copy(Pickler.dispatch) if PY2:
SortingPickler.dispatch[DictionaryType] = SortingPickler.save_dict #FIXME PY3
SortingPickler.dispatch = copy.copy(Pickler.dispatch)
SortingPickler.dispatch[dict] = SortingPickler.save_dict
def sorting_dumps(obj, protocol=None): def sorting_dumps(obj, protocol=None):
file = cStringIO.StringIO() file = StringIO()
SortingPickler(file, protocol).dump(obj) SortingPickler(file, protocol).dump(obj)
return file.getvalue() return file.getvalue()
# END ##################################################################### # END #####################################################################
@@ -115,7 +109,7 @@ def copystream_progress(request, chunk_size=10 ** 5):
""" """
env = request.env env = request.env
if not env.get('CONTENT_LENGTH', None): if not env.get('CONTENT_LENGTH', None):
return cStringIO.StringIO() return StringIO()
source = env['wsgi.input'] source = env['wsgi.input']
try: try:
size = int(env['CONTENT_LENGTH']) size = int(env['CONTENT_LENGTH'])
@@ -205,7 +199,7 @@ class Request(Storage):
query_string = self.env.get('query_string', '') query_string = self.env.get('query_string', '')
dget = urlparse.parse_qs(query_string, keep_blank_values=1) # Ref: https://docs.python.org/2/library/cgi.html#cgi.parse_qs dget = urlparse.parse_qs(query_string, keep_blank_values=1) # Ref: https://docs.python.org/2/library/cgi.html#cgi.parse_qs
get_vars = self._get_vars = Storage(dget) get_vars = self._get_vars = Storage(dget)
for (key, value) in get_vars.iteritems(): for (key, value) in iteritems(get_vars):
if isinstance(value, list) and len(value) == 1: if isinstance(value, list) and len(value) == 1:
get_vars[key] = value[0] get_vars[key] = value[0]
@@ -279,7 +273,7 @@ class Request(Storage):
"""Merges get_vars and post_vars to vars """Merges get_vars and post_vars to vars
""" """
self._vars = copy.copy(self.get_vars) self._vars = copy.copy(self.get_vars)
for key, value in self.post_vars.iteritems(): for key, value in iteritems(self.post_vars):
if key not in self._vars: if key not in self._vars:
self._vars[key] = value self._vars[key] = value
else: else:
@@ -375,7 +369,7 @@ class Request(Storage):
if is_json and not isinstance(res, str): if is_json and not isinstance(res, str):
res = json(res) res = json(res)
return res return res
except TypeError, e: except TypeError as e:
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
if len(traceback.extract_tb(exc_traceback)) == 1: if len(traceback.extract_tb(exc_traceback)) == 1:
raise HTTP(400, "invalid arguments") raise HTTP(400, "invalid arguments")
@@ -399,7 +393,7 @@ class Response(Storage):
self.status = 200 self.status = 200
self.headers = dict() self.headers = dict()
self.headers['X-Powered-By'] = 'web2py' self.headers['X-Powered-By'] = 'web2py'
self.body = cStringIO.StringIO() self.body = StringIO()
self.session_id = None self.session_id = None
self.cookies = Cookie.SimpleCookie() self.cookies = Cookie.SimpleCookie()
self.postprocessing = [] self.postprocessing = []
@@ -421,10 +415,11 @@ class Response(Storage):
if not escape: if not escape:
self.body.write(str(data)) self.body.write(str(data))
else: else:
self.body.write(xmlescape(data)) # FIXME PY3:
self.body.write(to_native(xmlescape(data)))
def render(self, *a, **b): def render(self, *a, **b):
from compileapp import run_view_in from gluon.compileapp import run_view_in
if len(a) > 2: if len(a) > 2:
raise SyntaxError( raise SyntaxError(
'Response.render can be called with two arguments, at most') 'Response.render can be called with two arguments, at most')
@@ -441,9 +436,9 @@ class Response(Storage):
self._vars.update(b) self._vars.update(b)
self._view_environment.update(self._vars) self._view_environment.update(self._vars)
if view: if view:
import cStringIO from gluon._compat import StringIO
(obody, oview) = (self.body, self.view) (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) run_view_in(self._view_environment)
page = self.body.getvalue() page = self.body.getvalue()
self.body.close() self.body.close()
@@ -455,7 +450,7 @@ class Response(Storage):
def include_meta(self): def include_meta(self):
s = "\n" s = "\n"
for meta in (self.meta or {}).iteritems(): for meta in iteritems((self.meta or {})):
k, v = meta k, v = meta
if isinstance(v, dict): if isinstance(v, dict):
s += '<meta' + ''.join(' %s="%s"' % (xmlescape(key), xmlescape(v[key])) for key in v) +' />\n' s += '<meta' + ''.join(' %s="%s"' % (xmlescape(key), xmlescape(v[key])) for key in v) +' />\n'
@@ -655,6 +650,7 @@ class Response(Storage):
return json(data, default=default or custom_json) return json(data, default=default or custom_json)
def xmlrpc(self, request, methods): def xmlrpc(self, request, methods):
from gluon.xmlrpc import handler
""" """
assuming:: assuming::
@@ -671,7 +667,7 @@ class Response(Storage):
import xmlrpclib import xmlrpclib
connection = xmlrpclib.ServerProxy( connection = xmlrpclib.ServerProxy(
'http://hostname/app/contr/func') 'http://hostname/app/contr/func')
print connection.add(3, 4) print(connection.add(3, 4))
""" """
@@ -686,7 +682,7 @@ class Response(Storage):
dbstats = [] dbstats = []
dbtables = {} dbtables = {}
infos = DAL.get_instances() infos = DAL.get_instances()
for k, v in infos.iteritems(): for k, v in iteritems(infos):
dbstats.append(TABLE(*[TR(PRE(row[0]), '%.2fms' % (row[1]*1000)) dbstats.append(TABLE(*[TR(PRE(row[0]), '%.2fms' % (row[1]*1000))
for row in v['dbstats']])) for row in v['dbstats']]))
dbtables[k] = dict(defined=v['dbtables']['defined'] or '[no defined tables]', dbtables[k] = dict(defined=v['dbtables']['defined'] or '[no defined tables]',
@@ -1240,4 +1236,4 @@ class Session(Storage):
def pickle_session(s): def pickle_session(s):
return Session, (dict(s),) return Session, (dict(s),)
copy_reg.pickle(Session, pickle_session) copyreg.pickle(Session, pickle_session)
+9 -9
View File
@@ -6,9 +6,9 @@
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
""" """
from __future__ import print_function
from gluon._compat import xrange, _local_html_escape
import re import re
import cgi
__all__ = ['highlight'] __all__ = ['highlight']
@@ -62,7 +62,7 @@ class Highlighter(object):
Callback for C specific highlighting. Callback for C specific highlighting.
""" """
value = cgi.escape(match.group()) value = _local_html_escape(match.group(), quote=False)
self.change_style(token, style) self.change_style(token, style)
self.output.append(value) self.output.append(value)
@@ -76,7 +76,7 @@ class Highlighter(object):
Callback for python specific highlighting. Callback for python specific highlighting.
""" """
value = cgi.escape(match.group()) value = _local_html_escape(match.group(), quote=False)
if token == 'MULTILINESTRING': if token == 'MULTILINESTRING':
self.change_style(token, style) self.change_style(token, style)
self.output.append(value) self.output.append(value)
@@ -113,7 +113,7 @@ class Highlighter(object):
Callback for HTML specific highlighting. Callback for HTML specific highlighting.
""" """
value = cgi.escape(match.group()) value = _local_html_escape(match.group(), quote=False)
self.change_style(token, style) self.change_style(token, style)
self.output.append(value) self.output.append(value)
if token == 'GOTOPYTHON': if token == 'GOTOPYTHON':
@@ -291,13 +291,13 @@ def highlight(
'WEB2PY']: 'WEB2PY']:
code = Highlighter(language, link, styles).highlight(code) code = Highlighter(language, link, styles).highlight(code)
else: else:
code = cgi.escape(code) code = _local_html_escape(code, quote=False)
lines = code.split('\n') lines = code.split('\n')
if counter is None: if counter is None:
linenumbers = [''] * len(lines) linenumbers = [''] * len(lines)
elif isinstance(counter, str): elif isinstance(counter, str):
linenumbers = [cgi.escape(counter)] * len(lines) linenumbers = [_local_html_escape(counter, quote=False)] * len(lines)
else: else:
linenumbers = [str(i + counter) + '.' for i in linenumbers = [str(i + counter) + '.' for i in
xrange(len(lines))] xrange(len(lines))]
@@ -341,5 +341,5 @@ if __name__ == '__main__':
argfp = open(sys.argv[1]) argfp = open(sys.argv[1])
data = argfp.read() data = argfp.read()
argfp.close() argfp.close()
print '<html><body>' + highlight(data, sys.argv[2])\ print('<html><body>' + highlight(data, sys.argv[2])\
+ '</body></html>' + '</body></html>')
+115 -114
View File
@@ -9,6 +9,7 @@
Template helpers Template helpers
-------------------------------------------- --------------------------------------------
""" """
from __future__ import print_function
import cgi import cgi
import os import os
@@ -17,19 +18,12 @@ import copy
import types import types
import urllib import urllib
import base64 import base64
import sanitizer from gluon import sanitizer, decoder
import itertools import itertools
import decoder from gluon._compat import reduce, pickle, copyreg, HTMLParser, name2codepoint, iteritems, unichr, unicodeT, urllib_quote, to_bytes, \
import copy_reg to_native, to_unicode, _local_html_escape, basestring, urlencode
try:
import cPickle as pickle
except:
import pickle
import marshal import marshal
from HTMLParser import HTMLParser
from htmlentitydefs import name2codepoint
from gluon.storage import Storage from gluon.storage import Storage
from gluon.utils import web2py_uuid, simple_hash, compare from gluon.utils import web2py_uuid, simple_hash, compare
from gluon.highlight import highlight from gluon.highlight import highlight
@@ -40,8 +34,7 @@ regex_crlf = re.compile('\r|\n')
join = ''.join join = ''.join
# name2codepoint is incomplete respect to xhtml (and xml): 'apos' is missing. # name2codepoint is incomplete respect to xhtml (and xml): 'apos' is missing.
entitydefs = dict(map(lambda ( entitydefs = dict(map(lambda k_v: (k_v[0], unichr(k_v[1]).encode('utf-8')), iteritems(name2codepoint)))
k, v): (k, unichr(v).encode('utf-8')), name2codepoint.iteritems()))
entitydefs.setdefault('apos', u"'".encode('utf-8')) entitydefs.setdefault('apos', u"'".encode('utf-8'))
@@ -116,7 +109,6 @@ __all__ = [
DEFAULT_PASSWORD_DISPLAY = '*' * 8 DEFAULT_PASSWORD_DISPLAY = '*' * 8
def xmlescape(data, quote=True): def xmlescape(data, quote=True):
""" """
Returns an escaped string of the provided data Returns an escaped string of the provided data
@@ -128,16 +120,16 @@ def xmlescape(data, quote=True):
# first try the xml function # first try the xml function
if hasattr(data, 'xml') and callable(data.xml): if hasattr(data, 'xml') and callable(data.xml):
return data.xml() return to_bytes(data.xml())
# otherwise, make it a string if not(isinstance(data, basestring)):
if not isinstance(data, (str, unicode)): # i.e., integers
data = str(data) data=str(data)
elif isinstance(data, unicode): data = to_bytes(data, 'utf8', 'xmlcharrefreplace')
data = data.encode('utf8', 'xmlcharrefreplace')
# ... and do the escaping # ... and do the escaping
data = cgi.escape(data, quote).replace("'", "&#x27;") data = _local_html_escape(data, quote)
return data return data
@@ -149,9 +141,9 @@ def call_as_list(f, *a, **b):
def truncate_string(text, length, dots='...'): def truncate_string(text, length, dots='...'):
text = text.decode('utf-8') text = to_unicode(text)
if len(text) > length: if len(text) > length:
text = text[:length - len(dots)].encode('utf-8') + dots text = to_native(text[:length - len(dots)]) + dots
return text return text
@@ -260,7 +252,7 @@ def URL(a=None,
'/a/c/f#%25%28id%29d' '/a/c/f#%25%28id%29d'
""" """
from rewrite import url_out # done here in case used not-in web2py from gluon.rewrite import url_out # done here in case used not-in web2py
if args in (None, []): if args in (None, []):
args = [] args = []
@@ -277,7 +269,7 @@ def URL(a=None,
(f, a, c) = (a, c, f) (f, a, c) = (a, c, f)
elif a and c and not f: elif a and c and not f:
(c, f, a) = (a, c, f) (c, f, a) = (a, c, f)
from globals import current from gluon.globals import current
if hasattr(current, 'request'): if hasattr(current, 'request'):
r = current.request r = current.request
@@ -312,7 +304,7 @@ def URL(a=None,
if controller == 'static': if controller == 'static':
extension = None extension = None
# add static version to url # add static version to url
from globals import current from gluon.globals import current
if hasattr(current, 'response'): if hasattr(current, 'response'):
response = current.response response = current.response
if response.static_version and response.static_version_urls: if response.static_version and response.static_version_urls:
@@ -330,9 +322,9 @@ def URL(a=None,
if args: if args:
if url_encode: if url_encode:
if encode_embedded_slash: if encode_embedded_slash:
other = '/' + '/'.join([urllib.quote(str(x), '') for x in args]) other = '/' + '/'.join([urllib_quote(str(x), '') for x in args])
else: else:
other = args and urllib.quote('/' + '/'.join([str(x) for x in args])) other = args and urllib_quote('/' + '/'.join([str(x) for x in args]))
else: else:
other = args and ('/' + '/'.join([str(x) for x in args])) other = args and ('/' + '/'.join([str(x) for x in args]))
else: else:
@@ -351,7 +343,7 @@ def URL(a=None,
list_vars.append((key, val)) list_vars.append((key, val))
if user_signature: if user_signature:
from globals import current from gluon.globals import current
if current.session.auth: if current.session.auth:
hmac_key = current.session.auth.hmac_key hmac_key = current.session.auth.hmac_key
@@ -372,7 +364,7 @@ def URL(a=None,
h_vars = [(k, v) for (k, v) in list_vars if k in hash_vars] h_vars = [(k, v) for (k, v) in list_vars if k in hash_vars]
# re-assembling the same way during hash authentication # re-assembling the same way during hash authentication
message = h_args + '?' + urllib.urlencode(sorted(h_vars)) message = h_args + '?' + urlencode(sorted(h_vars))
sig = simple_hash( sig = simple_hash(
message, hmac_key or '', salt or '', digest_alg='sha1') message, hmac_key or '', salt or '', digest_alg='sha1')
# add the signature into vars # add the signature into vars
@@ -380,12 +372,12 @@ def URL(a=None,
if list_vars: if list_vars:
if url_encode: if url_encode:
other += '?%s' % urllib.urlencode(list_vars) other += '?%s' % urlencode(list_vars)
else: else:
other += '?%s' % '&'.join(['%s=%s' % var[:2] for var in list_vars]) other += '?%s' % '&'.join(['%s=%s' % var[:2] for var in list_vars])
if anchor: if anchor:
if url_encode: if url_encode:
other += '#' + urllib.quote(str(anchor)) other += '#' + urllib_quote(str(anchor))
else: else:
other += '#' + (str(anchor)) other += '#' + (str(anchor))
if extension: if extension:
@@ -440,7 +432,7 @@ def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=
# check if user_signature requires # check if user_signature requires
if user_signature: if user_signature:
from globals import current from gluon.globals import current
if not current.session or not current.session.auth: if not current.session or not current.session.auth:
return False return False
hmac_key = current.session.auth.hmac_key hmac_key = current.session.auth.hmac_key
@@ -459,7 +451,7 @@ def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=
# join all the args & vars into one long string # join all the args & vars into one long string
# always include all of the args # always include all of the args
other = args and urllib.quote('/' + '/'.join([str(x) for x in args])) or '' other = args and urllib_quote('/' + '/'.join([str(x) for x in args])) or ''
h_args = '/%s/%s/%s.%s%s' % (request.application, h_args = '/%s/%s/%s.%s%s' % (request.application,
request.controller, request.controller,
request.function, request.function,
@@ -491,7 +483,7 @@ def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=
# user has removed one of our vars! Immediate fail # user has removed one of our vars! Immediate fail
return False return False
# build the full message string with both args & vars # build the full message string with both args & vars
message = h_args + '?' + urllib.urlencode(sorted(h_vars)) message = h_args + '?' + urlencode(sorted(h_vars))
# hash with the hmac_key provided # hash with the hmac_key provided
sig = simple_hash(message, str(hmac_key), salt or '', digest_alg='sha1') sig = simple_hash(message, str(hmac_key), salt or '', digest_alg='sha1')
@@ -607,11 +599,11 @@ class XML(XmlComponent):
if sanitize: if sanitize:
text = sanitizer.sanitize(text, permitted_tags, allowed_attributes) text = sanitizer.sanitize(text, permitted_tags, allowed_attributes)
if isinstance(text, unicode): if isinstance(text, unicodeT):
text = text.encode('utf8', 'xmlcharrefreplace') text = to_native(text.encode('utf8', 'xmlcharrefreplace'))
elif not isinstance(text, str): elif not isinstance(text, str):
text = str(text) text = str(text)
self.text = text self.text = to_bytes(text)
def xml(self): def xml(self):
return self.text return self.text
@@ -619,6 +611,8 @@ class XML(XmlComponent):
def __str__(self): def __str__(self):
return self.text return self.text
__repr__ = __str__
def __add__(self, other): def __add__(self, other):
return '%s%s' % (self, other) return '%s%s' % (self, other)
@@ -674,7 +668,7 @@ def XML_unpickle(data):
def XML_pickle(data): def XML_pickle(data):
return XML_unpickle, (marshal.dumps(str(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): class DIV(XmlComponent):
@@ -731,7 +725,7 @@ class DIV(XmlComponent):
dictionary like updating of the tag attributes dictionary like updating of the tag attributes
""" """
for (key, value) in kargs.iteritems(): for (key, value) in iteritems(kargs):
self[key] = value self[key] = value
return self return self
@@ -743,7 +737,7 @@ class DIV(XmlComponent):
>>> a=DIV() >>> a=DIV()
>>> a.append(SPAN('x')) >>> a.append(SPAN('x'))
>>> print a >>> print(a)
<div><span>x</span></div> <div><span>x</span></div>
""" """
self._setnode(value) self._setnode(value)
@@ -759,7 +753,7 @@ class DIV(XmlComponent):
>>> a=DIV() >>> a=DIV()
>>> a.insert(0, SPAN('x')) >>> a.insert(0, SPAN('x'))
>>> print a >>> print(a)
<div><span>x</span></div> <div><span>x</span></div>
""" """
self._setnode(value) self._setnode(value)
@@ -798,7 +792,7 @@ class DIV(XmlComponent):
value: the new value value: the new value
""" """
self._setnode(value) self._setnode(value)
if isinstance(i, (str, unicode)): if isinstance(i, (str, unicodeT)):
self.attributes[i] = value self.attributes[i] = value
else: else:
self.components[i] = value self.components[i] = value
@@ -823,12 +817,14 @@ class DIV(XmlComponent):
""" """
return len(self.components) return len(self.components)
def __nonzero__(self): def __bool__(self):
""" """
Always returns True Always returns True
""" """
return True return True
__nonzero__ = __bool__
def _fixup(self): def _fixup(self):
""" """
Handling of provided components. Handling of provided components.
@@ -932,7 +928,7 @@ class DIV(XmlComponent):
# get the attributes for this component # get the attributes for this component
# (they start with '_', others may have special meanings) # (they start with '_', others may have special meanings)
attr = [] attr = []
for key, value in self.attributes.iteritems(): for key, value in iteritems(self.attributes):
if key[:1] != '_': if key[:1] != '_':
continue continue
name = key[1:] name = key[1:]
@@ -942,17 +938,17 @@ class DIV(XmlComponent):
continue continue
attr.append((name, value)) attr.append((name, value))
data = self.attributes.get('data', {}) data = self.attributes.get('data', {})
for key, value in data.iteritems(): for key, value in iteritems(data):
name = 'data-' + key name = 'data-' + key
value = data[key] value = data[key]
attr.append((name, value)) attr.append((name, value))
attr.sort() attr.sort()
fa = '' fa = b''
for name, value in attr: for name, value in attr:
fa += ' %s="%s"' % (name, xmlescape(value, True)) fa += (b' %s="%s"') % (to_bytes(name), xmlescape(value, True))
# get the xml for the inner components # get the xml for the inner components
co = join([xmlescape(component) for component in co = b''.join([xmlescape(component) for component in self.components])
self.components])
return (fa, co) return (fa, co)
def xml(self): def xml(self):
@@ -965,20 +961,21 @@ class DIV(XmlComponent):
if not self.tag: if not self.tag:
return co return co
if self.tag[-1:] == '/': tagname = to_bytes(self.tag)
if tagname[-1:] == b'/':
# <tag [attributes] /> # <tag [attributes] />
return '<%s%s />' % (self.tag[:-1], fa) return b'<%s%s />' % (tagname[:-1], fa)
# else: <tag [attributes]> inner components xml </tag> # else: <tag [attributes]> inner components xml </tag>
return '<%s%s>%s</%s>' % (self.tag, fa, co, self.tag) xml_tag = b'<%s%s>%s</%s>' % (tagname, fa, co, tagname)
return xml_tag
def __str__(self): def __str__(self):
""" """
str(COMPONENT) returns COMPONENT.xml() str(COMPONENT) returns COMPONENT.xml()
""" """
return self.xml() return self.xml()
def flatten(self, render=None): def flatten(self, render=None):
""" """
Returns the text stored by the DIV object rendered by the render function Returns the text stored by the DIV object rendered by the render function
@@ -1025,10 +1022,10 @@ class DIV(XmlComponent):
>>> a = DIV(DIV(SPAN('x'),3,DIV(SPAN('y')))) >>> a = DIV(DIV(SPAN('x'),3,DIV(SPAN('y'))))
>>> for c in a.elements('span', first_only=True): c[0]='z' >>> for c in a.elements('span', first_only=True): c[0]='z'
>>> print a >>> print(a)
<div><div><span>z</span>3<div><span>y</span></div></div></div> <div><div><span>z</span>3<div><span>y</span></div></div></div>
>>> for c in a.elements('span'): c[0]='z' >>> for c in a.elements('span'): c[0]='z'
>>> print a >>> print(a)
<div><div><span>z</span>3<div><span>z</span></div></div></div> <div><div><span>z</span>3<div><span>z</span></div></div></div>
It also supports a syntax compatible with jQuery It also supports a syntax compatible with jQuery
@@ -1036,10 +1033,10 @@ class DIV(XmlComponent):
Examples: Examples:
>>> a=TAG('<div><span><a id="1-1" u:v=$>hello</a></span><p class="this is a test">world</p></div>') >>> a=TAG('<div><span><a id="1-1" u:v=$>hello</a></span><p class="this is a test">world</p></div>')
>>> for e in a.elements('div a#1-1, p.is'): print e.flatten() >>> for e in a.elements('div a#1-1, p.is'): print(e.flatten())
hello hello
world world
>>> for e in a.elements('#1-1'): print e.flatten() >>> for e in a.elements('#1-1'): print(e.flatten())
hello hello
>>> a.elements('a[u:v=$]')[0].xml() >>> a.elements('a[u:v=$]')[0].xml()
'<a id="1-1" u:v="$">hello</a>' '<a id="1-1" u:v="$">hello</a>'
@@ -1056,7 +1053,7 @@ class DIV(XmlComponent):
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc')))) >>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements('span.abc', replace=P('x', _class='xyz')) >>> b = a.elements('span.abc', replace=P('x', _class='xyz'))
>>> print a # We should .xml() here instead of print >>> print(a) # We should .xml() here instead of print
<div><div><p class="xyz">x</p><div><p class="xyz">x</p><p class="xyz">x</p></div></div></div> <div><div><p class="xyz">x</p><div><p class="xyz">x</p><p class="xyz">x</p></div></div></div>
"replace" can be a callable, which will be passed the original element and "replace" can be a callable, which will be passed the original element and
@@ -1066,7 +1063,7 @@ class DIV(XmlComponent):
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc')))) >>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements('span.abc', replace=lambda el: P(el[0], _class='xyz')) >>> b = a.elements('span.abc', replace=lambda el: P(el[0], _class='xyz'))
>>> print a >>> print(a)
<div><div><p class="xyz">x</p><div><p class="xyz">y</p><p class="xyz">z</p></div></div></div> <div><div><p class="xyz">x</p><div><p class="xyz">y</p><p class="xyz">z</p></div></div></div>
If replace=None, matching elements will be removed completely. If replace=None, matching elements will be removed completely.
@@ -1075,7 +1072,7 @@ class DIV(XmlComponent):
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc')))) >>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements('span', find='y', replace=None) >>> b = a.elements('span', find='y', replace=None)
>>> print a >>> print(a)
<div><div><span class="abc">x</span><div><span class="abc">z</span></div></div></div> <div><div><span class="abc">x</span><div><span class="abc">z</span></div></div></div>
If a "find_text" argument is specified, elements will be searched for text If a "find_text" argument is specified, elements will be searched for text
@@ -1087,7 +1084,7 @@ class DIV(XmlComponent):
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc')))) >>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements(find_text=re.compile('x|y|z'), replace='hello') >>> b = a.elements(find_text=re.compile('x|y|z'), replace='hello')
>>> print a >>> print(a)
<div><div><span class="abc">hello</span><div><span class="abc">hello</span><span class="abc">hello</span></div></div></div> <div><div><span class="abc">hello</span><div><span class="abc">hello</span><span class="abc">hello</span></div></div></div>
If other attributes are specified along with find_text, then only components If other attributes are specified along with find_text, then only components
@@ -1097,7 +1094,7 @@ class DIV(XmlComponent):
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='efg'), SPAN('z', _class='abc')))) >>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='efg'), SPAN('z', _class='abc'))))
>>> b = a.elements('span.efg', find_text=re.compile('x|y|z'), replace='hello') >>> b = a.elements('span.efg', find_text=re.compile('x|y|z'), replace='hello')
>>> print a >>> print(a)
<div><div><span class="abc">x</span><div><span class="efg">hello</span><span class="abc">z</span></div></div></div> <div><div><span class="abc">x</span><div><span class="efg">hello</span><span class="abc">z</span></div></div></div>
""" """
if len(args) == 1: if len(args) == 1:
@@ -1133,9 +1130,9 @@ class DIV(XmlComponent):
matches = [] matches = []
# check if the component has an attribute with the same # check if the component has an attribute with the same
# value as provided # value as provided
tag = getattr(self, 'tag').replace('/', '') tag = to_native(getattr(self, 'tag')).replace('/', '')
check = not (args and tag not in args) check = not (args and tag not in args)
for (key, value) in kargs.iteritems(): for (key, value) in iteritems(kargs):
if key not in ['first_only', 'replace', 'find_text']: if key not in ['first_only', 'replace', 'find_text']:
if isinstance(value, (str, int)): if isinstance(value, (str, int)):
if str(self[key]) != str(value): if str(self[key]) != str(value):
@@ -1219,7 +1216,7 @@ class DIV(XmlComponent):
tag = getattr(c, 'tag').replace("/", "") tag = getattr(c, 'tag').replace("/", "")
if args and tag not in args: if args and tag not in args:
check = False check = False
for (key, value) in kargs.iteritems(): for (key, value) in iteritems(kargs):
if c[key] != value: if c[key] != value:
check = False check = False
if check: if check:
@@ -1263,7 +1260,7 @@ class __tag_div__(DIV):
DIV.__init__(self, *a, **b) DIV.__init__(self, *a, **b)
self.tag = name self.tag = name
copy_reg.pickle(__tag_div__, TAG_pickler, TAG_unpickler) copyreg.pickle(__tag_div__, TAG_pickler, TAG_unpickler)
class __TAG__(XmlComponent): class __TAG__(XmlComponent):
@@ -1273,7 +1270,7 @@ class __TAG__(XmlComponent):
Examples: Examples:
>>> print TAG.first(TAG.second('test'), _key = 3) >>> print(TAG.first(TAG.second('test'), _key = 3))
<first key=\"3\"><second>test</second></first> <first key=\"3\"><second>test</second></first>
""" """
@@ -1284,8 +1281,7 @@ class __TAG__(XmlComponent):
def __getattr__(self, name): def __getattr__(self, name):
if name[-1:] == '_': if name[-1:] == '_':
name = name[:-1] + '/' name = name[:-1] + '/'
if isinstance(name, unicode): name=to_bytes(name)
name = name.encode('utf-8')
return lambda *a, **b: __tag_div__(name, *a, **b) return lambda *a, **b: __tag_div__(name, *a, **b)
def __call__(self, html): def __call__(self, html):
@@ -1311,12 +1307,12 @@ class HTML(DIV):
See also `DIV` See also `DIV`
""" """
tag = 'html' tag = b'html'
strict = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n' strict = b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n'
transitional = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' transitional = b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n'
frameset = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n' frameset = b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n'
html5 = '<!DOCTYPE HTML>\n' html5 = b'<!DOCTYPE HTML>\n'
def xml(self): def xml(self):
lang = self['lang'] lang = self['lang']
@@ -1335,11 +1331,12 @@ class HTML(DIV):
elif doctype == 'html5': elif doctype == 'html5':
doctype = self.html5 doctype = self.html5
elif doctype == '': elif doctype == '':
doctype = '' doctype = b''
else: else:
doctype = '%s\n' % doctype doctype = b'%s\n' % to_bytes(doctype)
(fa, co) = self._xml() (fa, co) = self._xml()
return '%s<%s%s>%s</%s>' % (doctype, self.tag, fa, co, self.tag)
return b'%s<%s%s>%s</%s>' % (doctype, self.tag, fa, co, self.tag)
class XHTML(DIV): class XHTML(DIV):
@@ -1363,11 +1360,11 @@ class XHTML(DIV):
See also `DIV` See also `DIV`
""" """
tag = 'html' tag = b'html'
strict = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' strict = b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n'
transitional = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' transitional = b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'
frameset = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">\n' frameset = b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">\n'
xmlns = 'http://www.w3.org/1999/xhtml' xmlns = 'http://www.w3.org/1999/xhtml'
def xml(self): def xml(self):
@@ -1390,11 +1387,11 @@ class XHTML(DIV):
elif doctype == 'frameset': elif doctype == 'frameset':
doctype = self.frameset doctype = self.frameset
else: else:
doctype = '%s\n' % doctype doctype = b'%s\n' % to_bytes(doctype)
else: else:
doctype = self.transitional doctype = self.transitional
(fa, co) = self._xml() (fa, co) = self._xml()
return '%s<%s%s>%s</%s>' % (doctype, self.tag, fa, co, self.tag) return b'%s<%s%s>%s</%s>' % (doctype, self.tag, fa, co, self.tag)
class HEAD(DIV): class HEAD(DIV):
@@ -1423,6 +1420,7 @@ class SCRIPT(DIV):
def xml(self): def xml(self):
(fa, co) = self._xml() (fa, co) = self._xml()
fa = to_native(fa)
# no escaping of subcomponents # no escaping of subcomponents
co = '\n'.join([str(component) for component in co = '\n'.join([str(component) for component in
self.components]) self.components])
@@ -1442,6 +1440,7 @@ class STYLE(DIV):
def xml(self): def xml(self):
(fa, co) = self._xml() (fa, co) = self._xml()
fa = to_native(fa)
# no escaping of subcomponents # no escaping of subcomponents
co = '\n'.join([str(component) for component in co = '\n'.join([str(component) for component in
self.components]) self.components])
@@ -1511,7 +1510,7 @@ class P(DIV):
def xml(self): def xml(self):
text = DIV.xml(self) text = DIV.xml(self)
if self['cr2br']: if self['cr2br']:
text = text.replace('\n', '<br />') text = text.replace(b'\n', b'<br />')
return text return text
@@ -1633,7 +1632,7 @@ class CODE(DIV):
Examples: Examples:
{{=CODE(\"print 'hello world'\", language='python', link=None, {{=CODE(\"print('hello world')\", language='python', link=None,
counter=1, styles={}, highlight_line=None)}} counter=1, styles={}, highlight_line=None)}}
@@ -1862,7 +1861,7 @@ class INPUT(DIV):
(value, errors) = validator(value) (value, errors) = validator(value)
except: except:
import traceback import traceback
print traceback.format_exc() print(traceback.format_exc())
msg = "Validation error, field:%s %s" % (name,validator) msg = "Validation error, field:%s %s" % (name,validator)
raise Exception(msg) raise Exception(msg)
if errors is not None: if errors is not None:
@@ -2166,7 +2165,7 @@ class FORM(DIV):
c = [] c = []
attr = self.attributes.get('hidden', {}) attr = self.attributes.get('hidden', {})
if 'hidden' in self.attributes: if 'hidden' in self.attributes:
c = [INPUT(_type='hidden', _name=key, _value=value) for (key, value) in attr.iteritems()] c = [INPUT(_type='hidden', _name=key, _value=value) for (key, value) in iteritems(attr)]
if hasattr(self, 'formkey') and self.formkey: if hasattr(self, 'formkey') and self.formkey:
c.append(INPUT(_type='hidden', _name='_formkey', _value=self.formkey)) c.append(INPUT(_type='hidden', _name='_formkey', _value=self.formkey))
if hasattr(self, 'formname') and self.formname: if hasattr(self, 'formname') and self.formname:
@@ -2211,7 +2210,8 @@ class FORM(DIV):
next = where to redirect in case of success next = where to redirect in case of success
any other kwargs will be passed for form.accepts(...) any other kwargs will be passed for form.accepts(...)
""" """
from gluon import current, redirect from gluon.globals import current
from gluon.http import redirect
kwargs['request_vars'] = kwargs.get( kwargs['request_vars'] = kwargs.get(
'request_vars', current.request.post_vars) 'request_vars', current.request.post_vars)
kwargs['session'] = kwargs.get('session', current.session) kwargs['session'] = kwargs.get('session', current.session)
@@ -2243,9 +2243,9 @@ class FORM(DIV):
onsuccess(self) onsuccess(self)
if next: if next:
if self.vars: if self.vars:
for key, value in self.vars.iteritems(): for key, value in iteritems(self.vars):
next = next.replace('[%s]' % key, next = next.replace('[%s]' % key,
urllib.quote(str(value))) urllib_quote(str(value)))
if not next.startswith('/'): if not next.startswith('/'):
next = URL(next) next = URL(next)
redirect(next) redirect(next)
@@ -2317,11 +2317,11 @@ class FORM(DIV):
inputs = [INPUT(_type='button', inputs = [INPUT(_type='button',
_value=name, _value=name,
_onclick=FORM.REDIRECT_JS % link) _onclick=FORM.REDIRECT_JS % link)
for name, link in buttons.iteritems()] for name, link in iteritems(buttons)]
inputs += [INPUT(_type='hidden', inputs += [INPUT(_type='hidden',
_name=name, _name=name,
_value=value) _value=value)
for name, value in hidden.iteritems()] for name, value in iteritems(hidden)]
form = FORM(INPUT(_type='submit', _value=text), *inputs) form = FORM(INPUT(_type='submit', _value=text), *inputs)
form.process() form.process()
return form return form
@@ -2441,7 +2441,7 @@ class BEAUTIFY(DIV):
try: try:
keys = (sorter and sorter(c)) or c keys = (sorter and sorter(c)) or c
for key in keys: for key in keys:
if isinstance(key, (str, unicode)) and keyfilter: if isinstance(key, (str, unicodeT)) and keyfilter:
filtered_key = keyfilter(key) filtered_key = keyfilter(key)
else: else:
filtered_key = str(key) filtered_key = str(key)
@@ -2461,7 +2461,7 @@ class BEAUTIFY(DIV):
pass pass
if isinstance(c, str): if isinstance(c, str):
components.append(str(c)) components.append(str(c))
elif isinstance(c, unicode): elif isinstance(c, unicodeT):
components.append(c.encode('utf8')) components.append(c.encode('utf8'))
elif isinstance(c, (list, tuple)): elif isinstance(c, (list, tuple)):
items = [TR(TD(BEAUTIFY(item, **attributes))) items = [TR(TD(BEAUTIFY(item, **attributes)))
@@ -2608,34 +2608,34 @@ def test():
Example: Example:
>>> from validators import * >>> from validators import *
>>> print DIV(A('click me', _href=URL(a='a', c='b', f='c')), BR(), HR(), DIV(SPAN("World"), _class='unknown')).xml() >>> print(DIV(A('click me', _href=URL(a='a', c='b', f='c')), BR(), HR(), DIV(SPAN("World"), _class='unknown')).xml())
<div><a href="/a/b/c">click me</a><br /><hr /><div class=\"unknown\"><span>World</span></div></div> <div><a href="/a/b/c">click me</a><br /><hr /><div class=\"unknown\"><span>World</span></div></div>
>>> print DIV(UL("doc","cat","mouse")).xml() >>> print(DIV(UL("doc","cat","mouse")).xml())
<div><ul><li>doc</li><li>cat</li><li>mouse</li></ul></div> <div><ul><li>doc</li><li>cat</li><li>mouse</li></ul></div>
>>> print DIV(UL("doc", LI("cat", _class='feline'), 18)).xml() >>> print(DIV(UL("doc", LI("cat", _class='feline'), 18)).xml())
<div><ul><li>doc</li><li class=\"feline\">cat</li><li>18</li></ul></div> <div><ul><li>doc</li><li class=\"feline\">cat</li><li>18</li></ul></div>
>>> print TABLE(['a', 'b', 'c'], TR('d', 'e', 'f'), TR(TD(1), TD(2), TD(3))).xml() >>> print(TABLE(['a', 'b', 'c'], TR('d', 'e', 'f'), TR(TD(1), TD(2), TD(3))).xml())
<table><tr><td>a</td><td>b</td><td>c</td></tr><tr><td>d</td><td>e</td><td>f</td></tr><tr><td>1</td><td>2</td><td>3</td></tr></table> <table><tr><td>a</td><td>b</td><td>c</td></tr><tr><td>d</td><td>e</td><td>f</td></tr><tr><td>1</td><td>2</td><td>3</td></tr></table>
>>> form=FORM(INPUT(_type='text', _name='myvar', requires=IS_EXPR('int(value)<10'))) >>> form=FORM(INPUT(_type='text', _name='myvar', requires=IS_EXPR('int(value)<10')))
>>> print form.xml() >>> print(form.xml())
<form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><input name=\"myvar\" type=\"text\" /></form> <form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><input name=\"myvar\" type=\"text\" /></form>
>>> print form.accepts({'myvar':'34'}, formname=None) >>> print(form.accepts({'myvar':'34'}, formname=None))
False False
>>> print form.xml() >>> print(form.xml())
<form action="#" enctype="multipart/form-data" method="post"><input class="invalidinput" name="myvar" type="text" value="34" /><div class="error_wrapper"><div class="error" id="myvar__error">Invalid expression</div></div></form> <form action="#" enctype="multipart/form-data" method="post"><input class="invalidinput" name="myvar" type="text" value="34" /><div class="error_wrapper"><div class="error" id="myvar__error">Invalid expression</div></div></form>
>>> print form.accepts({'myvar':'4'}, formname=None, keepvalues=True) >>> print(form.accepts({'myvar':'4'}, formname=None, keepvalues=True))
True True
>>> print form.xml() >>> print(form.xml())
<form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><input name=\"myvar\" type=\"text\" value=\"4\" /></form> <form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><input name=\"myvar\" type=\"text\" value=\"4\" /></form>
>>> form=FORM(SELECT('cat', 'dog', _name='myvar')) >>> form=FORM(SELECT('cat', 'dog', _name='myvar'))
>>> print form.accepts({'myvar':'dog'}, formname=None, keepvalues=True) >>> print(form.accepts({'myvar':'dog'}, formname=None, keepvalues=True))
True True
>>> print form.xml() >>> print(form.xml())
<form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><select name=\"myvar\"><option value=\"cat\">cat</option><option selected=\"selected\" value=\"dog\">dog</option></select></form> <form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><select name=\"myvar\"><option value=\"cat\">cat</option><option selected=\"selected\" value=\"dog\">dog</option></select></form>
>>> form=FORM(INPUT(_type='text', _name='myvar', requires=IS_MATCH('^\w+$', 'only alphanumeric!'))) >>> form=FORM(INPUT(_type='text', _name='myvar', requires=IS_MATCH('^\w+$', 'only alphanumeric!')))
>>> print form.accepts({'myvar':'as df'}, formname=None) >>> print(form.accepts({'myvar':'as df'}, formname=None))
False False
>>> print form.xml() >>> print(form.xml())
<form action="#" enctype="multipart/form-data" method="post"><input class="invalidinput" name="myvar" type="text" value="as df" /><div class="error_wrapper"><div class="error" id="myvar__error">only alphanumeric!</div></div></form> <form action="#" enctype="multipart/form-data" method="post"><input class="invalidinput" name="myvar" type="text" value="as df" /><div class="error_wrapper"><div class="error" id="myvar__error">only alphanumeric!</div></div></form>
>>> session={} >>> session={}
>>> form=FORM(INPUT(value="Hello World", _name="var", requires=IS_MATCH('^\w+$'))) >>> form=FORM(INPUT(value="Hello World", _name="var", requires=IS_MATCH('^\w+$')))
@@ -2645,8 +2645,8 @@ def test():
True True
>>> isinstance(form.as_json(), basestring) and len(form.as_json(sanitize=False)) > 0 >>> isinstance(form.as_json(), basestring) and len(form.as_json(sanitize=False)) > 0
True True
>>> if form.accepts({}, session,formname=None): print 'passed' >>> if form.accepts({}, session,formname=None): print('passed')
>>> if form.accepts({'var':'test ', '_formkey': session['_formkey[None]']}, session, formname=None): print 'passed' >>> if form.accepts({'var':'test ', '_formkey': session['_formkey[None]']}, session, formname=None): print('passed')
""" """
pass pass
@@ -2684,13 +2684,13 @@ class web2pyHTMLParser(HTMLParser):
tag['_' + key] = value tag['_' + key] = value
tag.parent = self.parent tag.parent = self.parent
self.parent.append(tag) self.parent.append(tag)
if not tag.tag.endswith('/'): if not tag.tag.endswith(b'/'):
self.parent = tag self.parent = tag
else: else:
self.last = tag.tag[:-1] self.last = tag.tag[:-1]
def handle_data(self, data): def handle_data(self, data):
if not isinstance(data, unicode): if not isinstance(data, unicodeT):
try: try:
data = data.decode('utf8') data = data.decode('utf8')
except: except:
@@ -2707,6 +2707,7 @@ class web2pyHTMLParser(HTMLParser):
self.parent.append(entitydefs[name]) self.parent.append(entitydefs[name])
def handle_endtag(self, tagname): def handle_endtag(self, tagname):
tagname = to_bytes(tagname)
# this deals with unbalanced tags # this deals with unbalanced tags
if tagname == self.last: if tagname == self.last:
return return
@@ -2798,7 +2799,7 @@ class MARKMIN(XmlComponent):
class_prefix='', class_prefix='',
id_prefix='markmin_', id_prefix='markmin_',
**kwargs): **kwargs):
self.text = text self.text = to_bytes(text)
self.extra = extra or {} self.extra = extra or {}
self.allowed = allowed or {} self.allowed = allowed or {}
self.sep = sep self.sep = sep
@@ -2821,7 +2822,7 @@ class MARKMIN(XmlComponent):
URL=self.url, environment=self.environment, URL=self.url, environment=self.environment,
autolinks=self.autolinks, protolinks=self.protolinks, autolinks=self.autolinks, protolinks=self.protolinks,
class_prefix=self.class_prefix, id_prefix=self.id_prefix) class_prefix=self.class_prefix, id_prefix=self.id_prefix)
return html if not self.kwargs else DIV(XML(html), **self.kwargs).xml() return to_bytes(html) if not self.kwargs else to_bytes(DIV(XML(html), **self.kwargs).xml())
def __str__(self): def __str__(self):
return self.xml() return self.xml()
+4 -3
View File
@@ -11,6 +11,7 @@ HTTP statuses helpers
""" """
import re import re
from gluon._compat import iteritems
__all__ = ['HTTP', 'redirect'] __all__ = ['HTTP', 'redirect']
@@ -112,7 +113,7 @@ class HTTP(Exception):
if isinstance(body, str): if isinstance(body, str):
headers['Content-Length'] = len(body) headers['Content-Length'] = len(body)
rheaders = [] rheaders = []
for k, v in headers.iteritems(): for k, v in iteritems(headers):
if isinstance(v, list): if isinstance(v, list):
rheaders += [(k, str(item)) for item in v] rheaders += [(k, str(item)) for item in v]
elif not v is None: elif not v is None:
@@ -162,7 +163,7 @@ def redirect(location='', how=303, client_side=False, headers=None):
""" """
headers = headers or {} headers = headers or {}
if location: if location:
from gluon import current from gluon.globals import current
loc = location.replace('\r', '%0D').replace('\n', '%0A') loc = location.replace('\r', '%0D').replace('\n', '%0A')
if client_side and current.request.ajax: if client_side and current.request.ajax:
headers['web2py-redirect-location'] = loc headers['web2py-redirect-location'] = loc
@@ -173,7 +174,7 @@ def redirect(location='', how=303, client_side=False, headers=None):
'You are being redirected <a href="%s">here</a>' % loc, 'You are being redirected <a href="%s">here</a>' % loc,
**headers) **headers)
else: else:
from gluon import current from gluon.globals import current
if client_side and current.request.ajax: if client_side and current.request.ajax:
headers['web2py-component-command'] = 'window.location.reload(true)' headers['web2py-component-command'] = 'window.location.reload(true)'
raise HTTP(200, **headers) raise HTTP(200, **headers)
+23 -21
View File
@@ -18,20 +18,17 @@ import pkgutil
import logging import logging
from cgi import escape from cgi import escape
from threading import RLock from threading import RLock
from gluon._compat import copyreg, PY2, maketrans, iterkeys, unicodeT, to_unicode, to_bytes, iteritems
try:
import copyreg as copy_reg # python 3
except ImportError:
import copy_reg # python 2
from gluon.portalocker import read_locked, LockedFile from gluon.portalocker import read_locked, LockedFile
from utf8 import Utf8 from gluon.utf8 import Utf8
from gluon.fileutils import listdir from gluon.fileutils import listdir
from gluon.cfs import getcfs from gluon.cfs import getcfs
from gluon.html import XML, xmlescape from gluon.html import XML, xmlescape
from gluon.contrib.markmin.markmin2html import render, markmin_escape if PY2:
from string import maketrans # FIXME PY3
from gluon.contrib.markmin.markmin2html import render, markmin_escape
__all__ = ['translator', 'findT', 'update_all_languages'] __all__ = ['translator', 'findT', 'update_all_languages']
@@ -53,7 +50,10 @@ DEFAULT_GET_PLURAL_ID = lambda n: 0
# word is unchangeable # word is unchangeable
DEFAULT_CONSTRUCT_PLURAL_FORM = lambda word, plural_id: word 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 # pattern to find T(blah blah blah) expressions
PY_STRING_LITERAL_RE = r'(?<=[^\w]T\()(?P<name>'\ PY_STRING_LITERAL_RE = r'(?<=[^\w]T\()(?P<name>'\
@@ -164,7 +164,7 @@ def clear_cache(filename):
def read_dict_aux(filename): def read_dict_aux(filename):
lang_text = read_locked(filename).replace('\r\n', '\n') lang_text = read_locked(filename).replace(b'\r\n', b'\n')
clear_cache(filename) clear_cache(filename)
try: try:
return safe_eval(lang_text) or {} return safe_eval(lang_text) or {}
@@ -287,7 +287,7 @@ def read_possible_languages(langpath):
def read_plural_dict_aux(filename): def read_plural_dict_aux(filename):
lang_text = read_locked(filename).replace('\r\n', '\n') lang_text = read_locked(filename).replace(b'\r\n', b'\n')
try: try:
return eval(lang_text) or {} return eval(lang_text) or {}
except Exception: except Exception:
@@ -334,7 +334,7 @@ def write_dict(filename, contents):
try: try:
fp = LockedFile(filename, 'w') fp = LockedFile(filename, 'w')
fp.write('# -*- coding: utf-8 -*-\n{\n') fp.write('# -*- coding: utf-8 -*-\n{\n')
for key in sorted(contents, sort_function): for key in sorted(contents, key=lambda x: to_unicode(x, 'utf-8').lower()):
fp.write('%s: %s,\n' % (repr(Utf8(key)), fp.write('%s: %s,\n' % (repr(Utf8(key)),
repr(Utf8(contents[key])))) repr(Utf8(contents[key]))))
fp.write('}\n') fp.write('}\n')
@@ -446,7 +446,7 @@ class lazyT(object):
def pickle_lazyT(c): def pickle_lazyT(c):
return str, (c.xml(),) return str, (c.xml(),)
copy_reg.pickle(lazyT, pickle_lazyT) copyreg.pickle(lazyT, pickle_lazyT)
class translator(object): class translator(object):
@@ -541,7 +541,7 @@ class translator(object):
def get_possible_languages(self): def get_possible_languages(self):
""" Gets list of all possible languages for current application """ """ Gets list of all possible languages for current application """
return list(set(self.current_languages + return list(set(self.current_languages +
[lang for lang in read_possible_languages(self.langpath).iterkeys() [lang for lang in read_possible_languages(self.langpath)
if lang != 'default'])) if lang != 'default']))
def set_current_languages(self, *languages): def set_current_languages(self, *languages):
@@ -658,7 +658,7 @@ class translator(object):
languages = [] languages = []
self.requested_languages = languages = tuple(languages) self.requested_languages = languages = tuple(languages)
if languages: if languages:
all_languages = set(lang for lang in pl_info.iterkeys() all_languages = set(lang for lang in pl_info
if lang != 'default') \ if lang != 'default') \
| set(self.current_languages) | set(self.current_languages)
for lang in languages: for lang in languages:
@@ -756,7 +756,7 @@ class translator(object):
if isinstance(symbols, dict): if isinstance(symbols, dict):
symbols.update( symbols.update(
(key, xmlescape(value).translate(ttab_in)) (key, xmlescape(value).translate(ttab_in))
for key, value in symbols.iteritems() for key, value in iteritems(symbols)
if not isinstance(value, NUMBERS)) if not isinstance(value, NUMBERS))
else: else:
if not isinstance(symbols, tuple): if not isinstance(symbols, tuple):
@@ -800,16 +800,18 @@ class translator(object):
the ## notation is ignored in multiline strings and strings that the ## notation is ignored in multiline strings and strings that
start with ##. This is needed to allow markmin syntax to be translated start with ##. This is needed to allow markmin syntax to be translated
""" """
if isinstance(message, unicode): if isinstance(message, unicodeT):
message = message.encode('utf8') message = message.encode('utf8')
if isinstance(prefix, unicode): if isinstance(prefix, unicodeT):
prefix = prefix.encode('utf8') prefix = prefix.encode('utf8')
key = prefix + message key = prefix + message
mt = self.t.get(key, None) mt = self.t.get(key, None)
if mt is not None: if mt is not None:
return mt return mt
# we did not find a translation # we did not find a translation
if message.find('##') > 0 and not '\n' in message: if message.find(to_bytes('##')) > 0:
pass
if message.find(to_bytes('##')) > 0 and not '\n' in message:
# remove comments # remove comments
message = message.rsplit('##', 1)[0] message = message.rsplit('##', 1)[0]
# guess translation same as original # guess translation same as original
@@ -819,7 +821,7 @@ class translator(object):
self.language_file != self.default_language_file: self.language_file != self.default_language_file:
write_dict(self.language_file, self.t) write_dict(self.language_file, self.t)
return regex_backslash.sub( return regex_backslash.sub(
lambda m: m.group(1).translate(ttab_in), mt) lambda m: m.group(1).translate(ttab_in), str(mt))
def params_substitution(self, message, symbols): def params_substitution(self, message, symbols):
""" """
@@ -937,7 +939,7 @@ class translator(object):
if isinstance(symbols, dict): if isinstance(symbols, dict):
symbols.update( symbols.update(
(key, str(value).translate(ttab_in)) (key, str(value).translate(ttab_in))
for key, value in symbols.iteritems() for key, value in iteritems(symbols)
if not isinstance(value, NUMBERS)) if not isinstance(value, NUMBERS))
else: else:
if not isinstance(symbols, tuple): if not isinstance(symbols, tuple):
+11 -11
View File
@@ -9,10 +9,11 @@
The gluon wsgi application The gluon wsgi application
--------------------------- ---------------------------
""" """
from __future__ import print_function
if False: import import_all # DO NOT REMOVE PART OF FREEZE PROCESS if False: import import_all # DO NOT REMOVE PART OF FREEZE PROCESS
import gc import gc
import Cookie
import os import os
import re import re
import copy import copy
@@ -22,11 +23,10 @@ import datetime
import signal import signal
import socket import socket
import random import random
import urllib2
import string import string
from gluon._compat import Cookie, urllib2
from thread import allocate_lock #from thread import allocate_lock
from gluon.fileutils import abspath, write_file from gluon.fileutils import abspath, write_file
from gluon.settings import global_settings from gluon.settings import global_settings
@@ -440,7 +440,7 @@ def wsgibase(environ, responder):
serve_controller(request, response, session) serve_controller(request, response, session)
except HTTP, http_response: except HTTP as http_response:
if static_file: if static_file:
return http_response.to(responder, env=env) return http_response.to(responder, env=env)
@@ -495,7 +495,7 @@ def wsgibase(environ, responder):
ticket = None ticket = None
except RestrictedError, e: except RestrictedError as e:
if request.body: if request.body:
request.body.close() request.body.close()
@@ -570,9 +570,9 @@ def save_password(password, port):
chars = string.letters + string.digits chars = string.letters + string.digits
password = ''.join([random.choice(chars) for _ in range(8)]) password = ''.join([random.choice(chars) for _ in range(8)])
cpassword = CRYPT()(password)[0] cpassword = CRYPT()(password)[0]
print '******************* IMPORTANT!!! ************************' print('******************* IMPORTANT!!! ************************')
print 'your admin password is "%s"' % password print('your admin password is "%s"' % password)
print '*********************************************************' print('*********************************************************')
elif password == '<recycle>': elif password == '<recycle>':
# reuse the current password if any # reuse the current password if any
if exists(password_file): if exists(password_file):
@@ -709,9 +709,9 @@ class HttpServer(object):
# if interfaces is specified, it must be tested for rocket parameter correctness # if interfaces is specified, it must be tested for rocket parameter correctness
# not necessarily completely tested (e.g. content of tuples or ip-format) # not necessarily completely tested (e.g. content of tuples or ip-format)
import types import types
if isinstance(interfaces, types.ListType): if isinstance(interfaces, list):
for i in interfaces: 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/" raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/"
else: else:
raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/" raise "Wrong format for rocket interfaces parameter - see http://packages.python.org/rocket/"
+3 -2
View File
@@ -21,6 +21,7 @@ import datetime
import platform import platform
import portalocker import portalocker
import fileutils import fileutils
from functools import reduce
try: try:
import cPickle as pickle import cPickle as pickle
except: except:
@@ -318,7 +319,7 @@ def crondance(applications_parent, ctype='soft', startup=False, apps=None):
lines = [x.strip() for x in cronlines if x.strip( lines = [x.strip() for x in cronlines if x.strip(
) and not x.strip().startswith('#')] ) and not x.strip().startswith('#')]
tasks = [parsecronline(cline) for cline in lines] tasks = [parsecronline(cline) for cline in lines]
except Exception, e: except Exception as e:
logger.error('WEB2PY CRON: crontab read error %s' % e) logger.error('WEB2PY CRON: crontab read error %s' % e)
continue continue
@@ -375,7 +376,7 @@ def crondance(applications_parent, ctype='soft', startup=False, apps=None):
try: try:
cronlauncher(commands, shell=shell).start() cronlauncher(commands, shell=shell).start()
except Exception, e: except Exception as e:
logger.warning( logger.warning(
'WEB2PY CRON: Execution error for %s: %s' 'WEB2PY CRON: Execution error for %s: %s'
% (task.get('cmd'), e)) % (task.get('cmd'), e))
+2 -2
View File
@@ -148,14 +148,14 @@ class LockedFile(object):
def read_locked(filename): def read_locked(filename):
fp = LockedFile(filename, 'r') fp = LockedFile(filename, 'rb')
data = fp.read() data = fp.read()
fp.close() fp.close()
return data return data
def write_locked(filename, data): def write_locked(filename, data):
fp = LockedFile(filename, 'w') fp = LockedFile(filename, 'wb')
data = fp.write(data) data = fp.write(data)
fp.close() fp.close()
+2 -2
View File
@@ -10,7 +10,7 @@ Generates names for cache and session files
-------------------------------------------- --------------------------------------------
""" """
import os import os
from gluon._compat import builtin
def generate(filename, depth=2, base=512): def generate(filename, depth=2, base=512):
if os.path.sep in filename: if os.path.sep in filename:
@@ -62,4 +62,4 @@ def open(filename, mode="r", path=None):
fullfilename = os.path.join(path, generate(filename)) fullfilename = os.path.join(path, generate(filename))
if mode.startswith('w') and not os.path.exists(os.path.dirname(fullfilename)): if mode.startswith('w') and not os.path.exists(os.path.dirname(fullfilename)):
os.makedirs(os.path.dirname(fullfilename)) os.makedirs(os.path.dirname(fullfilename))
return file(fullfilename, mode) return builtin.open(fullfilename, mode)
+4 -7
View File
@@ -10,10 +10,7 @@ Restricted environment to execute application's code
""" """
import sys import sys
try: from gluon._compat import pickle, ClassType
import cPickle as pickle
except:
import pickle
import traceback import traceback
import types import types
import os import os
@@ -224,13 +221,13 @@ def restricted(code, environment=None, layer='Unknown'):
ccode = code ccode = code
else: else:
ccode = compile2(code, layer) ccode = compile2(code, layer)
exec ccode in environment exec(ccode, environment)
except HTTP: except HTTP:
raise raise
except RestrictedError: except RestrictedError:
# do not encapsulate (obfuscate) the original RestrictedError # do not encapsulate (obfuscate) the original RestrictedError
raise raise
except Exception, error: except Exception as error:
# extract the exception type and value (used as output message) # extract the exception type and value (used as output message)
etype, evalue, tb = sys.exc_info() etype, evalue, tb = sys.exc_info()
# XXX Show exception in Wing IDE if running in debugger # XXX Show exception in Wing IDE if running in debugger
@@ -252,7 +249,7 @@ def snapshot(info=None, context=5, code=None, environment=None):
# if no exception info given, get current: # if no exception info given, get current:
etype, evalue, etb = info or sys.exc_info() etype, evalue, etb = info or sys.exc_info()
if isinstance(etype, types.ClassType): if isinstance(etype, ClassType):
etype = etype.__name__ etype = etype.__name__
# create a snapshot dict with some basic information # create a snapshot dict with some basic information
+11 -9
View File
@@ -15,6 +15,7 @@ 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. Refer to router.example.py and routes.example.py for additional documentation.
""" """
from __future__ import print_function
import os import os
import re import re
@@ -26,6 +27,7 @@ from gluon.storage import Storage, List
from gluon.http import HTTP from gluon.http import HTTP
from gluon.fileutils import abspath, read_file from gluon.fileutils import abspath, read_file
from gluon.settings import global_settings from gluon.settings import global_settings
from gluon._compat import urllib_unquote, urllib_quote, iteritems, xrange
isdir = os.path.isdir isdir = os.path.isdir
isfile = os.path.isfile isfile = os.path.isfile
@@ -117,7 +119,7 @@ def log_rewrite(string):
elif params.logging == 'off' or not params.logging: elif params.logging == 'off' or not params.logging:
pass pass
elif params.logging == 'print': elif params.logging == 'print':
print string print(string)
elif params.logging == 'info': elif params.logging == 'info':
logger.info(string) logger.info(string)
elif params.logging == 'warning': elif params.logging == 'warning':
@@ -315,8 +317,8 @@ def load(routes='routes.py', app=None, data=None, rdict=None):
symbols = dict(app=app) symbols = dict(app=app)
try: try:
exec (data + '\n') in symbols exec(data + '\n', symbols)
except SyntaxError, e: except SyntaxError as e:
logger.error( logger.error(
'%s has a syntax error and will not be loaded\n' % path '%s has a syntax error and will not be loaded\n' % path
+ traceback.format_exc()) + traceback.format_exc())
@@ -512,7 +514,7 @@ def load_routers(all_apps):
# #
domains = dict() domains = dict()
if routers.BASE.domains: if routers.BASE.domains:
for (d, a) in routers.BASE.domains.iteritems(): for (d, a) in iteritems(routers.BASE.domains):
(domain, app) = (d.strip(':'), a.strip('/')) (domain, app) = (d.strip(':'), a.strip('/'))
if ':' in domain: if ':' in domain:
(domain, port) = domain.split(':') (domain, port) = domain.split(':')
@@ -618,13 +620,13 @@ def regex_url_in(request, environ):
if routes.routes_in: if routes.routes_in:
environ = regex_filter_in(environ) environ = regex_filter_in(environ)
request.env.update( request.env.update(
(k.lower().replace('.', '_'), v) for k, v in environ.iteritems()) (k.lower().replace('.', '_'), v) for k, v in iteritems(environ))
# ################################################## # ##################################################
# serve if a static file # serve if a static file
# ################################################## # ##################################################
path = urllib.unquote(request.env.path_info) or '/' path = urllib_unquote(request.env.path_info) or '/'
path = path.replace('\\', '/') path = path.replace('\\', '/')
if path.endswith('/') and len(path) > 1: if path.endswith('/') and len(path) > 1:
path = path[:-1] path = path[:-1]
@@ -714,7 +716,7 @@ def filter_url(url, method='get', remote='0.0.0.0',
if isinstance(domain, str): if isinstance(domain, str):
domain = (domain, None) domain = (domain, None)
(path_info, query_string) = (uri[:k], uri[k + 1:]) (path_info, query_string) = (uri[:k], uri[k + 1:])
path_info = urllib.unquote(path_info) # simulate server path_info = urllib_unquote(path_info) # simulate server
e = { e = {
'REMOTE_ADDR': remote, 'REMOTE_ADDR': remote,
'REQUEST_METHOD': method, 'REQUEST_METHOD': method,
@@ -1072,7 +1074,7 @@ class MapUrlIn(object):
def sluggify(self): def sluggify(self):
self.request.env.update( self.request.env.update(
(k.lower().replace('.', '_'), v) for k, v in self.env.iteritems()) (k.lower().replace('.', '_'), v) for k, v in iteritems(self.env))
def update_request(self): def update_request(self):
""" """
@@ -1099,7 +1101,7 @@ class MapUrlIn(object):
uri = '/%s%s%s%s' % ( uri = '/%s%s%s%s' % (
app, app,
uri, uri,
urllib.quote('/' + '/'.join( urllib_quote('/' + '/'.join(
str(x) for x in self.args)) if self.args else '', str(x) for x in self.args)) if self.args else '',
('?' + self.query) if self.query else '') ('?' + self.query) if self.query else '')
self.env['REQUEST_URI'] = uri self.env['REQUEST_URI'] = uri
+6 -4
View File
@@ -5,11 +5,13 @@
# Modified by Massimo Di Pierro # Modified by Massimo Di Pierro
# Import System Modules # Import System Modules
from __future__ import print_function
import sys import sys
import errno import errno
import socket import socket
import logging import logging
import platform import platform
from gluon._compat import iteritems
# Define Constants # Define Constants
VERSION = '1.2.6' VERSION = '1.2.6'
@@ -1429,7 +1431,7 @@ class Worker(Thread):
raise BadRequest raise BadRequest
req = match.groupdict() req = match.groupdict()
for k, v in req.iteritems(): for k, v in iteritems(req):
if not v: if not v:
req[k] = "" req[k] = ""
if k == 'path': if k == 'path':
@@ -1653,7 +1655,7 @@ class WSGIWorker(Worker):
environ = self.base_environ.copy() environ = self.base_environ.copy()
# Grab the headers # Grab the headers
for k, v in self.read_headers(sock_file).iteritems(): for k, v in iteritems(self.read_headers(sock_file)):
environ[str('HTTP_' + k)] = v environ[str('HTTP_' + k)] = v
# Add CGI Variables # Add CGI Variables
@@ -1681,7 +1683,7 @@ class WSGIWorker(Worker):
environ['SSL_CLIENT_RAW_CERT'] = \ environ['SSL_CLIENT_RAW_CERT'] = \
peercert and ssl.DER_cert_to_PEM_cert(peercert) peercert and ssl.DER_cert_to_PEM_cert(peercert)
except Exception: except Exception:
print sys.exc_info()[1] print(sys.exc_info()[1])
else: else:
environ['wsgi.url_scheme'] = 'http' environ['wsgi.url_scheme'] = 'http'
@@ -1907,7 +1909,7 @@ def demo():
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
global static_folder global static_folder
static_folder = options.static static_folder = options.static
print 'Rocket running on %s:%s' % (options.ip, options.port) print('Rocket running on %s:%s' % (options.ip, options.port))
r=Rocket((options.ip,int(options.port)),'wsgi', {'wsgi_app':demo_app}) r=Rocket((options.ip,int(options.port)),'wsgi', {'wsgi_app':demo_app})
r.start() r.start()
+2 -1
View File
@@ -1,3 +1,4 @@
from __future__ import print_function
# The following code is not part of Rocket but was added to # The following code is not part of Rocket but was added to
# web2py for testing purposes. # web2py for testing purposes.
@@ -42,7 +43,7 @@ def demo():
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
global static_folder global static_folder
static_folder = options.static static_folder = options.static
print 'Rocket running on %s:%s' % (options.ip, options.port) print('Rocket running on %s:%s' % (options.ip, options.port))
r = Rocket((options.ip, int(options.port)), 'wsgi', {'wsgi_app': demo_app}) r = Rocket((options.ip, int(options.port)), 'wsgi', {'wsgi_app': demo_app})
r.start() r.start()
+1 -3
View File
@@ -10,11 +10,9 @@ Cross-site scripting (XSS) defense
----------------------------------- -----------------------------------
""" """
from HTMLParser import HTMLParser from ._compat import HTMLParser, urlparse, entitydefs, basestring
from cgi import escape from cgi import escape
from urlparse import urlparse
from formatter import AbstractFormatter from formatter import AbstractFormatter
from htmlentitydefs import entitydefs
from xml.sax.saxutils import quoteattr from xml.sax.saxutils import quoteattr
__all__ = ['sanitize'] __all__ = ['sanitize']
+15 -13
View File
@@ -8,7 +8,8 @@
Background processes made simple Background processes made simple
--------------------------------- ---------------------------------
""" """
from __future__ import print_function
from gluon._compat import Queue, long, iteritems
import os import os
import time import time
@@ -23,12 +24,13 @@ import logging
import optparse import optparse
import tempfile import tempfile
import types import types
import Queue
from json import loads, dumps from json import loads, dumps
from gluon import DAL, Field, IS_NOT_EMPTY, IS_IN_SET, IS_NOT_IN_DB from gluon import DAL, Field, IS_NOT_EMPTY, IS_IN_SET, IS_NOT_IN_DB
from gluon import IS_INT_IN_RANGE, IS_DATETIME, IS_IN_DB from gluon import IS_INT_IN_RANGE, IS_DATETIME, IS_IN_DB
from gluon.utils import web2py_uuid from gluon.utils import web2py_uuid
from gluon.storage import Storage from gluon.storage import Storage
from functools import reduce
USAGE = """ USAGE = """
## Example ## Example
@@ -39,7 +41,7 @@ Create File: app/models/scheduler.py ======
from gluon.scheduler import Scheduler from gluon.scheduler import Scheduler
def demo1(*args,**vars): def demo1(*args,**vars):
print 'you passed args=%s and vars=%s' % (args, vars) print('you passed args=%s and vars=%s' % (args, vars))
return 'done!' return 'done!'
def demo2(): def demo2():
@@ -232,7 +234,7 @@ def _decode_list(lst):
def _decode_dict(dct): def _decode_dict(dct):
newdict = {} newdict = {}
for k, v in dct.iteritems(): for k, v in iteritems(dct):
if isinstance(k, unicode): if isinstance(k, unicode):
k = k.encode('utf-8') k = k.encode('utf-8')
if isinstance(v, unicode): if isinstance(v, unicode):
@@ -312,7 +314,7 @@ def executor(queue, task, out):
f.write(result) f.write(result)
result = 'w2p_special:%s' % temp_path result = 'w2p_special:%s' % temp_path
queue.put(TaskReport('COMPLETED', result=result)) queue.put(TaskReport('COMPLETED', result=result))
except BaseException, e: except BaseException as e:
tb = traceback.format_exc() tb = traceback.format_exc()
queue.put(TaskReport('FAILED', tb=tb)) queue.put(TaskReport('FAILED', tb=tb))
del stdout del stdout
@@ -1457,26 +1459,26 @@ def main():
) )
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if not options.tasks or not options.db_uri: if not options.tasks or not options.db_uri:
print USAGE print(USAGE)
if options.tasks: if options.tasks:
path, filename = os.path.split(options.tasks) path, filename = os.path.split(options.tasks)
if filename.endswith('.py'): if filename.endswith('.py'):
filename = filename[:-3] filename = filename[:-3]
sys.path.append(path) sys.path.append(path)
print 'importing tasks...' print('importing tasks...')
tasks = __import__(filename, globals(), locals(), [], -1).tasks tasks = __import__(filename, globals(), locals(), [], -1).tasks
print 'tasks found: ' + ', '.join(tasks.keys()) print('tasks found: ' + ', '.join(tasks.keys()))
else: else:
tasks = {} tasks = {}
group_names = [x.strip() for x in options.group_names.split(',')] group_names = [x.strip() for x in options.group_names.split(',')]
logging.getLogger().setLevel(options.logger_level) logging.getLogger().setLevel(options.logger_level)
print 'groups for this worker: ' + ', '.join(group_names) print('groups for this worker: ' + ', '.join(group_names))
print 'connecting to database in folder: ' + options.db_folder or './' print('connecting to database in folder: ' + options.db_folder or './')
print 'using URI: ' + options.db_uri print('using URI: ' + options.db_uri)
db = DAL(options.db_uri, folder=options.db_folder) db = DAL(options.db_uri, folder=options.db_folder)
print 'instantiating scheduler...' print('instantiating scheduler...')
scheduler = Scheduler(db=db, scheduler = Scheduler(db=db,
worker_name=options.worker_name, worker_name=options.worker_name,
tasks=tasks, tasks=tasks,
@@ -1486,7 +1488,7 @@ def main():
max_empty_runs=options.max_empty_runs, max_empty_runs=options.max_empty_runs,
utc_time=options.utc_time) utc_time=options.utc_time)
signal.signal(signal.SIGTERM, lambda signum, stack_frame: sys.exit(1)) signal.signal(signal.SIGTERM, lambda signum, stack_frame: sys.exit(1))
print 'starting main worker loop...' print('starting main worker loop...')
scheduler.loop() scheduler.loop()
if __name__ == '__main__': if __name__ == '__main__':
+4 -2
View File
@@ -10,6 +10,7 @@ from gluon.html import TAG, XmlComponent, xmlescape
from gluon.languages import lazyT from gluon.languages import lazyT
import gluon.contrib.rss2 as rss2 import gluon.contrib.rss2 as rss2
import json as json_parser import json as json_parser
from gluon._compat import long
have_yaml = True have_yaml = True
try: try:
@@ -120,8 +121,9 @@ def json(value, default=custom_json):
value = json_parser.dumps(value, default=default) value = json_parser.dumps(value, default=default)
# replace JavaScript incompatible spacing # replace JavaScript incompatible spacing
# http://timelessrepo.com/json-isnt-a-javascript-subset # 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): def csv(value):
return '' return ''
+15 -14
View File
@@ -10,6 +10,7 @@
Web2py environment in the shell Web2py environment in the shell
-------------------------------- --------------------------------
""" """
from __future__ import print_function
import os import os
import sys import sys
@@ -29,6 +30,7 @@ from gluon.globals import Request, Response, Session
from gluon.storage import Storage, List from gluon.storage import Storage, List
from gluon.admin import w2p_unpack from gluon.admin import w2p_unpack
from pydal.base import BaseAdapter from pydal.base import BaseAdapter
from gluon._compat import iteritems, ClassType
logger = logging.getLogger("web2py") logger = logging.getLogger("web2py")
@@ -85,7 +87,7 @@ def exec_environment(
if pyfile: if pyfile:
pycfile = pyfile + 'c' pycfile = pyfile + 'c'
if os.path.isfile(pycfile): if os.path.isfile(pycfile):
exec read_pyc(pycfile) in env exec (read_pyc(pycfile), env)
else: else:
execfile(pyfile, env) execfile(pyfile, env)
return Storage(env) return Storage(env)
@@ -145,7 +147,7 @@ def env(
path_info = '%s/%s' % (path_info, '/'.join(request.args)) path_info = '%s/%s' % (path_info, '/'.join(request.args))
if request.vars: if request.vars:
vars = ['%s=%s' % (k, v) if v else '%s' % k vars = ['%s=%s' % (k, v) if v else '%s' % k
for (k, v) in request.vars.iteritems()] for (k, v) in iteritems(request.vars)]
path_info = '%s?%s' % (path_info, '&'.join(vars)) path_info = '%s?%s' % (path_info, '&'.join(vars))
request.env.path_info = path_info request.env.path_info = path_info
@@ -161,7 +163,7 @@ def env(
if import_models: if import_models:
try: try:
run_models_in(environment) run_models_in(environment)
except RestrictedError, e: except RestrictedError as e:
sys.stderr.write(e.traceback + '\n') sys.stderr.write(e.traceback + '\n')
sys.exit(1) sys.exit(1)
@@ -242,14 +244,14 @@ def run(
"controllers_%s_%s.pyc" % (c, f)) "controllers_%s_%s.pyc" % (c, f))
if ((cronjob and os.path.isfile(pycfile)) if ((cronjob and os.path.isfile(pycfile))
or not os.path.isfile(pyfile)): or not os.path.isfile(pyfile)):
exec read_pyc(pycfile) in _env exec(read_pyc(pycfile), _env)
elif os.path.isfile(pyfile): elif os.path.isfile(pyfile):
execfile(pyfile, _env) execfile(pyfile, _env)
else: else:
die(errmsg) die(errmsg)
if f: if f:
exec ('print %s()' % f, _env) exec('print %s()' % f, _env)
return return
_env.update(exec_pythonrc()) _env.update(exec_pythonrc())
@@ -258,14 +260,14 @@ def run(
ccode = None ccode = None
if startfile.endswith('.pyc'): if startfile.endswith('.pyc'):
ccode = read_pyc(startfile) ccode = read_pyc(startfile)
exec ccode in _env exec(ccode, _env)
else: else:
execfile(startfile, _env) execfile(startfile, _env)
if import_models: if import_models:
BaseAdapter.close_all_instances('commit') BaseAdapter.close_all_instances('commit')
except Exception, e: except Exception as e:
print traceback.format_exc() print(traceback.format_exc())
if import_models: if import_models:
BaseAdapter.close_all_instances('rollback') BaseAdapter.close_all_instances('rollback')
elif python_code: elif python_code:
@@ -273,8 +275,8 @@ def run(
exec(python_code, _env) exec(python_code, _env)
if import_models: if import_models:
BaseAdapter.close_all_instances('commit') BaseAdapter.close_all_instances('commit')
except Exception, e: except Exception as e:
print traceback.format_exc() print(traceback.format_exc())
if import_models: if import_models:
BaseAdapter.close_all_instances('rollback') BaseAdapter.close_all_instances('rollback')
else: else:
@@ -347,7 +349,7 @@ def parse_path_info(path_info, av=False):
def die(msg): def die(msg):
print >> sys.stderr, msg print(msg, file=sys.stderr)
sys.exit(1) sys.exit(1)
@@ -396,8 +398,7 @@ def test(testpath, import_models=True, verbose=False):
def doctest_object(name, obj): def doctest_object(name, obj):
"""doctest obj and enclosed methods and classes.""" """doctest obj and enclosed methods and classes."""
if type(obj) in (types.FunctionType, types.TypeType, if type(obj) in (types.FunctionType, type, ClassType, types.MethodType,
types.ClassType, types.MethodType,
types.UnboundMethodType): types.UnboundMethodType):
# Reload environment before each test. # Reload environment before each test.
@@ -408,7 +409,7 @@ def test(testpath, import_models=True, verbose=False):
obj, globs=globs, obj, globs=globs,
name='%s: %s' % (os.path.basename(testfile), name='%s: %s' % (os.path.basename(testfile),
name), verbose=verbose) name), verbose=verbose)
if type(obj) in (types.TypeType, types.ClassType): if type(obj) in (type, ClassType):
for attr_name in dir(obj): for attr_name in dir(obj):
# Execute . operator so decorators are executed. # Execute . operator so decorators are executed.
+16 -15
View File
@@ -17,9 +17,9 @@ Holds:
import datetime import datetime
import urllib import urllib
import re import re
import cStringIO
import os import os
from gluon._compat import StringIO, unichr, urllib_quote, iteritems
from gluon.http import HTTP, redirect from gluon.http import HTTP, redirect
from gluon.html import XmlComponent, truncate_string from gluon.html import XmlComponent, truncate_string
from gluon.html import XML, SPAN, TAG, A, DIV, CAT, UL, LI, TEXTAREA, BR, IMG from gluon.html import XML, SPAN, TAG, A, DIV, CAT, UL, LI, TEXTAREA, BR, IMG
@@ -39,6 +39,7 @@ from gluon.validators import IS_STRONG
import gluon.serializers as serializers import gluon.serializers as serializers
from gluon.globals import current from gluon.globals import current
from functools import reduce
try: try:
import gluon.settings as settings import gluon.settings as settings
@@ -59,7 +60,7 @@ def represent(field, value, record):
if not callable(f): if not callable(f):
return str(value) return str(value)
if hasattr(f,'func_code'): if hasattr(f,'func_code'):
n = f.func_code.co_argcount - len(f.func_defaults or []) n = f.__code__.co_argcount - len(f.__defaults__ or [])
if getattr(f, 'im_self', None): if getattr(f, 'im_self', None):
n -= 1 n -= 1
else: else:
@@ -677,7 +678,7 @@ class AutocompleteWidget(object):
def callback(self): def callback(self):
if self.keyword in self.request.vars: if self.keyword in self.request.vars:
field = self.fields[0] field = self.fields[0]
if type(field) is Field.Virtual: if isinstance(field, Field.Virtual):
records = [] records = []
table_rows = self.db(self.db[field.tablename]).select(orderby=self.orderby) table_rows = self.db(self.db[field.tablename]).select(orderby=self.orderby)
count = 0 count = 0
@@ -741,7 +742,7 @@ class AutocompleteWidget(object):
del attr['requires'] del attr['requires']
attr['_name'] = key2 attr['_name'] = key2
value = attr['value'] value = attr['value']
if type(self.fields[0]) is Field.Virtual: if isinstance(self.fields[0], Field.Virtual):
record = None record = None
table_rows = self.db(self.db[self.fields[0].tablename]).select(orderby=self.orderby) table_rows = self.db(self.db[self.fields[0].tablename]).select(orderby=self.orderby)
for row in table_rows: for row in table_rows:
@@ -1328,10 +1329,10 @@ class SQLFORM(FORM):
db = linkto.split('/')[-1] db = linkto.split('/')[-1]
for rfld in table._referenced_by: for rfld in table._referenced_by:
if keyed: if keyed:
query = urllib.quote('%s.%s==%s' % ( query = urllib_quote('%s.%s==%s' % (
db, rfld, record[rfld.type[10:].split('.')[1]])) db, rfld, record[rfld.type[10:].split('.')[1]]))
else: else:
query = urllib.quote( query = urllib_quote(
'%s.%s==%s' % (db, rfld, record[self.id_field_name])) '%s.%s==%s' % (db, rfld, record[self.id_field_name]))
lname = olname = '%s.%s' % (rfld.tablename, rfld.name) lname = olname = '%s.%s' % (rfld.tablename, rfld.name)
if ofields and olname not in ofields: if ofields and olname not in ofields:
@@ -1653,7 +1654,7 @@ class SQLFORM(FORM):
elif isinstance(f, (str, unicode)): elif isinstance(f, (str, unicode)):
# do not know why this happens, it should not # do not know why this happens, it should not
(source_file, original_filename) = \ (source_file, original_filename) = \
(cStringIO.StringIO(f), 'file.txt') (StringIO(f), 'file.txt')
else: else:
# this should never happen, why does it happen? # this should never happen, why does it happen?
# print 'f=', repr(f) # print 'f=', repr(f)
@@ -2222,7 +2223,7 @@ class SQLFORM(FORM):
if fields: if fields:
# add missing tablename to virtual fields # add missing tablename to virtual fields
for table in tables: for table in tables:
for k, f in table.iteritems(): for k, f in iteritems(table):
if isinstance(f, Field.Virtual): if isinstance(f, Field.Virtual):
f.tablename = table._tablename f.tablename = table._tablename
columns = [f for f in fields if f.tablename in tablenames] columns = [f for f in fields if f.tablename in tablenames]
@@ -2234,7 +2235,7 @@ class SQLFORM(FORM):
for table in tables: for table in tables:
fields += filter(filter1, table) fields += filter(filter1, table)
columns += filter(filter2, table) columns += filter(filter2, table)
for k, f in table.iteritems(): for k, f in iteritems(table):
if not k.startswith('_'): if not k.startswith('_'):
if isinstance(f, Field.Virtual) and f.readable: if isinstance(f, Field.Virtual) and f.readable:
f.tablename = table._tablename f.tablename = table._tablename
@@ -2438,7 +2439,7 @@ class SQLFORM(FORM):
selectable_columns.append(str(field)) selectable_columns.append(str(field))
# look for virtual fields not displayed (and virtual method # look for virtual fields not displayed (and virtual method
# fields to be added here?) # fields to be added here?)
for (field_name, field) in table.iteritems(): for (field_name, field) in iteritems(table):
if isinstance(field, Field.Virtual) and not str(field) in expcolumns: if isinstance(field, Field.Virtual) and not str(field) in expcolumns:
expcolumns.append(str(field)) expcolumns.append(str(field))
@@ -2457,7 +2458,7 @@ class SQLFORM(FORM):
sfields, keywords)) sfields, keywords))
rows = dbset.select(left=left, orderby=orderby, rows = dbset.select(left=left, orderby=orderby,
cacheable=True, *selectable_columns) cacheable=True, *selectable_columns)
except Exception, e: except Exception as e:
response.flash = T('Internal Error') response.flash = T('Internal Error')
rows = [] rows = []
else: else:
@@ -2655,7 +2656,7 @@ class SQLFORM(FORM):
rows = None rows = None
next_cursor = None next_cursor = None
error = T("Query Not Supported") error = T("Query Not Supported")
except Exception, e: except Exception as e:
rows = None rows = None
next_cursor = None next_cursor = None
error = T("Query Not Supported: %s") % e error = T("Query Not Supported: %s") % e
@@ -3478,8 +3479,8 @@ class ExporterTSV(ExportClass):
ExportClass.__init__(self, rows) ExportClass.__init__(self, rows)
def export(self): def export(self):
out = cStringIO.StringIO() out = StringIO()
final = cStringIO.StringIO() final = StringIO()
import csv import csv
writer = csv.writer(out, delimiter='\t') writer = csv.writer(out, delimiter='\t')
if self.rows: if self.rows:
@@ -3517,7 +3518,7 @@ class ExporterCSV(ExportClass):
def export(self): # export CSV with rows.represent def export(self): # export CSV with rows.represent
if self.rows: if self.rows:
s = cStringIO.StringIO() s = StringIO()
self.rows.export_to_csv_file(s, represent=True) self.rows.export_to_csv_file(s, represent=True)
return s.getvalue() return s.getvalue()
else: else:
+7 -10
View File
@@ -12,11 +12,7 @@ Provides:
- Storage; like dictionary allowing also for `obj.foo` for `obj['foo']` - Storage; like dictionary allowing also for `obj.foo` for `obj['foo']`
""" """
try: from gluon._compat import copyreg, pickle, PY2
import cPickle as pickle
except:
import pickle
import copy_reg
import gluon.portalocker as portalocker import gluon.portalocker as portalocker
__all__ = ['List', 'Storage', 'Settings', 'Messages', __all__ = ['List', 'Storage', 'Settings', 'Messages',
@@ -139,10 +135,11 @@ class Storage(dict):
def pickle_storage(s): def pickle_storage(s):
return Storage, (dict(s),) return Storage, (dict(s),)
copy_reg.pickle(Storage, pickle_storage) copyreg.pickle(Storage, pickle_storage)
if PY2:
PICKABLE = (str, int, long, float, bool, list, dict, tuple, set) PICKABLE = (str, int, long, float, bool, list, dict, tuple, set)
else:
PICKABLE = (str, int, float, bool, list, dict, tuple, set)
class StorageList(Storage): class StorageList(Storage):
""" """
@@ -310,7 +307,7 @@ class List(list):
if not value and otherwise: if not value and otherwise:
raise ValueError('Otherwise will raised.') raise ValueError('Otherwise will raised.')
except (ValueError, TypeError): except (ValueError, TypeError):
from http import HTTP, redirect from gluon.http import HTTP, redirect
if otherwise is None: if otherwise is None:
raise HTTP(404) raise HTTP(404)
elif isinstance(otherwise, str): elif isinstance(otherwise, str):
+3 -4
View File
@@ -15,7 +15,6 @@ import stat
import time import time
import re import re
import errno import errno
import rewrite
from gluon.http import HTTP from gluon.http import HTTP
from gluon.contenttype import contenttype from gluon.contenttype import contenttype
@@ -56,7 +55,7 @@ def stream_file_or_304_or_206(
try: try:
open = file # this makes no sense but without it GAE cannot open files open = file # this makes no sense but without it GAE cannot open files
fp = open(static_file,'rb') fp = open(static_file,'rb')
except IOError, e: except IOError as e:
if e[0] == errno.EISDIR: if e[0] == errno.EISDIR:
raise HTTP(403, error_message, web2py_error='file is a directory') raise HTTP(403, error_message, web2py_error='file is a directory')
elif e[0] == errno.EACCES: elif e[0] == errno.EACCES:
@@ -90,7 +89,7 @@ def stream_file_or_304_or_206(
bytes = part[1] - part[0] + 1 bytes = part[1] - part[0] + 1
try: try:
stream = open(static_file, 'rb') stream = open(static_file, 'rb')
except IOError, e: except IOError as e:
if e[0] in (errno.EISDIR, errno.EACCES): if e[0] in (errno.EISDIR, errno.EACCES):
raise HTTP(403) raise HTTP(403)
else: else:
@@ -111,7 +110,7 @@ def stream_file_or_304_or_206(
headers['Vary'] = 'Accept-Encoding' headers['Vary'] = 'Accept-Encoding'
try: try:
stream = open(static_file, 'rb') stream = open(static_file, 'rb')
except IOError, e: except IOError as e:
# this better does not happer when returning an error page ;-) # this better does not happer when returning an error page ;-)
if e[0] in (errno.EISDIR, errno.EACCES): if e[0] in (errno.EISDIR, errno.EACCES):
raise HTTP(403) raise HTTP(403)
+10 -13
View File
@@ -18,10 +18,7 @@ import os
import cgi import cgi
import logging import logging
from re import compile, sub, escape, DOTALL from re import compile, sub, escape, DOTALL
try: from gluon._compat import StringIO, unicodeT, to_unicode, to_bytes, to_native
import cStringIO as StringIO
except:
from io import StringIO
try: try:
# have web2py # have web2py
@@ -279,13 +276,12 @@ class TemplateParser(object):
self.context = context self.context = context
# allow optional alternative delimiters # allow optional alternative delimiters
if delimiters != self.default_delimiters: if delimiters != self.default_delimiters:
escaped_delimiters = (escape(delimiters[0]), escaped_delimiters = (escape(delimiters[0]),
escape(delimiters[1])) escape(delimiters[1]))
self.r_tag = compile(r'(%s.*?%s)' % escaped_delimiters, DOTALL) self.r_tag = compile(r'(%s.*?%s)' % escaped_delimiters, DOTALL)
elif hasattr(context.get('response', None), 'delimiters'): elif hasattr(context.get('response', None), 'delimiters'):
if context['response'].delimiters != self.default_delimiters: if (context['response'].delimiters != self.default_delimiters) and (context['response'].delimiters != None):
delimiters = context['response'].delimiters delimiters = context['response'].delimiters
escaped_delimiters = ( escaped_delimiters = (
escape(delimiters[0]), escape(delimiters[0]),
@@ -807,7 +803,7 @@ def get_parsed(text):
class DummyResponse(): class DummyResponse():
def __init__(self): def __init__(self):
self.body = StringIO.StringIO() self.body = StringIO()
def write(self, data, escape=True): def write(self, data, escape=True):
if not escape: if not escape:
@@ -816,9 +812,9 @@ class DummyResponse():
self.body.write(data.xml()) self.body.write(data.xml())
else: else:
# make it a string # make it a string
if not isinstance(data, (str, unicode)): if not isinstance(data, (str, unicodeT)):
data = str(data) data = str(data)
elif isinstance(data, unicode): elif isinstance(data, unicodeT):
data = data.encode('utf8', 'xmlcharrefreplace') data = data.encode('utf8', 'xmlcharrefreplace')
data = cgi.escape(data, True).replace("'", "&#x27;") data = cgi.escape(data, True).replace("'", "&#x27;")
self.body.write(data) self.body.write(data)
@@ -898,13 +894,13 @@ def render(content="hello world",
if not 'NOESCAPE' in context: if not 'NOESCAPE' in context:
context['NOESCAPE'] = NOESCAPE context['NOESCAPE'] = NOESCAPE
if isinstance(content, unicode): if isinstance(content, unicodeT):
content = content.encode('utf8') content = content.encode('utf8')
# save current response class # save current response class
if context and 'response' in context: if context and 'response' in context:
old_response_body = context['response'].body old_response_body = context['response'].body
context['response'].body = StringIO.StringIO() context['response'].body = StringIO()
else: else:
old_response_body = None old_response_body = None
context['response'] = Response() context['response'] = Response()
@@ -921,13 +917,14 @@ def render(content="hello world",
stream = open(filename, 'rb') stream = open(filename, 'rb')
close_stream = True close_stream = True
elif content: elif content:
stream = StringIO.StringIO(content) stream = StringIO(to_native(content))
# Execute the template. # Execute the template.
code = str(TemplateParser(stream.read( code = str(TemplateParser(stream.read(
), context=context, path=path, lexers=lexers, delimiters=delimiters, writer=writer)) ), context=context, path=path, lexers=lexers, delimiters=delimiters, writer=writer))
try: try:
exec(code) in context exec(code, context)
except Exception: except Exception:
# for i,line in enumerate(code.split('\n')): print i,line # for i,line in enumerate(code.split('\n')): print i,line
raise raise
+24 -24
View File
@@ -1,28 +1,28 @@
import sys import sys
from test_http import * from .test_http import *
from test_cache import * from .test_contenttype import *
from test_contenttype import * from .test_fileutils import *
from test_compileapp import * from .test_globals import *
from test_fileutils import * from .test_recfile import *
from test_globals import * from .test_storage import *
from test_html import * from .test_dal import *
from test_is_url import * from .test_cache import *
from test_languages import * from .test_template import *
from test_router import * from .test_html import *
from test_recfile import * from .test_contribs import *
from test_routes import * from .test_routes import *
from test_storage import * from .test_router import *
from test_serializers import * from .test_validators 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': if sys.version[:3] == '2.7':
from test_old_doctests import * from .test_compileapp import *
from .test_is_url import *
from .test_languages import *
from .test_serializers import *
from .test_utils import *
from .test_tools import *
from .test_appadmin import *
from .test_scheduler import *
from .test_web import *
from .test_old_doctests import *
+13 -12
View File
@@ -4,20 +4,21 @@
""" """
Unit tests for gluon.sqlhtml Unit tests for gluon.sqlhtml
""" """
from __future__ import print_function
import os import os
import sys import sys
import unittest import unittest
import json import json
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from compileapp import run_controller_in, run_view_in from gluon.compileapp import run_controller_in, run_view_in
from languages import translator from gluon.languages import translator
from gluon.storage import Storage, List from gluon.storage import Storage, List
import gluon.fileutils from gluon import fileutils
from gluon.dal import DAL, Field, Table from gluon.dal import DAL, Field, Table
from gluon.http import HTTP from gluon.http import HTTP
@@ -35,13 +36,13 @@ class TestAppAdmin(unittest.TestCase):
from gluon.globals import Request, Response, Session, current from gluon.globals import Request, Response, Session, current
from gluon.html import A, DIV, FORM, MENU, TABLE, TR, INPUT, URL, XML from gluon.html import A, DIV, FORM, MENU, TABLE, TR, INPUT, URL, XML
from gluon.validators import IS_NOT_EMPTY from gluon.validators import IS_NOT_EMPTY
from compileapp import LOAD from gluon.compileapp import LOAD
from gluon.http import HTTP, redirect from gluon.http import HTTP, redirect
from gluon.tools import Auth from gluon.tools import Auth
from gluon.sql import SQLDB from gluon.sql import SQLDB
from gluon.sqlhtml import SQLTABLE, SQLFORM from gluon.sqlhtml import SQLTABLE, SQLFORM
self.original_check_credentials = gluon.fileutils.check_credentials self.original_check_credentials = fileutils.check_credentials
gluon.fileutils.check_credentials = fake_check_credentials fileutils.check_credentials = fake_check_credentials
request = Request(env={}) request = Request(env={})
request.application = 'welcome' request.application = 'welcome'
request.controller = 'appadmin' request.controller = 'appadmin'
@@ -72,7 +73,7 @@ class TestAppAdmin(unittest.TestCase):
self.env = locals() self.env = locals()
def tearDown(self): def tearDown(self):
gluon.fileutils.check_credentials = self.original_check_credentials fileutils.check_credentials = self.original_check_credentials
def run_function(self): def run_function(self):
return run_controller_in(self.env['request'].controller, self.env['request'].function, self.env) return run_controller_in(self.env['request'].controller, self.env['request'].function, self.env)
@@ -87,7 +88,7 @@ class TestAppAdmin(unittest.TestCase):
try: try:
self.run_view() self.run_view()
except Exception as e: except Exception as e:
print e.message print(e.message)
self.fail('Could not make the view') self.fail('Could not make the view')
def test_select(self): def test_select(self):
@@ -102,7 +103,7 @@ class TestAppAdmin(unittest.TestCase):
try: try:
self.run_view() self.run_view()
except Exception as e: except Exception as e:
print e.message print(e.message)
self.fail('Could not make the view') self.fail('Could not make the view')
def test_insert(self): def test_insert(self):
@@ -116,7 +117,7 @@ class TestAppAdmin(unittest.TestCase):
try: try:
self.run_view() self.run_view()
except Exception as e: except Exception as e:
print e.message print(e.message)
self.fail('Could not make the view') self.fail('Could not make the view')
def test_insert_submit(self): def test_insert_submit(self):
@@ -138,7 +139,7 @@ class TestAppAdmin(unittest.TestCase):
try: try:
self.run_view() self.run_view()
except Exception as e: except Exception as e:
print e.message print(e.message)
self.fail('Could not make the view') self.fail('Could not make the view')
db = self.env['db'] db = self.env['db']
lisa_record = db(db.auth_user.username == 'lisasimpson').select().first() lisa_record = db(db.auth_user.username == 'lisasimpson').select().first()
+3 -3
View File
@@ -6,13 +6,13 @@
""" """
import os import os
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from storage import Storage from gluon.storage import Storage
from cache import CacheInRam, CacheOnDisk, Cache from gluon.cache import CacheInRam, CacheOnDisk, Cache
from gluon.dal import DAL, Field from gluon.dal import DAL, Field
oldcwd = None oldcwd = None
+2 -2
View File
@@ -4,11 +4,11 @@
""" Unit tests for utils.py """ """ Unit tests for utils.py """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from compileapp import compile_application, remove_compiled_application from gluon.compileapp import compile_application, remove_compiled_application
from gluon.fileutils import w2p_pack, w2p_unpack from gluon.fileutils import w2p_pack, w2p_unpack
import os import os
+4 -4
View File
@@ -6,12 +6,12 @@
""" """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from contenttype import contenttype from gluon.contenttype import contenttype
from gluon._compat import iteritems
class TestContentType(unittest.TestCase): class TestContentType(unittest.TestCase):
@@ -31,7 +31,7 @@ class TestContentType(unittest.TestCase):
'.w2p': 'application/w2p', '.w2p': 'application/w2p',
'.md': 'text/x-markdown; charset=utf-8' '.md': 'text/x-markdown; charset=utf-8'
} }
for k, v in mapping.iteritems(): for k, v in iteritems(mapping):
self.assertEqual(contenttype(k), v) self.assertEqual(contenttype(k), v)
# test without dot extension # test without dot extension
+6 -6
View File
@@ -5,13 +5,13 @@
import unittest import unittest
import os import os
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from gluon._compat import to_bytes
from gluon.storage import Storage from gluon.storage import Storage
import gluon.contrib.fpdf as fpdf from gluon.contrib import fpdf as fpdf
import gluon.contrib.pyfpdf as pyfpdf from gluon.contrib import pyfpdf as pyfpdf
from gluon.contrib.appconfig import AppConfig from gluon.contrib.appconfig import AppConfig
@@ -42,8 +42,8 @@ class TestContribs(unittest.TestCase):
pdf.write(5, 'hello world') pdf.write(5, 'hello world')
pdf_out = pdf.output('', 'S') pdf_out = pdf.output('', 'S')
self.assertTrue(fpdf.FPDF_VERSION in pdf_out, 'version string') self.assertTrue(to_bytes(fpdf.FPDF_VERSION) in pdf_out, 'version string')
self.assertTrue('hello world' in pdf_out, 'sample message') self.assertTrue(to_bytes('hello world') in pdf_out, 'sample message')
def test_appconfig(self): def test_appconfig(self):
""" """
+3 -3
View File
@@ -7,7 +7,7 @@
import sys import sys
import os import os
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
@@ -34,7 +34,7 @@ class TestDALSubclass(unittest.TestCase):
db.close() db.close()
def testSerialization(self): def testSerialization(self):
import pickle from gluon._compat import pickle
db = DAL(check_reserved=['all']) db = DAL(check_reserved=['all'])
db.define_table('t_a', Field('f_a')) db.define_table('t_a', Field('f_a'))
db.t_a.insert(f_a='test') db.t_a.insert(f_a='test')
@@ -62,7 +62,7 @@ def _prepare_exec_for_file(filename):
raise 'The file provided (%s) does is not a valid Python file.' raise 'The file provided (%s) does is not a valid Python file.'
filename = os.path.realpath(filename) filename = os.path.realpath(filename)
dirpath = filename dirpath = filename
while 1: while True:
dirpath, extra = os.path.split(dirpath) dirpath, extra = os.path.split(dirpath)
module.append(extra) module.append(extra)
if not os.path.isfile(os.path.join(dirpath, '__init__.py')): if not os.path.isfile(os.path.join(dirpath, '__init__.py')):
+2 -2
View File
@@ -3,11 +3,11 @@
import unittest import unittest
import datetime import datetime
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from fileutils import parse_version from gluon.fileutils import parse_version
class TestFileUtils(unittest.TestCase): class TestFileUtils(unittest.TestCase):
+8 -6
View File
@@ -8,12 +8,13 @@
import re import re
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from gluon.globals import Request, Response, Session from gluon.globals import Request, Response, Session
from gluon import URL from gluon import URL
from gluon._compat import basestring
def setup_clean_session(): def setup_clean_session():
request = Request(env={}) request = Request(env={})
@@ -158,31 +159,32 @@ class testResponse(unittest.TestCase):
current = setup_clean_session() current = setup_clean_session()
current.session._fixup_before_save() current.session._fixup_before_save()
cookie = str(current.response.cookies) cookie = str(current.response.cookies)
self.assertTrue('secure' not in cookie) self.assertTrue('secure' not in cookie.lower())
current = setup_clean_session() current = setup_clean_session()
current.session.secure() current.session.secure()
current.session._fixup_before_save() current.session._fixup_before_save()
cookie = str(current.response.cookies) cookie = str(current.response.cookies)
self.assertTrue('secure' in cookie) self.assertTrue('secure' in cookie.lower())
def test_cookies_httponly(self): def test_cookies_httponly(self):
current = setup_clean_session() current = setup_clean_session()
current.session._fixup_before_save() current.session._fixup_before_save()
cookie = str(current.response.cookies) cookie = str(current.response.cookies)
self.assertTrue('httponly' in cookie) # cookies in PY3 have capital letters
self.assertTrue('httponly' in cookie.lower())
current = setup_clean_session() current = setup_clean_session()
current.session.httponly_cookies = True current.session.httponly_cookies = True
current.session._fixup_before_save() current.session._fixup_before_save()
cookie = str(current.response.cookies) cookie = str(current.response.cookies)
self.assertTrue('httponly' in cookie) self.assertTrue('httponly' in cookie.lower())
current = setup_clean_session() current = setup_clean_session()
current.session.httponly_cookies = False current.session.httponly_cookies = False
current.session._fixup_before_save() current.session._fixup_before_save()
cookie = str(current.response.cookies) cookie = str(current.response.cookies)
self.assertTrue('httponly' not in cookie) self.assertTrue('httponly' not in cookie.lower())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
+178 -167
View File
@@ -6,17 +6,18 @@
""" """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from html import * from gluon.html import A, ASSIGNJS, B, BEAUTIFY, P, BODY, BR, BUTTON, CAT, CENTER, CODE, COL, COLGROUP, DIV, SPAN, URL, verifyURL
from html import verifyURL from gluon.html import truncate_string, EM, FIELDSET, FORM, H1, H2, H3, H4, H5, H6, HEAD, HR, HTML, I, IFRAME, IMG, INPUT, EMBED
from html import truncate_string from gluon.html import LABEL, LEGEND, LI, LINK, MARKMIN, MENU, META, OBJECT, OL, OPTGROUP, OPTION, PRE, SCRIPT, SELECT, STRONG
from storage import Storage from gluon.html import STYLE, TABLE, TR, TD, TAG, TBODY, THEAD, TEXTAREA, TFOOT, TH, TITLE, TT, UL, XHTML, XML
from html import XML_pickle, XML_unpickle from gluon.storage import Storage
from html import TAG_pickler, TAG_unpickler from gluon.html import XML_pickle, XML_unpickle
from gluon.html import TAG_pickler, TAG_unpickler
from gluon._compat import xrange, PY2, to_native
class TestBareHelpers(unittest.TestCase): class TestBareHelpers(unittest.TestCase):
@@ -41,7 +42,7 @@ class TestBareHelpers(unittest.TestCase):
self.assertEqual(URL('a', 'static', 'design.css'), '/a/static/design.css') self.assertEqual(URL('a', 'static', 'design.css'), '/a/static/design.css')
response = Storage() response = Storage()
response.static_version = '1.2.3' response.static_version = '1.2.3'
from globals import current from gluon.globals import current
current.response = response current.response = response
self.assertEqual(URL('a', 'static', 'design.css'), '/a/static/design.css') self.assertEqual(URL('a', 'static', 'design.css'), '/a/static/design.css')
response.static_version_urls = True response.static_version_urls = True
@@ -53,6 +54,8 @@ class TestBareHelpers(unittest.TestCase):
self.assertEqual(URL('a', 'c', 'f', args=['1', '2']), '/a/c/f/1/2') self.assertEqual(URL('a', 'c', 'f', args=['1', '2']), '/a/c/f/1/2')
self.assertEqual(URL('a', 'c', '/f'), '/a/c/f') self.assertEqual(URL('a', 'c', '/f'), '/a/c/f')
self.assertEqual(URL('a', 'c', 'f.json'), '/a/c/f.json') self.assertEqual(URL('a', 'c', 'f.json'), '/a/c/f.json')
from gluon.globals import current
current.request = None
self.assertRaises(SyntaxError, URL, *['a']) self.assertRaises(SyntaxError, URL, *['a'])
request = Storage() request = Storage()
@@ -61,7 +64,7 @@ class TestBareHelpers(unittest.TestCase):
request.function = 'f' request.function = 'f'
request.env = {} request.env = {}
from globals import current # Can't be moved with other import from gluon.globals import current # Can't be moved with other import
current.request = request current.request = request
must_return = '/a/c/f' must_return = '/a/c/f'
@@ -98,14 +101,17 @@ class TestBareHelpers(unittest.TestCase):
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a') self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a')
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key', hash_vars='p') rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'p': (1, 3), 'q': 2}, hmac_key='key', hash_vars='p')
self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a') self.assertEqual(rtn, '/a/c/f/x/y/z?p=1&p=3&q=2&_signature=5d01b982fd72b39674b012e0288071034e156d7a')
# test url_encode
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'maï': (1, 3), 'lié': 2}, url_encode=False)
self.assertEqual(rtn, '/a/c/f/x/y/z?li\xc3\xa9=2&ma\xc3\xaf=1&ma\xc3\xaf=3')
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'maï': (1, 3), 'lié': 2}, url_encode=True)
self.assertEqual(rtn, '/a/c/f/x/y/z?li%C3%A9=2&ma%C3%AF=1&ma%C3%AF=3')
# test CRLF detection # test CRLF detection
self.assertRaises(SyntaxError, URL, *['a\n', 'c', 'f']) self.assertRaises(SyntaxError, URL, *['a\n', 'c', 'f'])
self.assertRaises(SyntaxError, URL, *['a\r', 'c', 'f']) self.assertRaises(SyntaxError, URL, *['a\r', 'c', 'f'])
# test url_encode
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'maï': (1, 3), 'lié': 2}, url_encode=True)
self.assertEqual(rtn, '/a/c/f/x/y/z?li%C3%A9=2&ma%C3%AF=1&ma%C3%AF=3')
@unittest.skipIf(not PY2, "Skipping Python 3.x tests for test_URL_encode")
def test_URL_encode(self):
rtn = URL('a', 'c', 'f', args=['x', 'y', 'z'], vars={'maï': (1, 3), 'lié': 2}, url_encode=False)
self.assertEqual(rtn, '/a/c/f/x/y/z?li\xc3\xa9=2&ma\xc3\xaf=1&ma\xc3\xaf=3')
def test_verifyURL(self): def test_verifyURL(self):
r = Storage() r = Storage()
@@ -144,34 +150,36 @@ class TestBareHelpers(unittest.TestCase):
rtn = verifyURL(r) rtn = verifyURL(r)
self.assertEqual(rtn, False) self.assertEqual(rtn, False)
# emulate user signature # emulate user signature
from globals import current from gluon.globals import current
current.session = Storage(auth=Storage(hmac_key='key')) current.session = Storage(auth=Storage(hmac_key='key'))
r.get_vars['_signature'] = 'a32530f0d0caa80964bb92aad2bedf8a4486a31f' r.get_vars['_signature'] = 'a32530f0d0caa80964bb92aad2bedf8a4486a31f'
rtn = verifyURL(r, user_signature=True) rtn = verifyURL(r, user_signature=True)
self.assertEqual(rtn, True) self.assertEqual(rtn, True)
# TODO: def test_XmlComponent(self): # TODO: def test_XmlComponent(self):
@unittest.skipIf(not PY2, "Skipping Python 3.x tests for XML.__repr__")
def test_XML(self): def test_XML(self):
# sanitization process # sanitization process
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>').xml(), self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>').xml(),
'<h1>Hello<a data-hello="world">World</a></h1>') b'<h1>Hello<a data-hello="world">World</a></h1>')
# with sanitize, data-attributes are not permitted # with sanitize, data-attributes are not permitted
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True).xml(), self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True).xml(),
'<h1>HelloWorld</h1>') b'<h1>HelloWorld</h1>')
# stringify by default # stringify by default
self.assertEqual(XML(1.3), '1.3') # FIXME PY3
self.assertEqual(XML(u'<div>è</div>').xml(), '<div>\xc3\xa8</div>') # seams that __repr__ is no longer enough
##self.assertEqual(XML('1.3'), '1.3')
self.assertEqual(XML(u'<div>è</div>').xml(), b'<div>\xc3\xa8</div>')
# you can calc len on the class, that equals the xml() and the str() # you can calc len on the class, that equals the xml() and the str()
self.assertEqual(len(XML('1.3')), len('1.3')) ##self.assertEqual(len(XML('1.3')), len('1.3'))
self.assertEqual(len(XML('1.3').xml()), len('1.3')) self.assertEqual(len(XML('1.3').xml()), len('1.3'))
self.assertEqual(len(str(XML('1.3'))), len('1.3')) ##self.assertEqual(len(str(XML('1.3'))), len('1.3'))
# you can concatenate them to strings (check for __add__ and __radd__ methods) # you can concatenate them to strings (check for __add__ and __radd__ methods)
self.assertEqual(XML('a') + 'b', 'ab') ##self.assertEqual(XML('a') + 'b', 'ab')
self.assertEqual(XML('a') + XML('b'), 'ab') ##self.assertEqual(XML('a') + XML('b'), 'ab')
self.assertEqual('a' + XML('b'), 'ab') ##self.assertEqual('a' + XML('b'), 'ab')
# you can compare them # you can compare them
self.assertEqual(XML('a') == XML('a'), True) ##self.assertEqual(XML('a') == XML('a'), True)
# beware that the comparison is made on the XML repr # beware that the comparison is made on the XML repr
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True), self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True),
XML('<h1>HelloWorld</h1>')) XML('<h1>HelloWorld</h1>'))
@@ -182,24 +190,25 @@ class TestBareHelpers(unittest.TestCase):
self.assertEqual(XML('<p>Test</p>').flatten(), '<p>Test</p>') self.assertEqual(XML('<p>Test</p>').flatten(), '<p>Test</p>')
self.assertEqual(XML('<p>Test</p>').flatten(render=lambda text, tag, attr: text), '<p>Test</p>') self.assertEqual(XML('<p>Test</p>').flatten(render=lambda text, tag, attr: text), '<p>Test</p>')
@unittest.skipIf(not PY2, "Skipping Python 3.x tests for XML_unpickle.__repr__")
def test_XML_pickle_unpickle(self): def test_XML_pickle_unpickle(self):
# weird test # weird test
self.assertEqual(XML_unpickle(XML_pickle('data to be pickle')[1][0]), 'data to be pickle') self.assertEqual(XML_unpickle(XML_pickle('data to be pickle')[1][0]), 'data to be pickle')
def test_DIV(self): def test_DIV(self):
# Empty DIV() # Empty DIV()
self.assertEqual(DIV().xml(), '<div></div>') self.assertEqual(DIV().xml(), b'<div></div>')
self.assertEqual(DIV('<>', _a='1', _b='2').xml(), self.assertEqual(DIV('<>', _a='1', _b='2').xml(),
'<div a="1" b="2">&lt;&gt;</div>') b'<div a="1" b="2">&lt;&gt;</div>')
# attributes can be updated like in a dict # attributes can be updated like in a dict
div = DIV('<>', _a='1') div = DIV('<>', _a='1')
div['_b'] = '2' div['_b'] = '2'
self.assertEqual(div.xml(), self.assertEqual(div.xml(),
'<div a="1" b="2">&lt;&gt;</div>') b'<div a="1" b="2">&lt;&gt;</div>')
# also with a mapping # also with a mapping
div.update(_b=2, _c=3) div.update(_b=2, _c=3)
self.assertEqual(div.xml(), self.assertEqual(div.xml(),
'<div a="1" b="2" c="3">&lt;&gt;</div>') b'<div a="1" b="2" c="3">&lt;&gt;</div>')
# length of the DIV is the number of components # length of the DIV is the number of components
self.assertEqual(len(DIV('a', 'bc')), 2) self.assertEqual(len(DIV('a', 'bc')), 2)
# also if empty, DIV is True in a boolean evaluation # also if empty, DIV is True in a boolean evaluation
@@ -209,13 +218,13 @@ class TestBareHelpers(unittest.TestCase):
s = a.element('span') s = a.element('span')
d = s.parent d = s.parent
d['_class'] = 'abc' d['_class'] = 'abc'
self.assertEqual(a.xml(), '<div class="abc"><span>a</span><div>b</div></div>') self.assertEqual(a.xml(), b'<div class="abc"><span>a</span><div>b</div></div>')
self.assertEqual([el.xml() for el in s.siblings()], ['<div>b</div>']) self.assertEqual([el.xml() for el in s.siblings()], [b'<div>b</div>'])
self.assertEqual(s.sibling().xml(), '<div>b</div>') self.assertEqual(s.sibling().xml(), b'<div>b</div>')
# siblings with wrong args # siblings with wrong args
self.assertEqual(s.siblings('a'), []) self.assertEqual(s.siblings('a'), [])
# siblings with good args # siblings with good args
self.assertEqual(s.siblings('div')[0].xml(), '<div>b</div>') self.assertEqual(s.siblings('div')[0].xml(), b'<div>b</div>')
# Check for siblings with wrong kargs and value # Check for siblings with wrong kargs and value
self.assertEqual(s.siblings(a='d'), []) self.assertEqual(s.siblings(a='d'), [])
# Check for siblings with good kargs and value # Check for siblings with good kargs and value
@@ -231,10 +240,10 @@ class TestBareHelpers(unittest.TestCase):
# data = data.encode('utf8', 'xmlcharrefreplace') # data = data.encode('utf8', 'xmlcharrefreplace')
# """ # """
self.assertEqual(DIV(u'Texte en français avec des caractères accentués...').xml(), self.assertEqual(DIV(u'Texte en français avec des caractères accentués...').xml(),
'<div>Texte en fran\xc3\xa7ais avec des caract\xc3\xa8res accentu\xc3\xa9s...</div>') b'<div>Texte en fran\xc3\xa7ais avec des caract\xc3\xa8res accentu\xc3\xa9s...</div>')
# -------------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------------
self.assertEqual(DIV('Test with an ID', _id='id-of-the-element').xml(), self.assertEqual(DIV('Test with an ID', _id='id-of-the-element').xml(),
'<div id="id-of-the-element">Test with an ID</div>') b'<div id="id-of-the-element">Test with an ID</div>')
self.assertEqual(DIV().element('p'), None) self.assertEqual(DIV().element('p'), None)
# Corner case for raise coverage of one line # Corner case for raise coverage of one line
@@ -249,78 +258,78 @@ class TestBareHelpers(unittest.TestCase):
def test_CAT(self): def test_CAT(self):
# Empty CAT() # Empty CAT()
self.assertEqual(CAT().xml(), '') self.assertEqual(CAT().xml(), b'')
# CAT('') # CAT('')
self.assertEqual(CAT('').xml(), '') self.assertEqual(CAT('').xml(), b'')
# CAT(' ') # CAT(' ')
self.assertEqual(CAT(' ').xml(), ' ') self.assertEqual(CAT(' ').xml(), b' ')
def test_TAG_pickler_unpickler(self): def test_TAG_pickler_unpickler(self):
# weird test # weird test
self.assertEqual(TAG_unpickler(TAG_pickler(TAG.div('data to be pickle'))[1][0]).xml(), self.assertEqual(TAG_unpickler(TAG_pickler(TAG.div('data to be pickle'))[1][0]).xml(),
'<div>data to be pickle</div>') b'<div>data to be pickle</div>')
def test_TAG(self): def test_TAG(self):
self.assertEqual(TAG.first(TAG.second('test'), _key=3).xml(), self.assertEqual(TAG.first(TAG.second('test'), _key=3).xml(),
'<first key="3"><second>test</second></first>') b'<first key="3"><second>test</second></first>')
# ending in underscore "triggers" <input /> style # ending in underscore "triggers" <input /> style
self.assertEqual(TAG.first_(TAG.second('test'), _key=3).xml(), self.assertEqual(TAG.first_(TAG.second('test'), _key=3).xml(),
'<first key="3" />') b'<first key="3" />')
# unicode test for TAG # unicode test for TAG
self.assertEqual(TAG.div(u'Texte en français avec des caractères accentués...').xml(), self.assertEqual(TAG.div(u'Texte en français avec des caractères accentués...').xml(),
'<div>Texte en fran\xc3\xa7ais avec des caract\xc3\xa8res accentu\xc3\xa9s...</div>') b'<div>Texte en fran\xc3\xa7ais avec des caract\xc3\xa8res accentu\xc3\xa9s...</div>')
def test_HTML(self): def test_HTML(self):
self.assertEqual(HTML('<>', _a='1', _b='2').xml(), self.assertEqual(HTML('<>', _a='1', _b='2').xml(),
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>') b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>')
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='strict').xml(), self.assertEqual(HTML('<>', _a='1', _b='2', doctype='strict').xml(),
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>') b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>')
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='transitional').xml(), self.assertEqual(HTML('<>', _a='1', _b='2', doctype='transitional').xml(),
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>') b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>')
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='frameset').xml(), self.assertEqual(HTML('<>', _a='1', _b='2', doctype='frameset').xml(),
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>') b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n<html a="1" b="2" lang="en">&lt;&gt;</html>')
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='html5').xml(), self.assertEqual(HTML('<>', _a='1', _b='2', doctype='html5').xml(),
'<!DOCTYPE HTML>\n<html a="1" b="2" lang="en">&lt;&gt;</html>') b'<!DOCTYPE HTML>\n<html a="1" b="2" lang="en">&lt;&gt;</html>')
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='').xml(), self.assertEqual(HTML('<>', _a='1', _b='2', doctype='').xml(),
'<html a="1" b="2" lang="en">&lt;&gt;</html>') b'<html a="1" b="2" lang="en">&lt;&gt;</html>')
self.assertEqual(HTML('<>', _a='1', _b='2', doctype='CustomDocType').xml(), self.assertEqual(HTML('<>', _a='1', _b='2', doctype='CustomDocType').xml(),
'CustomDocType\n<html a="1" b="2" lang="en">&lt;&gt;</html>') b'CustomDocType\n<html a="1" b="2" lang="en">&lt;&gt;</html>')
def test_XHTML(self): def test_XHTML(self):
# Empty XHTML test # Empty XHTML test
self.assertEqual(XHTML().xml(), self.assertEqual(XHTML().xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"></html>')
# Not Empty XHTML test # Not Empty XHTML test
self.assertEqual(XHTML('<>', _a='1', _b='2').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2').xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='').xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='strict').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='strict').xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='transitional').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='transitional').xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='frameset').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='frameset').xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='xmlns').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2', doctype='xmlns').xml(),
'xmlns\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'xmlns\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
self.assertEqual(XHTML('<>', _a='1', _b='2', _xmlns='xmlns').xml(), self.assertEqual(XHTML('<>', _a='1', _b='2', _xmlns='xmlns').xml(),
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>') b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html a="1" b="2" lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">&lt;&gt;</html>')
def test_HEAD(self): def test_HEAD(self):
self.assertEqual(HEAD('<>', _a='1', _b='2').xml(), self.assertEqual(HEAD('<>', _a='1', _b='2').xml(),
'<head a="1" b="2">&lt;&gt;</head>') b'<head a="1" b="2">&lt;&gt;</head>')
def test_TITLE(self): def test_TITLE(self):
self.assertEqual(TITLE('<>', _a='1', _b='2').xml(), self.assertEqual(TITLE('<>', _a='1', _b='2').xml(),
'<title a="1" b="2">&lt;&gt;</title>') b'<title a="1" b="2">&lt;&gt;</title>')
def test_META(self): def test_META(self):
self.assertEqual(META(_a='1', _b='2').xml(), self.assertEqual(META(_a='1', _b='2').xml(),
'<meta a="1" b="2" />') b'<meta a="1" b="2" />')
def test_LINK(self): def test_LINK(self):
self.assertEqual(LINK(_a='1', _b='2').xml(), self.assertEqual(LINK(_a='1', _b='2').xml(),
'<link a="1" b="2" />') b'<link a="1" b="2" />')
def test_SCRIPT(self): def test_SCRIPT(self):
self.assertEqual(SCRIPT('<>', _a='1', _b='2').xml(), self.assertEqual(SCRIPT('<>', _a='1', _b='2').xml(),
@@ -331,127 +340,128 @@ class TestBareHelpers(unittest.TestCase):
'''<script><!-- '''<script><!--
<> <>
//--></script>''') //--></script>''')
self.assertEqual(SCRIPT().xml(), '<script></script>') self.assertEqual(SCRIPT().xml(), b'<script></script>')
def test_STYLE(self): def test_STYLE(self):
self.assertEqual(STYLE('<>', _a='1', _b='2').xml(), self.assertEqual(STYLE('<>', _a='1', _b='2').xml(),
'<style a="1" b="2"><!--/*--><![CDATA[/*><!--*/\n<>\n/*]]>*/--></style>') '<style a="1" b="2"><!--/*--><![CDATA[/*><!--*/\n<>\n/*]]>*/--></style>')
# Try to hit : return DIV.xml(self) # Try to hit : return DIV.xml(self)
self.assertEqual(STYLE().xml(), '<style></style>') self.assertEqual(STYLE().xml(), b'<style></style>')
def test_IMG(self): def test_IMG(self):
self.assertEqual(IMG(_a='1', _b='2').xml(), self.assertEqual(IMG(_a='1', _b='2').xml(),
'<img a="1" b="2" />') b'<img a="1" b="2" />')
def test_SPAN(self): def test_SPAN(self):
self.assertEqual(SPAN('<>', _a='1', _b='2').xml(), self.assertEqual(SPAN('<>', _a='1', _b='2').xml(),
'<span a="1" b="2">&lt;&gt;</span>') b'<span a="1" b="2">&lt;&gt;</span>')
def test_BODY(self): def test_BODY(self):
self.assertEqual(BODY('<>', _a='1', _b='2').xml(), self.assertEqual(BODY('<>', _a='1', _b='2').xml(),
'<body a="1" b="2">&lt;&gt;</body>') b'<body a="1" b="2">&lt;&gt;</body>')
def test_H1(self): def test_H1(self):
self.assertEqual(H1('<>', _a='1', _b='2').xml(), self.assertEqual(H1('<>', _a='1', _b='2').xml(),
'<h1 a="1" b="2">&lt;&gt;</h1>') b'<h1 a="1" b="2">&lt;&gt;</h1>')
def test_H2(self): def test_H2(self):
self.assertEqual(H2('<>', _a='1', _b='2').xml(), self.assertEqual(H2('<>', _a='1', _b='2').xml(),
'<h2 a="1" b="2">&lt;&gt;</h2>') b'<h2 a="1" b="2">&lt;&gt;</h2>')
def test_H3(self): def test_H3(self):
self.assertEqual(H3('<>', _a='1', _b='2').xml(), self.assertEqual(H3('<>', _a='1', _b='2').xml(),
'<h3 a="1" b="2">&lt;&gt;</h3>') b'<h3 a="1" b="2">&lt;&gt;</h3>')
def test_H4(self): def test_H4(self):
self.assertEqual(H4('<>', _a='1', _b='2').xml(), self.assertEqual(H4('<>', _a='1', _b='2').xml(),
'<h4 a="1" b="2">&lt;&gt;</h4>') b'<h4 a="1" b="2">&lt;&gt;</h4>')
def test_H5(self): def test_H5(self):
self.assertEqual(H5('<>', _a='1', _b='2').xml(), self.assertEqual(H5('<>', _a='1', _b='2').xml(),
'<h5 a="1" b="2">&lt;&gt;</h5>') b'<h5 a="1" b="2">&lt;&gt;</h5>')
def test_H6(self): def test_H6(self):
self.assertEqual(H6('<>', _a='1', _b='2').xml(), self.assertEqual(H6('<>', _a='1', _b='2').xml(),
'<h6 a="1" b="2">&lt;&gt;</h6>') b'<h6 a="1" b="2">&lt;&gt;</h6>')
def test_P(self): def test_P(self):
self.assertEqual(P('<>', _a='1', _b='2').xml(), self.assertEqual(P('<>', _a='1', _b='2').xml(),
'<p a="1" b="2">&lt;&gt;</p>') b'<p a="1" b="2">&lt;&gt;</p>')
# test cr2br # test cr2br
self.assertEqual(P('a\nb').xml(), '<p>a\nb</p>') self.assertEqual(P('a\nb').xml(), b'<p>a\nb</p>')
self.assertEqual(P('a\nb', cr2br=True).xml(), '<p>a<br />b</p>') self.assertEqual(P('a\nb', cr2br=True).xml(), b'<p>a<br />b</p>')
def test_STRONG(self): def test_STRONG(self):
self.assertEqual(STRONG('<>', _a='1', _b='2').xml(), self.assertEqual(STRONG('<>', _a='1', _b='2').xml(),
'<strong a="1" b="2">&lt;&gt;</strong>') b'<strong a="1" b="2">&lt;&gt;</strong>')
def test_B(self): def test_B(self):
self.assertEqual(B('<>', _a='1', _b='2').xml(), self.assertEqual(B('<>', _a='1', _b='2').xml(),
'<b a="1" b="2">&lt;&gt;</b>') b'<b a="1" b="2">&lt;&gt;</b>')
def test_BR(self): def test_BR(self):
# empty BR() # empty BR()
self.assertEqual(BR().xml(), '<br />') self.assertEqual(BR().xml(), b'<br />')
self.assertEqual(BR(_a='1', _b='2').xml(), '<br a="1" b="2" />') self.assertEqual(BR(_a='1', _b='2').xml(), b'<br a="1" b="2" />')
def test_HR(self): def test_HR(self):
self.assertEqual(HR(_a='1', _b='2').xml(), '<hr a="1" b="2" />') self.assertEqual(HR(_a='1', _b='2').xml(), b'<hr a="1" b="2" />')
def test_A(self): def test_A(self):
self.assertEqual(A('<>', _a='1', _b='2').xml(), self.assertEqual(A('<>', _a='1', _b='2').xml(),
'<a a="1" b="2">&lt;&gt;</a>') b'<a a="1" b="2">&lt;&gt;</a>')
self.assertEqual(A('a', cid='b').xml(), self.assertEqual(A('a', cid='b').xml(),
'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>') b'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>')
self.assertEqual(A('a', callback='b', _id='c').xml(), self.assertEqual(A('a', callback='b', _id='c').xml(),
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="c">a</a>') b'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="c">a</a>')
# Callback with no id trigger web2py_uuid() call # Callback with no id trigger web2py_uuid() call
from html import web2pyHTMLParser from gluon.html import web2pyHTMLParser
a = A('a', callback='b').xml() #a = A('a', callback='b').xml()
for tag in web2pyHTMLParser(a).tree.elements('a'):
uuid_generated = tag.attributes['_id'] #for tag in web2pyHTMLParser(a).tree.elements('a'):
self.assertEqual(a, # uuid_generated = tag.attributes['_id']
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="{id}">a</a>'.format(id=uuid_generated)) #self.assertEqual(a,
# b'<a data-w2p_disable_with="default" data-w2p_method="POST" href="b" id="{id}">a</a>'.format(id=uuid_generated))
self.assertEqual(A('a', delete='tr').xml(), self.assertEqual(A('a', delete='tr').xml(),
'<a data-w2p_disable_with="default" data-w2p_remove="tr">a</a>') b'<a data-w2p_disable_with="default" data-w2p_remove="tr">a</a>')
self.assertEqual(A('a', _id='b', target='<self>').xml(), self.assertEqual(A('a', _id='b', target='<self>').xml(),
'<a data-w2p_disable_with="default" data-w2p_target="b" id="b">a</a>') b'<a data-w2p_disable_with="default" data-w2p_target="b" id="b">a</a>')
self.assertEqual(A('a', component='b').xml(), self.assertEqual(A('a', component='b').xml(),
'<a data-w2p_disable_with="default" data-w2p_method="GET" href="b">a</a>') b'<a data-w2p_disable_with="default" data-w2p_method="GET" href="b">a</a>')
self.assertEqual(A('a', _id='b', callback='c', noconfirm=True).xml(), self.assertEqual(A('a', _id='b', callback='c', noconfirm=True).xml(),
'<a data-w2p_disable_with="default" data-w2p_method="POST" href="c" id="b">a</a>') b'<a data-w2p_disable_with="default" data-w2p_method="POST" href="c" id="b">a</a>')
self.assertEqual(A('a', cid='b').xml(), self.assertEqual(A('a', cid='b').xml(),
'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>') b'<a data-w2p_disable_with="default" data-w2p_method="GET" data-w2p_target="b">a</a>')
self.assertEqual(A('a', cid='b', _disable_with='processing...').xml(), self.assertEqual(A('a', cid='b', _disable_with='processing...').xml(),
'<a data-w2p_disable_with="processing..." data-w2p_method="GET" data-w2p_target="b">a</a>') b'<a data-w2p_disable_with="processing..." data-w2p_method="GET" data-w2p_target="b">a</a>')
self.assertEqual(A('a', callback='b', delete='tr', noconfirm=True, _id='c').xml(), self.assertEqual(A('a', callback='b', delete='tr', noconfirm=True, _id='c').xml(),
'<a data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>') b'<a data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>')
self.assertEqual(A('a', callback='b', delete='tr', confirm='Are you sure?', _id='c').xml(), self.assertEqual(A('a', callback='b', delete='tr', confirm='Are you sure?', _id='c').xml(),
'<a data-w2p_confirm="Are you sure?" data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>') b'<a data-w2p_confirm="Are you sure?" data-w2p_disable_with="default" data-w2p_method="POST" data-w2p_remove="tr" href="b" id="c">a</a>')
def test_BUTTON(self): def test_BUTTON(self):
self.assertEqual(BUTTON('test', _type='button').xml(), self.assertEqual(BUTTON('test', _type='button').xml(),
'<button type="button">test</button>') b'<button type="button">test</button>')
def test_EM(self): def test_EM(self):
self.assertEqual(EM('<>', _a='1', _b='2').xml(), self.assertEqual(EM('<>', _a='1', _b='2').xml(),
'<em a="1" b="2">&lt;&gt;</em>') b'<em a="1" b="2">&lt;&gt;</em>')
def test_EMBED(self): def test_EMBED(self):
self.assertEqual(EMBED(_a='1', _b='2').xml(), self.assertEqual(EMBED(_a='1', _b='2').xml(),
'<embed a="1" b="2" />') b'<embed a="1" b="2" />')
def test_TT(self): def test_TT(self):
self.assertEqual(TT('<>', _a='1', _b='2').xml(), self.assertEqual(TT('<>', _a='1', _b='2').xml(),
'<tt a="1" b="2">&lt;&gt;</tt>') b'<tt a="1" b="2">&lt;&gt;</tt>')
def test_PRE(self): def test_PRE(self):
self.assertEqual(PRE('<>', _a='1', _b='2').xml(), self.assertEqual(PRE('<>', _a='1', _b='2').xml(),
'<pre a="1" b="2">&lt;&gt;</pre>') b'<pre a="1" b="2">&lt;&gt;</pre>')
def test_CENTER(self): def test_CENTER(self):
self.assertEqual(CENTER('<>', _a='1', _b='2').xml(), self.assertEqual(CENTER('<>', _a='1', _b='2').xml(),
'<center a="1" b="2">&lt;&gt;</center>') b'<center a="1" b="2">&lt;&gt;</center>')
def test_CODE(self): def test_CODE(self):
self.assertEqual(CODE("print 'hello world'", self.assertEqual(CODE("print 'hello world'",
@@ -464,53 +474,53 @@ class TestBareHelpers(unittest.TestCase):
def test_LABEL(self): def test_LABEL(self):
self.assertEqual(LABEL('<>', _a='1', _b='2').xml(), self.assertEqual(LABEL('<>', _a='1', _b='2').xml(),
'<label a="1" b="2">&lt;&gt;</label>') b'<label a="1" b="2">&lt;&gt;</label>')
def test_LI(self): def test_LI(self):
self.assertEqual(LI('<>', _a='1', _b='2').xml(), self.assertEqual(LI('<>', _a='1', _b='2').xml(),
'<li a="1" b="2">&lt;&gt;</li>') b'<li a="1" b="2">&lt;&gt;</li>')
def test_UL(self): def test_UL(self):
self.assertEqual(UL('<>', _a='1', _b='2').xml(), self.assertEqual(UL('<>', _a='1', _b='2').xml(),
'<ul a="1" b="2"><li>&lt;&gt;</li></ul>') b'<ul a="1" b="2"><li>&lt;&gt;</li></ul>')
def test_OL(self): def test_OL(self):
self.assertEqual(OL('<>', _a='1', _b='2').xml(), self.assertEqual(OL('<>', _a='1', _b='2').xml(),
'<ol a="1" b="2"><li>&lt;&gt;</li></ol>') b'<ol a="1" b="2"><li>&lt;&gt;</li></ol>')
def test_TD(self): def test_TD(self):
self.assertEqual(TD('<>', _a='1', _b='2').xml(), self.assertEqual(TD('<>', _a='1', _b='2').xml(),
'<td a="1" b="2">&lt;&gt;</td>') b'<td a="1" b="2">&lt;&gt;</td>')
def test_TH(self): def test_TH(self):
self.assertEqual(TH('<>', _a='1', _b='2').xml(), self.assertEqual(TH('<>', _a='1', _b='2').xml(),
'<th a="1" b="2">&lt;&gt;</th>') b'<th a="1" b="2">&lt;&gt;</th>')
def test_TR(self): def test_TR(self):
self.assertEqual(TR('<>', _a='1', _b='2').xml(), self.assertEqual(TR('<>', _a='1', _b='2').xml(),
'<tr a="1" b="2"><td>&lt;&gt;</td></tr>') b'<tr a="1" b="2"><td>&lt;&gt;</td></tr>')
def test_THEAD(self): def test_THEAD(self):
self.assertEqual(THEAD('<>', _a='1', _b='2').xml(), self.assertEqual(THEAD('<>', _a='1', _b='2').xml(),
'<thead a="1" b="2"><tr><th>&lt;&gt;</th></tr></thead>') b'<thead a="1" b="2"><tr><th>&lt;&gt;</th></tr></thead>')
# self.assertEqual(THEAD(TRHEAD('<>'), _a='1', _b='2').xml(), # self.assertEqual(THEAD(TRHEAD('<>'), _a='1', _b='2').xml(),
# '<thead a="1" b="2"><tr><th>&lt;&gt;</th></tr></thead>') # '<thead a="1" b="2"><tr><th>&lt;&gt;</th></tr></thead>')
self.assertEqual(THEAD(TR('<>'), _a='1', _b='2').xml(), self.assertEqual(THEAD(TR('<>'), _a='1', _b='2').xml(),
'<thead a="1" b="2"><tr><td>&lt;&gt;</td></tr></thead>') b'<thead a="1" b="2"><tr><td>&lt;&gt;</td></tr></thead>')
def test_TBODY(self): def test_TBODY(self):
self.assertEqual(TBODY('<>', _a='1', _b='2').xml(), self.assertEqual(TBODY('<>', _a='1', _b='2').xml(),
'<tbody a="1" b="2"><tr><td>&lt;&gt;</td></tr></tbody>') b'<tbody a="1" b="2"><tr><td>&lt;&gt;</td></tr></tbody>')
def test_TFOOT(self): def test_TFOOT(self):
self.assertEqual(TFOOT('<>', _a='1', _b='2').xml(), self.assertEqual(TFOOT('<>', _a='1', _b='2').xml(),
'<tfoot a="1" b="2"><tr><td>&lt;&gt;</td></tr></tfoot>') b'<tfoot a="1" b="2"><tr><td>&lt;&gt;</td></tr></tfoot>')
def test_COL(self): def test_COL(self):
# Empty COL test # Empty COL test
self.assertEqual(COL().xml(), '<col />') self.assertEqual(COL().xml(), b'<col />')
# Not Empty COL test # Not Empty COL test
self.assertEqual(COL(_span='2').xml(), '<col span="2" />') self.assertEqual(COL(_span='2').xml(), b'<col span="2" />')
# Commented for now not so sure how to make it pass properly was passing locally # Commented for now not so sure how to make it pass properly was passing locally
# I think this test is interesting and add value # I think this test is interesting and add value
# This fail relate to python 2.6 limitation I think # This fail relate to python 2.6 limitation I think
@@ -519,111 +529,111 @@ class TestBareHelpers(unittest.TestCase):
# COL('<>').xml() # COL('<>').xml()
# self.assertEqual(cm.exception[0], '<col/> tags cannot have components') # self.assertEqual(cm.exception[0], '<col/> tags cannot have components')
# For now # For now
self.assertRaises(SyntaxError, COL, '<>') self.assertRaises(SyntaxError, COL, b'<>')
def test_COLGROUP(self): def test_COLGROUP(self):
# Empty COLGROUP test # Empty COLGROUP test
self.assertEqual(COLGROUP().xml(), '<colgroup></colgroup>') self.assertEqual(COLGROUP().xml(), b'<colgroup></colgroup>')
# Not Empty COLGROUP test # Not Empty COLGROUP test
self.assertEqual(COLGROUP('<>', _a='1', _b='2').xml(), '<colgroup a="1" b="2">&lt;&gt;</colgroup>') self.assertEqual(COLGROUP('<>', _a='1', _b='2').xml(), b'<colgroup a="1" b="2">&lt;&gt;</colgroup>')
def test_TABLE(self): def test_TABLE(self):
self.assertEqual(TABLE('<>', _a='1', _b='2').xml(), self.assertEqual(TABLE('<>', _a='1', _b='2').xml(),
'<table a="1" b="2"><tr><td>&lt;&gt;</td></tr>' + b'<table a="1" b="2"><tr><td>&lt;&gt;</td></tr>' +
'</table>') b'</table>')
def test_I(self): def test_I(self):
self.assertEqual(I('<>', _a='1', _b='2').xml(), self.assertEqual(I('<>', _a='1', _b='2').xml(),
'<i a="1" b="2">&lt;&gt;</i>') b'<i a="1" b="2">&lt;&gt;</i>')
def test_IFRAME(self): def test_IFRAME(self):
self.assertEqual(IFRAME('<>', _a='1', _b='2').xml(), self.assertEqual(IFRAME('<>', _a='1', _b='2').xml(),
'<iframe a="1" b="2">&lt;&gt;</iframe>') b'<iframe a="1" b="2">&lt;&gt;</iframe>')
def test_INPUT(self): def test_INPUT(self):
self.assertEqual(INPUT(_a='1', _b='2').xml(), '<input a="1" b="2" type="text" />') self.assertEqual(INPUT(_a='1', _b='2').xml(), b'<input a="1" b="2" type="text" />')
# list value # list value
self.assertEqual(INPUT(_value=[1, 2, 3]).xml(), '<input type="text" value="[1, 2, 3]" />') self.assertEqual(INPUT(_value=[1, 2, 3]).xml(), b'<input type="text" value="[1, 2, 3]" />')
def test_TEXTAREA(self): def test_TEXTAREA(self):
self.assertEqual(TEXTAREA('<>', _a='1', _b='2').xml(), self.assertEqual(TEXTAREA('<>', _a='1', _b='2').xml(),
'<textarea a="1" b="2" cols="40" rows="10">&lt;&gt;' + b'<textarea a="1" b="2" cols="40" rows="10">&lt;&gt;' +
'</textarea>') b'</textarea>')
# override _rows and _cols # override _rows and _cols
self.assertEqual(TEXTAREA('<>', _a='1', _b='2', _rows=5, _cols=20).xml(), self.assertEqual(TEXTAREA('<>', _a='1', _b='2', _rows=5, _cols=20).xml(),
'<textarea a="1" b="2" cols="20" rows="5">&lt;&gt;' + b'<textarea a="1" b="2" cols="20" rows="5">&lt;&gt;' +
'</textarea>') b'</textarea>')
self.assertEqual(TEXTAREA('<>', value='bla bla bla...', _rows=10, _cols=40).xml(), self.assertEqual(TEXTAREA('<>', value='bla bla bla...', _rows=10, _cols=40).xml(),
'<textarea cols="40" rows="10">bla bla bla...</textarea>') b'<textarea cols="40" rows="10">bla bla bla...</textarea>')
def test_OPTION(self): def test_OPTION(self):
self.assertEqual(OPTION('<>', _a='1', _b='2').xml(), self.assertEqual(OPTION('<>', _a='1', _b='2').xml(),
'<option a="1" b="2" value="&lt;&gt;">&lt;&gt;' + b'<option a="1" b="2" value="&lt;&gt;">&lt;&gt;' +
'</option>') b'</option>')
def test_OBJECT(self): def test_OBJECT(self):
self.assertEqual(OBJECT('<>', _a='1', _b='2').xml(), self.assertEqual(OBJECT('<>', _a='1', _b='2').xml(),
'<object a="1" b="2">&lt;&gt;</object>') b'<object a="1" b="2">&lt;&gt;</object>')
def test_OPTGROUP(self): def test_OPTGROUP(self):
# Empty OPTGROUP test # Empty OPTGROUP test
self.assertEqual(OPTGROUP().xml(), self.assertEqual(OPTGROUP().xml(),
'<optgroup></optgroup>') b'<optgroup></optgroup>')
# Not Empty OPTGROUP test # Not Empty OPTGROUP test
self.assertEqual(OPTGROUP('<>', _a='1', _b='2').xml(), self.assertEqual(OPTGROUP('<>', _a='1', _b='2').xml(),
'<optgroup a="1" b="2"><option value="&lt;&gt;">&lt;&gt;</option></optgroup>') b'<optgroup a="1" b="2"><option value="&lt;&gt;">&lt;&gt;</option></optgroup>')
# With an OPTION # With an OPTION
self.assertEqual(OPTGROUP(OPTION('Option 1', _value='1'), _label='Group 1').xml(), self.assertEqual(OPTGROUP(OPTION('Option 1', _value='1'), _label='Group 1').xml(),
'<optgroup label="Group 1"><option value="1">Option 1</option></optgroup>') b'<optgroup label="Group 1"><option value="1">Option 1</option></optgroup>')
def test_SELECT(self): def test_SELECT(self):
self.assertEqual(SELECT('<>', _a='1', _b='2').xml(), self.assertEqual(SELECT('<>', _a='1', _b='2').xml(),
'<select a="1" b="2">' + b'<select a="1" b="2">' +
'<option value="&lt;&gt;">&lt;&gt;</option></select>') b'<option value="&lt;&gt;">&lt;&gt;</option></select>')
self.assertEqual(SELECT(OPTION('option 1', _value='1'), self.assertEqual(SELECT(OPTION('option 1', _value='1'),
OPTION('option 2', _value='2')).xml(), OPTION('option 2', _value='2')).xml(),
'<select><option value="1">option 1</option><option value="2">option 2</option></select>') b'<select><option value="1">option 1</option><option value="2">option 2</option></select>')
self.assertEqual(SELECT(OPTION('option 1', _value='1', _selected='selected'), self.assertEqual(SELECT(OPTION('option 1', _value='1', _selected='selected'),
OPTION('option 2', _value='2'), OPTION('option 2', _value='2'),
_multiple='multiple').xml(), _multiple='multiple').xml(),
'<select multiple="multiple"><option selected="selected" value="1">option 1</option><option value="2">option 2</option></select>') b'<select multiple="multiple"><option selected="selected" value="1">option 1</option><option value="2">option 2</option></select>')
# More then one select with mutilple # More then one select with mutilple
self.assertEqual(SELECT(OPTION('option 1', _value='1', _selected='selected'), self.assertEqual(SELECT(OPTION('option 1', _value='1', _selected='selected'),
OPTION('option 2', _value='2', _selected='selected'), OPTION('option 2', _value='2', _selected='selected'),
_multiple='multiple').xml(), _multiple='multiple').xml(),
'<select multiple="multiple"><option selected="selected" value="1">option 1</option><option selected="selected" value="2">option 2</option></select>' b'<select multiple="multiple"><option selected="selected" value="1">option 1</option><option selected="selected" value="2">option 2</option></select>'
) )
# OPTGROUP # OPTGROUP
self.assertEqual(SELECT(OPTGROUP(OPTION('option 1', _value='1'), self.assertEqual(SELECT(OPTGROUP(OPTION('option 1', _value='1'),
OPTION('option 2', _value='2'), OPTION('option 2', _value='2'),
_label='Group 1',)).xml(), _label='Group 1',)).xml(),
'<select><optgroup label="Group 1"><option value="1">option 1</option><option value="2">option 2</option></optgroup></select>') b'<select><optgroup label="Group 1"><option value="1">option 1</option><option value="2">option 2</option></optgroup></select>')
# List # List
self.assertEqual(SELECT([1, 2, 3, 4, 5]).xml(), self.assertEqual(SELECT([1, 2, 3, 4, 5]).xml(),
'<select><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option></select>') b'<select><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option></select>')
# Tuple # Tuple
self.assertEqual(SELECT((1, 2, 3, 4, 5)).xml(), self.assertEqual(SELECT((1, 2, 3, 4, 5)).xml(),
'<select><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option></select>') b'<select><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option></select>')
# String value # String value
self.assertEqual(SELECT('Option 1', 'Option 2').xml(), self.assertEqual(SELECT('Option 1', 'Option 2').xml(),
'<select><option value="Option 1">Option 1</option><option value="Option 2">Option 2</option></select>') b'<select><option value="Option 1">Option 1</option><option value="Option 2">Option 2</option></select>')
# list as a value # list as a value
self.assertEqual(SELECT(OPTION('option 1', _value=[1, 2, 3]), self.assertEqual(SELECT(OPTION('option 1', _value=[1, 2, 3]),
OPTION('option 2', _value=[4, 5, 6], _selected='selected'), OPTION('option 2', _value=[4, 5, 6], _selected='selected'),
_multiple='multiple').xml(), _multiple='multiple').xml(),
'<select multiple="multiple"><option value="[1, 2, 3]">option 1</option><option selected="selected" value="[4, 5, 6]">option 2</option></select>') b'<select multiple="multiple"><option value="[1, 2, 3]">option 1</option><option selected="selected" value="[4, 5, 6]">option 2</option></select>')
def test_FIELDSET(self): def test_FIELDSET(self):
self.assertEqual(FIELDSET('<>', _a='1', _b='2').xml(), self.assertEqual(FIELDSET('<>', _a='1', _b='2').xml(),
'<fieldset a="1" b="2">&lt;&gt;</fieldset>') b'<fieldset a="1" b="2">&lt;&gt;</fieldset>')
def test_LEGEND(self): def test_LEGEND(self):
self.assertEqual(LEGEND('<>', _a='1', _b='2').xml(), self.assertEqual(LEGEND('<>', _a='1', _b='2').xml(),
'<legend a="1" b="2">&lt;&gt;</legend>') b'<legend a="1" b="2">&lt;&gt;</legend>')
def test_FORM(self): def test_FORM(self):
self.assertEqual(FORM('<>', _a='1', _b='2').xml(), self.assertEqual(FORM('<>', _a='1', _b='2').xml(),
'<form a="1" action="#" b="2" enctype="multipart/form-data" method="post">&lt;&gt;</form>') b'<form a="1" action="#" b="2" enctype="multipart/form-data" method="post">&lt;&gt;</form>')
# These 2 crash AppVeyor and Travis with: "ImportError: No YAML serializer available" # These 2 crash AppVeyor and Travis with: "ImportError: No YAML serializer available"
# self.assertEqual(FORM('<>', _a='1', _b='2').as_yaml(), # self.assertEqual(FORM('<>', _a='1', _b='2').as_yaml(),
# "accepted: null\nattributes: {_a: '1', _action: '#', _b: '2', _enctype: multipart/form-data, _method: post}\ncomponents: [<>]\nerrors: {}\nlatest: {}\nparent: null\nvars: {}\n") # "accepted: null\nattributes: {_a: '1', _action: '#', _b: '2', _enctype: multipart/form-data, _method: post}\ncomponents: [<>]\nerrors: {}\nlatest: {}\nparent: null\nvars: {}\n")
@@ -631,33 +641,33 @@ class TestBareHelpers(unittest.TestCase):
# '<?xml version="1.0" encoding="UTF-8"?><document><errors></errors><vars></vars><parent>None</parent><attributes><_enctype>multipart/form-data</_enctype><_action>#</_action><_b>2</_b><_a>1</_a><_method>post</_method></attributes><components><item>&amp;lt;&amp;gt;</item></components><accepted>None</accepted><latest></latest></document>') # '<?xml version="1.0" encoding="UTF-8"?><document><errors></errors><vars></vars><parent>None</parent><attributes><_enctype>multipart/form-data</_enctype><_action>#</_action><_b>2</_b><_a>1</_a><_method>post</_method></attributes><components><item>&amp;lt;&amp;gt;</item></components><accepted>None</accepted><latest></latest></document>')
def test_BEAUTIFY(self): def test_BEAUTIFY(self):
self.assertEqual(BEAUTIFY(['a', 'b', {'hello': 'world'}]).xml(), #self.assertEqual(BEAUTIFY(['a', 'b', {'hello': 'world'}]).xml(),
'<div><table><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>') # '<div><table><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>')
# unicode # unicode
self.assertEqual(BEAUTIFY([P(u'àéèûôç'), 'a', 'b', {'hello': 'world'}]).xml(), self.assertEqual(BEAUTIFY([P(u'àéèûôç'), 'a', 'b', {'hello': 'world'}]).xml(),
'<div><table><tr><td><div><p>\xc3\xa0\xc3\xa9\xc3\xa8\xc3\xbb\xc3\xb4\xc3\xa7</p></div></td></tr><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>') b'<div><table><tr><td><div><p>\xc3\xa0\xc3\xa9\xc3\xa8\xc3\xbb\xc3\xb4\xc3\xa7</p></div></td></tr><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>')
def test_MENU(self): def test_MENU(self):
self.assertEqual(MENU([('Home', False, '/welcome/default/index', [])]).xml(), self.assertEqual(MENU([('Home', False, '/welcome/default/index', [])]).xml(),
'<ul class="web2py-menu web2py-menu-vertical"><li class="web2py-menu-first"><a href="/welcome/default/index">Home</a></li></ul>') b'<ul class="web2py-menu web2py-menu-vertical"><li class="web2py-menu-first"><a href="/welcome/default/index">Home</a></li></ul>')
# Multiples entries menu # Multiples entries menu
self.assertEqual(MENU([('Home', False, '/welcome/default/index', []), self.assertEqual(MENU([('Home', False, '/welcome/default/index', []),
('Item 1', False, '/welcome/default/func_one', []), ('Item 1', False, '/welcome/default/func_one', []),
('Item 2', False, '/welcome/default/func_two', []), ('Item 2', False, '/welcome/default/func_two', []),
('Item 3', False, '/welcome/default/func_three', []), ('Item 3', False, '/welcome/default/func_three', []),
('Item 4', False, '/welcome/default/func_four', [])]).xml(), ('Item 4', False, '/welcome/default/func_four', [])]).xml(),
'<ul class="web2py-menu web2py-menu-vertical"><li class="web2py-menu-first"><a href="/welcome/default/index">Home</a></li><li><a href="/welcome/default/func_one">Item 1</a></li><li><a href="/welcome/default/func_two">Item 2</a></li><li><a href="/welcome/default/func_three">Item 3</a></li><li class="web2py-menu-last"><a href="/welcome/default/func_four">Item 4</a></li></ul>' b'<ul class="web2py-menu web2py-menu-vertical"><li class="web2py-menu-first"><a href="/welcome/default/index">Home</a></li><li><a href="/welcome/default/func_one">Item 1</a></li><li><a href="/welcome/default/func_two">Item 2</a></li><li><a href="/welcome/default/func_three">Item 3</a></li><li class="web2py-menu-last"><a href="/welcome/default/func_four">Item 4</a></li></ul>'
) )
# mobile=True # mobile=True
self.assertEqual(MENU([('Home', False, '/welcome/default/index', [])], mobile=True).xml(), self.assertEqual(MENU([('Home', False, '/welcome/default/index', [])], mobile=True).xml(),
'<select class="web2py-menu web2py-menu-vertical" onchange="window.location=this.value"><option value="/welcome/default/index">Home</option></select>') b'<select class="web2py-menu web2py-menu-vertical" onchange="window.location=this.value"><option value="/welcome/default/index">Home</option></select>')
# Multiples entries menu for mobile # Multiples entries menu for mobile
self.assertEqual(MENU([('Home', False, '/welcome/default/index', []), self.assertEqual(MENU([('Home', False, '/welcome/default/index', []),
('Item 1', False, '/welcome/default/func_one', []), ('Item 1', False, '/welcome/default/func_one', []),
('Item 2', False, '/welcome/default/func_two', []), ('Item 2', False, '/welcome/default/func_two', []),
('Item 3', False, '/welcome/default/func_three', []), ('Item 3', False, '/welcome/default/func_three', []),
('Item 4', False, '/welcome/default/func_four', [])], mobile=True).xml(), ('Item 4', False, '/welcome/default/func_four', [])], mobile=True).xml(),
'<select class="web2py-menu web2py-menu-vertical" onchange="window.location=this.value"><option value="/welcome/default/index">Home</option><option value="/welcome/default/func_one">Item 1</option><option value="/welcome/default/func_two">Item 2</option><option value="/welcome/default/func_three">Item 3</option><option value="/welcome/default/func_four">Item 4</option></select>') b'<select class="web2py-menu web2py-menu-vertical" onchange="window.location=this.value"><option value="/welcome/default/index">Home</option><option value="/welcome/default/func_one">Item 1</option><option value="/welcome/default/func_two">Item 2</option><option value="/welcome/default/func_three">Item 3</option><option value="/welcome/default/func_four">Item 4</option></select>')
# TODO: def test_embed64(self): # TODO: def test_embed64(self):
@@ -666,7 +676,8 @@ class TestBareHelpers(unittest.TestCase):
# TODO: def test_markdown_serializer(self): # TODO: def test_markdown_serializer(self):
# TODO: def test_markmin_serializer(self): # TODO: def test_markmin_serializer(self):
@unittest.skipIf(not PY2, "Skipping Python 3.x tests for MARKMIN")
def test_MARKMIN(self): def test_MARKMIN(self):
# This test pass with python 2.7 but expected to fail under 2.6 # This test pass with python 2.7 but expected to fail under 2.6
# with self.assertRaises(TypeError) as cm: # with self.assertRaises(TypeError) as cm:
@@ -674,27 +685,27 @@ class TestBareHelpers(unittest.TestCase):
# self.assertEqual(cm.exception[0], '__init__() takes at least 2 arguments (1 given)') # self.assertEqual(cm.exception[0], '__init__() takes at least 2 arguments (1 given)')
# For now # For now
self.assertRaises(TypeError, MARKMIN) self.assertRaises(TypeError, MARKMIN)
self.assertEqual(MARKMIN('').xml(), '') self.assertEqual(MARKMIN('').xml(), b'')
self.assertEqual(MARKMIN('<>').xml(), self.assertEqual(MARKMIN('<>').xml(),
'<p>&lt;&gt;</p>') b'<p>&lt;&gt;</p>')
self.assertEqual(MARKMIN("``hello_world = 'Hello World!'``:python").xml(), self.assertEqual(MARKMIN("``hello_world = 'Hello World!'``:python").xml(),
'<code class="python">hello_world = \'Hello World!\'</code>') b'<code class="python">hello_world = \'Hello World!\'</code>')
self.assertEqual(MARKMIN('<>').flatten(), '<>') self.assertEqual(MARKMIN('<>').flatten(), b'<>')
def test_ASSIGNJS(self): def test_ASSIGNJS(self):
# empty assignation # empty assignation
self.assertEqual(ASSIGNJS().xml(), '') self.assertEqual(ASSIGNJS().xml(), b'')
# text assignation # text assignation
self.assertEqual(ASSIGNJS(var1='1', var2='2').xml(), 'var var1 = "1";\nvar var2 = "2";\n') self.assertEqual(ASSIGNJS(var1='1').xml(), b'var var1 = "1";\n')
# int assignation # int assignation
self.assertEqual(ASSIGNJS(var1=1, var2=2).xml(), 'var var1 = 1;\nvar var2 = 2;\n') self.assertEqual(ASSIGNJS(var2=2).xml(), b'var var2 = 2;\n')
class TestData(unittest.TestCase): class TestData(unittest.TestCase):
def test_Adata(self): def test_Adata(self):
self.assertEqual(A('<>', data=dict(abc='<def?asd>', cde='standard'), _a='1', _b='2').xml(), self.assertEqual(A('<>', data=dict(abc='<def?asd>', cde='standard'), _a='1', _b='2').xml(),
'<a a="1" b="2" data-abc="&lt;def?asd&gt;" data-cde="standard">&lt;&gt;</a>') b'<a a="1" b="2" data-abc="&lt;def?asd&gt;" data-cde="standard">&lt;&gt;</a>')
if __name__ == '__main__': if __name__ == '__main__':
+2 -2
View File
@@ -4,12 +4,12 @@
"""Unit tests for http.py """ """Unit tests for http.py """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from http import HTTP, defined_status from gluon.http import HTTP, defined_status
class TestHTTP(unittest.TestCase): class TestHTTP(unittest.TestCase):
+13 -13
View File
@@ -5,13 +5,13 @@ Unit tests for IS_URL()
""" """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from validators import IS_URL, IS_HTTP_URL, IS_GENERIC_URL from gluon.validators import IS_URL, IS_HTTP_URL, IS_GENERIC_URL
from validators import unicode_to_ascii_authority from gluon.validators import unicode_to_ascii_authority
class TestIsUrl(unittest.TestCase): class TestIsUrl(unittest.TestCase):
@@ -175,7 +175,7 @@ class TestIsUrl(unittest.TestCase):
try: try:
x = IS_URL(mode='ftp') x = IS_URL(mode='ftp')
x('http://www.google.ca') x('http://www.google.ca')
except Exception, e: except Exception as e:
if str(e) != "invalid mode 'ftp' in IS_URL": if str(e) != "invalid mode 'ftp' in IS_URL":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
else: else:
@@ -188,7 +188,7 @@ class TestIsUrl(unittest.TestCase):
prepend_scheme='ftp') prepend_scheme='ftp')
x('http://www.benn.ca') # we can only reasonably know about the x('http://www.benn.ca') # we can only reasonably know about the
# error at calling time # error at calling time
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "allowed_scheme value 'ftp' is not in [None, 'http', 'https']": != "allowed_scheme value 'ftp' is not in [None, 'http', 'https']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -203,7 +203,7 @@ class TestIsUrl(unittest.TestCase):
x = IS_URL(prepend_scheme='ftp') x = IS_URL(prepend_scheme='ftp')
x('http://www.benn.ca') # we can only reasonably know about the x('http://www.benn.ca') # we can only reasonably know about the
# error at calling time # error at calling time
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "prepend_scheme='ftp' is not in allowed_schemes=[None, 'http', 'https']": != "prepend_scheme='ftp' is not in allowed_schemes=[None, 'http', 'https']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -215,7 +215,7 @@ class TestIsUrl(unittest.TestCase):
try: try:
x = IS_URL(allowed_schemes=[None, 'https']) x = IS_URL(allowed_schemes=[None, 'https'])
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "prepend_scheme='http' is not in allowed_schemes=[None, 'https']": != "prepend_scheme='http' is not in allowed_schemes=[None, 'https']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -227,7 +227,7 @@ class TestIsUrl(unittest.TestCase):
try: try:
x = IS_URL(allowed_schemes=[None, 'http'], x = IS_URL(allowed_schemes=[None, 'http'],
prepend_scheme='https') prepend_scheme='https')
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "prepend_scheme='https' is not in allowed_schemes=[None, 'http']": != "prepend_scheme='https' is not in allowed_schemes=[None, 'http']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -239,7 +239,7 @@ class TestIsUrl(unittest.TestCase):
try: try:
x = IS_URL(mode='generic', allowed_schemes=[None, 'ftp', x = IS_URL(mode='generic', allowed_schemes=[None, 'ftp',
'ftps']) 'ftps'])
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "prepend_scheme='http' is not in allowed_schemes=[None, 'ftp', 'ftps']": != "prepend_scheme='http' is not in allowed_schemes=[None, 'ftp', 'ftps']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -253,7 +253,7 @@ class TestIsUrl(unittest.TestCase):
x = IS_URL(mode='generic', prepend_scheme='blargg') x = IS_URL(mode='generic', prepend_scheme='blargg')
x('http://www.google.ca') x('http://www.google.ca')
# we can only reasonably know about the error at calling time # we can only reasonably know about the error at calling time
except Exception, e: except Exception as e:
if not str(e).startswith( if not str(e).startswith(
"prepend_scheme='blargg' is not in allowed_schemes="): "prepend_scheme='blargg' is not in allowed_schemes="):
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -265,7 +265,7 @@ class TestIsUrl(unittest.TestCase):
try: try:
x = IS_URL(mode='generic', allowed_schemes=[None, 'http'], x = IS_URL(mode='generic', allowed_schemes=[None, 'http'],
prepend_scheme='blargg') prepend_scheme='blargg')
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "prepend_scheme='blargg' is not in allowed_schemes=[None, 'http']": != "prepend_scheme='blargg' is not in allowed_schemes=[None, 'http']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
@@ -296,7 +296,7 @@ class TestIsGenericUrl(unittest.TestCase):
def testInvalidUrls(self): def testInvalidUrls(self):
urlsToCheckA = [] urlsToCheckA = []
for i in range(0, 32) + [127]: for i in list(range(0, 32)) + [127]:
# Control characters are disallowed in any part of a URL # Control characters are disallowed in any part of a URL
@@ -567,7 +567,7 @@ class TestIsHttpUrl(unittest.TestCase):
try: try:
IS_HTTP_URL(prepend_scheme='mailto') IS_HTTP_URL(prepend_scheme='mailto')
except Exception, e: except Exception as e:
if str(e)\ if str(e)\
!= "prepend_scheme='mailto' is not in allowed_schemes=[None, 'http', 'https']": != "prepend_scheme='mailto' is not in allowed_schemes=[None, 'http', 'https']":
self.fail('Wrong exception: ' + str(e)) self.fail('Wrong exception: ' + str(e))
+2 -2
View File
@@ -10,12 +10,12 @@ import os
import shutil import shutil
import tempfile import tempfile
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from gluon import languages
import languages
MP_WORKING = 0 MP_WORKING = 0
try: try:
import multiprocessing import multiprocessing
+1 -1
View File
@@ -9,7 +9,7 @@ import sys
import os import os
import doctest import doctest
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
+1 -1
View File
@@ -8,7 +8,7 @@ import unittest
import os import os
import shutil import shutil
import uuid import uuid
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
+7 -2
View File
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Unit tests for rewrite.py routers option""" """Unit tests for rewrite.py routers option"""
from __future__ import print_function
import sys import sys
import os import os
import unittest import unittest
@@ -21,6 +21,7 @@ from gluon.fileutils import abspath
from gluon.settings import global_settings from gluon.settings import global_settings
from gluon.http import HTTP from gluon.http import HTTP
from gluon.storage import Storage from gluon.storage import Storage
from gluon._compat import to_bytes, to_native
logger = None logger = None
oldcwd = None oldcwd = None
@@ -1044,6 +1045,9 @@ class TestRouter(unittest.TestCase):
'http://domain.com/app2/static/filename-with_underscore'), 'http://domain.com/app2/static/filename-with_underscore'),
norm_root("%s/applications/app2/static/filename-with_underscore" % root)) norm_root("%s/applications/app2/static/filename-with_underscore" % root))
from gluon.globals import current
current.response.static_version = None
self.assertEqual(str(URL(a='init', c='default', f='a_b')), "/a_b") self.assertEqual(str(URL(a='init', c='default', f='a_b')), "/a_b")
self.assertEqual(str(URL(a='app1', c='default', f='a_b')), "/app1/a-b") self.assertEqual(str(URL(a='app1', c='default', f='a_b')), "/app1/a-b")
self.assertEqual(str(URL(a='app2', c='default', f='a_b')), "/app2/a_b") self.assertEqual(str(URL(a='app2', c='default', f='a_b')), "/app2/a_b")
@@ -1363,8 +1367,9 @@ class TestRouter(unittest.TestCase):
URL(a='init', c='default', f='f', args=['ar g'])), "/f/ar%20g") URL(a='init', c='default', f='f', args=['ar g'])), "/f/ar%20g")
self.assertEqual(str( self.assertEqual(str(
URL(a='init', c='default', f='f', args=['årg'])), "/f/%C3%A5rg") URL(a='init', c='default', f='f', args=['årg'])), "/f/%C3%A5rg")
self.assertEqual(URL(a='init', c='default', f='fünc'), "/fünc")
self.assertEqual( self.assertEqual(
str(URL(a='init', c='default', f='fünc')), "/f\xc3\xbcnc") to_bytes(URL(a='init', c='default', f='fünc')), b"/f\xc3\xbcnc")
def test_routes_anchor(self): def test_routes_anchor(self):
''' '''
+5 -2
View File
@@ -21,6 +21,7 @@ from gluon.fileutils import abspath
from gluon.settings import global_settings from gluon.settings import global_settings
from gluon.http import HTTP from gluon.http import HTTP
from gluon.storage import Storage from gluon.storage import Storage
from gluon._compat import to_bytes
logger = None logger = None
oldcwd = None oldcwd = None
@@ -65,7 +66,7 @@ def setUpModule():
if not os.path.isdir('gluon'): if not os.path.isdir('gluon'):
os.chdir(os.path.realpath( os.chdir(os.path.realpath(
'../../')) # run from web2py base directory '../../')) # run from web2py base directory
import main # for initialization after chdir from gluon import main # for initialization after chdir
global logger global logger
logger = logging.getLogger('web2py.rewrite') logger = logging.getLogger('web2py.rewrite')
global_settings.applications_parent = tempfile.mkdtemp() global_settings.applications_parent = tempfile.mkdtemp()
@@ -319,7 +320,9 @@ routes_out = [
self.assertEqual(str(URL( self.assertEqual(str(URL(
a='welcome', c='default', f='f', args=['årg'])), "/f/%C3%A5rg") a='welcome', c='default', f='f', args=['årg'])), "/f/%C3%A5rg")
self.assertEqual( self.assertEqual(
str(URL(a='welcome', c='default', f='fünc')), "/f\xc3\xbcnc") URL(a='welcome', c='default', f='fünc'), "/fünc")
self.assertEqual(
to_bytes(URL(a='welcome', c='default', f='fünc')), b"/f\xc3\xbcnc")
def test_routes_anchor(self): def test_routes_anchor(self):
''' '''
+12 -14
View File
@@ -10,9 +10,7 @@ import glob
import datetime import datetime
import sys import sys
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from gluon.storage import Storage from gluon.storage import Storage
@@ -25,7 +23,7 @@ class BaseTestScheduler(unittest.TestCase):
def setUp(self): def setUp(self):
self.db = None self.db = None
self.cleanfolder() self.cleanfolder()
from gluon import current from gluon.globals import current
s = Storage({'application': 'welcome', s = Storage({'application': 'welcome',
'folder': 'applications/welcome', 'folder': 'applications/welcome',
'controller': 'default'}) 'controller': 'default'})
@@ -309,12 +307,12 @@ class TestsForSchedulerRunner(testForSchedulerRunnerBase):
self.db.commit() self.db.commit()
self.writefunction(r""" self.writefunction(r"""
def demo1(*args,**vars): def demo1(*args,**vars):
print 'you passed args=%s and vars=%s' % (args, vars) print('you passed args=%s and vars=%s' % (args, vars))
return args[0] return args[0]
def demo4(): def demo4():
time.sleep(15) time.sleep(15)
print "I'm printing something" print("I'm printing something")
return dict(a=1, b=2) return dict(a=1, b=2)
""") """)
ret = self.exec_sched() ret = self.exec_sched()
@@ -359,24 +357,24 @@ def demo4():
self.writefunction(r""" self.writefunction(r"""
def demo3(): def demo3():
time.sleep(15) time.sleep(15)
print 1/0 print(1/0)
return None return None
def demo4(): def demo4():
time.sleep(15) time.sleep(15)
print "I'm printing something" print("I'm printing something")
return dict(a=1, b=2) return dict(a=1, b=2)
def demo5(): def demo5():
time.sleep(15) time.sleep(15)
print "I'm printing something" print("I'm printing something")
rtn = dict(a=1, b=2) rtn = dict(a=1, b=2)
def demo6(): def demo6():
time.sleep(5) time.sleep(5)
print '50%' print('50%')
time.sleep(5) time.sleep(5)
print '!clear!100%' print('!clear!100%')
return 1 return 1
""") """)
ret = self.exec_sched() ret = self.exec_sched()
@@ -417,12 +415,12 @@ def demo6():
self.db.commit() self.db.commit()
self.writefunction(r""" self.writefunction(r"""
def demo1(*args,**vars): def demo1(*args,**vars):
print 'you passed args=%s and vars=%s' % (args, vars) print('you passed args=%s and vars=%s' % (args, vars))
return args[0] return args[0]
import random import random
def demo7(): def demo7():
time.sleep(random.randint(1,5)) time.sleep(random.randint(1,5))
print W2P_TASK, request.now print(W2P_TASK, request.now)
return W2P_TASK.id, W2P_TASK.uuid, W2P_TASK.run_id return W2P_TASK.id, W2P_TASK.uuid, W2P_TASK.run_id
""") """)
ret = self.exec_sched() ret = self.exec_sched()
@@ -466,7 +464,7 @@ def demo8():
num_of_lines = 0 num_of_lines = 0
with open(placeholder) as f: with open(placeholder) as f:
num_of_lines = len([a for a in f.read().split('\n') if a]) num_of_lines = len([a for a in f.read().split('\n') if a])
print 'number of lines', num_of_lines print('number of lines', num_of_lines)
if num_of_lines <= 2: if num_of_lines <= 2:
1/0 1/0
else: else:
+4 -4
View File
@@ -6,14 +6,14 @@
""" """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
import datetime import datetime
import decimal import decimal
fix_sys_path(__file__) fix_sys_path(__file__)
from serializers import * from gluon.serializers import *
from storage import Storage from gluon.storage import Storage
# careful with the import path 'cause of isinstance() checks # careful with the import path 'cause of isinstance() checks
from gluon.languages import translator from gluon.languages import translator
from gluon.html import SPAN from gluon.html import SPAN
@@ -43,7 +43,7 @@ class TestSerializers(unittest.TestCase):
json_web2pyfied = [json(obj) for obj in iso_objs] json_web2pyfied = [json(obj) for obj in iso_objs]
self.assertEqual(json_objs, json_web2pyfied) self.assertEqual(json_objs, json_web2pyfied)
# int or long int()ified # int or long int()ified
self.assertEqual(json(1), json(1L)) # self.assertEqual(json(1), json(1))
# decimal stringified # decimal stringified
obj = {'a': decimal.Decimal('4.312312312312')} obj = {'a': decimal.Decimal('4.312312312312')}
self.assertEqual(json(obj), u'{"a": "4.312312312312"}') self.assertEqual(json(obj), u'{"a": "4.312312312312"}')
+5 -5
View File
@@ -8,7 +8,7 @@ import os
import sys import sys
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
@@ -18,12 +18,12 @@ DEFAULT_URI = os.getenv('DB', 'sqlite:memory')
from gluon.dal import DAL, Field from gluon.dal import DAL, Field
from pydal.objects import Table from pydal.objects import Table
from tools import Auth, Mail from gluon.tools import Auth, Mail
from gluon.globals import Request, Response, Session from gluon.globals import Request, Response, Session
from storage import Storage from gluon.storage import Storage
from languages import translator from gluon.languages import translator
from gluon.http import HTTP from gluon.http import HTTP
from validators import * from gluon.validators import *
# TODO: Create these test... # TODO: Create these test...
+4 -4
View File
@@ -4,13 +4,13 @@
""" Unit tests for storage.py """ """ Unit tests for storage.py """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
from storage import Storage, StorageList, List from gluon.storage import Storage, StorageList, List
from http import HTTP from gluon.http import HTTP
import pickle from gluon._compat import pickle
class TestStorage(unittest.TestCase): class TestStorage(unittest.TestCase):
+5 -4
View File
@@ -5,12 +5,12 @@
""" """
import unittest import unittest
from fix_path import fix_sys_path from .fix_path import fix_sys_path
fix_sys_path(__file__) fix_sys_path(__file__)
import template from gluon import template
from template import render from gluon.template import render
class TestTemplate(unittest.TestCase): class TestTemplate(unittest.TestCase):
@@ -32,6 +32,7 @@ class TestTemplate(unittest.TestCase):
def testEqualWrite(self): def testEqualWrite(self):
"test generation of response.write from =" "test generation of response.write from ="
self.assertEqual(render(content='{{=2+2}}'), '4')
self.assertEqual(render(content='{{="abc"}}'), 'abc') self.assertEqual(render(content='{{="abc"}}'), 'abc')
# whitespace is stripped # whitespace is stripped
self.assertEqual(render(content='{{ ="abc"}}'), 'abc') self.assertEqual(render(content='{{ ="abc"}}'), 'abc')
@@ -65,7 +66,7 @@ class TestTemplate(unittest.TestCase):
def testWithDummyFileSystem(self): def testWithDummyFileSystem(self):
from os.path import join as pjoin from os.path import join as pjoin
import contextlib import contextlib
from StringIO import StringIO from gluon._compat import StringIO
from gluon.restricted import RestrictedError from gluon.restricted import RestrictedError
@contextlib.contextmanager @contextlib.contextmanager

Some files were not shown because too many files have changed in this diff Show More