mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Drop support for Python 2
Co-Authored-By: Dustin Ingram <di@users.noreply.github.com> Co-Authored-By: Berker Peksag <berker.peksag@gmail.com>
This commit is contained in:
parent
78208c8c32
commit
e974f30517
@ -6,8 +6,6 @@ ignore=
|
|||||||
examples,
|
examples,
|
||||||
scripts,
|
scripts,
|
||||||
_compat.py,
|
_compat.py,
|
||||||
argparse_compat.py,
|
|
||||||
six.py,
|
|
||||||
_gaiohttp.py,
|
_gaiohttp.py,
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
[MESSAGES CONTROL]
|
||||||
@ -53,5 +51,3 @@ disable=
|
|||||||
useless-import-alias,
|
useless-import-alias,
|
||||||
comparison-with-callable,
|
comparison-with-callable,
|
||||||
try-except-raise,
|
try-except-raise,
|
||||||
# TODO: use dict comprehensions once we drop Python 2.6 support.
|
|
||||||
consider-using-dict-comprehension,
|
|
||||||
|
|||||||
@ -2,10 +2,6 @@ sudo: false
|
|||||||
language: python
|
language: python
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- python: 2.6
|
|
||||||
env: TOXENV=py26
|
|
||||||
- python: 2.7
|
|
||||||
env: TOXENV=py27
|
|
||||||
- python: 3.4
|
- python: 3.4
|
||||||
env: TOXENV=py34
|
env: TOXENV=py34
|
||||||
- python: 3.5
|
- python: 3.5
|
||||||
|
|||||||
@ -28,7 +28,7 @@ The documentation is hosted at http://docs.gunicorn.org.
|
|||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Gunicorn requires **Python 2.x >= 2.6** or **Python 3.x >= 3.4**.
|
Gunicorn requires **Python **Python 3.x >= 3.4**.
|
||||||
|
|
||||||
Install from PyPI::
|
Install from PyPI::
|
||||||
|
|
||||||
|
|||||||
@ -3,15 +3,12 @@ environment:
|
|||||||
matrix:
|
matrix:
|
||||||
- TOXENV: lint
|
- TOXENV: lint
|
||||||
PYTHON: "C:\\Python35-x64"
|
PYTHON: "C:\\Python35-x64"
|
||||||
- TOXENV: py27
|
|
||||||
PYTHON: "C:\\Python27-x64"
|
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
PYTHON: "C:\\Python35-x64"
|
PYTHON: "C:\\Python35-x64"
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
PYTHON: "C:\\Python36-x64"
|
PYTHON: "C:\\Python36-x64"
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- TOXENV: py27
|
|
||||||
- TOXENV: py35
|
- TOXENV: py35
|
||||||
- TOXENV: py36
|
- TOXENV: py36
|
||||||
init: SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
init: SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||||
|
|||||||
@ -6,7 +6,7 @@ Requirements
|
|||||||
|
|
||||||
To generate documentation you need to install:
|
To generate documentation you need to install:
|
||||||
|
|
||||||
- Python >= 2.5
|
- Python >= 3.4
|
||||||
- Sphinx (http://sphinx-doc.org/)
|
- Sphinx (http://sphinx-doc.org/)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -50,15 +50,6 @@ Usage: python sitemap_gen.py --config=config.xml [--help] [--testing]
|
|||||||
--testing, specified when user is experimenting
|
--testing, specified when user is experimenting
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Please be careful that all syntax used in this file can be parsed on
|
|
||||||
# Python 1.5 -- this version check is not evaluated until after the
|
|
||||||
# entire file has been parsed.
|
|
||||||
import sys
|
|
||||||
if sys.hexversion < 0x02020000:
|
|
||||||
print 'This script requires Python 2.2 or later.'
|
|
||||||
print 'Currently run with version: %s' % sys.version
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import glob
|
import glob
|
||||||
import gzip
|
import gzip
|
||||||
@ -72,14 +63,6 @@ import urllib
|
|||||||
import urlparse
|
import urlparse
|
||||||
import xml.sax
|
import xml.sax
|
||||||
|
|
||||||
# True and False were introduced in Python2.2.2
|
|
||||||
try:
|
|
||||||
testTrue=True
|
|
||||||
del testTrue
|
|
||||||
except NameError:
|
|
||||||
True=1
|
|
||||||
False=0
|
|
||||||
|
|
||||||
# Text encodings
|
# Text encodings
|
||||||
ENC_ASCII = 'ASCII'
|
ENC_ASCII = 'ASCII'
|
||||||
ENC_UTF8 = 'UTF-8'
|
ENC_UTF8 = 'UTF-8'
|
||||||
|
|||||||
@ -21,8 +21,8 @@ source_suffix = '.rst'
|
|||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'Gunicorn'
|
project = 'Gunicorn'
|
||||||
copyright = u'2009-%s, Benoit Chesneau' % time.strftime('%Y')
|
copyright = '2009-%s, Benoit Chesneau' % time.strftime('%Y')
|
||||||
# gunicorn version
|
# gunicorn version
|
||||||
import gunicorn
|
import gunicorn
|
||||||
release = version = gunicorn.__version__
|
release = version = gunicorn.__version__
|
||||||
@ -55,19 +55,19 @@ latex_elements = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'Gunicorn.tex', u'Gunicorn Documentation',
|
('index', 'Gunicorn.tex', 'Gunicorn Documentation',
|
||||||
u'Benoit Chesneau', 'manual'),
|
'Benoit Chesneau', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output --------------------------------------------
|
# -- Options for manual page output --------------------------------------------
|
||||||
man_pages = [
|
man_pages = [
|
||||||
('index', 'gunicorn', u'Gunicorn Documentation',
|
('index', 'gunicorn', 'Gunicorn Documentation',
|
||||||
[u'Benoit Chesneau'], 1)
|
['Benoit Chesneau'], 1)
|
||||||
]
|
]
|
||||||
|
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'Gunicorn', u'Gunicorn Documentation',
|
('index', 'Gunicorn', 'Gunicorn Documentation',
|
||||||
u'Benoit Chesneau', 'Gunicorn', 'One line description of project.',
|
'Benoit Chesneau', 'Gunicorn', 'One line description of project.',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -23,7 +23,7 @@ Features
|
|||||||
* Simple Python configuration
|
* Simple Python configuration
|
||||||
* Multiple worker configurations
|
* Multiple worker configurations
|
||||||
* Various server hooks for extensibility
|
* Various server hooks for extensibility
|
||||||
* Compatible with Python 2.x >= 2.6 or 3.x >= 3.4
|
* Compatible with Python 3.x >= 3.4
|
||||||
|
|
||||||
|
|
||||||
Contents
|
Contents
|
||||||
|
|||||||
@ -4,7 +4,7 @@ Installation
|
|||||||
|
|
||||||
.. highlight:: bash
|
.. highlight:: bash
|
||||||
|
|
||||||
:Requirements: **Python 2.x >= 2.6** or **Python 3.x >= 3.4**
|
:Requirements: **Python 3.x >= 3.4**
|
||||||
|
|
||||||
To install the latest released version of Gunicorn::
|
To install the latest released version of Gunicorn::
|
||||||
|
|
||||||
|
|||||||
@ -200,7 +200,7 @@ def worker_int(worker):
|
|||||||
|
|
||||||
## get traceback info
|
## get traceback info
|
||||||
import threading, sys, traceback
|
import threading, sys, traceback
|
||||||
id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
|
id2name = {th.ident: th.name for th in threading.enumerate()}
|
||||||
code = []
|
code = []
|
||||||
for threadId, stack in sys._current_frames().items():
|
for threadId, stack in sys._current_frames().items():
|
||||||
code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""),
|
code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""),
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
Use this config file in your script like this:
|
Use this config file in your script like this:
|
||||||
|
|
||||||
$ gunicorn project_name.wsgi:application -c read_django_settings.py
|
$ gunicorn project_name.wsgi:application -c read_django_settings.py
|
||||||
|
|
||||||
You need to replace the exec() call if you want it to work on Python 2.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
settings_dict = {}
|
settings_dict = {}
|
||||||
|
|||||||
@ -8,14 +8,10 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
||||||
import gunicorn.app.base
|
import gunicorn.app.base
|
||||||
|
|
||||||
from gunicorn.six import iteritems
|
|
||||||
|
|
||||||
|
|
||||||
def number_of_workers():
|
def number_of_workers():
|
||||||
return (multiprocessing.cpu_count() * 2) + 1
|
return (multiprocessing.cpu_count() * 2) + 1
|
||||||
@ -42,9 +38,9 @@ class StandaloneApplication(gunicorn.app.base.BaseApplication):
|
|||||||
super(StandaloneApplication, self).__init__()
|
super(StandaloneApplication, self).__init__()
|
||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
config = dict([(key, value) for key, value in iteritems(self.options)
|
config = {key: value for key, value in self.options.items()
|
||||||
if key in self.cfg.settings and value is not None])
|
if key in self.cfg.settings and value is not None}
|
||||||
for key, value in iteritems(config):
|
for key, value in config.items():
|
||||||
self.cfg.set(key.lower(), value)
|
self.cfg.set(key.lower(), value)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
|||||||
@ -1,10 +1,3 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
PY26 = (sys.version_info[:2] == (2, 6))
|
|
||||||
|
|
||||||
|
|
||||||
def _check_if_pyc(fname):
|
def _check_if_pyc(fname):
|
||||||
"""Return True if the extension is .pyc, False if .py
|
"""Return True if the extension is .pyc, False if .py
|
||||||
and None if otherwise"""
|
and None if otherwise"""
|
||||||
@ -62,147 +55,12 @@ def _get_codeobj(pyfile):
|
|||||||
# Return code object
|
# Return code object
|
||||||
return code_obj
|
return code_obj
|
||||||
|
|
||||||
if six.PY3:
|
|
||||||
def execfile_(fname, *args):
|
|
||||||
if fname.endswith(".pyc"):
|
|
||||||
code = _get_codeobj(fname)
|
|
||||||
else:
|
|
||||||
code = compile(open(fname, 'rb').read(), fname, 'exec')
|
|
||||||
return six.exec_(code, *args)
|
|
||||||
|
|
||||||
def bytes_to_str(b):
|
def execfile_(fname, *args):
|
||||||
if isinstance(b, six.text_type):
|
if fname.endswith(".pyc"):
|
||||||
return b
|
code = _get_codeobj(fname)
|
||||||
return str(b, 'latin1')
|
else:
|
||||||
|
code = compile(open(fname, 'rb').read(), fname, 'exec')
|
||||||
import urllib.parse
|
return exec(code, *args)
|
||||||
|
|
||||||
def unquote_to_wsgi_str(string):
|
|
||||||
return _unquote_to_bytes(string).decode('latin-1')
|
|
||||||
|
|
||||||
_unquote_to_bytes = urllib.parse.unquote_to_bytes
|
|
||||||
|
|
||||||
else:
|
|
||||||
def execfile_(fname, *args):
|
|
||||||
""" Overriding PY2 execfile() implementation to support .pyc files """
|
|
||||||
if fname.endswith(".pyc"):
|
|
||||||
return six.exec_(_get_codeobj(fname), *args)
|
|
||||||
return execfile(fname, *args)
|
|
||||||
|
|
||||||
def bytes_to_str(s):
|
|
||||||
if isinstance(s, unicode):
|
|
||||||
return s.encode('utf-8')
|
|
||||||
return s
|
|
||||||
|
|
||||||
import urllib
|
|
||||||
unquote_to_wsgi_str = urllib.unquote
|
|
||||||
|
|
||||||
|
|
||||||
# The following code adapted from trollius.py33_exceptions
|
|
||||||
def _wrap_error(exc, mapping, key):
|
|
||||||
if key not in mapping:
|
|
||||||
return
|
|
||||||
new_err_cls = mapping[key]
|
|
||||||
new_err = new_err_cls(*exc.args)
|
|
||||||
|
|
||||||
# raise a new exception with the original traceback
|
|
||||||
six.reraise(new_err_cls, new_err,
|
|
||||||
exc.__traceback__ if hasattr(exc, '__traceback__') else sys.exc_info()[2])
|
|
||||||
|
|
||||||
if PY26:
|
|
||||||
from urlparse import (
|
|
||||||
_parse_cache, MAX_CACHE_SIZE, clear_cache, _splitnetloc, SplitResult,
|
|
||||||
scheme_chars,
|
|
||||||
)
|
|
||||||
|
|
||||||
def urlsplit(url, scheme='', allow_fragments=True):
|
|
||||||
"""Parse a URL into 5 components:
|
|
||||||
<scheme>://<netloc>/<path>?<query>#<fragment>
|
|
||||||
Return a 5-tuple: (scheme, netloc, path, query, fragment).
|
|
||||||
Note that we don't break the components up in smaller bits
|
|
||||||
(e.g. netloc is a single string) and we don't expand % escapes."""
|
|
||||||
allow_fragments = bool(allow_fragments)
|
|
||||||
key = url, scheme, allow_fragments, type(url), type(scheme)
|
|
||||||
cached = _parse_cache.get(key, None)
|
|
||||||
if cached:
|
|
||||||
return cached
|
|
||||||
if len(_parse_cache) >= MAX_CACHE_SIZE: # avoid runaway growth
|
|
||||||
clear_cache()
|
|
||||||
netloc = query = fragment = ''
|
|
||||||
i = url.find(':')
|
|
||||||
if i > 0:
|
|
||||||
if url[:i] == 'http': # optimize the common case
|
|
||||||
scheme = url[:i].lower()
|
|
||||||
url = url[i+1:]
|
|
||||||
if url[:2] == '//':
|
|
||||||
netloc, url = _splitnetloc(url, 2)
|
|
||||||
if (('[' in netloc and ']' not in netloc) or
|
|
||||||
(']' in netloc and '[' not in netloc)):
|
|
||||||
raise ValueError("Invalid IPv6 URL")
|
|
||||||
if allow_fragments and '#' in url:
|
|
||||||
url, fragment = url.split('#', 1)
|
|
||||||
if '?' in url:
|
|
||||||
url, query = url.split('?', 1)
|
|
||||||
v = SplitResult(scheme, netloc, url, query, fragment)
|
|
||||||
_parse_cache[key] = v
|
|
||||||
return v
|
|
||||||
for c in url[:i]:
|
|
||||||
if c not in scheme_chars:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# make sure "url" is not actually a port number (in which case
|
|
||||||
# "scheme" is really part of the path)
|
|
||||||
rest = url[i+1:]
|
|
||||||
if not rest or any(c not in '0123456789' for c in rest):
|
|
||||||
# not a port number
|
|
||||||
scheme, url = url[:i].lower(), rest
|
|
||||||
|
|
||||||
if url[:2] == '//':
|
|
||||||
netloc, url = _splitnetloc(url, 2)
|
|
||||||
if (('[' in netloc and ']' not in netloc) or
|
|
||||||
(']' in netloc and '[' not in netloc)):
|
|
||||||
raise ValueError("Invalid IPv6 URL")
|
|
||||||
if allow_fragments and '#' in url:
|
|
||||||
url, fragment = url.split('#', 1)
|
|
||||||
if '?' in url:
|
|
||||||
url, query = url.split('?', 1)
|
|
||||||
v = SplitResult(scheme, netloc, url, query, fragment)
|
|
||||||
_parse_cache[key] = v
|
|
||||||
return v
|
|
||||||
|
|
||||||
else:
|
|
||||||
from gunicorn.six.moves.urllib.parse import urlsplit
|
|
||||||
|
|
||||||
|
|
||||||
import inspect
|
|
||||||
|
|
||||||
if hasattr(inspect, 'signature'):
|
|
||||||
positionals = (
|
|
||||||
inspect.Parameter.POSITIONAL_ONLY,
|
|
||||||
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_arity(f):
|
|
||||||
sig = inspect.signature(f)
|
|
||||||
arity = 0
|
|
||||||
|
|
||||||
for param in sig.parameters.values():
|
|
||||||
if param.kind in positionals:
|
|
||||||
arity += 1
|
|
||||||
|
|
||||||
return arity
|
|
||||||
else:
|
|
||||||
def get_arity(f):
|
|
||||||
return len(inspect.getargspec(f)[0])
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
import html
|
|
||||||
|
|
||||||
def html_escape(s):
|
|
||||||
return html.escape(s)
|
|
||||||
except ImportError:
|
|
||||||
import cgi
|
|
||||||
|
|
||||||
def html_escape(s):
|
|
||||||
return cgi.escape(s, quote=True)
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
#
|
#
|
||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#
|
#
|
||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
# pylint: skip-file
|
# pylint: skip-file
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
#
|
#
|
||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -5,27 +5,21 @@
|
|||||||
|
|
||||||
# Please remember to run "make -C docs html" after update "desc" attributes.
|
# Please remember to run "make -C docs html" after update "desc" attributes.
|
||||||
|
|
||||||
|
import argparse
|
||||||
import copy
|
import copy
|
||||||
import grp
|
import grp
|
||||||
import inspect
|
import inspect
|
||||||
try:
|
|
||||||
import argparse
|
|
||||||
except ImportError: # python 2.6
|
|
||||||
from . import argparse_compat as argparse
|
|
||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
import re
|
import re
|
||||||
|
import shlex
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import shlex
|
|
||||||
|
|
||||||
from gunicorn import __version__
|
from gunicorn import __version__, util
|
||||||
from gunicorn import _compat
|
|
||||||
from gunicorn.errors import ConfigError
|
from gunicorn.errors import ConfigError
|
||||||
from gunicorn.reloader import reloader_engines
|
from gunicorn.reloader import reloader_engines
|
||||||
from gunicorn import six
|
|
||||||
from gunicorn import util
|
|
||||||
|
|
||||||
KNOWN_SETTINGS = []
|
KNOWN_SETTINGS = []
|
||||||
PLATFORM = sys.platform
|
PLATFORM = sys.platform
|
||||||
@ -122,7 +116,7 @@ class Config(object):
|
|||||||
@property
|
@property
|
||||||
def address(self):
|
def address(self):
|
||||||
s = self.settings['bind'].get()
|
s = self.settings['bind'].get()
|
||||||
return [util.parse_address(_compat.bytes_to_str(bind)) for bind in s]
|
return [util.parse_address(util.bytes_to_str(bind)) for bind in s]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def uid(self):
|
def uid(self):
|
||||||
@ -183,7 +177,7 @@ class Config(object):
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
for e in raw_env:
|
for e in raw_env:
|
||||||
s = _compat.bytes_to_str(e)
|
s = util.bytes_to_str(e)
|
||||||
try:
|
try:
|
||||||
k, v = s.split('=', 1)
|
k, v = s.split('=', 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -216,7 +210,7 @@ class Config(object):
|
|||||||
|
|
||||||
global_conf = {}
|
global_conf = {}
|
||||||
for e in raw_global_conf:
|
for e in raw_global_conf:
|
||||||
s = _compat.bytes_to_str(e)
|
s = util.bytes_to_str(e)
|
||||||
try:
|
try:
|
||||||
k, v = re.split(r'(?<!\\)=', s, 1)
|
k, v = re.split(r'(?<!\\)=', s, 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -305,7 +299,7 @@ class Setting(object):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
def set(self, val):
|
def set(self, val):
|
||||||
if not six.callable(self.validator):
|
if not callable(self.validator):
|
||||||
raise TypeError('Invalid validator: %s' % self.name)
|
raise TypeError('Invalid validator: %s' % self.name)
|
||||||
self.value = self.validator(val)
|
self.value = self.validator(val)
|
||||||
|
|
||||||
@ -323,7 +317,7 @@ def validate_bool(val):
|
|||||||
|
|
||||||
if isinstance(val, bool):
|
if isinstance(val, bool):
|
||||||
return val
|
return val
|
||||||
if not isinstance(val, six.string_types):
|
if not isinstance(val, str):
|
||||||
raise TypeError("Invalid type for casting: %s" % val)
|
raise TypeError("Invalid type for casting: %s" % val)
|
||||||
if val.lower().strip() == "true":
|
if val.lower().strip() == "true":
|
||||||
return True
|
return True
|
||||||
@ -340,7 +334,7 @@ def validate_dict(val):
|
|||||||
|
|
||||||
|
|
||||||
def validate_pos_int(val):
|
def validate_pos_int(val):
|
||||||
if not isinstance(val, six.integer_types):
|
if not isinstance(val, int):
|
||||||
val = int(val, 0)
|
val = int(val, 0)
|
||||||
else:
|
else:
|
||||||
# Booleans are ints!
|
# Booleans are ints!
|
||||||
@ -353,7 +347,7 @@ def validate_pos_int(val):
|
|||||||
def validate_string(val):
|
def validate_string(val):
|
||||||
if val is None:
|
if val is None:
|
||||||
return None
|
return None
|
||||||
if not isinstance(val, six.string_types):
|
if not isinstance(val, str):
|
||||||
raise TypeError("Not a string: %s" % val)
|
raise TypeError("Not a string: %s" % val)
|
||||||
return val.strip()
|
return val.strip()
|
||||||
|
|
||||||
@ -371,7 +365,7 @@ def validate_list_string(val):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
# legacy syntax
|
# legacy syntax
|
||||||
if isinstance(val, six.string_types):
|
if isinstance(val, str):
|
||||||
val = [val]
|
val = [val]
|
||||||
|
|
||||||
return [validate_string(v) for v in val]
|
return [validate_string(v) for v in val]
|
||||||
@ -400,7 +394,7 @@ def validate_class(val):
|
|||||||
|
|
||||||
def validate_callable(arity):
|
def validate_callable(arity):
|
||||||
def _validate_callable(val):
|
def _validate_callable(val):
|
||||||
if isinstance(val, six.string_types):
|
if isinstance(val, str):
|
||||||
try:
|
try:
|
||||||
mod_name, obj_name = val.rsplit(".", 1)
|
mod_name, obj_name = val.rsplit(".", 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@ -414,9 +408,9 @@ def validate_callable(arity):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise TypeError("Can not load '%s' from '%s'"
|
raise TypeError("Can not load '%s' from '%s'"
|
||||||
"" % (obj_name, mod_name))
|
"" % (obj_name, mod_name))
|
||||||
if not six.callable(val):
|
if not callable(val):
|
||||||
raise TypeError("Value is not six.callable: %s" % val)
|
raise TypeError("Value is not callable: %s" % val)
|
||||||
if arity != -1 and arity != _compat.get_arity(val):
|
if arity != -1 and arity != util.get_arity(val):
|
||||||
raise TypeError("Value must have an arity of: %s" % arity)
|
raise TypeError("Value must have an arity of: %s" % arity)
|
||||||
return val
|
return val
|
||||||
return _validate_callable
|
return _validate_callable
|
||||||
@ -454,7 +448,7 @@ def validate_group(val):
|
|||||||
def validate_post_request(val):
|
def validate_post_request(val):
|
||||||
val = validate_callable(-1)(val)
|
val = validate_callable(-1)(val)
|
||||||
|
|
||||||
largs = _compat.get_arity(val)
|
largs = util.get_arity(val)
|
||||||
if largs == 4:
|
if largs == 4:
|
||||||
return val
|
return val
|
||||||
elif largs == 3:
|
elif largs == 3:
|
||||||
@ -1540,7 +1534,7 @@ class OnStarting(Setting):
|
|||||||
name = "on_starting"
|
name = "on_starting"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def on_starting(server):
|
def on_starting(server):
|
||||||
pass
|
pass
|
||||||
@ -1556,7 +1550,7 @@ class OnReload(Setting):
|
|||||||
name = "on_reload"
|
name = "on_reload"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def on_reload(server):
|
def on_reload(server):
|
||||||
pass
|
pass
|
||||||
@ -1572,7 +1566,7 @@ class WhenReady(Setting):
|
|||||||
name = "when_ready"
|
name = "when_ready"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def when_ready(server):
|
def when_ready(server):
|
||||||
pass
|
pass
|
||||||
@ -1588,7 +1582,7 @@ class Prefork(Setting):
|
|||||||
name = "pre_fork"
|
name = "pre_fork"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(2)
|
validator = validate_callable(2)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def pre_fork(server, worker):
|
def pre_fork(server, worker):
|
||||||
pass
|
pass
|
||||||
@ -1605,7 +1599,7 @@ class Postfork(Setting):
|
|||||||
name = "post_fork"
|
name = "post_fork"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(2)
|
validator = validate_callable(2)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def post_fork(server, worker):
|
def post_fork(server, worker):
|
||||||
pass
|
pass
|
||||||
@ -1622,7 +1616,7 @@ class PostWorkerInit(Setting):
|
|||||||
name = "post_worker_init"
|
name = "post_worker_init"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def post_worker_init(worker):
|
def post_worker_init(worker):
|
||||||
pass
|
pass
|
||||||
@ -1639,7 +1633,7 @@ class WorkerInt(Setting):
|
|||||||
name = "worker_int"
|
name = "worker_int"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def worker_int(worker):
|
def worker_int(worker):
|
||||||
pass
|
pass
|
||||||
@ -1657,7 +1651,7 @@ class WorkerAbort(Setting):
|
|||||||
name = "worker_abort"
|
name = "worker_abort"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def worker_abort(worker):
|
def worker_abort(worker):
|
||||||
pass
|
pass
|
||||||
@ -1677,7 +1671,7 @@ class PreExec(Setting):
|
|||||||
name = "pre_exec"
|
name = "pre_exec"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(1)
|
validator = validate_callable(1)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def pre_exec(server):
|
def pre_exec(server):
|
||||||
pass
|
pass
|
||||||
@ -1693,7 +1687,7 @@ class PreRequest(Setting):
|
|||||||
name = "pre_request"
|
name = "pre_request"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(2)
|
validator = validate_callable(2)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def pre_request(worker, req):
|
def pre_request(worker, req):
|
||||||
worker.log.debug("%s %s" % (req.method, req.path))
|
worker.log.debug("%s %s" % (req.method, req.path))
|
||||||
@ -1710,7 +1704,7 @@ class PostRequest(Setting):
|
|||||||
name = "post_request"
|
name = "post_request"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_post_request
|
validator = validate_post_request
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def post_request(worker, req, environ, resp):
|
def post_request(worker, req, environ, resp):
|
||||||
pass
|
pass
|
||||||
@ -1727,7 +1721,7 @@ class ChildExit(Setting):
|
|||||||
name = "child_exit"
|
name = "child_exit"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(2)
|
validator = validate_callable(2)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def child_exit(server, worker):
|
def child_exit(server, worker):
|
||||||
pass
|
pass
|
||||||
@ -1746,7 +1740,7 @@ class WorkerExit(Setting):
|
|||||||
name = "worker_exit"
|
name = "worker_exit"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(2)
|
validator = validate_callable(2)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def worker_exit(server, worker):
|
def worker_exit(server, worker):
|
||||||
pass
|
pass
|
||||||
@ -1763,7 +1757,7 @@ class NumWorkersChanged(Setting):
|
|||||||
name = "nworkers_changed"
|
name = "nworkers_changed"
|
||||||
section = "Server Hooks"
|
section = "Server Hooks"
|
||||||
validator = validate_callable(3)
|
validator = validate_callable(3)
|
||||||
type = six.callable
|
type = callable
|
||||||
|
|
||||||
def nworkers_changed(server, new_value, old_value):
|
def nworkers_changed(server, new_value, old_value):
|
||||||
pass
|
pass
|
||||||
@ -1916,16 +1910,15 @@ class DoHandshakeOnConnect(Setting):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (2, 7):
|
class Ciphers(Setting):
|
||||||
class Ciphers(Setting):
|
name = "ciphers"
|
||||||
name = "ciphers"
|
section = "SSL"
|
||||||
section = "SSL"
|
cli = ["--ciphers"]
|
||||||
cli = ["--ciphers"]
|
validator = validate_string
|
||||||
validator = validate_string
|
default = 'TLSv1'
|
||||||
default = 'TLSv1'
|
desc = """\
|
||||||
desc = """\
|
Ciphers to use (see stdlib ssl module's)
|
||||||
Ciphers to use (see stdlib ssl module's)
|
"""
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class PasteGlobalConf(Setting):
|
class PasteGlobalConf(Setting):
|
||||||
|
|||||||
@ -8,12 +8,8 @@ import binascii
|
|||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
logging.Logger.manager.emittedNoHandlerWarning = 1
|
logging.Logger.manager.emittedNoHandlerWarning = 1
|
||||||
|
from logging.config import dictConfig
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
try:
|
|
||||||
from logging.config import dictConfig
|
|
||||||
except ImportError:
|
|
||||||
# python 2.6
|
|
||||||
dictConfig = None
|
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
@ -21,7 +17,6 @@ import threading
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
from gunicorn.six import PY3, string_types
|
|
||||||
|
|
||||||
|
|
||||||
# syslog facility codes
|
# syslog facility codes
|
||||||
@ -104,7 +99,7 @@ class SafeAtoms(dict):
|
|||||||
def __init__(self, atoms):
|
def __init__(self, atoms):
|
||||||
dict.__init__(self)
|
dict.__init__(self)
|
||||||
for key, value in atoms.items():
|
for key, value in atoms.items():
|
||||||
if isinstance(value, string_types):
|
if isinstance(value, str):
|
||||||
self[key] = value.replace('"', '\\"')
|
self[key] = value.replace('"', '\\"')
|
||||||
else:
|
else:
|
||||||
self[key] = value
|
self[key] = value
|
||||||
@ -231,11 +226,7 @@ class Logger(object):
|
|||||||
self.access_log, cfg, self.syslog_fmt, "access"
|
self.access_log, cfg, self.syslog_fmt, "access"
|
||||||
)
|
)
|
||||||
|
|
||||||
if dictConfig is None and cfg.logconfig_dict:
|
if cfg.logconfig_dict:
|
||||||
util.warn("Dictionary-based log configuration requires "
|
|
||||||
"Python 2.7 or above.")
|
|
||||||
|
|
||||||
if dictConfig and cfg.logconfig_dict:
|
|
||||||
config = CONFIG_DEFAULTS.copy()
|
config = CONFIG_DEFAULTS.copy()
|
||||||
config.update(cfg.logconfig_dict)
|
config.update(cfg.logconfig_dict)
|
||||||
try:
|
try:
|
||||||
@ -277,7 +268,7 @@ class Logger(object):
|
|||||||
self.error_log.exception(msg, *args, **kwargs)
|
self.error_log.exception(msg, *args, **kwargs)
|
||||||
|
|
||||||
def log(self, lvl, msg, *args, **kwargs):
|
def log(self, lvl, msg, *args, **kwargs):
|
||||||
if isinstance(lvl, string_types):
|
if isinstance(lvl, str):
|
||||||
lvl = self.LOG_LEVELS.get(lvl.lower(), logging.INFO)
|
lvl = self.LOG_LEVELS.get(lvl.lower(), logging.INFO)
|
||||||
self.error_log.log(lvl, msg, *args, **kwargs)
|
self.error_log.log(lvl, msg, *args, **kwargs)
|
||||||
|
|
||||||
@ -318,18 +309,18 @@ class Logger(object):
|
|||||||
if hasattr(req_headers, "items"):
|
if hasattr(req_headers, "items"):
|
||||||
req_headers = req_headers.items()
|
req_headers = req_headers.items()
|
||||||
|
|
||||||
atoms.update(dict([("{%s}i" % k.lower(), v) for k, v in req_headers]))
|
atoms.update({"{%s}i" % k.lower(): v for k, v in req_headers})
|
||||||
|
|
||||||
resp_headers = resp.headers
|
resp_headers = resp.headers
|
||||||
if hasattr(resp_headers, "items"):
|
if hasattr(resp_headers, "items"):
|
||||||
resp_headers = resp_headers.items()
|
resp_headers = resp_headers.items()
|
||||||
|
|
||||||
# add response headers
|
# add response headers
|
||||||
atoms.update(dict([("{%s}o" % k.lower(), v) for k, v in resp_headers]))
|
atoms.update({"{%s}o" % k.lower(): v for k, v in resp_headers})
|
||||||
|
|
||||||
# add environ variables
|
# add environ variables
|
||||||
environ_variables = environ.items()
|
environ_variables = environ.items()
|
||||||
atoms.update(dict([("{%s}e" % k.lower(), v) for k, v in environ_variables]))
|
atoms.update({"{%s}e" % k.lower(): v for k, v in environ_variables})
|
||||||
|
|
||||||
return atoms
|
return atoms
|
||||||
|
|
||||||
@ -444,14 +435,8 @@ class Logger(object):
|
|||||||
socktype, addr = parse_syslog_address(cfg.syslog_addr)
|
socktype, addr = parse_syslog_address(cfg.syslog_addr)
|
||||||
|
|
||||||
# finally setup the syslog handler
|
# finally setup the syslog handler
|
||||||
if sys.version_info >= (2, 7):
|
h = logging.handlers.SysLogHandler(address=addr,
|
||||||
h = logging.handlers.SysLogHandler(address=addr,
|
facility=facility, socktype=socktype)
|
||||||
facility=facility, socktype=socktype)
|
|
||||||
else:
|
|
||||||
# socktype is only supported in 2.7 and sup
|
|
||||||
# fix issue #541
|
|
||||||
h = logging.handlers.SysLogHandler(address=addr,
|
|
||||||
facility=facility)
|
|
||||||
|
|
||||||
h.setFormatter(fmt)
|
h.setFormatter(fmt)
|
||||||
h._gunicorn = True
|
h._gunicorn = True
|
||||||
@ -467,8 +452,8 @@ class Logger(object):
|
|||||||
# b64decode doesn't accept unicode in Python < 3.3
|
# b64decode doesn't accept unicode in Python < 3.3
|
||||||
# so we need to convert it to a byte string
|
# so we need to convert it to a byte string
|
||||||
auth = base64.b64decode(auth[1].strip().encode('utf-8'))
|
auth = base64.b64decode(auth[1].strip().encode('utf-8'))
|
||||||
if PY3: # b64decode returns a byte string in Python 3
|
# b64decode returns a byte string
|
||||||
auth = auth.decode('utf-8')
|
auth = auth.decode('utf-8')
|
||||||
auth = auth.split(":", 1)
|
auth = auth.split(":", 1)
|
||||||
except (TypeError, binascii.Error, UnicodeDecodeError) as exc:
|
except (TypeError, binascii.Error, UnicodeDecodeError) as exc:
|
||||||
self.debug("Couldn't get username: %s", exc)
|
self.debug("Couldn't get username: %s", exc)
|
||||||
|
|||||||
@ -1,67 +0,0 @@
|
|||||||
# -*- coding: utf-8 -
|
|
||||||
#
|
|
||||||
# This file is part of gunicorn released under the MIT license.
|
|
||||||
# See the NOTICE for more information.
|
|
||||||
|
|
||||||
import errno
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
try:
|
|
||||||
import ctypes
|
|
||||||
import ctypes.util
|
|
||||||
except MemoryError:
|
|
||||||
# selinux execmem denial
|
|
||||||
# https://bugzilla.redhat.com/show_bug.cgi?id=488396
|
|
||||||
raise ImportError
|
|
||||||
|
|
||||||
SUPPORTED_PLATFORMS = (
|
|
||||||
'darwin',
|
|
||||||
'freebsd',
|
|
||||||
'dragonfly',
|
|
||||||
'linux2')
|
|
||||||
|
|
||||||
if sys.platform not in SUPPORTED_PLATFORMS:
|
|
||||||
raise ImportError("sendfile isn't supported on this platform")
|
|
||||||
|
|
||||||
_libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
|
|
||||||
_sendfile = _libc.sendfile
|
|
||||||
|
|
||||||
|
|
||||||
def sendfile(fdout, fdin, offset, nbytes):
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
|
|
||||||
ctypes.POINTER(ctypes.c_uint64), ctypes.c_voidp,
|
|
||||||
ctypes.c_int]
|
|
||||||
_nbytes = ctypes.c_uint64(nbytes)
|
|
||||||
result = _sendfile(fdin, fdout, offset, _nbytes, None, 0)
|
|
||||||
|
|
||||||
if result == -1:
|
|
||||||
e = ctypes.get_errno()
|
|
||||||
if e == errno.EAGAIN and _nbytes.value is not None:
|
|
||||||
return _nbytes.value
|
|
||||||
raise OSError(e, os.strerror(e))
|
|
||||||
return _nbytes.value
|
|
||||||
elif sys.platform in ('freebsd', 'dragonfly',):
|
|
||||||
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
|
|
||||||
ctypes.c_uint64, ctypes.c_voidp,
|
|
||||||
ctypes.POINTER(ctypes.c_uint64), ctypes.c_int]
|
|
||||||
_sbytes = ctypes.c_uint64()
|
|
||||||
result = _sendfile(fdin, fdout, offset, nbytes, None, _sbytes, 0)
|
|
||||||
if result == -1:
|
|
||||||
e = ctypes.get_errno()
|
|
||||||
if e == errno.EAGAIN and _sbytes.value is not None:
|
|
||||||
return _sbytes.value
|
|
||||||
raise OSError(e, os.strerror(e))
|
|
||||||
return _sbytes.value
|
|
||||||
|
|
||||||
else:
|
|
||||||
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int,
|
|
||||||
ctypes.POINTER(ctypes.c_uint64), ctypes.c_size_t]
|
|
||||||
|
|
||||||
_offset = ctypes.c_uint64(offset)
|
|
||||||
sent = _sendfile(fdout, fdin, _offset, nbytes)
|
|
||||||
if sent == -1:
|
|
||||||
e = ctypes.get_errno()
|
|
||||||
raise OSError(e, os.strerror(e))
|
|
||||||
return sent
|
|
||||||
@ -3,19 +3,21 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
|
||||||
from gunicorn.http.errors import (NoMoreData, ChunkMissingTerminator,
|
from gunicorn.http.errors import (NoMoreData, ChunkMissingTerminator,
|
||||||
InvalidChunkSize)
|
InvalidChunkSize)
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
|
|
||||||
class ChunkedReader(object):
|
class ChunkedReader(object):
|
||||||
def __init__(self, req, unreader):
|
def __init__(self, req, unreader):
|
||||||
self.req = req
|
self.req = req
|
||||||
self.parser = self.parse_chunked(unreader)
|
self.parser = self.parse_chunked(unreader)
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
if not isinstance(size, six.integer_types):
|
if not isinstance(size, int):
|
||||||
raise TypeError("size must be an integral type")
|
raise TypeError("size must be an integral type")
|
||||||
if size < 0:
|
if size < 0:
|
||||||
raise ValueError("Size must be positive.")
|
raise ValueError("Size must be positive.")
|
||||||
@ -25,19 +27,19 @@ class ChunkedReader(object):
|
|||||||
if self.parser:
|
if self.parser:
|
||||||
while self.buf.tell() < size:
|
while self.buf.tell() < size:
|
||||||
try:
|
try:
|
||||||
self.buf.write(six.next(self.parser))
|
self.buf.write(next(self.parser))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self.parser = None
|
self.parser = None
|
||||||
break
|
break
|
||||||
|
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
ret, rest = data[:size], data[size:]
|
ret, rest = data[:size], data[size:]
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.buf.write(rest)
|
self.buf.write(rest)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def parse_trailers(self, unreader, data):
|
def parse_trailers(self, unreader, data):
|
||||||
buf = six.BytesIO()
|
buf = io.BytesIO()
|
||||||
buf.write(data)
|
buf.write(data)
|
||||||
|
|
||||||
idx = buf.getvalue().find(b"\r\n\r\n")
|
idx = buf.getvalue().find(b"\r\n\r\n")
|
||||||
@ -71,7 +73,7 @@ class ChunkedReader(object):
|
|||||||
(size, rest) = self.parse_chunk_size(unreader, data=rest[2:])
|
(size, rest) = self.parse_chunk_size(unreader, data=rest[2:])
|
||||||
|
|
||||||
def parse_chunk_size(self, unreader, data=None):
|
def parse_chunk_size(self, unreader, data=None):
|
||||||
buf = six.BytesIO()
|
buf = io.BytesIO()
|
||||||
if data is not None:
|
if data is not None:
|
||||||
buf.write(data)
|
buf.write(data)
|
||||||
|
|
||||||
@ -110,7 +112,7 @@ class LengthReader(object):
|
|||||||
self.length = length
|
self.length = length
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
if not isinstance(size, six.integer_types):
|
if not isinstance(size, int):
|
||||||
raise TypeError("size must be an integral type")
|
raise TypeError("size must be an integral type")
|
||||||
|
|
||||||
size = min(self.length, size)
|
size = min(self.length, size)
|
||||||
@ -119,7 +121,7 @@ class LengthReader(object):
|
|||||||
if size == 0:
|
if size == 0:
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
buf = six.BytesIO()
|
buf = io.BytesIO()
|
||||||
data = self.unreader.read()
|
data = self.unreader.read()
|
||||||
while data:
|
while data:
|
||||||
buf.write(data)
|
buf.write(data)
|
||||||
@ -137,11 +139,11 @@ class LengthReader(object):
|
|||||||
class EOFReader(object):
|
class EOFReader(object):
|
||||||
def __init__(self, unreader):
|
def __init__(self, unreader):
|
||||||
self.unreader = unreader
|
self.unreader = unreader
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.finished = False
|
self.finished = False
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
if not isinstance(size, six.integer_types):
|
if not isinstance(size, int):
|
||||||
raise TypeError("size must be an integral type")
|
raise TypeError("size must be an integral type")
|
||||||
if size < 0:
|
if size < 0:
|
||||||
raise ValueError("Size must be positive.")
|
raise ValueError("Size must be positive.")
|
||||||
@ -151,7 +153,7 @@ class EOFReader(object):
|
|||||||
if self.finished:
|
if self.finished:
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
ret, rest = data[:size], data[size:]
|
ret, rest = data[:size], data[size:]
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.buf.write(rest)
|
self.buf.write(rest)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -167,7 +169,7 @@ class EOFReader(object):
|
|||||||
|
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
ret, rest = data[:size], data[size:]
|
ret, rest = data[:size], data[size:]
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.buf.write(rest)
|
self.buf.write(rest)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -175,7 +177,7 @@ class EOFReader(object):
|
|||||||
class Body(object):
|
class Body(object):
|
||||||
def __init__(self, reader):
|
def __init__(self, reader):
|
||||||
self.reader = reader
|
self.reader = reader
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
@ -189,11 +191,11 @@ class Body(object):
|
|||||||
|
|
||||||
def getsize(self, size):
|
def getsize(self, size):
|
||||||
if size is None:
|
if size is None:
|
||||||
return six.MAXSIZE
|
return sys.maxsize
|
||||||
elif not isinstance(size, six.integer_types):
|
elif not isinstance(size, int):
|
||||||
raise TypeError("size must be an integral type")
|
raise TypeError("size must be an integral type")
|
||||||
elif size < 0:
|
elif size < 0:
|
||||||
return six.MAXSIZE
|
return sys.maxsize
|
||||||
return size
|
return size
|
||||||
|
|
||||||
def read(self, size=None):
|
def read(self, size=None):
|
||||||
@ -204,7 +206,7 @@ class Body(object):
|
|||||||
if size < self.buf.tell():
|
if size < self.buf.tell():
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
ret, rest = data[:size], data[size:]
|
ret, rest = data[:size], data[size:]
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.buf.write(rest)
|
self.buf.write(rest)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -216,7 +218,7 @@ class Body(object):
|
|||||||
|
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
ret, rest = data[:size], data[size:]
|
ret, rest = data[:size], data[size:]
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.buf.write(rest)
|
self.buf.write(rest)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -226,7 +228,7 @@ class Body(object):
|
|||||||
return b""
|
return b""
|
||||||
|
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
while 1:
|
while 1:
|
||||||
|
|||||||
@ -3,11 +3,11 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
import io
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
from errno import ENOTCONN
|
from errno import ENOTCONN
|
||||||
|
|
||||||
from gunicorn._compat import bytes_to_str
|
|
||||||
from gunicorn.http.unreader import SocketUnreader
|
from gunicorn.http.unreader import SocketUnreader
|
||||||
from gunicorn.http.body import ChunkedReader, LengthReader, EOFReader, Body
|
from gunicorn.http.body import ChunkedReader, LengthReader, EOFReader, Body
|
||||||
from gunicorn.http.errors import (InvalidHeader, InvalidHeaderName, NoMoreData,
|
from gunicorn.http.errors import (InvalidHeader, InvalidHeaderName, NoMoreData,
|
||||||
@ -15,8 +15,7 @@ from gunicorn.http.errors import (InvalidHeader, InvalidHeaderName, NoMoreData,
|
|||||||
LimitRequestLine, LimitRequestHeaders)
|
LimitRequestLine, LimitRequestHeaders)
|
||||||
from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
|
from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
|
||||||
from gunicorn.http.errors import InvalidSchemeHeaders
|
from gunicorn.http.errors import InvalidSchemeHeaders
|
||||||
from gunicorn.six import BytesIO, string_types
|
from gunicorn.util import bytes_to_str, split_request_uri
|
||||||
from gunicorn.util import split_request_uri
|
|
||||||
|
|
||||||
MAX_REQUEST_LINE = 8190
|
MAX_REQUEST_LINE = 8190
|
||||||
MAX_HEADERS = 32768
|
MAX_HEADERS = 32768
|
||||||
@ -76,7 +75,7 @@ class Message(object):
|
|||||||
remote_host = remote_addr[0]
|
remote_host = remote_addr[0]
|
||||||
if remote_host in cfg.forwarded_allow_ips:
|
if remote_host in cfg.forwarded_allow_ips:
|
||||||
secure_scheme_headers = cfg.secure_scheme_headers
|
secure_scheme_headers = cfg.secure_scheme_headers
|
||||||
elif isinstance(remote_addr, string_types):
|
elif isinstance(remote_addr, str):
|
||||||
secure_scheme_headers = cfg.secure_scheme_headers
|
secure_scheme_headers = cfg.secure_scheme_headers
|
||||||
|
|
||||||
# Parse headers into key/value pairs paying attention
|
# Parse headers into key/value pairs paying attention
|
||||||
@ -189,7 +188,7 @@ class Request(Message):
|
|||||||
buf.write(data)
|
buf.write(data)
|
||||||
|
|
||||||
def parse(self, unreader):
|
def parse(self, unreader):
|
||||||
buf = BytesIO()
|
buf = io.BytesIO()
|
||||||
self.get_data(unreader, buf, stop=True)
|
self.get_data(unreader, buf, stop=True)
|
||||||
|
|
||||||
# get request line
|
# get request line
|
||||||
@ -198,12 +197,12 @@ class Request(Message):
|
|||||||
# proxy protocol
|
# proxy protocol
|
||||||
if self.proxy_protocol(bytes_to_str(line)):
|
if self.proxy_protocol(bytes_to_str(line)):
|
||||||
# get next request line
|
# get next request line
|
||||||
buf = BytesIO()
|
buf = io.BytesIO()
|
||||||
buf.write(rbuf)
|
buf.write(rbuf)
|
||||||
line, rbuf = self.read_line(unreader, buf, self.limit_request_line)
|
line, rbuf = self.read_line(unreader, buf, self.limit_request_line)
|
||||||
|
|
||||||
self.parse_request_line(line)
|
self.parse_request_line(line)
|
||||||
buf = BytesIO()
|
buf = io.BytesIO()
|
||||||
buf.write(rbuf)
|
buf.write(rbuf)
|
||||||
|
|
||||||
# Headers
|
# Headers
|
||||||
|
|||||||
@ -3,23 +3,22 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
# Classes that can undo reading data from
|
# Classes that can undo reading data from
|
||||||
# a given type of data source.
|
# a given type of data source.
|
||||||
|
|
||||||
|
|
||||||
class Unreader(object):
|
class Unreader(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
|
|
||||||
def chunk(self):
|
def chunk(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def read(self, size=None):
|
def read(self, size=None):
|
||||||
if size is not None and not isinstance(size, six.integer_types):
|
if size is not None and not isinstance(size, int):
|
||||||
raise TypeError("size parameter must be an int or long.")
|
raise TypeError("size parameter must be an int or long.")
|
||||||
|
|
||||||
if size is not None:
|
if size is not None:
|
||||||
@ -32,7 +31,7 @@ class Unreader(object):
|
|||||||
|
|
||||||
if size is None and self.buf.tell():
|
if size is None and self.buf.tell():
|
||||||
ret = self.buf.getvalue()
|
ret = self.buf.getvalue()
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
return ret
|
return ret
|
||||||
if size is None:
|
if size is None:
|
||||||
d = self.chunk()
|
d = self.chunk()
|
||||||
@ -42,11 +41,11 @@ class Unreader(object):
|
|||||||
chunk = self.chunk()
|
chunk = self.chunk()
|
||||||
if not chunk:
|
if not chunk:
|
||||||
ret = self.buf.getvalue()
|
ret = self.buf.getvalue()
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
return ret
|
return ret
|
||||||
self.buf.write(chunk)
|
self.buf.write(chunk)
|
||||||
data = self.buf.getvalue()
|
data = self.buf.getvalue()
|
||||||
self.buf = six.BytesIO()
|
self.buf = io.BytesIO()
|
||||||
self.buf.write(data[size:])
|
self.buf.write(data[size:])
|
||||||
return data[:size]
|
return data[:size]
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ class IterUnreader(Unreader):
|
|||||||
if not self.iter:
|
if not self.iter:
|
||||||
return b""
|
return b""
|
||||||
try:
|
try:
|
||||||
return six.next(self.iter)
|
return next(self.iter)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
self.iter = None
|
self.iter = None
|
||||||
return b""
|
return b""
|
||||||
|
|||||||
@ -9,22 +9,11 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from gunicorn._compat import unquote_to_wsgi_str
|
|
||||||
from gunicorn.http.message import HEADER_RE
|
from gunicorn.http.message import HEADER_RE
|
||||||
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName
|
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName
|
||||||
from gunicorn.six import string_types, binary_type, reraise
|
|
||||||
from gunicorn import SERVER_SOFTWARE
|
from gunicorn import SERVER_SOFTWARE
|
||||||
import gunicorn.util as util
|
import gunicorn.util as util
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 3.3 has os.sendfile().
|
|
||||||
from os import sendfile
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from ._sendfile import sendfile
|
|
||||||
except ImportError:
|
|
||||||
sendfile = None
|
|
||||||
|
|
||||||
# Send files in at most 1GB blocks as some operating systems can have problems
|
# Send files in at most 1GB blocks as some operating systems can have problems
|
||||||
# with sending files in blocks over 2GB.
|
# with sending files in blocks over 2GB.
|
||||||
BLKSIZE = 0x3FFFFFFF
|
BLKSIZE = 0x3FFFFFFF
|
||||||
@ -155,9 +144,9 @@ def create(req, sock, client, server, cfg):
|
|||||||
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
|
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
|
||||||
# may not qualify the remote addr:
|
# may not qualify the remote addr:
|
||||||
# http://www.ietf.org/rfc/rfc3875
|
# http://www.ietf.org/rfc/rfc3875
|
||||||
if isinstance(client, string_types):
|
if isinstance(client, str):
|
||||||
environ['REMOTE_ADDR'] = client
|
environ['REMOTE_ADDR'] = client
|
||||||
elif isinstance(client, binary_type):
|
elif isinstance(client, bytes):
|
||||||
environ['REMOTE_ADDR'] = client.decode()
|
environ['REMOTE_ADDR'] = client.decode()
|
||||||
else:
|
else:
|
||||||
environ['REMOTE_ADDR'] = client[0]
|
environ['REMOTE_ADDR'] = client[0]
|
||||||
@ -167,7 +156,7 @@ def create(req, sock, client, server, cfg):
|
|||||||
# Normally only the application should use the Host header but since the
|
# Normally only the application should use the Host header but since the
|
||||||
# WSGI spec doesn't support unix sockets, we are using it to create
|
# WSGI spec doesn't support unix sockets, we are using it to create
|
||||||
# viable SERVER_* if possible.
|
# viable SERVER_* if possible.
|
||||||
if isinstance(server, string_types):
|
if isinstance(server, str):
|
||||||
server = server.split(":")
|
server = server.split(":")
|
||||||
if len(server) == 1:
|
if len(server) == 1:
|
||||||
# unix socket
|
# unix socket
|
||||||
@ -191,7 +180,7 @@ def create(req, sock, client, server, cfg):
|
|||||||
path_info = req.path
|
path_info = req.path
|
||||||
if script_name:
|
if script_name:
|
||||||
path_info = path_info.split(script_name, 1)[1]
|
path_info = path_info.split(script_name, 1)[1]
|
||||||
environ['PATH_INFO'] = unquote_to_wsgi_str(path_info)
|
environ['PATH_INFO'] = util.unquote_to_wsgi_str(path_info)
|
||||||
environ['SCRIPT_NAME'] = script_name
|
environ['SCRIPT_NAME'] = script_name
|
||||||
|
|
||||||
# override the environ with the correct remote and server address if
|
# override the environ with the correct remote and server address if
|
||||||
@ -234,7 +223,7 @@ class Response(object):
|
|||||||
if exc_info:
|
if exc_info:
|
||||||
try:
|
try:
|
||||||
if self.status and self.headers_sent:
|
if self.status and self.headers_sent:
|
||||||
reraise(exc_info[0], exc_info[1], exc_info[2])
|
util.reraise(exc_info[0], exc_info[1], exc_info[2])
|
||||||
finally:
|
finally:
|
||||||
exc_info = None
|
exc_info = None
|
||||||
elif self.status is not None:
|
elif self.status is not None:
|
||||||
@ -256,7 +245,7 @@ class Response(object):
|
|||||||
|
|
||||||
def process_headers(self, headers):
|
def process_headers(self, headers):
|
||||||
for name, value in headers:
|
for name, value in headers:
|
||||||
if not isinstance(name, string_types):
|
if not isinstance(name, str):
|
||||||
raise TypeError('%r is not a string' % name)
|
raise TypeError('%r is not a string' % name)
|
||||||
|
|
||||||
if HEADER_RE.search(name):
|
if HEADER_RE.search(name):
|
||||||
@ -331,7 +320,7 @@ class Response(object):
|
|||||||
|
|
||||||
def write(self, arg):
|
def write(self, arg):
|
||||||
self.send_headers()
|
self.send_headers()
|
||||||
if not isinstance(arg, binary_type):
|
if not isinstance(arg, bytes):
|
||||||
raise TypeError('%r is not a byte' % arg)
|
raise TypeError('%r is not a byte' % arg)
|
||||||
arglen = len(arg)
|
arglen = len(arg)
|
||||||
tosend = arglen
|
tosend = arglen
|
||||||
@ -353,7 +342,7 @@ class Response(object):
|
|||||||
util.write(self.sock, arg, self.chunked)
|
util.write(self.sock, arg, self.chunked)
|
||||||
|
|
||||||
def can_sendfile(self):
|
def can_sendfile(self):
|
||||||
return self.cfg.sendfile is not False and sendfile is not None
|
return self.cfg.sendfile is not False
|
||||||
|
|
||||||
def sendfile(self, respiter):
|
def sendfile(self, respiter):
|
||||||
if self.cfg.is_ssl or not self.can_sendfile():
|
if self.cfg.is_ssl or not self.can_sendfile():
|
||||||
@ -390,7 +379,7 @@ class Response(object):
|
|||||||
|
|
||||||
while sent != nbytes:
|
while sent != nbytes:
|
||||||
count = min(nbytes - sent, BLKSIZE)
|
count = min(nbytes - sent, BLKSIZE)
|
||||||
sent += sendfile(sockno, fileno, offset + sent, count)
|
sent += os.sendfile(sockno, fileno, offset + sent, count)
|
||||||
|
|
||||||
if self.is_chunked():
|
if self.is_chunked():
|
||||||
self.sock.sendall(b"\r\n")
|
self.sock.sendall(b"\r\n")
|
||||||
|
|||||||
@ -5,12 +5,11 @@
|
|||||||
|
|
||||||
"Bare-bones implementation of statsD's protocol, client-side"
|
"Bare-bones implementation of statsD's protocol, client-side"
|
||||||
|
|
||||||
import socket
|
|
||||||
import logging
|
import logging
|
||||||
|
import socket
|
||||||
from re import sub
|
from re import sub
|
||||||
|
|
||||||
from gunicorn.glogging import Logger
|
from gunicorn.glogging import Logger
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
# Instrumentation constants
|
# Instrumentation constants
|
||||||
METRIC_VAR = "metric"
|
METRIC_VAR = "metric"
|
||||||
@ -115,7 +114,7 @@ class Statsd(Logger):
|
|||||||
|
|
||||||
def _sock_send(self, msg):
|
def _sock_send(self, msg):
|
||||||
try:
|
try:
|
||||||
if isinstance(msg, six.text_type):
|
if isinstance(msg, str):
|
||||||
msg = msg.encode("ascii")
|
msg = msg.encode("ascii")
|
||||||
if self.sock:
|
if self.sock:
|
||||||
self.sock.send(msg)
|
self.sock.send(msg)
|
||||||
|
|||||||
762
gunicorn/six.py
762
gunicorn/six.py
@ -1,762 +0,0 @@
|
|||||||
"""Utilities for writing code that runs on Python 2 and 3"""
|
|
||||||
|
|
||||||
# Copyright (c) 2010-2014 Benjamin Peterson
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
import functools
|
|
||||||
import operator
|
|
||||||
import sys
|
|
||||||
import types
|
|
||||||
|
|
||||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
|
||||||
__version__ = "1.8.0"
|
|
||||||
|
|
||||||
|
|
||||||
# Useful for very coarse version differentiation.
|
|
||||||
PY2 = sys.version_info[0] == 2
|
|
||||||
PY3 = sys.version_info[0] == 3
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
string_types = str,
|
|
||||||
integer_types = int,
|
|
||||||
class_types = type,
|
|
||||||
text_type = str
|
|
||||||
binary_type = bytes
|
|
||||||
|
|
||||||
MAXSIZE = sys.maxsize
|
|
||||||
else:
|
|
||||||
string_types = basestring,
|
|
||||||
integer_types = (int, long)
|
|
||||||
class_types = (type, types.ClassType)
|
|
||||||
text_type = unicode
|
|
||||||
binary_type = str
|
|
||||||
|
|
||||||
if sys.platform.startswith("java"):
|
|
||||||
# Jython always uses 32 bits.
|
|
||||||
MAXSIZE = int((1 << 31) - 1)
|
|
||||||
else:
|
|
||||||
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
|
||||||
class X(object):
|
|
||||||
def __len__(self):
|
|
||||||
return 1 << 31
|
|
||||||
try:
|
|
||||||
len(X())
|
|
||||||
except OverflowError:
|
|
||||||
# 32-bit
|
|
||||||
MAXSIZE = int((1 << 31) - 1)
|
|
||||||
else:
|
|
||||||
# 64-bit
|
|
||||||
MAXSIZE = int((1 << 63) - 1)
|
|
||||||
del X
|
|
||||||
|
|
||||||
|
|
||||||
def _add_doc(func, doc):
|
|
||||||
"""Add documentation to a function."""
|
|
||||||
func.__doc__ = doc
|
|
||||||
|
|
||||||
|
|
||||||
def _import_module(name):
|
|
||||||
"""Import module, returning the module after the last dot."""
|
|
||||||
__import__(name)
|
|
||||||
return sys.modules[name]
|
|
||||||
|
|
||||||
|
|
||||||
class _LazyDescr(object):
|
|
||||||
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def __get__(self, obj, tp):
|
|
||||||
result = self._resolve()
|
|
||||||
setattr(obj, self.name, result) # Invokes __set__.
|
|
||||||
# This is a bit ugly, but it avoids running this again.
|
|
||||||
delattr(obj.__class__, self.name)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class MovedModule(_LazyDescr):
|
|
||||||
|
|
||||||
def __init__(self, name, old, new=None):
|
|
||||||
super(MovedModule, self).__init__(name)
|
|
||||||
if PY3:
|
|
||||||
if new is None:
|
|
||||||
new = name
|
|
||||||
self.mod = new
|
|
||||||
else:
|
|
||||||
self.mod = old
|
|
||||||
|
|
||||||
def _resolve(self):
|
|
||||||
return _import_module(self.mod)
|
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
_module = self._resolve()
|
|
||||||
value = getattr(_module, attr)
|
|
||||||
setattr(self, attr, value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class _LazyModule(types.ModuleType):
|
|
||||||
|
|
||||||
def __init__(self, name):
|
|
||||||
super(_LazyModule, self).__init__(name)
|
|
||||||
self.__doc__ = self.__class__.__doc__
|
|
||||||
|
|
||||||
def __dir__(self):
|
|
||||||
attrs = ["__doc__", "__name__"]
|
|
||||||
attrs += [attr.name for attr in self._moved_attributes]
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
# Subclasses should override this
|
|
||||||
_moved_attributes = []
|
|
||||||
|
|
||||||
|
|
||||||
class MovedAttribute(_LazyDescr):
|
|
||||||
|
|
||||||
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
|
|
||||||
super(MovedAttribute, self).__init__(name)
|
|
||||||
if PY3:
|
|
||||||
if new_mod is None:
|
|
||||||
new_mod = name
|
|
||||||
self.mod = new_mod
|
|
||||||
if new_attr is None:
|
|
||||||
if old_attr is None:
|
|
||||||
new_attr = name
|
|
||||||
else:
|
|
||||||
new_attr = old_attr
|
|
||||||
self.attr = new_attr
|
|
||||||
else:
|
|
||||||
self.mod = old_mod
|
|
||||||
if old_attr is None:
|
|
||||||
old_attr = name
|
|
||||||
self.attr = old_attr
|
|
||||||
|
|
||||||
def _resolve(self):
|
|
||||||
module = _import_module(self.mod)
|
|
||||||
return getattr(module, self.attr)
|
|
||||||
|
|
||||||
|
|
||||||
class _SixMetaPathImporter(object):
|
|
||||||
"""
|
|
||||||
A meta path importer to import six.moves and its submodules.
|
|
||||||
|
|
||||||
This class implements a PEP302 finder and loader. It should be compatible
|
|
||||||
with Python 2.5 and all existing versions of Python3
|
|
||||||
"""
|
|
||||||
def __init__(self, six_module_name):
|
|
||||||
self.name = six_module_name
|
|
||||||
self.known_modules = {}
|
|
||||||
|
|
||||||
def _add_module(self, mod, *fullnames):
|
|
||||||
for fullname in fullnames:
|
|
||||||
self.known_modules[self.name + "." + fullname] = mod
|
|
||||||
|
|
||||||
def _get_module(self, fullname):
|
|
||||||
return self.known_modules[self.name + "." + fullname]
|
|
||||||
|
|
||||||
def find_module(self, fullname, path=None):
|
|
||||||
if fullname in self.known_modules:
|
|
||||||
return self
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __get_module(self, fullname):
|
|
||||||
try:
|
|
||||||
return self.known_modules[fullname]
|
|
||||||
except KeyError:
|
|
||||||
raise ImportError("This loader does not know module " + fullname)
|
|
||||||
|
|
||||||
def load_module(self, fullname):
|
|
||||||
try:
|
|
||||||
# in case of a reload
|
|
||||||
return sys.modules[fullname]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
mod = self.__get_module(fullname)
|
|
||||||
if isinstance(mod, MovedModule):
|
|
||||||
mod = mod._resolve()
|
|
||||||
else:
|
|
||||||
mod.__loader__ = self
|
|
||||||
sys.modules[fullname] = mod
|
|
||||||
return mod
|
|
||||||
|
|
||||||
def is_package(self, fullname):
|
|
||||||
"""
|
|
||||||
Return true, if the named module is a package.
|
|
||||||
|
|
||||||
We need this method to get correct spec objects with
|
|
||||||
Python 3.4 (see PEP451)
|
|
||||||
"""
|
|
||||||
return hasattr(self.__get_module(fullname), "__path__")
|
|
||||||
|
|
||||||
def get_code(self, fullname):
|
|
||||||
"""Return None
|
|
||||||
|
|
||||||
Required, if is_package is implemented"""
|
|
||||||
self.__get_module(fullname) # eventually raises ImportError
|
|
||||||
return None
|
|
||||||
get_source = get_code # same as get_code
|
|
||||||
|
|
||||||
_importer = _SixMetaPathImporter(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class _MovedItems(_LazyModule):
|
|
||||||
"""Lazy loading of moved objects"""
|
|
||||||
__path__ = [] # mark as package
|
|
||||||
|
|
||||||
|
|
||||||
_moved_attributes = [
|
|
||||||
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
|
||||||
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
|
||||||
MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
|
|
||||||
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
|
||||||
MovedAttribute("intern", "__builtin__", "sys"),
|
|
||||||
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
|
||||||
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
|
||||||
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
|
|
||||||
MovedAttribute("reduce", "__builtin__", "functools"),
|
|
||||||
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
|
|
||||||
MovedAttribute("StringIO", "StringIO", "io"),
|
|
||||||
MovedAttribute("UserDict", "UserDict", "collections"),
|
|
||||||
MovedAttribute("UserList", "UserList", "collections"),
|
|
||||||
MovedAttribute("UserString", "UserString", "collections"),
|
|
||||||
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
|
||||||
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
|
||||||
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
|
|
||||||
|
|
||||||
MovedModule("builtins", "__builtin__"),
|
|
||||||
MovedModule("configparser", "ConfigParser"),
|
|
||||||
MovedModule("copyreg", "copy_reg"),
|
|
||||||
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
|
||||||
MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
|
|
||||||
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
|
||||||
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
|
||||||
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
|
||||||
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
|
||||||
MovedModule("http_client", "httplib", "http.client"),
|
|
||||||
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
|
||||||
MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
|
|
||||||
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
|
||||||
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
|
||||||
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
|
||||||
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
|
|
||||||
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
|
|
||||||
MovedModule("cPickle", "cPickle", "pickle"),
|
|
||||||
MovedModule("queue", "Queue"),
|
|
||||||
MovedModule("reprlib", "repr"),
|
|
||||||
MovedModule("socketserver", "SocketServer"),
|
|
||||||
MovedModule("_thread", "thread", "_thread"),
|
|
||||||
MovedModule("tkinter", "Tkinter"),
|
|
||||||
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
|
||||||
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
|
||||||
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
|
||||||
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
|
||||||
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
|
||||||
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
|
||||||
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
|
||||||
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
|
||||||
MovedModule("tkinter_colorchooser", "tkColorChooser",
|
|
||||||
"tkinter.colorchooser"),
|
|
||||||
MovedModule("tkinter_commondialog", "tkCommonDialog",
|
|
||||||
"tkinter.commondialog"),
|
|
||||||
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
|
||||||
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
|
||||||
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
|
||||||
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
|
|
||||||
"tkinter.simpledialog"),
|
|
||||||
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
|
||||||
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
|
||||||
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
|
||||||
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
|
||||||
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
|
|
||||||
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
|
|
||||||
MovedModule("winreg", "_winreg"),
|
|
||||||
]
|
|
||||||
for attr in _moved_attributes:
|
|
||||||
setattr(_MovedItems, attr.name, attr)
|
|
||||||
if isinstance(attr, MovedModule):
|
|
||||||
_importer._add_module(attr, "moves." + attr.name)
|
|
||||||
del attr
|
|
||||||
|
|
||||||
_MovedItems._moved_attributes = _moved_attributes
|
|
||||||
|
|
||||||
moves = _MovedItems(__name__ + ".moves")
|
|
||||||
_importer._add_module(moves, "moves")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_parse(_LazyModule):
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
|
||||||
|
|
||||||
|
|
||||||
_urllib_parse_moved_attributes = [
|
|
||||||
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("urljoin", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("urlparse", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("quote", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("splitquery", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("splittag", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("splituser", "urllib", "urllib.parse"),
|
|
||||||
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("uses_query", "urlparse", "urllib.parse"),
|
|
||||||
MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
|
|
||||||
]
|
|
||||||
for attr in _urllib_parse_moved_attributes:
|
|
||||||
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
|
||||||
del attr
|
|
||||||
|
|
||||||
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
|
||||||
|
|
||||||
_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
|
|
||||||
"moves.urllib_parse", "moves.urllib.parse")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_error(_LazyModule):
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
|
||||||
|
|
||||||
|
|
||||||
_urllib_error_moved_attributes = [
|
|
||||||
MovedAttribute("URLError", "urllib2", "urllib.error"),
|
|
||||||
MovedAttribute("HTTPError", "urllib2", "urllib.error"),
|
|
||||||
MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
|
|
||||||
]
|
|
||||||
for attr in _urllib_error_moved_attributes:
|
|
||||||
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
|
||||||
del attr
|
|
||||||
|
|
||||||
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
|
||||||
|
|
||||||
_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
|
|
||||||
"moves.urllib_error", "moves.urllib.error")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_request(_LazyModule):
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
|
||||||
|
|
||||||
|
|
||||||
_urllib_request_moved_attributes = [
|
|
||||||
MovedAttribute("urlopen", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("install_opener", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("build_opener", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("pathname2url", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("url2pathname", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("getproxies", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("Request", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("FileHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
|
|
||||||
MovedAttribute("urlretrieve", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
|
||||||
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
|
||||||
]
|
|
||||||
for attr in _urllib_request_moved_attributes:
|
|
||||||
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
|
||||||
del attr
|
|
||||||
|
|
||||||
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
|
||||||
|
|
||||||
_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
|
|
||||||
"moves.urllib_request", "moves.urllib.request")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_response(_LazyModule):
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
|
||||||
|
|
||||||
|
|
||||||
_urllib_response_moved_attributes = [
|
|
||||||
MovedAttribute("addbase", "urllib", "urllib.response"),
|
|
||||||
MovedAttribute("addclosehook", "urllib", "urllib.response"),
|
|
||||||
MovedAttribute("addinfo", "urllib", "urllib.response"),
|
|
||||||
MovedAttribute("addinfourl", "urllib", "urllib.response"),
|
|
||||||
]
|
|
||||||
for attr in _urllib_response_moved_attributes:
|
|
||||||
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
|
||||||
del attr
|
|
||||||
|
|
||||||
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
|
||||||
|
|
||||||
_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
|
|
||||||
"moves.urllib_response", "moves.urllib.response")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib_robotparser(_LazyModule):
|
|
||||||
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
|
||||||
|
|
||||||
|
|
||||||
_urllib_robotparser_moved_attributes = [
|
|
||||||
MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
|
|
||||||
]
|
|
||||||
for attr in _urllib_robotparser_moved_attributes:
|
|
||||||
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
|
||||||
del attr
|
|
||||||
|
|
||||||
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
|
|
||||||
|
|
||||||
_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
|
||||||
"moves.urllib_robotparser", "moves.urllib.robotparser")
|
|
||||||
|
|
||||||
|
|
||||||
class Module_six_moves_urllib(types.ModuleType):
|
|
||||||
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
|
|
||||||
__path__ = [] # mark as package
|
|
||||||
parse = _importer._get_module("moves.urllib_parse")
|
|
||||||
error = _importer._get_module("moves.urllib_error")
|
|
||||||
request = _importer._get_module("moves.urllib_request")
|
|
||||||
response = _importer._get_module("moves.urllib_response")
|
|
||||||
robotparser = _importer._get_module("moves.urllib_robotparser")
|
|
||||||
|
|
||||||
def __dir__(self):
|
|
||||||
return ['parse', 'error', 'request', 'response', 'robotparser']
|
|
||||||
|
|
||||||
_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
|
|
||||||
"moves.urllib")
|
|
||||||
|
|
||||||
|
|
||||||
def add_move(move):
|
|
||||||
"""Add an item to six.moves."""
|
|
||||||
setattr(_MovedItems, move.name, move)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_move(name):
|
|
||||||
"""Remove item from six.moves."""
|
|
||||||
try:
|
|
||||||
delattr(_MovedItems, name)
|
|
||||||
except AttributeError:
|
|
||||||
try:
|
|
||||||
del moves.__dict__[name]
|
|
||||||
except KeyError:
|
|
||||||
raise AttributeError("no such move, %r" % (name,))
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
_meth_func = "__func__"
|
|
||||||
_meth_self = "__self__"
|
|
||||||
|
|
||||||
_func_closure = "__closure__"
|
|
||||||
_func_code = "__code__"
|
|
||||||
_func_defaults = "__defaults__"
|
|
||||||
_func_globals = "__globals__"
|
|
||||||
else:
|
|
||||||
_meth_func = "im_func"
|
|
||||||
_meth_self = "im_self"
|
|
||||||
|
|
||||||
_func_closure = "func_closure"
|
|
||||||
_func_code = "func_code"
|
|
||||||
_func_defaults = "func_defaults"
|
|
||||||
_func_globals = "func_globals"
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
advance_iterator = next
|
|
||||||
except NameError:
|
|
||||||
def advance_iterator(it):
|
|
||||||
return it.next()
|
|
||||||
next = advance_iterator
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
callable = callable
|
|
||||||
except NameError:
|
|
||||||
def callable(obj):
|
|
||||||
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
def get_unbound_function(unbound):
|
|
||||||
return unbound
|
|
||||||
|
|
||||||
create_bound_method = types.MethodType
|
|
||||||
|
|
||||||
Iterator = object
|
|
||||||
else:
|
|
||||||
def get_unbound_function(unbound):
|
|
||||||
return unbound.im_func
|
|
||||||
|
|
||||||
def create_bound_method(func, obj):
|
|
||||||
return types.MethodType(func, obj, obj.__class__)
|
|
||||||
|
|
||||||
class Iterator(object):
|
|
||||||
|
|
||||||
def next(self):
|
|
||||||
return type(self).__next__(self)
|
|
||||||
|
|
||||||
callable = callable
|
|
||||||
_add_doc(get_unbound_function,
|
|
||||||
"""Get the function out of a possibly unbound function""")
|
|
||||||
|
|
||||||
|
|
||||||
get_method_function = operator.attrgetter(_meth_func)
|
|
||||||
get_method_self = operator.attrgetter(_meth_self)
|
|
||||||
get_function_closure = operator.attrgetter(_func_closure)
|
|
||||||
get_function_code = operator.attrgetter(_func_code)
|
|
||||||
get_function_defaults = operator.attrgetter(_func_defaults)
|
|
||||||
get_function_globals = operator.attrgetter(_func_globals)
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
def iterkeys(d, **kw):
|
|
||||||
return iter(d.keys(**kw))
|
|
||||||
|
|
||||||
def itervalues(d, **kw):
|
|
||||||
return iter(d.values(**kw))
|
|
||||||
|
|
||||||
def iteritems(d, **kw):
|
|
||||||
return iter(d.items(**kw))
|
|
||||||
|
|
||||||
def iterlists(d, **kw):
|
|
||||||
return iter(d.lists(**kw))
|
|
||||||
else:
|
|
||||||
def iterkeys(d, **kw):
|
|
||||||
return iter(d.iterkeys(**kw))
|
|
||||||
|
|
||||||
def itervalues(d, **kw):
|
|
||||||
return iter(d.itervalues(**kw))
|
|
||||||
|
|
||||||
def iteritems(d, **kw):
|
|
||||||
return iter(d.iteritems(**kw))
|
|
||||||
|
|
||||||
def iterlists(d, **kw):
|
|
||||||
return iter(d.iterlists(**kw))
|
|
||||||
|
|
||||||
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
|
|
||||||
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
|
|
||||||
_add_doc(iteritems,
|
|
||||||
"Return an iterator over the (key, value) pairs of a dictionary.")
|
|
||||||
_add_doc(iterlists,
|
|
||||||
"Return an iterator over the (key, [values]) pairs of a dictionary.")
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
def b(s):
|
|
||||||
return s.encode("latin-1")
|
|
||||||
def u(s):
|
|
||||||
return s
|
|
||||||
unichr = chr
|
|
||||||
if sys.version_info[1] <= 1:
|
|
||||||
def int2byte(i):
|
|
||||||
return bytes((i,))
|
|
||||||
else:
|
|
||||||
# This is about 2x faster than the implementation above on 3.2+
|
|
||||||
int2byte = operator.methodcaller("to_bytes", 1, "big")
|
|
||||||
byte2int = operator.itemgetter(0)
|
|
||||||
indexbytes = operator.getitem
|
|
||||||
iterbytes = iter
|
|
||||||
import io
|
|
||||||
StringIO = io.StringIO
|
|
||||||
BytesIO = io.BytesIO
|
|
||||||
else:
|
|
||||||
def b(s):
|
|
||||||
return s
|
|
||||||
# Workaround for standalone backslash
|
|
||||||
def u(s):
|
|
||||||
return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
|
|
||||||
unichr = unichr
|
|
||||||
int2byte = chr
|
|
||||||
def byte2int(bs):
|
|
||||||
return ord(bs[0])
|
|
||||||
def indexbytes(buf, i):
|
|
||||||
return ord(buf[i])
|
|
||||||
def iterbytes(buf):
|
|
||||||
return (ord(byte) for byte in buf)
|
|
||||||
import StringIO
|
|
||||||
StringIO = BytesIO = StringIO.StringIO
|
|
||||||
_add_doc(b, """Byte literal""")
|
|
||||||
_add_doc(u, """Text literal""")
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
exec_ = getattr(moves.builtins, "exec")
|
|
||||||
|
|
||||||
|
|
||||||
def reraise(tp, value, tb=None):
|
|
||||||
if value is None:
|
|
||||||
value = tp()
|
|
||||||
if value.__traceback__ is not tb:
|
|
||||||
raise value.with_traceback(tb)
|
|
||||||
raise value
|
|
||||||
|
|
||||||
else:
|
|
||||||
def exec_(_code_, _globs_=None, _locs_=None):
|
|
||||||
"""Execute code in a namespace."""
|
|
||||||
if _globs_ is None:
|
|
||||||
frame = sys._getframe(1)
|
|
||||||
_globs_ = frame.f_globals
|
|
||||||
if _locs_ is None:
|
|
||||||
_locs_ = frame.f_locals
|
|
||||||
del frame
|
|
||||||
elif _locs_ is None:
|
|
||||||
_locs_ = _globs_
|
|
||||||
exec("""exec _code_ in _globs_, _locs_""")
|
|
||||||
|
|
||||||
|
|
||||||
exec_("""def reraise(tp, value, tb=None):
|
|
||||||
raise tp, value, tb
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
print_ = getattr(moves.builtins, "print", None)
|
|
||||||
if print_ is None:
|
|
||||||
def print_(*args, **kwargs):
|
|
||||||
"""The new-style print function for Python 2.4 and 2.5."""
|
|
||||||
fp = kwargs.pop("file", sys.stdout)
|
|
||||||
if fp is None:
|
|
||||||
return
|
|
||||||
def write(data):
|
|
||||||
if not isinstance(data, basestring):
|
|
||||||
data = str(data)
|
|
||||||
# If the file has an encoding, encode unicode with it.
|
|
||||||
if (isinstance(fp, file) and
|
|
||||||
isinstance(data, unicode) and
|
|
||||||
fp.encoding is not None):
|
|
||||||
errors = getattr(fp, "errors", None)
|
|
||||||
if errors is None:
|
|
||||||
errors = "strict"
|
|
||||||
data = data.encode(fp.encoding, errors)
|
|
||||||
fp.write(data)
|
|
||||||
want_unicode = False
|
|
||||||
sep = kwargs.pop("sep", None)
|
|
||||||
if sep is not None:
|
|
||||||
if isinstance(sep, unicode):
|
|
||||||
want_unicode = True
|
|
||||||
elif not isinstance(sep, str):
|
|
||||||
raise TypeError("sep must be None or a string")
|
|
||||||
end = kwargs.pop("end", None)
|
|
||||||
if end is not None:
|
|
||||||
if isinstance(end, unicode):
|
|
||||||
want_unicode = True
|
|
||||||
elif not isinstance(end, str):
|
|
||||||
raise TypeError("end must be None or a string")
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError("invalid keyword arguments to print()")
|
|
||||||
if not want_unicode:
|
|
||||||
for arg in args:
|
|
||||||
if isinstance(arg, unicode):
|
|
||||||
want_unicode = True
|
|
||||||
break
|
|
||||||
if want_unicode:
|
|
||||||
newline = unicode("\n")
|
|
||||||
space = unicode(" ")
|
|
||||||
else:
|
|
||||||
newline = "\n"
|
|
||||||
space = " "
|
|
||||||
if sep is None:
|
|
||||||
sep = space
|
|
||||||
if end is None:
|
|
||||||
end = newline
|
|
||||||
for i, arg in enumerate(args):
|
|
||||||
if i:
|
|
||||||
write(sep)
|
|
||||||
write(arg)
|
|
||||||
write(end)
|
|
||||||
|
|
||||||
_add_doc(reraise, """Reraise an exception.""")
|
|
||||||
|
|
||||||
if sys.version_info[0:2] < (3, 4):
|
|
||||||
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
|
|
||||||
updated=functools.WRAPPER_UPDATES):
|
|
||||||
def wrapper(f):
|
|
||||||
f = functools.wraps(wrapped)(f)
|
|
||||||
f.__wrapped__ = wrapped
|
|
||||||
return f
|
|
||||||
return wrapper
|
|
||||||
else:
|
|
||||||
wraps = functools.wraps
|
|
||||||
|
|
||||||
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):
|
|
||||||
def __new__(cls, name, this_bases, d):
|
|
||||||
return meta(name, bases, d)
|
|
||||||
return type.__new__(metaclass, 'temporary_class', (), {})
|
|
||||||
|
|
||||||
|
|
||||||
def add_metaclass(metaclass):
|
|
||||||
"""Class decorator for creating a class with a metaclass."""
|
|
||||||
def wrapper(cls):
|
|
||||||
orig_vars = cls.__dict__.copy()
|
|
||||||
slots = orig_vars.get('__slots__')
|
|
||||||
if slots is not None:
|
|
||||||
if isinstance(slots, str):
|
|
||||||
slots = [slots]
|
|
||||||
for slots_var in slots:
|
|
||||||
orig_vars.pop(slots_var)
|
|
||||||
orig_vars.pop('__dict__', None)
|
|
||||||
orig_vars.pop('__weakref__', None)
|
|
||||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
# Complete the moves implementation.
|
|
||||||
# This code is at the end of this module to speed up module loading.
|
|
||||||
# Turn this module into a package.
|
|
||||||
__path__ = [] # required for PEP 302 and PEP 451
|
|
||||||
__package__ = __name__ # see PEP 366 @ReservedAssignment
|
|
||||||
if globals().get("__spec__") is not None:
|
|
||||||
__spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
|
|
||||||
# Remove other six meta path importers, since they cause problems. This can
|
|
||||||
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
|
|
||||||
# this for some reason.)
|
|
||||||
if sys.meta_path:
|
|
||||||
for i, importer in enumerate(sys.meta_path):
|
|
||||||
# Here's some real nastiness: Another "instance" of the six module might
|
|
||||||
# be floating around. Therefore, we can't use isinstance() to check for
|
|
||||||
# the six meta path importer, since the other six instance will have
|
|
||||||
# inserted an importer with different class.
|
|
||||||
if (type(importer).__name__ == "_SixMetaPathImporter" and
|
|
||||||
importer.name == __name__):
|
|
||||||
del sys.meta_path[i]
|
|
||||||
break
|
|
||||||
del i, importer
|
|
||||||
# Finally, add the importer to the meta path import hook.
|
|
||||||
sys.meta_path.append(_importer)
|
|
||||||
@ -11,7 +11,6 @@ import sys
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
from gunicorn.six import string_types
|
|
||||||
|
|
||||||
|
|
||||||
class BaseSocket(object):
|
class BaseSocket(object):
|
||||||
@ -133,7 +132,7 @@ def _sock_type(addr):
|
|||||||
sock_type = TCP6Socket
|
sock_type = TCP6Socket
|
||||||
else:
|
else:
|
||||||
sock_type = TCPSocket
|
sock_type = TCPSocket
|
||||||
elif isinstance(addr, string_types):
|
elif isinstance(addr, str):
|
||||||
sock_type = UnixSocket
|
sock_type = UnixSocket
|
||||||
else:
|
else:
|
||||||
raise TypeError("Unable to create socket from: %r" % addr)
|
raise TypeError("Unable to create socket from: %r" % addr)
|
||||||
|
|||||||
@ -3,30 +3,29 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import email.utils
|
import email.utils
|
||||||
|
import errno
|
||||||
import fcntl
|
import fcntl
|
||||||
|
import html
|
||||||
|
import inspect
|
||||||
import io
|
import io
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import pkg_resources
|
|
||||||
import pwd
|
import pwd
|
||||||
import random
|
import random
|
||||||
|
import re
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import inspect
|
|
||||||
import errno
|
|
||||||
import warnings
|
import warnings
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
|
|
||||||
from gunicorn import _compat
|
import pkg_resources
|
||||||
|
|
||||||
from gunicorn.errors import AppImportError
|
from gunicorn.errors import AppImportError
|
||||||
from gunicorn.six import text_type
|
|
||||||
from gunicorn.workers import SUPPORTED_WORKERS
|
from gunicorn.workers import SUPPORTED_WORKERS
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
REDIRECT_TO = getattr(os, 'devnull', '/dev/null')
|
REDIRECT_TO = getattr(os, 'devnull', '/dev/null')
|
||||||
|
|
||||||
@ -140,6 +139,23 @@ def load_class(uri, default="gunicorn.workers.sync.SyncWorker",
|
|||||||
return getattr(mod, klass)
|
return getattr(mod, klass)
|
||||||
|
|
||||||
|
|
||||||
|
positionals = (
|
||||||
|
inspect.Parameter.POSITIONAL_ONLY,
|
||||||
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_arity(f):
|
||||||
|
sig = inspect.signature(f)
|
||||||
|
arity = 0
|
||||||
|
|
||||||
|
for param in sig.parameters.values():
|
||||||
|
if param.kind in positionals:
|
||||||
|
arity += 1
|
||||||
|
|
||||||
|
return arity
|
||||||
|
|
||||||
|
|
||||||
def get_username(uid):
|
def get_username(uid):
|
||||||
""" get the username for a user id"""
|
""" get the username for a user id"""
|
||||||
return pwd.getpwuid(uid).pw_name
|
return pwd.getpwuid(uid).pw_name
|
||||||
@ -169,7 +185,6 @@ def set_owner_process(uid, gid, initgroups=False):
|
|||||||
|
|
||||||
|
|
||||||
def chown(path, uid, gid):
|
def chown(path, uid, gid):
|
||||||
gid = abs(gid) & 0x7FFFFFFF # see note above.
|
|
||||||
os.chown(path, uid, gid)
|
os.chown(path, uid, gid)
|
||||||
|
|
||||||
|
|
||||||
@ -291,7 +306,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
def write_chunk(sock, data):
|
def write_chunk(sock, data):
|
||||||
if isinstance(data, text_type):
|
if isinstance(data, str):
|
||||||
data = data.encode('utf-8')
|
data = data.encode('utf-8')
|
||||||
chunk_size = "%X\r\n" % len(data)
|
chunk_size = "%X\r\n" % len(data)
|
||||||
chunk = b"".join([chunk_size.encode('utf-8'), data, b"\r\n"])
|
chunk = b"".join([chunk_size.encode('utf-8'), data, b"\r\n"])
|
||||||
@ -317,7 +332,7 @@ def write_nonblock(sock, data, chunked=False):
|
|||||||
|
|
||||||
|
|
||||||
def write_error(sock, status_int, reason, mesg):
|
def write_error(sock, status_int, reason, mesg):
|
||||||
html = textwrap.dedent("""\
|
html_error = textwrap.dedent("""\
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>%(reason)s</title>
|
<title>%(reason)s</title>
|
||||||
@ -327,7 +342,7 @@ def write_error(sock, status_int, reason, mesg):
|
|||||||
%(mesg)s
|
%(mesg)s
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
""") % {"reason": reason, "mesg": _compat.html_escape(mesg)}
|
""") % {"reason": reason, "mesg": html.escape(mesg)}
|
||||||
|
|
||||||
http = textwrap.dedent("""\
|
http = textwrap.dedent("""\
|
||||||
HTTP/1.1 %s %s\r
|
HTTP/1.1 %s %s\r
|
||||||
@ -335,7 +350,7 @@ def write_error(sock, status_int, reason, mesg):
|
|||||||
Content-Type: text/html\r
|
Content-Type: text/html\r
|
||||||
Content-Length: %d\r
|
Content-Length: %d\r
|
||||||
\r
|
\r
|
||||||
%s""") % (str(status_int), reason, len(html), html)
|
%s""") % (str(status_int), reason, len(html_error), html_error)
|
||||||
write_nonblock(sock, http.encode('latin1'))
|
write_nonblock(sock, http.encode('latin1'))
|
||||||
|
|
||||||
|
|
||||||
@ -501,7 +516,7 @@ def to_bytestring(value, encoding="utf8"):
|
|||||||
"""Converts a string argument to a byte string"""
|
"""Converts a string argument to a byte string"""
|
||||||
if isinstance(value, bytes):
|
if isinstance(value, bytes):
|
||||||
return value
|
return value
|
||||||
if not isinstance(value, text_type):
|
if not isinstance(value, str):
|
||||||
raise TypeError('%r is not a string' % value)
|
raise TypeError('%r is not a string' % value)
|
||||||
|
|
||||||
return value.encode(encoding)
|
return value.encode(encoding)
|
||||||
@ -551,7 +566,30 @@ def split_request_uri(uri):
|
|||||||
# relative uri while the RFC says we should consider it as abs_path
|
# relative uri while the RFC says we should consider it as abs_path
|
||||||
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
||||||
# We use temporary dot prefix to workaround this behaviour
|
# We use temporary dot prefix to workaround this behaviour
|
||||||
parts = _compat.urlsplit("." + uri)
|
parts = urllib.parse.urlsplit("." + uri)
|
||||||
return parts._replace(path=parts.path[1:])
|
return parts._replace(path=parts.path[1:])
|
||||||
|
|
||||||
return _compat.urlsplit(uri)
|
return urllib.parse.urlsplit(uri)
|
||||||
|
|
||||||
|
|
||||||
|
# From six.reraise
|
||||||
|
def reraise(tp, value, tb=None):
|
||||||
|
try:
|
||||||
|
if value is None:
|
||||||
|
value = tp()
|
||||||
|
if value.__traceback__ is not tb:
|
||||||
|
raise value.with_traceback(tb)
|
||||||
|
raise value
|
||||||
|
finally:
|
||||||
|
value = None
|
||||||
|
tb = None
|
||||||
|
|
||||||
|
|
||||||
|
def bytes_to_str(b):
|
||||||
|
if isinstance(b, str):
|
||||||
|
return b
|
||||||
|
return str(b, 'latin1')
|
||||||
|
|
||||||
|
|
||||||
|
def unquote_to_wsgi_str(string):
|
||||||
|
return urllib.parse.unquote_to_bytes(string).decode('latin-1')
|
||||||
|
|||||||
@ -3,20 +3,14 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# supported gunicorn workers.
|
# supported gunicorn workers.
|
||||||
SUPPORTED_WORKERS = {
|
SUPPORTED_WORKERS = {
|
||||||
"sync": "gunicorn.workers.sync.SyncWorker",
|
"sync": "gunicorn.workers.sync.SyncWorker",
|
||||||
"eventlet": "gunicorn.workers.geventlet.EventletWorker",
|
"eventlet": "gunicorn.workers.geventlet.EventletWorker",
|
||||||
|
"gaiohttp": "gunicorn.workers.gaiohttp.AiohttpWorker",
|
||||||
"gevent": "gunicorn.workers.ggevent.GeventWorker",
|
"gevent": "gunicorn.workers.ggevent.GeventWorker",
|
||||||
"gevent_wsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
"gevent_wsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
||||||
"gevent_pywsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
"gevent_pywsgi": "gunicorn.workers.ggevent.GeventPyWSGIWorker",
|
||||||
"tornado": "gunicorn.workers.gtornado.TornadoWorker",
|
"tornado": "gunicorn.workers.gtornado.TornadoWorker",
|
||||||
"gthread": "gunicorn.workers.gthread.ThreadWorker",
|
"gthread": "gunicorn.workers.gthread.ThreadWorker",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
|
||||||
# gaiohttp worker can be used with Python 3.4+ only.
|
|
||||||
SUPPORTED_WORKERS["gaiohttp"] = "gunicorn.workers.gaiohttp.AiohttpWorker"
|
|
||||||
|
|||||||
@ -3,27 +3,27 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
from datetime import datetime
|
import io
|
||||||
import os
|
import os
|
||||||
from random import randint
|
|
||||||
import signal
|
import signal
|
||||||
from ssl import SSLError
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
from datetime import datetime
|
||||||
|
from random import randint
|
||||||
|
from ssl import SSLError
|
||||||
|
|
||||||
from gunicorn import six
|
|
||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
from gunicorn.workers.workertmp import WorkerTmp
|
|
||||||
from gunicorn.reloader import reloader_engines
|
|
||||||
from gunicorn.http.errors import (
|
from gunicorn.http.errors import (
|
||||||
InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,
|
ForbiddenProxyRequest, InvalidHeader,
|
||||||
InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,
|
InvalidHeaderName, InvalidHTTPVersion,
|
||||||
|
InvalidProxyLine, InvalidRequestLine,
|
||||||
|
InvalidRequestMethod, InvalidSchemeHeaders,
|
||||||
|
LimitRequestHeaders, LimitRequestLine,
|
||||||
)
|
)
|
||||||
from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
|
from gunicorn.http.wsgi import Response, default_environ
|
||||||
from gunicorn.http.errors import InvalidSchemeHeaders
|
from gunicorn.reloader import reloader_engines
|
||||||
from gunicorn.http.wsgi import default_environ, Response
|
from gunicorn.workers.workertmp import WorkerTmp
|
||||||
from gunicorn.six import MAXSIZE
|
|
||||||
|
|
||||||
|
|
||||||
class Worker(object):
|
class Worker(object):
|
||||||
@ -52,7 +52,7 @@ class Worker(object):
|
|||||||
|
|
||||||
self.nr = 0
|
self.nr = 0
|
||||||
jitter = randint(0, cfg.max_requests_jitter)
|
jitter = randint(0, cfg.max_requests_jitter)
|
||||||
self.max_requests = cfg.max_requests + jitter or MAXSIZE
|
self.max_requests = cfg.max_requests + jitter or sys.maxsize
|
||||||
self.alive = True
|
self.alive = True
|
||||||
self.log = log
|
self.log = log
|
||||||
self.tmp = WorkerTmp(cfg)
|
self.tmp = WorkerTmp(cfg)
|
||||||
@ -150,7 +150,7 @@ class Worker(object):
|
|||||||
_, exc_val, exc_tb = sys.exc_info()
|
_, exc_val, exc_tb = sys.exc_info()
|
||||||
self.reloader.add_extra_file(exc_val.filename)
|
self.reloader.add_extra_file(exc_val.filename)
|
||||||
|
|
||||||
tb_string = six.StringIO()
|
tb_string = io.StringIO()
|
||||||
traceback.print_tb(exc_tb, file=tb_string)
|
traceback.print_tb(exc_tb, file=tb_string)
|
||||||
self.wsgi = util.make_fail_app(tb_string.getvalue())
|
self.wsgi = util.make_fail_app(tb_string.getvalue())
|
||||||
finally:
|
finally:
|
||||||
@ -170,9 +170,8 @@ class Worker(object):
|
|||||||
|
|
||||||
# Don't let SIGTERM and SIGUSR1 disturb active requests
|
# Don't let SIGTERM and SIGUSR1 disturb active requests
|
||||||
# by interrupting system calls
|
# by interrupting system calls
|
||||||
if hasattr(signal, 'siginterrupt'): # python >= 2.6
|
signal.siginterrupt(signal.SIGTERM, False)
|
||||||
signal.siginterrupt(signal.SIGTERM, False)
|
signal.siginterrupt(signal.SIGUSR1, False)
|
||||||
signal.siginterrupt(signal.SIGUSR1, False)
|
|
||||||
|
|
||||||
if hasattr(signal, 'set_wakeup_fd'):
|
if hasattr(signal, 'set_wakeup_fd'):
|
||||||
signal.set_wakeup_fd(self.PIPE[1])
|
signal.set_wakeup_fd(self.PIPE[1])
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import gunicorn.http as http
|
|||||||
import gunicorn.http.wsgi as wsgi
|
import gunicorn.http.wsgi as wsgi
|
||||||
import gunicorn.util as util
|
import gunicorn.util as util
|
||||||
import gunicorn.workers.base as base
|
import gunicorn.workers.base as base
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
ALREADY_HANDLED = object()
|
ALREADY_HANDLED = object()
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ class AsyncWorker(base.Worker):
|
|||||||
try:
|
try:
|
||||||
listener_name = listener.getsockname()
|
listener_name = listener.getsockname()
|
||||||
if not self.cfg.keepalive:
|
if not self.cfg.keepalive:
|
||||||
req = six.next(parser)
|
req = next(parser)
|
||||||
self.handle_request(listener_name, req, client, addr)
|
self.handle_request(listener_name, req, client, addr)
|
||||||
else:
|
else:
|
||||||
# keepalive loop
|
# keepalive loop
|
||||||
@ -46,7 +45,7 @@ class AsyncWorker(base.Worker):
|
|||||||
while True:
|
while True:
|
||||||
req = None
|
req = None
|
||||||
with self.timeout_ctx():
|
with self.timeout_ctx():
|
||||||
req = six.next(parser)
|
req = next(parser)
|
||||||
if not req:
|
if not req:
|
||||||
break
|
break
|
||||||
if req.proxy_protocol_info:
|
if req.proxy_protocol_info:
|
||||||
@ -60,10 +59,10 @@ class AsyncWorker(base.Worker):
|
|||||||
self.log.debug("Closing connection. %s", e)
|
self.log.debug("Closing connection. %s", e)
|
||||||
except ssl.SSLError:
|
except ssl.SSLError:
|
||||||
# pass to next try-except level
|
# pass to next try-except level
|
||||||
six.reraise(*sys.exc_info())
|
util.reraise(*sys.exc_info())
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
# pass to next try-except level
|
# pass to next try-except level
|
||||||
six.reraise(*sys.exc_info())
|
util.reraise(*sys.exc_info())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.handle_error(req, client, addr, e)
|
self.handle_error(req, client, addr, e)
|
||||||
except ssl.SSLError as e:
|
except ssl.SSLError as e:
|
||||||
@ -126,7 +125,7 @@ class AsyncWorker(base.Worker):
|
|||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
# If the original exception was a socket.error we delegate
|
# If the original exception was a socket.error we delegate
|
||||||
# handling it to the caller (where handle() might ignore it)
|
# handling it to the caller (where handle() might ignore it)
|
||||||
six.reraise(*sys.exc_info())
|
util.reraise(*sys.exc_info())
|
||||||
except Exception:
|
except Exception:
|
||||||
if resp and resp.headers_sent:
|
if resp and resp.headers_sent:
|
||||||
# If the requests have already been sent, we should close the
|
# If the requests have already been sent, we should close the
|
||||||
|
|||||||
@ -3,25 +3,20 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
try:
|
||||||
try:
|
import aiohttp # pylint: disable=unused-import
|
||||||
import aiohttp # pylint: disable=unused-import
|
except ImportError:
|
||||||
except ImportError:
|
raise RuntimeError("You need aiohttp installed to use this worker.")
|
||||||
raise RuntimeError("You need aiohttp installed to use this worker.")
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
from aiohttp.worker import GunicornWebWorker as AiohttpWorker
|
|
||||||
except ImportError:
|
|
||||||
from gunicorn.workers._gaiohttp import AiohttpWorker
|
|
||||||
|
|
||||||
util.warn(
|
|
||||||
"The 'gaiohttp' worker is deprecated. See --worker-class "
|
|
||||||
"documentation for more information."
|
|
||||||
)
|
|
||||||
__all__ = ['AiohttpWorker']
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("You need Python >= 3.4 to use the gaiohttp worker")
|
try:
|
||||||
|
from aiohttp.worker import GunicornWebWorker as AiohttpWorker
|
||||||
|
except ImportError:
|
||||||
|
from gunicorn.workers._gaiohttp import AiohttpWorker
|
||||||
|
|
||||||
|
util.warn(
|
||||||
|
"The 'gaiohttp' worker is deprecated. See --worker-class "
|
||||||
|
"documentation for more information."
|
||||||
|
)
|
||||||
|
__all__ = ['AiohttpWorker']
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import errno
|
import errno
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -23,13 +24,12 @@ from eventlet.hubs import trampoline
|
|||||||
from eventlet.wsgi import ALREADY_HANDLED as EVENTLET_ALREADY_HANDLED
|
from eventlet.wsgi import ALREADY_HANDLED as EVENTLET_ALREADY_HANDLED
|
||||||
import greenlet
|
import greenlet
|
||||||
|
|
||||||
from gunicorn.http.wsgi import sendfile as o_sendfile
|
|
||||||
from gunicorn.workers.base_async import AsyncWorker
|
from gunicorn.workers.base_async import AsyncWorker
|
||||||
|
|
||||||
def _eventlet_sendfile(fdout, fdin, offset, nbytes):
|
def _eventlet_sendfile(fdout, fdin, offset, nbytes):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
return o_sendfile(fdout, fdin, offset, nbytes)
|
return os.sendfile(fdout, fdin, offset, nbytes)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.args[0] == errno.EAGAIN:
|
if e.args[0] == errno.EAGAIN:
|
||||||
trampoline(fdout, write=True)
|
trampoline(fdout, write=True)
|
||||||
@ -79,10 +79,7 @@ def _eventlet_stop(client, server, conn):
|
|||||||
|
|
||||||
|
|
||||||
def patch_sendfile():
|
def patch_sendfile():
|
||||||
from gunicorn.http import wsgi
|
setattr(os, "sendfile", _eventlet_sendfile)
|
||||||
|
|
||||||
if o_sendfile is not None:
|
|
||||||
setattr(wsgi, "sendfile", _eventlet_sendfile)
|
|
||||||
|
|
||||||
|
|
||||||
class EventletWorker(AsyncWorker):
|
class EventletWorker(AsyncWorker):
|
||||||
|
|||||||
@ -28,14 +28,13 @@ from gevent import pywsgi
|
|||||||
import gunicorn
|
import gunicorn
|
||||||
from gunicorn.http.wsgi import base_environ
|
from gunicorn.http.wsgi import base_environ
|
||||||
from gunicorn.workers.base_async import AsyncWorker
|
from gunicorn.workers.base_async import AsyncWorker
|
||||||
from gunicorn.http.wsgi import sendfile as o_sendfile
|
|
||||||
|
|
||||||
VERSION = "gevent/%s gunicorn/%s" % (gevent.__version__, gunicorn.__version__)
|
VERSION = "gevent/%s gunicorn/%s" % (gevent.__version__, gunicorn.__version__)
|
||||||
|
|
||||||
def _gevent_sendfile(fdout, fdin, offset, nbytes):
|
def _gevent_sendfile(fdout, fdin, offset, nbytes):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
return o_sendfile(fdout, fdin, offset, nbytes)
|
return os.sendfile(fdout, fdin, offset, nbytes)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.args[0] == errno.EAGAIN:
|
if e.args[0] == errno.EAGAIN:
|
||||||
wait_write(fdout)
|
wait_write(fdout)
|
||||||
@ -43,10 +42,7 @@ def _gevent_sendfile(fdout, fdin, offset, nbytes):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def patch_sendfile():
|
def patch_sendfile():
|
||||||
from gunicorn.http import wsgi
|
setattr(os, "sendfile", _gevent_sendfile)
|
||||||
|
|
||||||
if o_sendfile is not None:
|
|
||||||
setattr(wsgi, "sendfile", _gevent_sendfile)
|
|
||||||
|
|
||||||
|
|
||||||
class GeventWorker(AsyncWorker):
|
class GeventWorker(AsyncWorker):
|
||||||
@ -70,12 +66,8 @@ class GeventWorker(AsyncWorker):
|
|||||||
# patch sockets
|
# patch sockets
|
||||||
sockets = []
|
sockets = []
|
||||||
for s in self.sockets:
|
for s in self.sockets:
|
||||||
if sys.version_info[0] == 3:
|
sockets.append(socket(s.FAMILY, _socket.SOCK_STREAM,
|
||||||
sockets.append(socket(s.FAMILY, _socket.SOCK_STREAM,
|
fileno=s.sock.fileno()))
|
||||||
fileno=s.sock.fileno()))
|
|
||||||
else:
|
|
||||||
sockets.append(socket(s.FAMILY, _socket.SOCK_STREAM,
|
|
||||||
_sock=s))
|
|
||||||
self.sockets = sockets
|
self.sockets = sockets
|
||||||
|
|
||||||
def notify(self):
|
def notify(self):
|
||||||
|
|||||||
@ -10,23 +10,22 @@
|
|||||||
# If no event happen after the keep alive timeout, the connectoin is
|
# If no event happen after the keep alive timeout, the connectoin is
|
||||||
# closed.
|
# closed.
|
||||||
|
|
||||||
from collections import deque
|
|
||||||
from datetime import datetime
|
|
||||||
import errno
|
import errno
|
||||||
from functools import partial
|
|
||||||
import os
|
import os
|
||||||
|
import selectors
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
from threading import RLock
|
|
||||||
import time
|
import time
|
||||||
|
from collections import deque
|
||||||
|
from datetime import datetime
|
||||||
|
from functools import partial
|
||||||
|
from threading import RLock
|
||||||
|
|
||||||
from .. import http
|
|
||||||
from ..http import wsgi
|
|
||||||
from .. import util
|
|
||||||
from . import base
|
from . import base
|
||||||
from .. import six
|
from .. import http
|
||||||
|
from .. import util
|
||||||
|
from ..http import wsgi
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import concurrent.futures as futures
|
import concurrent.futures as futures
|
||||||
@ -36,19 +35,6 @@ except ImportError:
|
|||||||
Python version.
|
Python version.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 3.4+
|
|
||||||
import selectors
|
|
||||||
except ImportError:
|
|
||||||
# Python 2
|
|
||||||
try:
|
|
||||||
import selectors34 as selectors
|
|
||||||
except ImportError:
|
|
||||||
raise RuntimeError(
|
|
||||||
"You need to install the 'selectors34' package to use this worker "
|
|
||||||
"with this Python version."
|
|
||||||
)
|
|
||||||
|
|
||||||
class TConn(object):
|
class TConn(object):
|
||||||
|
|
||||||
def __init__(self, cfg, sock, client, server):
|
def __init__(self, cfg, sock, client, server):
|
||||||
@ -278,7 +264,7 @@ class ThreadWorker(base.Worker):
|
|||||||
keepalive = False
|
keepalive = False
|
||||||
req = None
|
req = None
|
||||||
try:
|
try:
|
||||||
req = six.next(conn.parser)
|
req = next(conn.parser)
|
||||||
if not req:
|
if not req:
|
||||||
return (False, conn)
|
return (False, conn)
|
||||||
|
|
||||||
@ -352,7 +338,7 @@ class ThreadWorker(base.Worker):
|
|||||||
return False
|
return False
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
# pass to next try-except level
|
# pass to next try-except level
|
||||||
six.reraise(*sys.exc_info())
|
util.reraise(*sys.exc_info())
|
||||||
except Exception:
|
except Exception:
|
||||||
if resp and resp.headers_sent:
|
if resp and resp.headers_sent:
|
||||||
# If the requests have already been sent, we should close the
|
# If the requests have already been sent, we should close the
|
||||||
|
|||||||
@ -16,7 +16,6 @@ import gunicorn.http as http
|
|||||||
import gunicorn.http.wsgi as wsgi
|
import gunicorn.http.wsgi as wsgi
|
||||||
import gunicorn.util as util
|
import gunicorn.util as util
|
||||||
import gunicorn.workers.base as base
|
import gunicorn.workers.base as base
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
class StopWaiting(Exception):
|
class StopWaiting(Exception):
|
||||||
""" exception raised to stop waiting for a connnection """
|
""" exception raised to stop waiting for a connnection """
|
||||||
@ -131,7 +130,7 @@ class SyncWorker(base.Worker):
|
|||||||
**self.cfg.ssl_options)
|
**self.cfg.ssl_options)
|
||||||
|
|
||||||
parser = http.RequestParser(self.cfg, client)
|
parser = http.RequestParser(self.cfg, client)
|
||||||
req = six.next(parser)
|
req = next(parser)
|
||||||
self.handle_request(listener, req, client, addr)
|
self.handle_request(listener, req, client, addr)
|
||||||
except http.errors.NoMoreData as e:
|
except http.errors.NoMoreData as e:
|
||||||
self.log.debug("Ignored premature client disconnection. %s", e)
|
self.log.debug("Ignored premature client disconnection. %s", e)
|
||||||
@ -188,7 +187,7 @@ class SyncWorker(base.Worker):
|
|||||||
respiter.close()
|
respiter.close()
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
# pass to next try-except level
|
# pass to next try-except level
|
||||||
six.reraise(*sys.exc_info())
|
util.reraise(*sys.exc_info())
|
||||||
except Exception:
|
except Exception:
|
||||||
if resp and resp.headers_sent:
|
if resp and resp.headers_sent:
|
||||||
# If the requests have already been sent, we should close the
|
# If the requests have already been sent, we should close the
|
||||||
|
|||||||
@ -38,13 +38,8 @@ class WorkerTmp(object):
|
|||||||
self.spinner = 0
|
self.spinner = 0
|
||||||
|
|
||||||
def notify(self):
|
def notify(self):
|
||||||
try:
|
self.spinner = (self.spinner + 1) % 2
|
||||||
self.spinner = (self.spinner + 1) % 2
|
os.fchmod(self._tmp.fileno(), self.spinner)
|
||||||
os.fchmod(self._tmp.fileno(), self.spinner)
|
|
||||||
except AttributeError:
|
|
||||||
# python < 2.6
|
|
||||||
self._tmp.truncate(0)
|
|
||||||
os.write(self._tmp.fileno(), b"X")
|
|
||||||
|
|
||||||
def last_update(self):
|
def last_update(self):
|
||||||
return os.fstat(self._tmp.fileno()).st_ctime
|
return os.fstat(self._tmp.fileno()).st_ctime
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
coverage>=4.0,<4.4 # TODO: https://github.com/benoitc/gunicorn/issues/1548
|
coverage>=4.0,<4.4 # TODO: https://github.com/benoitc/gunicorn/issues/1548
|
||||||
pytest==3.2.5 # TODO: upgrade to latest version requires drop support to Python 2.6
|
pytest
|
||||||
pytest-cov==2.5.1
|
pytest-cov==2.5.1
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
# =======
|
# =======
|
||||||
# pip install validate_email pyDNS
|
# pip install validate_email pyDNS
|
||||||
#
|
#
|
||||||
from __future__ import print_function
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from validate_email import validate_email
|
from validate_email import validate_email
|
||||||
|
|||||||
14
setup.py
14
setup.py
@ -20,13 +20,12 @@ CLASSIFIERS = [
|
|||||||
'Operating System :: MacOS :: MacOS X',
|
'Operating System :: MacOS :: MacOS X',
|
||||||
'Operating System :: POSIX',
|
'Operating System :: POSIX',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 2',
|
|
||||||
'Programming Language :: Python :: 2.6',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Programming Language :: Python :: 3 :: Only',
|
||||||
'Topic :: Internet',
|
'Topic :: Internet',
|
||||||
'Topic :: Utilities',
|
'Topic :: Utilities',
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
@ -44,11 +43,6 @@ fname = os.path.join(os.path.dirname(__file__), 'requirements_test.txt')
|
|||||||
with open(fname) as f:
|
with open(fname) as f:
|
||||||
tests_require = [l.strip() for l in f.readlines()]
|
tests_require = [l.strip() for l in f.readlines()]
|
||||||
|
|
||||||
if sys.version_info[:2] < (3, 3):
|
|
||||||
tests_require.append('mock')
|
|
||||||
if sys.version_info[:2] < (2, 7):
|
|
||||||
tests_require.append('unittest2')
|
|
||||||
|
|
||||||
class PyTestCommand(TestCommand):
|
class PyTestCommand(TestCommand):
|
||||||
user_options = [
|
user_options = [
|
||||||
("cov", None, "measure coverage")
|
("cov", None, "measure coverage")
|
||||||
@ -77,8 +71,6 @@ extra_require = {
|
|||||||
'tornado': ['tornado>=0.2'],
|
'tornado': ['tornado>=0.2'],
|
||||||
'gthread': [],
|
'gthread': [],
|
||||||
}
|
}
|
||||||
if sys.version_info[0] < 3:
|
|
||||||
extra_require['gthread'] = ['futures']
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='gunicorn',
|
name='gunicorn',
|
||||||
@ -91,7 +83,7 @@ setup(
|
|||||||
license='MIT',
|
license='MIT',
|
||||||
url='http://gunicorn.org',
|
url='http://gunicorn.org',
|
||||||
|
|
||||||
python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
|
python_requires='>=3.4',
|
||||||
classifiers=CLASSIFIERS,
|
classifiers=CLASSIFIERS,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
packages=find_packages(exclude=['examples', 'tests']),
|
packages=find_packages(exclude=['examples', 'tests']),
|
||||||
|
|||||||
@ -4,17 +4,17 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
dirname = os.path.dirname(__file__)
|
dirname = os.path.dirname(__file__)
|
||||||
|
|
||||||
from gunicorn.http.parser import RequestParser
|
from gunicorn.http.parser import RequestParser
|
||||||
from gunicorn.six import BytesIO
|
|
||||||
|
|
||||||
|
|
||||||
def data_source(fname):
|
def data_source(fname):
|
||||||
buf = BytesIO()
|
buf = io.BytesIO()
|
||||||
with open(fname) as handle:
|
with open(fname) as handle:
|
||||||
for line in handle:
|
for line in handle:
|
||||||
line = line.rstrip("\n").replace("\\r\\n", "\r\n")
|
line = line.rstrip("\n").replace("\\r\\n", "\r\n")
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
import io
|
||||||
import t
|
import t
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -7,7 +8,6 @@ from gunicorn import util
|
|||||||
from gunicorn.http.body import Body, LengthReader, EOFReader
|
from gunicorn.http.body import Body, LengthReader, EOFReader
|
||||||
from gunicorn.http.wsgi import Response
|
from gunicorn.http.wsgi import Response
|
||||||
from gunicorn.http.unreader import Unreader, IterUnreader, SocketUnreader
|
from gunicorn.http.unreader import Unreader, IterUnreader, SocketUnreader
|
||||||
from gunicorn.six import BytesIO
|
|
||||||
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName
|
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -17,7 +17,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
def assert_readline(payload, size, expected):
|
def assert_readline(payload, size, expected):
|
||||||
body = Body(BytesIO(payload))
|
body = Body(io.BytesIO(payload))
|
||||||
assert body.readline(size) == expected
|
assert body.readline(size) == expected
|
||||||
|
|
||||||
|
|
||||||
@ -32,28 +32,28 @@ def test_readline_zero_size():
|
|||||||
|
|
||||||
|
|
||||||
def test_readline_new_line_before_size():
|
def test_readline_new_line_before_size():
|
||||||
body = Body(BytesIO(b"abc\ndef"))
|
body = Body(io.BytesIO(b"abc\ndef"))
|
||||||
assert body.readline(4) == b"abc\n"
|
assert body.readline(4) == b"abc\n"
|
||||||
assert body.readline() == b"def"
|
assert body.readline() == b"def"
|
||||||
|
|
||||||
|
|
||||||
def test_readline_new_line_after_size():
|
def test_readline_new_line_after_size():
|
||||||
body = Body(BytesIO(b"abc\ndef"))
|
body = Body(io.BytesIO(b"abc\ndef"))
|
||||||
assert body.readline(2) == b"ab"
|
assert body.readline(2) == b"ab"
|
||||||
assert body.readline() == b"c\n"
|
assert body.readline() == b"c\n"
|
||||||
|
|
||||||
|
|
||||||
def test_readline_no_new_line():
|
def test_readline_no_new_line():
|
||||||
body = Body(BytesIO(b"abcdef"))
|
body = Body(io.BytesIO(b"abcdef"))
|
||||||
assert body.readline() == b"abcdef"
|
assert body.readline() == b"abcdef"
|
||||||
body = Body(BytesIO(b"abcdef"))
|
body = Body(io.BytesIO(b"abcdef"))
|
||||||
assert body.readline(2) == b"ab"
|
assert body.readline(2) == b"ab"
|
||||||
assert body.readline(2) == b"cd"
|
assert body.readline(2) == b"cd"
|
||||||
assert body.readline(2) == b"ef"
|
assert body.readline(2) == b"ef"
|
||||||
|
|
||||||
|
|
||||||
def test_readline_buffer_loaded():
|
def test_readline_buffer_loaded():
|
||||||
reader = BytesIO(b"abc\ndef")
|
reader = io.BytesIO(b"abc\ndef")
|
||||||
body = Body(reader)
|
body = Body(reader)
|
||||||
body.read(1) # load internal buffer
|
body.read(1) # load internal buffer
|
||||||
reader.write(b"g\nhi")
|
reader.write(b"g\nhi")
|
||||||
@ -64,7 +64,7 @@ def test_readline_buffer_loaded():
|
|||||||
|
|
||||||
|
|
||||||
def test_readline_buffer_loaded_with_size():
|
def test_readline_buffer_loaded_with_size():
|
||||||
body = Body(BytesIO(b"abc\ndef"))
|
body = Body(io.BytesIO(b"abc\ndef"))
|
||||||
body.read(1) # load internal buffer
|
body.read(1) # load internal buffer
|
||||||
assert body.readline(2) == b"bc"
|
assert body.readline(2) == b"bc"
|
||||||
assert body.readline(2) == b"\n"
|
assert body.readline(2) == b"\n"
|
||||||
@ -82,7 +82,7 @@ def test_http_header_encoding():
|
|||||||
response = Response(mocked_request, mocked_socket, None)
|
response = Response(mocked_request, mocked_socket, None)
|
||||||
|
|
||||||
# set umlaut header
|
# set umlaut header
|
||||||
response.headers.append(('foo', u'häder'))
|
response.headers.append(('foo', 'häder'))
|
||||||
with pytest.raises(UnicodeEncodeError):
|
with pytest.raises(UnicodeEncodeError):
|
||||||
response.send_headers()
|
response.send_headers()
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ def test_iter_unreader_chunk():
|
|||||||
|
|
||||||
|
|
||||||
def test_socket_unreader_chunk():
|
def test_socket_unreader_chunk():
|
||||||
fake_sock = t.FakeSocket(BytesIO(b'Lorem ipsum dolor'))
|
fake_sock = t.FakeSocket(io.BytesIO(b'Lorem ipsum dolor'))
|
||||||
sock_unreader = SocketUnreader(fake_sock, max_chunk=5)
|
sock_unreader = SocketUnreader(fake_sock, max_chunk=5)
|
||||||
|
|
||||||
assert sock_unreader.chunk() == b'Lorem'
|
assert sock_unreader.chunk() == b'Lorem'
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import sys
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import unittest.mock as mock
|
import unittest.mock as mock
|
||||||
@ -15,12 +14,7 @@ import gunicorn.pidfile
|
|||||||
|
|
||||||
|
|
||||||
def builtin(name):
|
def builtin(name):
|
||||||
if sys.version_info >= (3, 0):
|
return 'builtins.{}'.format(name)
|
||||||
module = 'builtins'
|
|
||||||
else:
|
|
||||||
module = '__builtin__'
|
|
||||||
|
|
||||||
return '{0}.{1}'.format(module, name)
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch(builtin('open'), new_callable=mock.mock_open)
|
@mock.patch(builtin('open'), new_callable=mock.mock_open)
|
||||||
|
|||||||
@ -5,13 +5,11 @@
|
|||||||
# This file is part of gunicorn released under the MIT license.
|
# This file is part of gunicorn released under the MIT license.
|
||||||
# See the NOTICE for more information.
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from gunicorn.config import (
|
from gunicorn.config import (
|
||||||
KeyFile, CertFile, SSLVersion, CACerts, SuppressRaggedEOFs,
|
KeyFile, CertFile, SSLVersion, CACerts, SuppressRaggedEOFs,
|
||||||
DoHandshakeOnConnect, Setting,
|
DoHandshakeOnConnect, Setting, Ciphers,
|
||||||
)
|
)
|
||||||
|
|
||||||
ssl = pytest.importorskip('ssl')
|
ssl = pytest.importorskip('ssl')
|
||||||
@ -69,11 +67,7 @@ def test_do_handshake_on_connect():
|
|||||||
assert DoHandshakeOnConnect.default is False
|
assert DoHandshakeOnConnect.default is False
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (2, 7),
|
|
||||||
reason="requires Python 2.7+")
|
|
||||||
def test_ciphers():
|
def test_ciphers():
|
||||||
from gunicorn.config import Ciphers
|
|
||||||
|
|
||||||
assert issubclass(Ciphers, Setting)
|
assert issubclass(Ciphers, Setting)
|
||||||
assert Ciphers.name == 'ciphers'
|
assert Ciphers.name == 'ciphers'
|
||||||
assert Ciphers.section == 'SSL'
|
assert Ciphers.section == 'SSL'
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
from datetime import timedelta
|
import io
|
||||||
import socket
|
|
||||||
import logging
|
import logging
|
||||||
import tempfile
|
|
||||||
import shutil
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import socket
|
||||||
|
import tempfile
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from gunicorn.config import Config
|
from gunicorn.config import Config
|
||||||
from gunicorn.instrument.statsd import Statsd
|
from gunicorn.instrument.statsd import Statsd
|
||||||
from gunicorn.six import StringIO
|
|
||||||
|
|
||||||
from support import SimpleNamespace
|
from support import SimpleNamespace
|
||||||
|
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ def test_statsd_fail():
|
|||||||
def test_instrument():
|
def test_instrument():
|
||||||
logger = Statsd(Config())
|
logger = Statsd(Config())
|
||||||
# Capture logged messages
|
# Capture logged messages
|
||||||
sio = StringIO()
|
sio = io.StringIO()
|
||||||
logger.error_log.addHandler(logging.StreamHandler(sio))
|
logger.error_log.addHandler(logging.StreamHandler(sio))
|
||||||
logger.sock = MockSocket(False)
|
logger.sock = MockSocket(False)
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import pytest
|
|||||||
|
|
||||||
from gunicorn import util
|
from gunicorn import util
|
||||||
from gunicorn.errors import AppImportError
|
from gunicorn.errors import AppImportError
|
||||||
from gunicorn.six.moves.urllib.parse import SplitResult # pylint: disable=no-name-in-module
|
from urllib.parse import SplitResult
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('test_input, expected', [
|
@pytest.mark.parametrize('test_input, expected', [
|
||||||
|
|||||||
@ -11,7 +11,6 @@ from gunicorn._compat import execfile_
|
|||||||
from gunicorn.config import Config
|
from gunicorn.config import Config
|
||||||
from gunicorn.http.parser import RequestParser
|
from gunicorn.http.parser import RequestParser
|
||||||
from gunicorn.util import split_request_uri
|
from gunicorn.util import split_request_uri
|
||||||
from gunicorn import six
|
|
||||||
|
|
||||||
dirname = os.path.dirname(__file__)
|
dirname = os.path.dirname(__file__)
|
||||||
random.seed()
|
random.seed()
|
||||||
@ -71,10 +70,7 @@ class request(object):
|
|||||||
|
|
||||||
def send_bytes(self):
|
def send_bytes(self):
|
||||||
for d in self.data:
|
for d in self.data:
|
||||||
if six.PY3:
|
yield bytes([d])
|
||||||
yield bytes([d])
|
|
||||||
else:
|
|
||||||
yield d
|
|
||||||
|
|
||||||
def send_random(self):
|
def send_random(self):
|
||||||
maxs = round(len(self.data) / 10)
|
maxs = round(len(self.data) / 10)
|
||||||
@ -205,7 +201,7 @@ class request(object):
|
|||||||
if body:
|
if body:
|
||||||
raise AssertionError("Failed to read entire body: %r" % body)
|
raise AssertionError("Failed to read entire body: %r" % body)
|
||||||
try:
|
try:
|
||||||
data = six.next(iter(req.body))
|
data = next(iter(req.body))
|
||||||
raise AssertionError("Read data after body finished: %r" % data)
|
raise AssertionError("Read data after body finished: %r" % data)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
pass
|
pass
|
||||||
@ -284,4 +280,4 @@ class badrequest(object):
|
|||||||
|
|
||||||
def check(self, cfg):
|
def check(self, cfg):
|
||||||
p = RequestParser(cfg, self.send())
|
p = RequestParser(cfg, self.send())
|
||||||
six.next(p)
|
next(p)
|
||||||
|
|||||||
4
tox.ini
4
tox.ini
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py26, py27, py34, py35, py36, py36-dev, py37, pypy, lint
|
envlist = py34, py35, py36, py36-dev, py37, pypy, lint
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
@ -7,8 +7,6 @@ usedevelop = True
|
|||||||
commands = py.test {posargs}
|
commands = py.test {posargs}
|
||||||
deps =
|
deps =
|
||||||
-rrequirements_test.txt
|
-rrequirements_test.txt
|
||||||
py26: unittest2
|
|
||||||
py{26,27},pypy: mock
|
|
||||||
py{34,35,36,36-dev,37}: aiohttp
|
py{34,35,36,36-dev,37}: aiohttp
|
||||||
|
|
||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user