merge with the single-source branch
This commit is contained in:
commit
9b14fbfb08
|
@ -4,13 +4,11 @@
|
|||
sources = """
|
||||
@SOURCES@"""
|
||||
|
||||
import sys, base64, zlib, cPickle
|
||||
|
||||
sources = cPickle.loads(zlib.decompress(base64.decodestring(sources)))
|
||||
import sys, base64, zlib
|
||||
|
||||
|
||||
class DictImporter(object):
|
||||
sources = sources
|
||||
sources = None
|
||||
|
||||
def find_module(self, fullname, path=None):
|
||||
if fullname in self.sources:
|
||||
|
@ -34,7 +32,7 @@ class DictImporter(object):
|
|||
if is_pkg:
|
||||
module.__path__ = [fullname]
|
||||
|
||||
exec co in module.__dict__
|
||||
do_exec(co, module.__dict__)
|
||||
return sys.modules[fullname]
|
||||
|
||||
def get_source(self, name):
|
||||
|
@ -44,7 +42,19 @@ class DictImporter(object):
|
|||
return res
|
||||
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
import pickle
|
||||
exec("def do_exec(co, loc): exec(co, loc)\n")
|
||||
sources = sources.encode("ascii") # ensure bytes
|
||||
d = zlib.decompress(base64.decodebytes(sources))
|
||||
sources = pickle.loads(zlib.decompress(base64.decodebytes(sources)), encoding="utf-8")
|
||||
else:
|
||||
import cPickle as pickle
|
||||
exec("def do_exec(co, loc): exec co in loc\n")
|
||||
sources = pickle.loads(zlib.decompress(base64.decodestring(sources)))
|
||||
|
||||
importer = DictImporter()
|
||||
importer.sources = sources
|
||||
sys.meta_path.append(importer)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
__version_info__ = (0, 4, 1)
|
||||
version = __version__ = "0.4.1"
|
||||
__version_info__ = (0, 5, 0)
|
||||
version = __version__ = "0.5.0"
|
||||
|
|
|
@ -23,7 +23,6 @@ import cgi
|
|||
import email.utils
|
||||
import functools
|
||||
import hmac
|
||||
import httplib
|
||||
import imp
|
||||
import itertools
|
||||
import mimetypes
|
||||
|
@ -32,29 +31,41 @@ import re
|
|||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import thread
|
||||
if sys.version_info >= (3,0):
|
||||
import _thread as thread
|
||||
else:
|
||||
import thread
|
||||
import threading
|
||||
import time
|
||||
import warnings
|
||||
|
||||
from Cookie import SimpleCookie
|
||||
if sys.version_info >= (3,0):
|
||||
from http.cookies import SimpleCookie
|
||||
else:
|
||||
from Cookie import SimpleCookie
|
||||
from tempfile import TemporaryFile
|
||||
from traceback import format_exc
|
||||
from urlparse import urlunsplit, urljoin, SplitResult as UrlSplitResult
|
||||
|
||||
# Workaround for a bug in some versions of lib2to3 (fixed on CPython 2.7 and 3.2)
|
||||
import urllib
|
||||
urlencode = urllib.urlencode
|
||||
urlquote = urllib.quote
|
||||
urlunquote = urllib.unquote
|
||||
if sys.version_info >= (3,0):
|
||||
from urllib.parse import urlunsplit, urljoin, SplitResult as UrlSplitResult
|
||||
else:
|
||||
from urlparse import urlunsplit, urljoin, SplitResult as UrlSplitResult
|
||||
|
||||
if sys.version_info >= (3,0):
|
||||
from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote
|
||||
else:
|
||||
from urllib import urlencode, quote as urlquote, unquote as urlunquote
|
||||
|
||||
try: from collections import MutableMapping as DictMixin
|
||||
except ImportError: # pragma: no cover
|
||||
from UserDict import DictMixin
|
||||
|
||||
try: from urlparse import parse_qs
|
||||
except ImportError: # pragma: no cover
|
||||
from cgi import parse_qs
|
||||
if sys.version_info >= (3,0):
|
||||
from urllib.parse import parse_qs
|
||||
else:
|
||||
try: from urlparse import parse_qs
|
||||
except ImportError: # pragma: no cover
|
||||
from cgi import parse_qs
|
||||
|
||||
try: import cPickle as pickle
|
||||
except ImportError: # pragma: no cover
|
||||
|
@ -68,8 +79,18 @@ except ImportError: # pragma: no cover
|
|||
except ImportError: # pragma: no cover
|
||||
json_dumps = None
|
||||
|
||||
try:
|
||||
next
|
||||
except NameError:
|
||||
def next(it):
|
||||
return it.next()
|
||||
|
||||
|
||||
NCTextIOWrapper = None
|
||||
if sys.version_info >= (3,0,0): # pragma: no cover
|
||||
imap = map
|
||||
basestring = str
|
||||
unicode = str
|
||||
# See Request.POST
|
||||
from io import BytesIO
|
||||
def touni(x, enc='utf8', err='strict'):
|
||||
|
@ -82,6 +103,7 @@ if sys.version_info >= (3,0,0): # pragma: no cover
|
|||
the wrapped buffer. This subclass keeps it open. '''
|
||||
def close(self): pass
|
||||
else:
|
||||
imap = itertools.imap
|
||||
from StringIO import StringIO as BytesIO
|
||||
bytes = str
|
||||
def touni(x, enc='utf8', err='strict'):
|
||||
|
@ -287,7 +309,7 @@ class Router(object):
|
|||
parts = [p.replace('\\:',':') for p in token[::3]]
|
||||
names = token[1::3]
|
||||
if len(parts) > len(names): names.append(None)
|
||||
pairs = zip(parts, names)
|
||||
pairs = list(zip(parts, names))
|
||||
self.named[_name] = (rule, pairs)
|
||||
try:
|
||||
anon = list(anon)
|
||||
|
@ -297,7 +319,8 @@ class Router(object):
|
|||
except IndexError:
|
||||
msg = "Not enough arguments to fill out anonymous wildcards."
|
||||
raise RouteBuildError(msg)
|
||||
except KeyError, e:
|
||||
except KeyError:
|
||||
e = sys.exc_info()[1]
|
||||
raise RouteBuildError(*e.args)
|
||||
|
||||
if args: url += ['?', urlencode(args)]
|
||||
|
@ -367,10 +390,12 @@ class Router(object):
|
|||
combined = '%s|(%s)' % (self.dynamic[-1][0].pattern, fpat)
|
||||
self.dynamic[-1] = (re.compile(combined), self.dynamic[-1][1])
|
||||
self.dynamic[-1][1].append((gpat, target))
|
||||
except (AssertionError, IndexError), e: # AssertionError: Too many groups
|
||||
except (AssertionError, IndexError): # AssertionError: Too many groups
|
||||
e = sys.exc_info()[1]
|
||||
self.dynamic.append((re.compile('(^%s$)'%fpat),
|
||||
[(gpat, target)]))
|
||||
except re.error, e:
|
||||
except re.error:
|
||||
e = sys.exc_info()[1]
|
||||
raise RouteSyntaxError("Could not add Route: %s (%s)" % (rule, e))
|
||||
|
||||
def _compile_pattern(self, rule):
|
||||
|
@ -433,7 +458,7 @@ class Bottle(object):
|
|||
'''
|
||||
if not isinstance(app, Bottle):
|
||||
raise TypeError('Only Bottle instances are supported for now.')
|
||||
prefix = '/'.join(filter(None, prefix.split('/')))
|
||||
prefix = '/'.join([x for x in prefix.split('/') if x])
|
||||
if not prefix:
|
||||
raise TypeError('Empty prefix. Perhaps you want a merge()?')
|
||||
for other in self.mounts:
|
||||
|
@ -654,14 +679,16 @@ class Bottle(object):
|
|||
try:
|
||||
callback, args = self._match(environ)
|
||||
return callback(**args)
|
||||
except HTTPResponse, r:
|
||||
except HTTPResponse:
|
||||
r = sys.exc_info()[1]
|
||||
return r
|
||||
except RouteReset: # Route reset requested by the callback or a plugin.
|
||||
del self.ccache[handle]
|
||||
return self._handle(environ) # Try again.
|
||||
except (KeyboardInterrupt, SystemExit, MemoryError):
|
||||
raise
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
e = sys.exc_info()[1]
|
||||
if not self.catchall: raise
|
||||
return HTTPError(500, "Internal Server Error", e, format_exc(10))
|
||||
|
||||
|
@ -708,14 +735,16 @@ class Bottle(object):
|
|||
# Handle Iterables. We peek into them to detect their inner type.
|
||||
try:
|
||||
out = iter(out)
|
||||
first = out.next()
|
||||
first = next(out)
|
||||
while not first:
|
||||
first = out.next()
|
||||
first = next(out)
|
||||
except StopIteration:
|
||||
return self._cast('', request, response)
|
||||
except HTTPResponse, e:
|
||||
except HTTPResponse:
|
||||
e = sys.exc_info()[1]
|
||||
first = e
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
e = sys.exc_info()[1]
|
||||
first = HTTPError(500, 'Unhandled exception', e, format_exc(10))
|
||||
if isinstance(e, (KeyboardInterrupt, SystemExit, MemoryError))\
|
||||
or not self.catchall:
|
||||
|
@ -726,8 +755,8 @@ class Bottle(object):
|
|||
if isinstance(first, bytes):
|
||||
return itertools.chain([first], out)
|
||||
if isinstance(first, unicode):
|
||||
return itertools.imap(lambda x: x.encode(response.charset),
|
||||
itertools.chain([first], out))
|
||||
return imap(lambda x: x.encode(response.charset),
|
||||
itertools.chain([first], out))
|
||||
return self._cast(HTTPError(500, 'Unsupported response type: %s'\
|
||||
% type(first)), request, response)
|
||||
|
||||
|
@ -748,7 +777,8 @@ class Bottle(object):
|
|||
return out
|
||||
except (KeyboardInterrupt, SystemExit, MemoryError):
|
||||
raise
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
e = sys.exc_info()[1]
|
||||
if not self.catchall: raise
|
||||
err = '<h1>Critical error while processing request: %s</h1>' \
|
||||
% environ.get('PATH_INFO', '/')
|
||||
|
@ -818,7 +848,7 @@ class Request(threading.local, DictMixin):
|
|||
def __delitem__(self, key): self[key] = ""; del(self.environ[key])
|
||||
def __iter__(self): return iter(self.environ)
|
||||
def __len__(self): return len(self.environ)
|
||||
def keys(self): return self.environ.keys()
|
||||
def keys(self): return list(self.environ.keys())
|
||||
def __setitem__(self, key, value):
|
||||
""" Shortcut for Request.environ.__setitem__ """
|
||||
self.environ[key] = value
|
||||
|
@ -888,7 +918,7 @@ class Request(threading.local, DictMixin):
|
|||
""" The QUERY_STRING parsed into an instance of :class:`MultiDict`. """
|
||||
data = parse_qs(self.query_string, keep_blank_values=True)
|
||||
get = self.environ['bottle.get'] = MultiDict()
|
||||
for key, values in data.iteritems():
|
||||
for key, values in data.items():
|
||||
for value in values:
|
||||
get[key] = value
|
||||
return get
|
||||
|
@ -989,7 +1019,7 @@ class Request(threading.local, DictMixin):
|
|||
"""
|
||||
raw_dict = SimpleCookie(self.headers.get('Cookie',''))
|
||||
cookies = {}
|
||||
for cookie in raw_dict.itervalues():
|
||||
for cookie in raw_dict.values():
|
||||
cookies[cookie.key] = cookie.value
|
||||
return cookies
|
||||
|
||||
|
@ -1104,7 +1134,7 @@ class Response(threading.local):
|
|||
raise TypeError('Secret missing for non-string Cookie.')
|
||||
|
||||
self.COOKIES[key] = value
|
||||
for k, v in kargs.iteritems():
|
||||
for k, v in kargs.items():
|
||||
self.COOKIES[key][k.replace('_', '-')] = v
|
||||
|
||||
def delete_cookie(self, key, **kwargs):
|
||||
|
@ -1285,14 +1315,14 @@ class MultiDict(DictMixin):
|
|||
# collections.MutableMapping would be better for Python >= 2.6
|
||||
def __init__(self, *a, **k):
|
||||
self.dict = dict()
|
||||
for k, v in dict(*a, **k).iteritems():
|
||||
for k, v in dict(*a, **k).items():
|
||||
self[k] = v
|
||||
|
||||
def __len__(self): return len(self.dict)
|
||||
def __iter__(self): return iter(self.dict)
|
||||
def __contains__(self, key): return key in self.dict
|
||||
def __delitem__(self, key): del self.dict[key]
|
||||
def keys(self): return self.dict.keys()
|
||||
def keys(self): return list(self.dict.keys())
|
||||
def __getitem__(self, key): return self.get(key, KeyError, -1)
|
||||
def __setitem__(self, key, value): self.append(key, value)
|
||||
|
||||
|
@ -1306,7 +1336,7 @@ class MultiDict(DictMixin):
|
|||
return self.dict[key][index]
|
||||
|
||||
def iterallitems(self):
|
||||
for key, values in self.dict.iteritems():
|
||||
for key, values in self.dict.items():
|
||||
for value in values:
|
||||
yield key, value
|
||||
|
||||
|
@ -1615,7 +1645,7 @@ def validate(**vkargs):
|
|||
"""
|
||||
def decorator(func):
|
||||
def wrapper(**kargs):
|
||||
for key, value in vkargs.iteritems():
|
||||
for key, value in vkargs.items():
|
||||
if key not in kargs:
|
||||
abort(403, 'Missing parameter: %s' % key)
|
||||
try:
|
||||
|
@ -1751,8 +1781,8 @@ class FapwsServer(ServerAdapter):
|
|||
evwsgi.start(self.host, port)
|
||||
# fapws3 never releases the GIL. Complain upstream. I tried. No luck.
|
||||
if 'BOTTLE_CHILD' in os.environ and not self.quiet:
|
||||
print "WARNING: Auto-reloading does not work with Fapws3."
|
||||
print " (Fapws3 breaks python thread support)"
|
||||
sys.stdout.write("WARNING: Auto-reloading does not work with Fapws3.\n")
|
||||
sys.stdout.write(" (Fapws3 breaks python thread support)\n")
|
||||
evwsgi.set_base_module(base)
|
||||
def app(environ, start_response):
|
||||
environ['wsgi.multiprocess'] = False
|
||||
|
@ -1976,10 +2006,9 @@ def run(app=None, server='wsgiref', host='127.0.0.1', port=8080,
|
|||
raise RuntimeError("Server must be a subclass of ServerAdapter")
|
||||
server.quiet = server.quiet or quiet
|
||||
if not server.quiet and not os.environ.get('BOTTLE_CHILD'):
|
||||
print "Bottle server starting up (using %s)..." % repr(server)
|
||||
print "Listening on http://%s:%d/" % (server.host, server.port)
|
||||
print "Use Ctrl-C to quit."
|
||||
print
|
||||
sys.stdout.write("Bottle server starting up (using %s)...\n" % repr(server))
|
||||
sys.stdout.write("Listening on http://%s:%d/\n" % (server.host, server.port))
|
||||
sys.stdout.write("Use Ctrl-C to quit.\n\n")
|
||||
try:
|
||||
if reloader:
|
||||
interval = min(interval, 1)
|
||||
|
@ -1992,7 +2021,7 @@ def run(app=None, server='wsgiref', host='127.0.0.1', port=8080,
|
|||
except KeyboardInterrupt:
|
||||
pass
|
||||
if not server.quiet and not os.environ.get('BOTTLE_CHILD'):
|
||||
print "Shutting down..."
|
||||
sys.stdout.write("Shutting down...\n")
|
||||
|
||||
|
||||
class FileCheckerThread(threading.Thread):
|
||||
|
@ -2014,7 +2043,7 @@ class FileCheckerThread(threading.Thread):
|
|||
if path[-4:] in ('.pyo', '.pyc'): path = path[:-1]
|
||||
if path and exists(path): files[path] = mtime(path)
|
||||
while not self.status:
|
||||
for path, lmtime in files.iteritems():
|
||||
for path, lmtime in files.items():
|
||||
if not exists(path) or mtime(path) > lmtime:
|
||||
self.status = 3
|
||||
if not exists(self.lockfile):
|
||||
|
@ -2068,7 +2097,7 @@ def _reloader_observer(server, app, interval):
|
|||
if os.path.exists(lockfile): os.unlink(lockfile)
|
||||
sys.exit(p.poll())
|
||||
elif not server.quiet:
|
||||
print "Reloading server..."
|
||||
sys.stdout.write("Reloading server...\n")
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
if os.path.exists(lockfile): os.unlink(lockfile)
|
||||
|
@ -2108,7 +2137,7 @@ class BaseTemplate(object):
|
|||
self.name = name
|
||||
self.source = source.read() if hasattr(source, 'read') else source
|
||||
self.filename = source.filename if hasattr(source, 'filename') else None
|
||||
self.lookup = map(os.path.abspath, lookup)
|
||||
self.lookup = [os.path.abspath(x) for x in lookup]
|
||||
self.encoding = encoding
|
||||
self.settings = self.settings.copy() # Copy from class variable
|
||||
self.settings.update(settings) # Apply
|
||||
|
@ -2237,7 +2266,10 @@ class SimpleTALTemplate(BaseTemplate):
|
|||
|
||||
def render(self, *args, **kwargs):
|
||||
from simpletal import simpleTALES
|
||||
from StringIO import StringIO
|
||||
if sys.version_info >= (3, 0):
|
||||
from io import StringIO
|
||||
else:
|
||||
from StringIO import StringIO
|
||||
for dictarg in args: kwargs.update(dictarg)
|
||||
# TODO: maybe reuse a context instead of always creating one
|
||||
context = simpleTALES.Context()
|
||||
|
@ -2475,7 +2507,10 @@ DEBUG = False
|
|||
MEMFILE_MAX = 1024*100
|
||||
|
||||
#: A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found')
|
||||
HTTP_CODES = httplib.responses
|
||||
if sys.version_info >= (3,0):
|
||||
from http.client import responses as HTTP_CODES
|
||||
else:
|
||||
from httplib import responses as HTTP_CODES
|
||||
HTTP_CODES[418] = "I'm a teapot" # RFC 2324
|
||||
|
||||
#: The default template used for error pages. Override with @error()
|
||||
|
|
|
@ -240,7 +240,8 @@ def main(argv=None):
|
|||
|
||||
try:
|
||||
opts, roots = getopt.getopt(argv[1:], "i:p:r:d:Uuxh", ["interface=", "port=", "root=", "server=", "disable-fallback", "version", "help"])
|
||||
except getopt.GetoptError, err:
|
||||
except getopt.GetoptError:
|
||||
err = sys.exc_info()[1]
|
||||
sys.exit("usage error: %s" % (err,))
|
||||
|
||||
for k, v in opts:
|
||||
|
@ -280,7 +281,8 @@ def main(argv=None):
|
|||
|
||||
try:
|
||||
os.listdir(root)
|
||||
except Exception, err:
|
||||
except Exception:
|
||||
err = sys.exc_info()[1]
|
||||
sys.exit("Error: while trying to list %r: %s" % (root, err))
|
||||
|
||||
packages = pkgset(root)
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
|
||||
import sys, os, re, xmlrpclib
|
||||
import sys, os, re
|
||||
from pypiserver import core
|
||||
|
||||
if sys.version_info >= (3,0):
|
||||
from xmlrpc.client import Server
|
||||
else:
|
||||
from xmlrpclib import Server
|
||||
|
||||
# --- the following two functions were copied from distribute's pkg_resources module
|
||||
component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
|
||||
|
@ -65,7 +69,7 @@ def find_updates(pkgset, stable_only=True):
|
|||
sys.stdout.write(s)
|
||||
sys.stdout.flush()
|
||||
|
||||
pypi = xmlrpclib.Server("http://pypi.python.org/pypi/")
|
||||
pypi = Server("http://pypi.python.org/pypi/")
|
||||
pkgname2latest = {}
|
||||
|
||||
pkgfiles = [pkgfile(x) for x in pkgset.find_packages()]
|
||||
|
|
7
setup.py
7
setup.py
|
@ -1,14 +1,10 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
extrakw = {}
|
||||
|
||||
try:
|
||||
from setuptools import setup
|
||||
extrakw["use_2to3"] = True
|
||||
except ImportError:
|
||||
if sys.version_info >= (3, 0):
|
||||
raise
|
||||
from distutils.core import setup
|
||||
|
||||
|
||||
|
@ -57,5 +53,4 @@ setup(name="pypiserver",
|
|||
"Programming Language :: Python :: 3.1",
|
||||
"Programming Language :: Python :: 3.2",
|
||||
"Topic :: Software Development :: Build Tools",
|
||||
"Topic :: System :: Software Distribution"],
|
||||
**extrakw)
|
||||
"Topic :: System :: Software Distribution"])
|
||||
|
|
Loading…
Reference in New Issue