Skip to content

Commit

Permalink
Drop support for Python 2
Browse files Browse the repository at this point in the history
Co-Authored-By: Dustin Ingram <[email protected]>
Co-Authored-By: Berker Peksag <[email protected]>
  • Loading branch information
3 people committed Aug 1, 2018
1 parent 78208c8 commit e974f30
Show file tree
Hide file tree
Showing 48 changed files with 257 additions and 3,698 deletions.
4 changes: 0 additions & 4 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ ignore=
examples,
scripts,
_compat.py,
argparse_compat.py,
six.py,
_gaiohttp.py,

[MESSAGES CONTROL]
Expand Down Expand Up @@ -53,5 +51,3 @@ disable=
useless-import-alias,
comparison-with-callable,
try-except-raise,
# TODO: use dict comprehensions once we drop Python 2.6 support.
consider-using-dict-comprehension,
4 changes: 0 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ sudo: false
language: python
matrix:
include:
- python: 2.6
env: TOXENV=py26
- python: 2.7
env: TOXENV=py27
- python: 3.4
env: TOXENV=py34
- python: 3.5
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The documentation is hosted at http://docs.gunicorn.org.
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::

Expand Down
3 changes: 0 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ environment:
matrix:
- TOXENV: lint
PYTHON: "C:\\Python35-x64"
- TOXENV: py27
PYTHON: "C:\\Python27-x64"
- TOXENV: py35
PYTHON: "C:\\Python35-x64"
- TOXENV: py36
PYTHON: "C:\\Python36-x64"
matrix:
allow_failures:
- TOXENV: py27
- TOXENV: py35
- TOXENV: py36
init: SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
Expand Down
2 changes: 1 addition & 1 deletion docs/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Requirements

To generate documentation you need to install:

- Python >= 2.5
- Python >= 3.4
- Sphinx (http://sphinx-doc.org/)


Expand Down
17 changes: 0 additions & 17 deletions docs/sitemap_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,6 @@
--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 glob
import gzip
Expand All @@ -72,14 +63,6 @@
import urlparse
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
ENC_ASCII = 'ASCII'
ENC_UTF8 = 'UTF-8'
Expand Down
16 changes: 8 additions & 8 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
master_doc = 'index'

# General information about the project.
project = u'Gunicorn'
copyright = u'2009-%s, Benoit Chesneau' % time.strftime('%Y')
project = 'Gunicorn'
copyright = '2009-%s, Benoit Chesneau' % time.strftime('%Y')
# gunicorn version
import gunicorn
release = version = gunicorn.__version__
Expand Down Expand Up @@ -55,19 +55,19 @@
}

latex_documents = [
('index', 'Gunicorn.tex', u'Gunicorn Documentation',
u'Benoit Chesneau', 'manual'),
('index', 'Gunicorn.tex', 'Gunicorn Documentation',
'Benoit Chesneau', 'manual'),
]


# -- Options for manual page output --------------------------------------------
man_pages = [
('index', 'gunicorn', u'Gunicorn Documentation',
[u'Benoit Chesneau'], 1)
('index', 'gunicorn', 'Gunicorn Documentation',
['Benoit Chesneau'], 1)
]

texinfo_documents = [
('index', 'Gunicorn', u'Gunicorn Documentation',
u'Benoit Chesneau', 'Gunicorn', 'One line description of project.',
('index', 'Gunicorn', 'Gunicorn Documentation',
'Benoit Chesneau', 'Gunicorn', 'One line description of project.',
'Miscellaneous'),
]
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Features
* Simple Python configuration
* Multiple worker configurations
* 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
Expand Down
2 changes: 1 addition & 1 deletion docs/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Installation

.. 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::

Expand Down
2 changes: 1 addition & 1 deletion examples/example_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def worker_int(worker):

## get traceback info
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 = []
for threadId, stack in sys._current_frames().items():
code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""),
Expand Down
2 changes: 0 additions & 2 deletions examples/read_django_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
Use this config file in your script like this:
$ 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 = {}
Expand Down
10 changes: 3 additions & 7 deletions examples/standalone_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.

from __future__ import unicode_literals

import multiprocessing

import gunicorn.app.base

from gunicorn.six import iteritems


def number_of_workers():
return (multiprocessing.cpu_count() * 2) + 1
Expand All @@ -42,9 +38,9 @@ def __init__(self, app, options=None):
super(StandaloneApplication, self).__init__()

def load_config(self):
config = dict([(key, value) for key, value in iteritems(self.options)
if key in self.cfg.settings and value is not None])
for key, value in iteritems(config):
config = {key: value for key, value in self.options.items()
if key in self.cfg.settings and value is not None}
for key, value in config.items():
self.cfg.set(key.lower(), value)

def load(self):
Expand Down
154 changes: 6 additions & 148 deletions gunicorn/_compat.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import sys

from gunicorn import six

PY26 = (sys.version_info[:2] == (2, 6))


def _check_if_pyc(fname):
"""Return True if the extension is .pyc, False if .py
and None if otherwise"""
Expand Down Expand Up @@ -62,147 +55,12 @@ def _get_codeobj(pyfile):
# Return code object
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):
if isinstance(b, six.text_type):
return b
return str(b, 'latin1')

import urllib.parse

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 execfile_(fname, *args):
if fname.endswith(".pyc"):
code = _get_codeobj(fname)
else:
code = compile(open(fname, 'rb').read(), fname, 'exec')
return exec(code, *args)

def html_escape(s):
return html.escape(s)
except ImportError:
import cgi

def html_escape(s):
return cgi.escape(s, quote=True)
2 changes: 0 additions & 2 deletions gunicorn/app/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
from __future__ import print_function

import os
import sys
import traceback
Expand Down
1 change: 0 additions & 1 deletion gunicorn/app/pasterapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
from __future__ import print_function

# pylint: skip-file

Expand Down
2 changes: 0 additions & 2 deletions gunicorn/arbiter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
from __future__ import print_function

import errno
import os
import random
Expand Down
Loading

0 comments on commit e974f30

Please sign in to comment.