-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Drop support for Python 2 #1764
Conversation
hugovk
commented
Apr 28, 2018
•
edited
Loading
edited
- Continues "[WIP] Delete all Python 2 compatibility code" [WIP] Delete all Python 2 compatibility code #1288,
- includes "Drop Python 2.6 support" Drop Python 2.6 support #1379,
- for "gunicorn 20" gunicorn 21 #1195.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
One more change we can do: I think we can get rid of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all % to str.format() changes need to be reverted. There's nothing wrong with using %-formatting and I don't think it's worth introducing code churn.
I can say the same thing for reordering imports but I don't have a strong objection.
docs/gunicorn_ext.py
Outdated
@@ -39,7 +39,7 @@ def format_settings(app): | |||
known_settings = sorted(guncfg.KNOWN_SETTINGS, key=lambda s: s.section) | |||
for i, s in enumerate(known_settings): | |||
if i == 0 or s.section != known_settings[i - 1].section: | |||
ret.append("%s\n%s\n\n" % (s.section, "-" * len(s.section))) | |||
ret.append("{}\n{}\n\n".format(s.section, "-" * len(s.section))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%-formatting will stay forever in Python, so I don't think these changes are in the scope of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i"m also not sure i really like it, it makes it a little hard to parse for a human. I would keep the %s
which is also quite similar to other languages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done by reverting 159aa1e.
gunicorn/config.py
Outdated
@@ -340,7 +334,7 @@ def validate_dict(val): | |||
|
|||
|
|||
def validate_pos_int(val): | |||
if not isinstance(val, six.integer_types): | |||
if not isinstance(val, int,): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int, -> int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/glogging.py
Outdated
CONFIG_DEFAULTS = dict( | ||
version=1, | ||
disable_existing_loggers=False, | ||
CONFIG_DEFAULTS = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dict(...)
version is pretty readable. I don't think we should do cosmetic-only changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ by reverting 4aa3a5e. (It's not only cosmetic, it's faster too: https://stackoverflow.com/a/6612024/724176. But this might not be important here, and let's keep the one you find more readable.)
gunicorn/http/body.py
Outdated
|
||
def read(self, size): | ||
if not isinstance(size, six.integer_types): | ||
if not isinstance(size, int,): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int, -> int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/http/body.py
Outdated
@@ -110,7 +112,7 @@ def __init__(self, unreader, length): | |||
self.length = length | |||
|
|||
def read(self, size): | |||
if not isinstance(size, six.integer_types): | |||
if not isinstance(size, int,): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int, -> int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/http/body.py
Outdated
return six.MAXSIZE | ||
elif not isinstance(size, six.integer_types): | ||
return sys.maxsize | ||
elif not isinstance(size, int,): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int, -> int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/http/unreader.py
Outdated
|
||
def chunk(self): | ||
raise NotImplementedError() | ||
|
||
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,): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int, -> int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/workers/base.py
Outdated
from gunicorn import util | ||
from gunicorn.workers.workertmp import WorkerTmp | ||
from gunicorn.http.errors import (ForbiddenProxyRequest, InvalidHeader, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current style is much better and it makes future diffs less noisy:
from gunicorn.http.errors import (
Spam, Eggs,
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/workers/gthread.py
Outdated
from . import base | ||
from .. import six | ||
|
||
from .. import http, six, util |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can six be removed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/util.py
Outdated
@@ -155,10 +154,6 @@ def set_owner_process(uid, gid, initgroups=False): | |||
except KeyError: | |||
initgroups = False | |||
|
|||
# versions of python < 2.6.2 don't manage unsigned int for | |||
# groups like on osx or fedora | |||
gid = abs(gid) & 0x7FFFFFFF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has this change been checked? fedora do some odd things sometimes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've not checked it so have reverted it to be on the safe side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR!
I have for now only reviewed the code (see the comments) and I still have to test it but these changes looks good.
Maybe a little nitpicking, but I am not sure about the string format changes, I am thinking the current way is more readable especially for those who have to switch languages . Maybe that could be discussed in a separate change? Thoughts?
gunicorn/util.py
Outdated
@@ -317,7 +311,7 @@ def write_nonblock(sock, data, chunked=False): | |||
|
|||
|
|||
def write_error(sock, status_int, reason, mesg): | |||
html = textwrap.dedent("""\ | |||
markup = textwrap.dedent("""\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would make it more explicit, like html_error
or just respbody
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/workers/gthread.py
Outdated
from . import base | ||
from .. import six | ||
|
||
from .. import http, six, util |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please keep it on multiple lines, it's easier to read that way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
docs/gunicorn_ext.py
Outdated
@@ -39,7 +39,7 @@ def format_settings(app): | |||
known_settings = sorted(guncfg.KNOWN_SETTINGS, key=lambda s: s.section) | |||
for i, s in enumerate(known_settings): | |||
if i == 0 or s.section != known_settings[i - 1].section: | |||
ret.append("%s\n%s\n\n" % (s.section, "-" * len(s.section))) | |||
ret.append("{}\n{}\n\n".format(s.section, "-" * len(s.section))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i"m also not sure i really like it, it makes it a little hard to parse for a human. I would keep the %s
which is also quite similar to other languages
gunicorn/arbiter.py
Outdated
@@ -45,10 +43,10 @@ class Arbiter(object): | |||
SIG_QUEUE = [] | |||
SIGNALS = [getattr(signal, "SIG%s" % x) | |||
for x in "HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split()] | |||
SIG_NAMES = dict( | |||
(getattr(signal, name), name[3:].lower()) for name in dir(signal) | |||
SIG_NAMES = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would have kept the dict( .. )
syntax there, it was easier to parse for human eyes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done by reverting 159aa1e.
gunicorn/config.py
Outdated
inspect.Parameter.POSITIONAL_OR_KEYWORD, | ||
) | ||
|
||
def get_arity(f): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be in gunicorn.util
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/glogging.py
Outdated
CONFIG_DEFAULTS = dict( | ||
version=1, | ||
disable_existing_loggers=False, | ||
CONFIG_DEFAULTS = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree
Thanks for the reviews! I've updated the PR as requested, please let me know if I've missed anything. There's now a linting error:
How should |
gunicorn/http/wsgi.py
Outdated
@@ -234,7 +233,7 @@ def start_response(self, status, headers, exc_info=None): | |||
if exc_info: | |||
try: | |||
if self.status and self.headers_sent: | |||
reraise(exc_info[0], exc_info[1], exc_info[2]) | |||
raise exc_info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wsgiref module does this:
if exc_info:
try:
if self.headers_sent:
# Re-raise original exception if headers sent
raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
finally:
exc_info = None # avoid dangling circular ref
https://github.com/python/cpython/blob/master/Lib/wsgiref/handlers.py#L215-L221
six's implementation is more defensive:
https://github.com/benjaminp/six/blob/master/six.py#L687-L696
We can copy six's implementation into gunicorn/util.py
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And note that reraise()
from six ignores exc_type
. This would cause a problem if we want to raise the exception with a different exception type, but since we no longer support Python 2, we can do the same thing with raise new from old
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/util.py
Outdated
return urlsplit(uri) | ||
|
||
|
||
def reraise(tp, value, tb=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Can you add a comment to note that we borrow this code from six?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
gunicorn/workers/sync.py
Outdated
@@ -188,7 +187,7 @@ def handle_request(self, listener, req, client, addr): | |||
respiter.close() | |||
except EnvironmentError: | |||
# pass to next try-except level | |||
six.reraise(*sys.exc_info()) | |||
raise sys.exc_info() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sys.exc_info()
returns a tuple. I think using a plain raise
would be enough here. Also, I'm not sure we still need the comment # pass to next try-except level
though. @benoitc what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -20,13 +20,11 @@ | |||
'Operating System :: MacOS :: MacOS X', | |||
'Operating System :: POSIX', | |||
'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.4', | |||
'Programming Language :: Python :: 3.5', | |||
'Programming Language :: Python :: 3.6', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Can you add 3.7 as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
Please delete |
Thanks for all the detailed reviews! Still looking good to me. |
Unfortunately, there are still a few >>> import sys
>>> try:
... 1/0
... except Exception:
... raise sys.exc_info()
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
TypeError: exceptions must derive from BaseException Unfortunately, I don't have time to make a review and decide which one is the best this week :( |
Thanks, I've replaced them with |
gunicorn/_compat.py
Outdated
import urllib | ||
unquote_to_wsgi_str = urllib.unquote | ||
def unquote_to_wsgi_str(string): | ||
return urllib.parse.unquote_to_bytes(string).decode('latin-1') | ||
|
||
|
||
# The following code adapted from trollius.py33_exceptions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_wrap_error()
can also be deleted.
gunicorn/_compat.py
Outdated
return exec(code, *args) | ||
|
||
|
||
def bytes_to_str(b): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can now move bytes_to_str()
and unquote_to_wsgi_str()
to gunicorn.util
since they no longer behave differently in Python 2 and Python 3.
execfile_()
and its friends can stay here for now. There was a discussion about deprecating PYC support in 20 and rewriting it with importlib (instead of deprecated imp) is a complex task.
tests/test_pidfile.py
Outdated
else: | ||
module = '__builtin__' | ||
|
||
module = 'builtins' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit:
return 'builtins.{}'.format(name)
This looks pretty good to me, thanks! One more request: Could you squash all commits into one and add the following Co-Authored-By markers to the commit message?
|
Co-Authored-By: Dustin Ingram <di@users.noreply.github.com> Co-Authored-By: Berker Peksag <berker.peksag@gmail.com>
Done! How's that look? |
Perfect, thanks! :) |
Thanks, I will test later today with the use cases from the example folder. Can others d the same and report the result there also? |
tests seems OK. If no news I will do a merge next week on monday. master needs to be frozen until then (cc @tilgovi @berkerpeksag ) |
Ah, I forgot to left a comment here. I played with the examples and use this branch in my project without any problems. I think this is good to merge. |
@benoitc let me know if you want me to do the merging if you don't have time to do it :) |
i'm still testing it in a somewhat loaded platform. I will take care of the merge next week :) |
PR has been merged (not sure why it doesn't appear in closed in PR). @hugovk thanks for it and thanks all for the reviews. In addition to the PR I also fixed examples that didn't pass in python3. |
You're welcome! |