Python-checkins
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
October 2015
- 3 participants
- 562 discussions
results for 89d00c0a9eae on branch "default"
--------------------------------------------
test_capi leaked [5411, 5411, 5411] references, sum=16233
test_capi leaked [1421, 1423, 1423] memory blocks, sum=4267
test_functools leaked [0, 2, 2] memory blocks, sum=4
test_threading leaked [10820, 10820, 10820] references, sum=32460
test_threading leaked [2842, 2844, 2844] memory blocks, sum=8530
Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/psf-users/antoine/refleaks/reflogx9Xhkt', '--timeout', '7200']
1
0
Oct. 21, 2015
https://hg.python.org/peps/rev/aade283f99c0
changeset: 6120:aade283f99c0
user: Guido van Rossum <guido(a)python.org>
date: Tue Oct 20 20:24:08 2015 -0700
summary:
Remove outdated motivation for short module names.
files:
pep-0008.txt | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/pep-0008.txt b/pep-0008.txt
--- a/pep-0008.txt
+++ b/pep-0008.txt
@@ -758,12 +758,6 @@
should also have short, all-lowercase names, although the use of
underscores is discouraged.
-Since module names are mapped to file names, and some file systems are
-case insensitive and truncate long names, it is important that module
-names be chosen to be fairly short -- this won't be a problem on Unix,
-but it may be a problem when the code is transported to older Mac or
-Windows versions, or DOS.
-
When an extension module written in C or C++ has an accompanying
Python module that provides a higher level (e.g. more object oriented)
interface, the C/C++ module has a leading underscore
--
Repository URL: https://hg.python.org/peps
1
0
https://hg.python.org/peps/rev/c95970bdc088
changeset: 6119:c95970bdc088
user: Chris Angelico <rosuav(a)gmail.com>
date: Wed Oct 21 12:44:00 2015 +1100
summary:
Apply more PEP 505 changes from Mark
files:
pep-0505.txt | 184 ++++++++++++++++++++--------------
pep-0505/test.py | 2 +-
2 files changed, 108 insertions(+), 78 deletions(-)
diff --git a/pep-0505.txt b/pep-0505.txt
--- a/pep-0505.txt
+++ b/pep-0505.txt
@@ -22,7 +22,7 @@
* The "``null``-aware member access" operator accesses an instance member only
if that instance is non-``null``. Otherwise it returns ``null``. (This is also
called a "safe navigation" operator.)
-* The "``null``-aware index access" operator accesses a member of a collection
+* The "``null``-aware index access" operator accesses an element of a collection
only if that collection is non-``null``. Otherwise it returns ``null``. (This
is another type of "safe navigation" operator.)
@@ -36,9 +36,10 @@
when the question inevitably arises again. (This is the null alternative, so to
speak!)
-This proposal includes several new operators and should not be considered an
-all-or-nothing proposal. For example, the safe navigation operators might be
-rejected even if the ``null``-coalescing operator is approved, or vice-versa.
+This proposal advances multiple alternatives, and it should be considered
+severable. It may be accepted in whole or in part. For example, the safe
+navigation operators might be rejected even if the ``null``-coalescing operator
+is approved, or vice-versa.
Of course, Python does not have ``null``; it has ``None``, which is conceptually
distinct. Although this PEP is inspired by "``null``-aware" operators in other
@@ -110,8 +111,8 @@
<https://github.com/pyca/pyopenssl/blob/3257877f8846e4357b495fa6c9344d01b11c…
/OpenSSL/crypto.py#L1219>`_ that returns either a timestamp or ``None``. This
function is a thin wrapper around an OpenSSL function with the return type
-``ASN1_TIME *``. Since this C pointer is allowed to be null, the Python wrapper
-must be able to express a missing "not before" date, e.g. ``None``.
+``ASN1_TIME *``. Because this C pointer may be ``null``, the Python wrapper must
+be able to represent ``null``, and ``None`` is the chosen representation.
The representation of ``null`` is particularly noticeable when Python code is
marshalling data between two systems. For example, consider a Python server that
@@ -123,7 +124,7 @@
Python glue code.
Therefore, the preference for avoiding ``None`` is nothing more than a
-preference; ``None`` has legitimate uses, particularly in specific types of
+preference. ``None`` has legitimate uses, particularly in specific types of
software. Any hypothetical ``None``-aware operators should be construed as
syntactic sugar for simplifying common patterns involving ``None``, and *should
not be construed* as error handling behavior.
@@ -219,8 +220,8 @@
An experienced Python developer should know how ``or`` works and be capable of
avoiding bugs like this. However, getting in the habit of using ``or`` for this
-purpose still might cause even an experienced developer to occasionally make
-this mistake, especially refactoring existing code and not carefully paying
+purpose still might cause an experienced developer to occasionally make this
+mistake, especially when refactoring existing code and not carefully paying
attention to the possible values of the left-hand operand.
For inexperienced developers, the problem is worse. The top Google hit for
@@ -266,9 +267,9 @@
This ordering of the operands is more intuitive, but it requires 4 extra
characters (for "not "). It also highlights the repetition of identifiers:
-``data if data``, ``files if files``, etc. This example also benefits from short
-identifiers. What if the tested expression is longer and/or has side effects?
-This is addressed in the next section.
+``data if data``, ``files if files``, etc. This example benefits from short
+identifiers, but what if the tested expression is longer and/or has side
+effects? This is addressed in the next section.
Motivating Examples
@@ -498,9 +499,10 @@
-----------------------------------------
The previous sections show some code patterns that are claimed to be "common",
-but how common are they? The attached script ``find-pep505.py`` is meant to
-answer this question. It uses the ``ast`` module to search for these patterns in
-any ``*.py`` file. It checks for variations of the following patterns.
+but how common are they? The attached script `find-pep505.py
+<https://hg.python.org/peps/file/tip/pep-0505/find-pep505.py>`_ is meant to
+answer this question. It uses the ``ast`` module to search for variations of the
+following patterns in any ``*.py`` file.
>>> # None-coalescing if block
...
@@ -566,14 +568,16 @@
.. note::
Coalescing with ``or`` is marked as a "possible" match, because it's not
- trivial to infer whether ``or`` it is meant to coalesce False-y values
+ trivial to infer whether ``or`` is meant to coalesce False-y values
(correct) or if it meant to coalesce ``None`` (incorrect). On the other
- hand, we assume that `and` is always incorrect for safe navigation.
+ hand, we assume that ``and`` is always incorrect for safe navigation.
-The script is tested against ``test.py`` (also attached to this document) and
-the Python 3.4 standard library, but it should work on any arbitrary Python
-source code. The complete output from running it against the standard library is
-attached to this proposal as ``find-pep505.out``.
+The script has been tested against `test.py
+<https://hg.python.org/peps/file/tip/pep-0505/test.py>`_ and the Python 3.4
+standard library, but it should work on any arbitrary Python 3 source code. The
+complete output from running it against the standard library is attached to this
+proposal as `find-pep505.out <https://hg.python.org/peps/raw-file/tip/pep-0505
+/find-pep505.out>`_.
The script counts how many matches it finds and prints the totals at the
end::
@@ -602,13 +606,13 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``None``-aware syntax applies to attribute and index access, so it seems
-natural to ask if it should also apply to function invocation syntax. Borrowing
-a spelling similar to C#, it might be spelled ``foo?()``, where ``foo`` is only
-called if it is not None. This idea was quickly rejected, for several reasons.
+natural to ask if it should also apply to function invocation syntax. It might
+be written as ``foo?()``, where ``foo`` is only called if it is not None. This
+idea was quickly rejected, for several reasons.
-No other mainstream language has such syntax. Moreover, it would be difficult to
-discern if a function expression returned ``None`` because it was short-
-circuited or because the function itself returned ``None``. Finally, Python
+First, no other mainstream language has such syntax. Moreover, it would be
+difficult to discern if a function call returned ``None`` because the function
+itself returned ``None`` or because it was short-circuited. Finally, Python
evaluates arguments to a function before it looks up the function itself, so
``foo?(bar())`` would still call ``bar()`` even if ``foo`` is ``None``. This
behaviour is unexpected for a so-called "short-circuiting" operator.
@@ -622,8 +626,10 @@
To generalize the ``None``-aware behavior and limit the number of new operators
introduced, a unary, postfix operator spelled ``?`` was suggested. The idea is
-that ``?`` would return a special object that could would override dunder
-methods to return itself or to return None. For example::
+that ``?`` might return a special object that could would override dunder
+methods that return ``self``. For example, ``foo?`` would evaluate to ``foo`` if
+it is not ``None``, otherwise it would evaluate to an instance of
+``NoneQuestion``::
class NoneQuestion():
def __call__(self, *args, **kwargs):
@@ -633,14 +639,13 @@
return self
def __getitem__(self, key):
- reutrn self
+ return self
-An expression like ``foo?`` would return a ``NoneQuestion`` instance if ``foo``
-is ``None``; otherwise, it returns ``foo``. With this operator, an expression
-like ``foo?.bar[baz]`` evaluates to ``NoneQuestion`` if ``foo`` is None. This is
-a nice generalization, but it's difficult to use in practice since most existing
-code won't know what ``NoneQuestion`` is.
+With this new operator and new type, an expression like ``foo?.bar[baz]``
+evaluates to ``NoneQuestion`` if ``foo`` is None. This is a nifty
+generalization, but it's difficult to use in practice since most existing code
+won't know what ``NoneQuestion`` is.
Going back to one of the motivating examples above, consider the following::
@@ -652,8 +657,9 @@
any other API. This proposal actually requires *lots of specialized logic*
throughout the standard library and any third party library.
-The ``?`` operator may also be **too general**, in the sense that it can be
-combined with any other operator. What should the following expressions mean?
+At the same time, the ``?`` operator may also be **too general**, in the sense
+that it can be combined with any other operator. What should the following
+expressions mean?
>>> x? + 1
>>> x? -= 1
@@ -707,9 +713,12 @@
3. ``None``-aware attribute access
4. ``None``-aware index access/slicing
-We will continue to assume the same spellings as in the previous sections in
-order to focus on behavior before diving into the much more contentious issue of
-how to spell these operators.
+We will continue to assume the same spellings as in
+the previous sections in order to focus on behavior before diving into the much
+more contentious issue of how to spell these operators.
+
+A generalization of these operators is also proposed below under the heading
+"Generalized Coalescing".
``None``-Coalescing Operator
@@ -831,13 +840,11 @@
--------------------------
The idea of a ``None``-aware function invocation syntax was discussed on python-
-ideas, but the idea was rejected by BDFL. The syntax comes dangerously close to
-allowing a caller to change the return type of a function. If a function is
-defined to always return a value, then it seems strange that the call site could
-change the function to return "value or ``None``".
+ideas, but the idea was rejected by BDFL. The reasons for this rejection are
+detailed above.
-Still, conditional function execution is a common idiom in Python, particularly
-for callback functions. Consider this hypothetical example::
+Still, calling a function when it is not ``None`` is a common idiom in Python,
+particularly for callback functions. Consider this hypothetical example::
import time
@@ -847,8 +854,8 @@
if callback is not None:
callback()
-With a ``None``-aware function invocation, this example might be written more
-concisely as::
+With the rejected ``None``-aware function call syntax, this example might be
+written more concisely as::
import time
@@ -856,11 +863,12 @@
time.sleep(seconds)
callback?()
-Consider a "``None``-severing" operator, however, which is a short-circuiting,
-boolean operator similar to the ``None``-coalesing operator, except it returns
-its left operand if that operand is None. If the left operand is None, then the
-right operand is not evaluated. Let's temporarily spell this operator ``✂`` and
-rewrite the example accordingly::
+Instead, consider a "``None``-severing" operator, however, which is a short-
+circuiting, boolean operator similar to the ``None``-coalesing operator, except
+it returns its left operand if that operand is None and otherwise returns the
+right operand. If the left operand is None, then the right operand is not
+evaluated. Let's temporarily spell this operator ``✂`` and rewrite the example
+accordingly::
import time
@@ -925,8 +933,9 @@
The operator has the same precedence and associativity as the plain attribute
access operator ``.``, but this operator is also short-circuiting in a unique
-way: if the left operand is ``None``, then any adjacent attribute access, index
-access, slicing, or function call operators *are not evaluated*.
+way: if the left operand is ``None``, then any series of attribute access, index
+access, slicing, or function call operators immediately to the right of it *are
+not evaluated*.
>>> name = ' The Black Knight '
>>> name.strip()[4:].upper()
@@ -953,10 +962,10 @@
original goal of writing common cases more concisely. The Dart semantics are
nearly useless.
-This operator short circuits one or more immediately adjacent attribute access,
-index access, slicing, or function call operators, but it does not short circuit
-any other operators (logical, bitwise, arithmetic, etc.), nor does it escape
-parentheses::
+This operator short circuits one or more attribute access, index access,
+slicing, or function call operators that are immediately to its right, but it
+does not short circuit any other operators (logical, bitwise, arithmetic, etc.),
+nor does it escape parentheses::
>>> d = date.today()
>>> d💩year.numerator + 1
@@ -982,22 +991,23 @@
that example, the attribute access ``numerator`` is evaluated and fails because
``None`` does not have that attribute.
-Finally, observe that short circuiting adjacent operators is not at all the same thing as propagating ``None`` throughout an expression.
+Finally, observe that short circuiting adjacent operators is not at all the same thing as propagating ``None`` throughout an expression::
>>> user💩first_name.upper()
If ``user`` is not ``None``, then ``user.first_name`` is evaluated. If
``user.first_name`` evaluates to ``None``, then ``user.first_name.upper()`` is
-an error! In English, this expression says ``user`` is optional but if it has a
-value, then it must have a ``first_name``, too.
+an error! In English, this expression says, "``user`` is optional but if it has
+a value, then it must have a ``first_name``, too.""
If ``first_name`` is supposed to be optional attribute, then the expression must
-make that explicit:
+make that explicit::
>>> user💩first_name💩upper()
The operator is not intended as an error silencing mechanism, and it would be
-wrong if its presence infected nearby operators.
+undesirable if its presence infected nearby operators.
+
``None``-Aware Index Access/Slicing Operator
--------------------------------------------
@@ -1036,11 +1046,12 @@
None
These operators have the same precedence as the plain index access and slicing
-operators.
+operators. They also have the same short-circuiting behavior as the
+``None``-aware attribute access.
-Generalization
---------------
+Generalized Coalescing
+----------------------
Making ``None`` a special case may seem too specialized and magical. It is
possible to generalize the behavior by making the ``None``-aware operators
@@ -1058,13 +1069,32 @@
def __coalesce__(self):
return True
+If this generalization is accepted, then the operators will need to be renamed
+such that the term ``None`` is not used, e.g. "Coalescing Operator", "Coalesced
+Member Access Operator", etc.
+
+The coalescing operator would invoke this dunder method. The following two expressions are semantically equivalent::
+
+ >>> foo ✊🍆 bar
+ >>> bar if foo.__coalesce__() else foo
+
+The coalesced attribute and index access operators would invoke the same dunder
+method::
+
+ >>> user💩first_name.upper()
+ >>> None if user.__coalesce__() else user.first_name.upper()
+
This generalization allows for domain-specific ``null`` objects to be coalesced
just like ``None``. For example the ``pyasn1`` package has a type called
``Null`` that represents an ASN.1 ``null``.
-If this generalization is accepted, then the operators will need to be renamed
-such that the term ``None`` is not used, e.g. "Coalescing Operator", "Coalesced
-Member Access Operator", etc.
+ >>> from pyasn1.type import univ
+ >>> univ.Null() ✊🍆 univ.Integer(123)
+ Integer(123)
+
+In addition to making the proposed operators less specialized, this
+generalization also makes it easier to work with the Null Object Pattern, [3]_
+for those developers who prefer to avoid using ``None``.
Operator Spelling
@@ -1081,7 +1111,7 @@
<http://opensource.com/life/14/9/why-python-4-wont-be-python-3>`_.)
Furthermore, nearly every single punctuation character on a standard keyboard
-already has special meaning in Python. The only exceptions are ``$``, ``~``,
+already has special meaning in Python. The only exceptions are ``$``, ``!``,
``?``, and backtick (as of Python 3). This leaves few options for a new, single-
character operator. A two character spelling is more likely, such as the ``??``
and ``?.`` spellings in other programming languages, but this decreases the
@@ -1124,24 +1154,24 @@
- Pros: similar to existing ``or`` operator
- Cons: the difference between this and ``or`` is not intuitive; punctuation
is ugly
-3. ``foo ? bar``
+3. ``foo ? bar ? baz``
- Pros: similar to ``??`` used in other languages
- Cons: punctuation is ugly; possible conflict with IPython; not used by any
other language
-4. ``foo $$ bar``
+4. ``foo $$ bar $$ baz``
- Pros: pronounced "value operator" because it returns the first operand
that has a "value"
- Cons: punctuation is ugly; not used by any other language
-5. ``foo else bar``
+5. ``foo else bar else baz``
- Pros: prettier than punctuation; uses an existing keyword
- Cons: difficult or impossible to implement with Python's LL(1) parser
-6. ``foo or else bar``
+6. ``foo or else bar or else baz``
- Pros: prettier than punctuation; use existing keywords
- Cons: difficult or impossible to implement with Python's LL(1) parser
-7. ``foo def bar``
+7. ``foo def bar def baz``
- Pros: pronounced 'default'; prettier than punctuation
- Cons: difficult or impossible to implement with Python's LL(1) parser
-8. ``foo then bar``
+8. ``foo then bar then baz``
- Pros: prettier than punctuation
- Cons: requires a new keyword, probably can't be implemented until Python 4
(and maybe not even then)
diff --git a/pep-0505/test.py b/pep-0505/test.py
--- a/pep-0505/test.py
+++ b/pep-0505/test.py
@@ -1,5 +1,5 @@
'''
-This file is used for testing find-pep505.out.
+This file is used for testing find-pep505.py.
nc_* and Nc* are examples of null coalescing.
sn_* and Sn* are examples of save navigation.
--
Repository URL: https://hg.python.org/peps
1
0
cpython (3.5): Issue #21515: Elaborate tempfile.TemporaryFile() comment
by victor.stinner Oct. 20, 2015
by victor.stinner Oct. 20, 2015
Oct. 20, 2015
https://hg.python.org/cpython/rev/dc2deecb2346
changeset: 98815:dc2deecb2346
branch: 3.5
parent: 98813:93f948120773
user: Victor Stinner <victor.stinner(a)gmail.com>
date: Wed Oct 21 00:15:08 2015 +0200
summary:
Issue #21515: Elaborate tempfile.TemporaryFile() comment
Explain why calling os.open() with os.O_TMPFILE is a safe test to check if
O_TMPFILE is supported by the running kernel.
files:
Lib/tempfile.py | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -591,12 +591,20 @@
flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
fd = _os.open(dir, flags2, 0o600)
except IsADirectoryError:
- # Linux kernel older than 3.11 ignores O_TMPFILE flag.
- # Set flag to False to not try again.
+ # Linux kernel older than 3.11 ignores the O_TMPFILE flag:
+ # O_TMPFILE is read as O_DIRECTORY. Trying to open a directory
+ # with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a
+ # directory cannot be open to write. Set flag to False to not
+ # try again.
_O_TMPFILE_WORKS = False
except OSError:
# The filesystem of the directory does not support O_TMPFILE.
# For example, OSError(95, 'Operation not supported').
+ #
+ # On Linux kernel older than 3.11, trying to open a regular
+ # file (or a symbolic link to a regular file) with O_TMPFILE
+ # fails with NotADirectoryError, because O_TMPFILE is read as
+ # O_DIRECTORY.
pass
else:
try:
--
Repository URL: https://hg.python.org/cpython
1
0
https://hg.python.org/cpython/rev/89d00c0a9eae
changeset: 98816:89d00c0a9eae
parent: 98814:c3cec0f77eff
parent: 98815:dc2deecb2346
user: Victor Stinner <victor.stinner(a)gmail.com>
date: Wed Oct 21 00:15:17 2015 +0200
summary:
Merge 3.5
files:
Lib/tempfile.py | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -591,12 +591,20 @@
flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
fd = _os.open(dir, flags2, 0o600)
except IsADirectoryError:
- # Linux kernel older than 3.11 ignores O_TMPFILE flag.
- # Set flag to False to not try again.
+ # Linux kernel older than 3.11 ignores the O_TMPFILE flag:
+ # O_TMPFILE is read as O_DIRECTORY. Trying to open a directory
+ # with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a
+ # directory cannot be open to write. Set flag to False to not
+ # try again.
_O_TMPFILE_WORKS = False
except OSError:
# The filesystem of the directory does not support O_TMPFILE.
# For example, OSError(95, 'Operation not supported').
+ #
+ # On Linux kernel older than 3.11, trying to open a regular
+ # file (or a symbolic link to a regular file) with O_TMPFILE
+ # fails with NotADirectoryError, because O_TMPFILE is read as
+ # O_DIRECTORY.
pass
else:
try:
--
Repository URL: https://hg.python.org/cpython
1
0
cpython (merge 3.5 -> default): Issue #25410: Fixed a memory leak in OrderedDict in the case when key's hash
by serhiy.storchaka Oct. 20, 2015
by serhiy.storchaka Oct. 20, 2015
Oct. 20, 2015
https://hg.python.org/cpython/rev/c3cec0f77eff
changeset: 98814:c3cec0f77eff
parent: 98812:75285bd6991b
parent: 98813:93f948120773
user: Serhiy Storchaka <storchaka(a)gmail.com>
date: Tue Oct 20 18:22:36 2015 +0300
summary:
Issue #25410: Fixed a memory leak in OrderedDict in the case when key's hash
calculation fails.
files:
Objects/odictobject.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Objects/odictobject.c b/Objects/odictobject.c
--- a/Objects/odictobject.c
+++ b/Objects/odictobject.c
@@ -648,11 +648,11 @@
Py_ssize_t i;
_ODictNode *node;
- Py_INCREF(key);
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
+ Py_INCREF(key);
i = _odict_get_index(od, key);
if (i < 0) {
if (!PyErr_Occurred())
--
Repository URL: https://hg.python.org/cpython
1
0
Oct. 20, 2015
Results for project Python 2.7, build date 2015-10-20 13:35:11
commit: 8953a42c2ac459b95ae23da264028f1d2a834d5b
revision date: 2015-10-20 06:15:23 +0000
environment: Haswell-EP
cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB
mem: 128 GB
os: CentOS 7.1
kernel: Linux 3.10.0-229.4.2.el7.x86_64
Baseline results were generated using release v2.7.10, with hash
15c95b7d81dcf821daade360741e00714667653f from 2015-05-23 16:02:14+00:00
----------------------------------------------------------------------------------
benchmark relative change since change since current rev run
std_dev* last run baseline with PGO
----------------------------------------------------------------------------------
:-) django_v2 0.14% -0.65% 4.55% 7.75%
:-) pybench 0.25% 0.01% 6.86% 6.12%
:-| regex_v8 0.54% -0.30% -1.98% 6.91%
:-) nbody 0.18% -0.01% 8.28% 5.63%
:-) json_dump_v2 0.25% -0.29% 2.67% 15.49%
:-| normal_startup 2.05% 0.45% -1.95% 3.73%
:-| ssbench 0.57% 0.08% 1.01% 3.73%
----------------------------------------------------------------------------------
Note: Benchmark results for ssbench are measured in requests/second while all
other are measured in seconds.
* Relative Standard Deviation (Standard Deviation/Average)
Our lab does a nightly source pull and build of the Python project and measures
performance changes against the previous stable version and the previous nightly
measurement. This is provided as a service to the community so that quality
issues with current hardware can be identified quickly.
Intel technologies' features and benefits depend on system configuration and may
require enabled hardware, software or service activation. Performance varies
depending on system configuration.
1
0
Oct. 20, 2015
Results for project Python default, build date 2015-10-20 12:49:10
commit: 75285bd6991bcacfa8bb4b08a3f64a5c8fdd222d
revision date: 2015-10-20 07:03:33 +0000
environment: Haswell-EP
cpu: Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz 2x18 cores, stepping 2, LLC 45 MB
mem: 128 GB
os: CentOS 7.1
kernel: Linux 3.10.0-229.4.2.el7.x86_64
Baseline results were generated using release v3.4.3, with hash
b4cbecbc0781e89a309d03b60a1f75f8499250e6 from 2015-02-25 12:15:33+00:00
----------------------------------------------------------------------------------
benchmark relative change since change since current rev run
std_dev* last run baseline with PGO
----------------------------------------------------------------------------------
:-) django_v2 0.23% 1.11% 8.48% 16.03%
:-( pybench 0.17% -0.16% -2.47% 8.29%
:-( regex_v8 2.71% -0.33% -4.77% 6.22%
:-| nbody 0.14% 0.31% -1.97% 8.81%
:-| json_dump_v2 0.27% 0.45% -1.53% 10.98%
:-| normal_startup 0.82% -0.15% -0.61% 5.17%
----------------------------------------------------------------------------------
Note: Benchmark results are measured in seconds.
* Relative Standard Deviation (Standard Deviation/Average)
Our lab does a nightly source pull and build of the Python project and measures
performance changes against the previous stable version and the previous nightly
measurement. This is provided as a service to the community so that quality
issues with current hardware can be identified quickly.
Intel technologies' features and benefits depend on system configuration and may
require enabled hardware, software or service activation. Performance varies
depending on system configuration.
1
0
peps: Incorporate PEP 505 changes from Mark Haase, including aux files
by chris.angelico Oct. 20, 2015
by chris.angelico Oct. 20, 2015
Oct. 20, 2015
https://hg.python.org/peps/rev/5d9e1c787f16
changeset: 6118:5d9e1c787f16
user: Chris Angelico <rosuav(a)gmail.com>
date: Wed Oct 21 02:25:57 2015 +1100
summary:
Incorporate PEP 505 changes from Mark Haase, including aux files
files:
pep-0505.txt | 1248 ++++++++++++-
pep-0505/find-pep505.out | 2514 ++++++++++++++++++++++++++
pep-0505/find-pep505.py | 434 ++++
pep-0505/test.py | 92 +
4 files changed, 4201 insertions(+), 87 deletions(-)
diff --git a/pep-0505.txt b/pep-0505.txt
--- a/pep-0505.txt
+++ b/pep-0505.txt
@@ -1,5 +1,5 @@
PEP: 505
-Title: None coalescing operators
+Title: None-aware operators
Version: $Revision$
Last-Modified: $Date$
Author: Mark E. Haase <mehaase(a)gmail.com>
@@ -12,44 +12,193 @@
Abstract
========
-Several modern programming languages have so-called "null coalescing" or
-"null aware" operators, including C#, Dart, Perl, Swift, and PHP (starting in
-version 7). These operators provide syntactic sugar for common patterns
-involving null references. [1]_ [2]_
+Several modern programming languages have so-called "``null``-coalescing" or
+"``null``- aware" operators, including C# [1]_, Dart [2]_, Perl, Swift, and PHP
+(starting in version 7). These operators provide syntactic sugar for common
+patterns involving null references.
-* The "null coalescing" operator is a binary operator that returns its first
- first non-null operand.
-* The "null aware member access" operator is a binary operator that accesses
- an instance member only if that instance is non-null. It returns null
- otherwise.
-* The "null aware index access" operator is a binary operator that accesses a
- member of a collection only if that collection is non-null. It returns null
- otherwise.
+* The "``null``-coalescing" operator is a binary operator that returns its left
+ operand if it is not ``null``. Otherwise it returns its right operand.
+* The "``null``-aware member access" operator accesses an instance member only
+ if that instance is non-``null``. Otherwise it returns ``null``. (This is also
+ called a "safe navigation" operator.)
+* The "``null``-aware index access" operator accesses a member of a collection
+ only if that collection is non-``null``. Otherwise it returns ``null``. (This
+ is another type of "safe navigation" operator.)
-Python does not have any directly equivalent syntax. The ``or`` operator can
-be used to similar effect but checks for a truthy value, not ``None``
-specifically. The ternary operator ``... if ... else ...`` can be used for
-explicit null checks but is more verbose and typically duplicates part of the
-expression in between ``if`` and ``else``. The proposed ``None`` coalescing
-and ``None`` aware operators ofter an alternative syntax that is more
-intuitive and concise.
+The purpose of this PEP is to explore the possibility of implementing similar
+operators in Python. It provides some background material and then offers
+several competing alternatives for implementation.
+
+The initial reaction to this idea is majority negative. Even if ultimately
+rejected, this PEP still serves a purpose: to fully document the reasons why
+Python should not add this behavior, so that it can be pointed to in the future
+when the question inevitably arises again. (This is the null alternative, so to
+speak!)
+
+This proposal includes several new operators and should not be considered an
+all-or-nothing proposal. For example, the safe navigation operators might be
+rejected even if the ``null``-coalescing operator is approved, or vice-versa.
+
+Of course, Python does not have ``null``; it has ``None``, which is conceptually
+distinct. Although this PEP is inspired by "``null``-aware" operators in other
+languages, it uses the term "``None``-aware" operators to describe some
+hypothetical Python implementations.
+
+
+Background
+==========
+
+Specialness of ``None``
+-----------------------
+
+The Python language does not currently define any special behavior for ``None``.
+This PEP suggests making ``None`` a special case. This loss of generality is a
+noticeable drawback of the proposal. A generalization of ``None``-aware
+operators is set forth later in this document in order to avoid this
+specialization.
+
+
+Utility of ``None``
+-------------------
+
+One common criticism of adding special syntax for ``None`` is that ``None``
+shouldn't be used in the first place: it's a code smell. A related criticism is
+that ``None``-aware operators are used to silence errors (such as the novice
+misunderstanding of an implicit ``return None``) akin to `PHP's @ operator
+<http://php.net/manual/en/language.operators.errorcontrol.php>`_. Therefore,
+the utility of ``None`` must be debated before discussing whether to add new
+behavior around it.
+
+Python does not have any concept of ``null``. Every Python identifier must
+refer to an instance, so there cannot be any ``null`` references. Python does
+have a special instance called ``None`` that can be used to represent missing
+values, but ``None`` is conceptually distinct from ``null``.
+
+The most frequent use of ``None`` in Python is to provide a default value for
+optional arguments when some other default object is unwieldy. For example:
+``def get(url, proxy=None):``. In this case, ``proxy`` is an optional
+argument. If ``proxy`` is ``None``, then the request should be sent directly to
+the server; otherwise, the request should be routed through the specified proxy
+server. This use of ``None`` is preferred here to some other sentinel value or
+the Null Object Pattern. [3]_
+
+Examples of this form abound. Consider ``types.py`` in the standard library::
+
+ def prepare_class(name, bases=(), kwds=None):
+ if kwds is None:
+ kwds = {}
+ else:
+ kwds = dict(kwds)
+ ...
+
+Another frequent use of ``None`` is interfacing with external systems. Many of
+those other systems have a concept of ``null``. Therefore, Python code must have
+a way of representing ``null``, and typically it is represented by ``None``. For
+example, databases can have ``null`` values, and most Python database drivers
+will convert ``null`` to ``None`` when retrieving data from a database, and will
+convert from ``None`` back to ``null`` when sending data to a database.
+
+This convention of interchanging ``null`` and ``None`` is widespread in Python.
+It is canonized in the Python DBAPI (PEP-249). [4]_ The ``json`` module in the
+standard library and the third party PyYAML package both use ``None`` to
+represent their respective languages' ``null``.
+
+The C language ``null`` often bleeds into Python, too, particularly for thin
+wrappers around C libraries. For example, in ``pyopenssl``, the ``X509`` class
+has `a get_notBefore() method
+<https://github.com/pyca/pyopenssl/blob/3257877f8846e4357b495fa6c9344d01b11c…
+/OpenSSL/crypto.py#L1219>`_ that returns either a timestamp or ``None``. This
+function is a thin wrapper around an OpenSSL function with the return type
+``ASN1_TIME *``. Since this C pointer is allowed to be null, the Python wrapper
+must be able to express a missing "not before" date, e.g. ``None``.
+
+The representation of ``null`` is particularly noticeable when Python code is
+marshalling data between two systems. For example, consider a Python server that
+fetches data from a database and converts it to JSON for consumption by another
+process. In this case, it's often desirable that ``null`` in the database can be
+easily translated to ``null`` in JSON. If ``None`` is not used for this purpose,
+then each package will have to define its own representation of ``null``, and
+converting between these representations adds unnecessary complexity to the
+Python glue code.
+
+Therefore, the preference for avoiding ``None`` is nothing more than a
+preference; ``None`` has legitimate uses, particularly in specific types of
+software. Any hypothetical ``None``-aware operators should be construed as
+syntactic sugar for simplifying common patterns involving ``None``, and *should
+not be construed* as error handling behavior.
+
+
+Behavior In Other Languages
+---------------------------
+
+Given that ``null``-aware operators exist in other modern languages, it may be
+helpful to quickly understand how they work in those languages.
+
+C# example::
+
+ /* Null-coalescing. */
+
+ String s1 = null;
+ String s2 = "hello";
+ String s3 = s1 ?? s2;
+ Console.WriteLine("s3 is: " + s3);
+ // s3 is: hello
+
+ /* Null-aware member access, a.k.a. safe navigation. */
+
+ Console.WriteLine("s1.Length is: " + s1?.Length);
+ Console.WriteLine("s2.Length is: " + s2?.Length);
+ // s1.Length is:
+ // s2.Length is: 5
+
+ /* Null-aware index access, a.k.a. safe navigation. */
+
+ Dictionary<string,string> d1 = null;
+ Dictionary<string,string> d2 = new Dictionary<string, string>
+ {
+ { "foo", "bar" },
+ { "baz", "bat" }
+ };
+
+ Console.WriteLine("d1[\"foo\"] is: " + d1?["foo"]);
+ Console.WriteLine("d2[\"foo\"] is: " + d2?["foo"]);
+ // d1["foo"] is:
+ // d2["foo"] is: bar
+
+ /* Short Circuiting */
+
+ Console.WriteLine("s1 trim/upper is: " + s1?.Trim().Length);
+ Console.WriteLine("s2 trim/upper is: " + s2?.Trim().Length);
+ // s1 trimmed length is:
+ // s2 trimmed length is: 5
+
+ String s4 = s1 ?? s2 ?? DoError();
+ Console.WriteLine("s4 is: " + s4)
+ // s4 is: hello
+
+A `working example <https://dotnetfiddle.net/SxQNG8>`_ can be viewed online.
+
+Of utmost importance, notice the short circuiting behavior. The short circuiting
+of ``??`` is similar to short circuiting of other boolean operators such as
+``||`` or ``&&`` and should not be surprising. Helpfully, `?.` is *also* short
+circuiting: ``s1?.Trim()`` evaluates to null, but ``s1?.Trim().Length`` does not
+attempt to dereference the ``null`` pointer.
Rationale
=========
-Null Coalescing Operator
-------------------------
+Existing Alternatives
+---------------------
-The following code illustrates how the ``None`` coalescing operators would
-work in Python::
+Python does not have any specific ``None``-aware operators, but it does have
+operators that can be used for a similar purpose. This section describes why
+these alternatives may be undesirable for some common ``None`` patterns.
- >>> title = 'My Title'
- >>> title ?? 'Default Title'
- 'My Title'
- >>> title = None
- >>> title ?? 'Default Title'
- 'Default Title'
+
+``or`` Operator
+~~~~~~~~~~~~~~~
Similar behavior can be achieved with the ``or`` operator, but ``or`` checks
whether its left operand is false-y, not specifically ``None``. This can lead
@@ -68,17 +217,33 @@
>>> (requested_quantity or default_quantity) * price # oops!
100
-This type of bug is not possible with the ``None`` coalescing operator,
-because there is no implicit type coersion to ``bool``::
+An experienced Python developer should know how ``or`` works and be capable of
+avoiding bugs like this. However, getting in the habit of using ``or`` for this
+purpose still might cause even an experienced developer to occasionally make
+this mistake, especially refactoring existing code and not carefully paying
+attention to the possible values of the left-hand operand.
- >>> price = 100
- >>> requested_quantity = 0
- >>> default_quantity = 1
- >>> (requested_quantity ?? default_quantity) * price
- 0
+For inexperienced developers, the problem is worse. The top Google hit for
+"python null coalesce" is a `StackOverflow page
+<http://stackoverflow.com/questions/4978738/is-there-a-python-equivalent-of-
+the-c-sharp-null-coalescing-operator>`_, and the top answer says to use ``or``.
+The top answer goes on to explain the caveats of using ``or`` like this, but how
+many beginning developers go on to read all those caveats?
-The same correct behavior can be achieved with the ternary operator. Here is
-an excerpt from the popular Requests package::
+The common usage of ``or`` for the purpose of providing default values is
+undeniable, and yet it is also booby-trapped for unsuspecting newcomers. This
+suggests that a safe operator for providing default values would have positive
+utility. While some critics claim that ``None-aware`` operators will be abused
+for error handling, they are no more prone to abuse than ``or`` is.
+
+
+Ternary Operator
+~~~~~~~~~~~~~~~~
+
+Another common way to intialize default values is to use the ternary operator.
+Here is an excerpt from the popular `Requests package <https://github.com/kennet
+hreitz/requests/blob/14a555ac716866678bf17e43e23230d81a8149f5/requests/models.py
+#L212>`_::
data = [] if data is None else data
files = [] if files is None else files
@@ -101,91 +266,1000 @@
This ordering of the operands is more intuitive, but it requires 4 extra
characters (for "not "). It also highlights the repetition of identifiers:
-``data if data``, ``files if files``, etc. The ``None`` coalescing operator
-improves readability::
+``data if data``, ``files if files``, etc. This example also benefits from short
+identifiers. What if the tested expression is longer and/or has side effects?
+This is addressed in the next section.
- data = data ?? []
- files = files ?? []
- headers = headers ?? {}
- params = params ?? {}
- hooks = hooks ?? {}
-The ``None`` coalescing operator also has a corresponding assignment shortcut.
+Motivating Examples
+-------------------
-::
+The purpose of this PEP is to simplify some common patterns involving ``None``.
+This section presents some examples of common ``None`` patterns and explains
+the drawbacks.
- data ?= []
- files ?= []
- headers ?= {}
- params ?= {}
- hooks ?= {}
+This first example is from a Python web crawler that uses the popular Flask
+framework as a front-end. This function retrieves information about a web site
+from a SQL database and formats it as JSON to send to an HTTP client::
-The ``None`` coalescing operator is left-associative, which allows for easy
-chaining::
+ class SiteView(FlaskView):
+ @route('/site/<id_>', methods=['GET'])
+ def get_site(self, id_):
+ site = db.query('site_table').find(id_)
- >>> user_title = None
- >>> local_default_title = None
- >>> global_default_title = 'Global Default Title'
- >>> title = user_title ?? local_default_title ?? global_default_title
- 'Global Default Title'
+ return jsonify(
+ first_seen=site.first_seen.isoformat() if site.first_seen is not None else None,
+ id=site.id,
+ is_active=site.is_active,
+ last_seen=site.last_seen.isoformat() if site.last_seen is not None else None,
+ url=site.url.rstrip('/')
+ )
-The direction of associativity is important because the ``None`` coalescing
-operator short circuits: if its left operand is non-null, then the right
-operand is not evaluated.
+Both ``first_seen`` and ``last_seen`` are allowed to be ``null`` in the
+database, and they are also allowed to be ``null`` in the JSON response. JSON
+does not have a native way to represent a ``datetime``, so the the server's
+contract states that any non-``null`` date is represented as a ISO-8601 string.
-::
+Note that this code is invalid by PEP-8 standards: several lines are over the
+line length limit. In fact, *including it in this document* violates the PEP
+formatting standard! But it's not unreasonably indented, nor are any of the
+identifiers excessively long. The excessive line length is due to the
+repetition of identifiers on both sides of the ternary ``if`` and the verbosity
+of the ternary itself (10 characters out of a 78 character line length).
- >>> def get_default(): raise Exception()
- >>> 'My Title' ?? get_default()
- 'My Title'
+One way to fix this code is to replace each ternary with a full ``if/else``
+block::
+ class SiteView(FlaskView):
+ @route('/site/<id_>', methods=['GET'])
+ def get_site(self, id_):
+ site = db.query('site_table').find(id_)
-Null-Aware Member Access Operator
----------------------------------
+ if site.first_seen is None:
+ first_seen = None
+ else:
+ first_seen = site.first_seen.isoformat()
-::
+ if site.last_seen is None:
+ last_seen = None
+ else:
+ last_seen = site.last_seen.isoformat()
- >>> title = 'My Title'
- >>> title.upper()
- 'MY TITLE'
- >>> title = None
- >>> title.upper()
+ return jsonify(
+ first_seen=first_seen,
+ id=site.id,
+ is_active=site.is_active,
+ last_seen=last_seen,
+ url=site.url.rstrip('/')
+ )
+
+This version definitely isn't *bad*. It is easy to read and understand. On the
+other hand, adding 8 lines of code to express this common behavior feels a bit
+heavy, especially for a deliberately simplified example. If a larger, more
+complicated data model was being used, then it would get tedious to continually
+write in this long form. The readability would start to suffer as the number of
+lines in the function grows, and a refactoring would be forced.
+
+Another alternative is to rename some of the identifiers::
+
+ class SiteView(FlaskView):
+ @route('/site/<id_>', methods=['GET'])
+ def get_site(self, id_):
+ site = db.query('site_table').find(id_)
+
+ fs = site.first_seen
+ ls = site.last_seen
+
+ return jsonify(
+ first_seen=fs.isodate() if fs is not None else None,
+ id=site.id,
+ is_active=site.is_active,
+ last_seen=ls.isodate() if ls is not None else None,,
+ url=site.url.rstrip('/')
+ )
+
+This adds fewer lines of code than the previous example, but it comes at the
+expense of introducing extraneous identifiers that amount to nothing more than
+aliases. These new identifiers are short enough to fit a ternary expression onto
+one line, but the identifiers are also less intuitive, e.g. ``fs`` versus
+``first_seen``.
+
+As a quick preview, consider an alternative rewrite using a new operator ``💩``.
+(This spelling of the operator is merely a placeholder so that the *concept* can
+be debated without arguing about *spelling*. It is not intended to reflect the
+public's opinion of said operator. It may, however, bring new meaning to the
+phrase "code smell".)::
+
+ class SiteView(FlaskView):
+ @route('/site/<id_>', methods=['GET'])
+ def get_site(self, id_):
+ site = db.query('site_table').find(id_)
+
+ return jsonify(
+ first_seen=site💩first_seen.isoformat(),
+ id=site.id,
+ is_active=site.is_active,
+ last_seen=site💩last_seen.isoformat(),
+ url=site.url.rstrip('/')
+ )
+
+The ``💩`` operator behaves as a "safe navigation" operator, allowing a more
+concise syntax where the expression ``site.first_seen`` is not duplicated.
+
+The next example is from a trending project on GitHub called `Grab
+<https://github.com/lorien/grab/blob/4c95b18dcb0fa88eeca81f5643c0ebfb114bf72…>`_,
+which is a Python scraping library::
+
+ class BaseUploadObject(object):
+ def find_content_type(self, filename):
+ ctype, encoding = mimetypes.guess_type(filename)
+ if ctype is None:
+ return 'application/octet-stream'
+ else:
+ return ctype
+
+ class UploadContent(BaseUploadObject):
+ def __init__(self, content, filename=None, content_type=None):
+ self.content = content
+ if filename is None:
+ self.filename = self.get_random_filename()
+ else:
+ self.filename = filename
+ if content_type is None:
+ self.content_type = self.find_content_type(self.filename)
+ else:
+ self.content_type = content_type
+
+ class UploadFile(BaseUploadObject):
+ def __init__(self, path, filename=None, content_type=None):
+ self.path = path
+ if filename is None:
+ self.filename = os.path.split(path)[1]
+ else:
+ self.filename = filename
+ if content_type is None:
+ self.content_type = self.find_content_type(self.filename)
+ else:
+ self.content_type = content_type
+
+.. note::
+
+ I don't know the author of the Grab project. I used it as an example
+ because it is a trending repo on GitHub and it has good examples of common
+ ``None`` patterns.
+
+This example contains several good examples of needing to provide default
+values. It is a bit verbose as it is, and it is certainly not improved by the
+ternary operator::
+
+ class BaseUploadObject(object):
+ def find_content_type(self, filename):
+ ctype, encoding = mimetypes.guess_type(filename)
+ return 'application/octet-stream' if ctype is None else ctype
+
+ class UploadContent(BaseUploadObject):
+ def __init__(self, content, filename=None, content_type=None):
+ self.content = content
+ self.filename = self.get_random_filename() if filename \
+ is None else filename
+ self.content_type = self.find_content_type(self.filename) \
+ if content_type is None else content_type
+
+ class UploadFile(BaseUploadObject):
+ def __init__(self, path, filename=None, content_type=None):
+ self.path = path
+ self.filename = os.path.split(path)[1] if filename is \
+ None else filename
+ self.content_type = self.find_content_type(self.filename) \
+ if content_type is None else content_type
+
+The first ternary expression is tidy, but it reverses the intuitive order of
+the operands: it should return ``ctype`` if it has a value and use the string
+literal as fallback. The other ternary expressions are unintuitive and so
+long that they must be wrapped. The overall readability is worsened, not
+improved.
+
+This code *might* be improved, though, if there was a syntactic shortcut for
+this common need to supply a default value. We'll assume the fictitious
+operator ``✊🍆`` to avoid a premature debate about the spelling of said
+operator::
+
+ class BaseUploadObject(object):
+ def find_ctype(self, filename):
+ ctype, encoding = mimetypes.guess_type(filename)
+ return ctype ✊🍆 'application/octet-stream'
+
+ class UploadContent(BaseUploadObject):
+ def __init__(self, content, filename=None, content_type=None):
+ self.content = content
+ self.filename = filename ✊🍆 self.get_random_filename()
+ self.content_type = content_type ✊🍆 self.find_ctype(self.filename)
+
+ class UploadFile(BaseUploadObject):
+ def __init__(self, path, filename=None, content_type=None):
+ self.path = path
+ self.filename = filename ✊🍆 os.path.split(path)[1]
+ self.content_type = content_type ✊🍆 self.find_ctype(self.filename)
+
+This syntax has an intuitive ordering of the operands, e.g. ``ctype`` -- the
+preferred value -- comes before the fallback value. The terseness of the syntax
+also makes for fewer lines of code and less code to visually parse.
+
+.. note::
+
+ I cheated on the last example: I renamed ``find_content_type`` to
+ ``find_ctype`` in order to fit two of the lines under 80 characters. If you
+ find this underhanded, you can go back and apply the same renaming to the
+ previous 2 examples. You'll find that it doesn't change the
+ conclusions.
+
+
+Usage Of ``None`` In The Standard Library
+-----------------------------------------
+
+The previous sections show some code patterns that are claimed to be "common",
+but how common are they? The attached script ``find-pep505.py`` is meant to
+answer this question. It uses the ``ast`` module to search for these patterns in
+any ``*.py`` file. It checks for variations of the following patterns.
+
+ >>> # None-coalescing if block
+ ...
+ >>> if a is None:
+ ... a = b
+
+ >>> # [Possible] None-coalescing "or" operator
+ ...
+ >>> a or 'foo'
+ >>> a or []
+ >>> a or {}
+
+ >>> # None-coalescing ternary
+ ...
+ >>> a if a is not None else b
+ >>> b if a is None else a
+
+ >>> # Safe navigation "and" operator
+ ...
+ >>> a and a.foo
+ >>> a and a['foo']
+ >>> a and a.foo()
+
+ >>> # Safe navigation if block
+ ...
+ >>> if a is not None:
+ ... a.foo()
+
+ >>> # Safe navigation ternary
+ ...
+ >>> a.foo if a is not None else b
+ >>> b if a is None else a.foo
+
+This script takes one or more names of Python source files to analyze::
+
+ $ python3 find-pep505.py test.py
+ $ find /usr/lib/python3.4 -name '*.py' | xargs python3 find-pep505.py
+
+The script prints out any matches it finds. Sample::
+
+ None-coalescing if block: /usr/lib/python3.4/inspect.py:594
+ if _filename is None:
+ _filename = getsourcefile(object) or getfile(object)
+
+ [Possible] None-coalescing `or`: /usr/lib/python3.4/lib2to3/refactor.py:191
+ self.explicit = explicit or []
+
+ None-coalescing ternary: /usr/lib/python3.4/decimal.py:3909
+ self.clamp = clamp if clamp is not None else dc.clamp
+
+ Safe navigation `and`: /usr/lib/python3.4/weakref.py:512
+ obj = info and info.weakref()
+
+ Safe navigation `if` block: /usr/lib/python3.4/http/cookiejar.py:1895
+ if k is not None:
+ lc = k.lower()
+ else:
+ lc = None
+
+ Safe navigation ternary: /usr/lib/python3.4/sre_parse.py:856
+ literals = [None if s is None else s.encode('latin-1') for s in literals]
+
+.. note::
+
+ Coalescing with ``or`` is marked as a "possible" match, because it's not
+ trivial to infer whether ``or`` it is meant to coalesce False-y values
+ (correct) or if it meant to coalesce ``None`` (incorrect). On the other
+ hand, we assume that `and` is always incorrect for safe navigation.
+
+The script is tested against ``test.py`` (also attached to this document) and
+the Python 3.4 standard library, but it should work on any arbitrary Python
+source code. The complete output from running it against the standard library is
+attached to this proposal as ``find-pep505.out``.
+
+The script counts how many matches it finds and prints the totals at the
+end::
+
+ Total None-coalescing `if` blocks: 426
+ Total [possible] None-coalescing `or`: 119
+ Total None-coalescing ternaries: 21
+ Total Safe navigation `and`: 9
+ Total Safe navigation `if` blocks: 55
+ Total Safe navigation ternaries: 7
+
+This is a total of 637 possible matches for these common code patterns in the
+standard library. Allowing for some false positives and false negatives, it is
+fair to say that these code patterns are definitely common in the standard
+library.
+
+
+Rejected Ideas
+--------------
+
+Several related ideas were discussed on python-ideas, and some of these were
+roundly rejected by BDFL, the community, or both. For posterity's sake, some of
+those ideas are recorded here.
+
+``None``-aware Function Call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``None``-aware syntax applies to attribute and index access, so it seems
+natural to ask if it should also apply to function invocation syntax. Borrowing
+a spelling similar to C#, it might be spelled ``foo?()``, where ``foo`` is only
+called if it is not None. This idea was quickly rejected, for several reasons.
+
+No other mainstream language has such syntax. Moreover, it would be difficult to
+discern if a function expression returned ``None`` because it was short-
+circuited or because the function itself returned ``None``. Finally, Python
+evaluates arguments to a function before it looks up the function itself, so
+``foo?(bar())`` would still call ``bar()`` even if ``foo`` is ``None``. This
+behaviour is unexpected for a so-called "short-circuiting" operator.
+
+Instead, the "``None``-severing" operator is proposed below. This operator
+offers a concise form for writing ``None``-aware function expressions that is
+truly short-circuiting.
+
+``?`` Unary Postfix Operator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To generalize the ``None``-aware behavior and limit the number of new operators
+introduced, a unary, postfix operator spelled ``?`` was suggested. The idea is
+that ``?`` would return a special object that could would override dunder
+methods to return itself or to return None. For example::
+
+ class NoneQuestion():
+ def __call__(self, *args, **kwargs):
+ return self
+
+ def __getattr__(self, name):
+ return self
+
+ def __getitem__(self, key):
+ reutrn self
+
+
+An expression like ``foo?`` would return a ``NoneQuestion`` instance if ``foo``
+is ``None``; otherwise, it returns ``foo``. With this operator, an expression
+like ``foo?.bar[baz]`` evaluates to ``NoneQuestion`` if ``foo`` is None. This is
+a nice generalization, but it's difficult to use in practice since most existing
+code won't know what ``NoneQuestion`` is.
+
+Going back to one of the motivating examples above, consider the following::
+
+ >>> import json
+ >>> created = None
+ >>> json.dumps({'created': created?.isoformat()})``
+
+The JSON serializer does not know how to serialize ``NoneQuestion``, nor will
+any other API. This proposal actually requires *lots of specialized logic*
+throughout the standard library and any third party library.
+
+The ``?`` operator may also be **too general**, in the sense that it can be
+combined with any other operator. What should the following expressions mean?
+
+ >>> x? + 1
+ >>> x? -= 1
+ >>> x? == 1
+ >>> ~x?
+
+This degree of generalization is not useful. The operators actually proposed
+herein are intentionally limited to a few operators that are expected to make it
+easier to write common code patterns.
+
+Haskell-style ``Maybe``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Haskell has a concept called `Maybe <https://wiki.haskell.org/Maybe>`_ that
+encapsulates the idea of an optional value without relying on any special
+keyword (e.g. ``null``) or any special instance (e.g. ``None``). In Haskell, the
+purpose of ``Maybe`` is to avoid separate handling of "something" and nothing".
+The concept is so heavily intertwined with Haskell's lazy evaluation that it
+doesn't translate cleanly into Python.
+
+There is a Python package called `pymaybe
+<https://pypi.python.org/pypi/pymaybe/0.1.1>`_ that provides a rough
+approximation. The documentation shows the following example that appears
+relevant to the discussion at hand::
+
+ >>> maybe('VALUE').lower()
+ 'value'
+
+ >>> maybe(None).invalid().method().or_else('unknown')
+ 'unknown'
+
+The function ``maybe()`` returns either a ``Something`` instance or a
+``Nothing`` instance. Similar to the unary postfix operator described in the
+previous section, ``Nothing`` overrides dunder methods in order to allow
+chaining on a missing value.
+
+Note that ``or_else()`` is eventually required to retrieve the underlying value
+from ``pymaybe``'s wrappers. Furthermore, ``pymaybe`` does not short circuit any
+evaluation. Although ``pymaybe`` has some strengths and may be useful in its own
+right, it also demonstrates why a pure Python implementation of coalescing is
+not nearly as powerful as support built into the language.
+
+
+Specification
+=============
+
+This PEP suggests 4 new operators be added to Python:
+
+1. ``None``-coalescing operator
+2. ``None``-severing operator
+3. ``None``-aware attribute access
+4. ``None``-aware index access/slicing
+
+We will continue to assume the same spellings as in the previous sections in
+order to focus on behavior before diving into the much more contentious issue of
+how to spell these operators.
+
+
+``None``-Coalescing Operator
+----------------------------
+
+The ``None``-coalescing operator is a short-circuiting, binary operator that behaves
+in the following way.
+
+1. Evaluate the left operand first.
+2. If the left operand is not ``None``, then return it immediately.
+3. Else, evaluate the right operand and return the result.
+
+Some simple examples::
+
+ >>> 1 ✊🍆 2
+ 1
+ >>> None ✊🍆 2
+ 2
+ >>> 1 ✊🍆 None
+ 1
+
+Importantly, note that the right operand is not evaluated unless the left
+operand is None::
+
+ >>> def err(): raise Exception('foo')
+ >>> 1 ✊🍆 err()
+ 1
+ >>> None ✊🍆 err()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
- AttributeError: 'NoneType' object has no attribute 'upper'
- >>> title?.upper()
+ File "<stdin>", line 1, in err
+ Exception: foo
+
+The operator is left associative. Combined with its short circuiting behavior,
+this makes the operator easy to chain::
+
+ >>> timeout = None
+ >>> local_timeout = 60
+ >>> global_timeout = 300
+ >>> timeout ✊🍆 local_timeout ✊🍆 global_timeout
+ 60
+
+ >>> local_timeout = None
+ >>> timeout ✊🍆 local_timeout ✊🍆 global_timeout
+ 300
+
+ >>> import time
+ >>> timeout ✊🍆 local_timeout ✊🍆 global_timeout ✊🍆 time.sleep(10)
+ 300
+
+Note in the last example that ``time.sleep(10)`` represents an expensive
+function call, e.g. initializing a complex data structure. In this example
+``time.sleep`` is not evaluated, and the result ``300`` is returned instantly.
+
+The operator has precedence lower than ``not`` but higher than ``and`` and
+``or``. This precedence makes reasoning about the order of operations
+comfortable, because it has precedence similar to the operators used for
+coalescing false-y values. Here are pairs of examples, where each item in the
+pair is evaluated identically to the other item in the pair::
+
+ >>> not None ✊🍆 False
+ True
+ >>> (not None) ✊🍆 False
+ True
+
+ >>> 'foo' in dict() ✊🍆 {'foo': 'bar'}
+ False
+ >>> ('foo' in dict()) ✊🍆 {'foo': 'bar'}
+ False
+
+ >>> 1 == None ✊🍆 1
+ False
+ >>> (1 == None) ✊🍆 1
+ False
+
+But ``and`` and ``or`` have lower precedence::
+
+ >>> 2 or None ✊🍆 err()
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ File "<stdin>", line 1, in err
+ Exception: foo
+ >>> (2 or None) ✊🍆 err()
+ 2
+
+Recall the example above of calculating the cost of items in a shopping cart,
+and the easy-to-miss bug. This type of bug is not possible with the ``None``-
+coalescing operator, because there is no implicit type coersion to ``bool``::
+
+ >>> price = 100
+ >>> requested_quantity = 0
+ >>> default_quantity = 1
+ >>> (requested_quantity ✊🍆 default_quantity) * price
+ 0
+
+The ``None``-coalescing operator also has a corresponding assignment shortcut.
+The following assignments are semantically equivalent::
+
+ >>> foo ✊🍆= []
+ >>> foo = foo ✊🍆 []
+
+The ``None`` coalescing operator improves readability, especially when handling
+default function arguments. Consider again the example of requests, rewritten to
+use ``None``-coalescing::
+
+ def __init__(self, data=None, files=None, headers=None, params=None, hooks=None):
+ self.data = data ✊🍆 []
+ self.files = files ✊🍆 []
+ self.headers = headers ✊🍆 {}
+ self.params = params ✊🍆 {}
+ self.hooks = hooks ✊🍆 {}
+
+The operator makes the intent easier to follow (by putting operands in an
+intuitive order) and is more concise than the ternary operator, while still
+preserving the short circuit semantics of the code that it replaces.
+
+
+``None``-Severing Operator
+--------------------------
+
+The idea of a ``None``-aware function invocation syntax was discussed on python-
+ideas, but the idea was rejected by BDFL. The syntax comes dangerously close to
+allowing a caller to change the return type of a function. If a function is
+defined to always return a value, then it seems strange that the call site could
+change the function to return "value or ``None``".
+
+Still, conditional function execution is a common idiom in Python, particularly
+for callback functions. Consider this hypothetical example::
+
+ import time
+
+ def delay(seconds, callback=None):
+ time.sleep(seconds)
+
+ if callback is not None:
+ callback()
+
+With a ``None``-aware function invocation, this example might be written more
+concisely as::
+
+ import time
+
+ def delay(seconds, callback=None):
+ time.sleep(seconds)
+ callback?()
+
+Consider a "``None``-severing" operator, however, which is a short-circuiting,
+boolean operator similar to the ``None``-coalesing operator, except it returns
+its left operand if that operand is None. If the left operand is None, then the
+right operand is not evaluated. Let's temporarily spell this operator ``✂`` and
+rewrite the example accordingly::
+
+ import time
+
+ def delay(seconds, callback=None):
+ time.sleep(seconds)
+ callback ✂ callback()
+
+At this point, you may be astonished at the mere suggestion of such a strange
+operator with limited practical usefulness. It is proposed here because of the
+symmetry it has with the ``None``-coalescing operator. This symmetry may be more
+apparent if the two operators have complementary spellings.
+
+In the same way that ``or`` and ``and`` go together, ``None``-coalescing and
+``None``- severing might be spelled in a pleasing, symmetric way, e.g. ``or?``
+and ``and?``. If such a spelling can be decided on, then this operator adds very
+little cognitive load or special machinery to the language, and it's minor
+utility may justify its inclusion in the language.
+
+Note that ``None``-severing could also be used as an alternative to "safe
+navigation", at the expense of some repeated expressions::
+
+ >>> from datetime import datetime
+ >>> d = None
+ >>> type(d ✂ d.isoformat())
+ <class 'NoneType'>
+
+ >>> d = datetime.now()
+ >>> d ✂ d.isoformat()
+ '2015-10-16T20:53:40.312135'
+
+The repeated expression ``d`` makes this less useful than a ``None``-aware
+attribute access operator, but to repeat what was said at the outset: this
+proposal may be approved or rejected in whole or in part. This unlikely operator
+is included in the proposal in order to be comprehensive.
+
+The precedence and associativity of the ``None``-severing operator are the same
+as the ``None``-coalescing operator.
+
+
+``None``-Aware Attribute Access Operator
+----------------------------------------
+
+The ``None``-aware attribute access operator (also called "safe navigation")
+checks its left operand. If the left operand is ``None``, then the operator
+evaluates to ``None``. If the the left operand is not ``None``, then the
+operator accesses the attribute named by the right operand. As in the previous
+section, we continue to use the temporary spelling ``💩``::
+
+ >>> from datetime import date
+ >>> d = date.today()
+ >>> d.year
+ 2015
+
+ >>> d = None
+ >>> d.year
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ AttributeError: 'NoneType' object has no attribute 'year'
+
+ >>> d💩year
None
+The operator has the same precedence and associativity as the plain attribute
+access operator ``.``, but this operator is also short-circuiting in a unique
+way: if the left operand is ``None``, then any adjacent attribute access, index
+access, slicing, or function call operators *are not evaluated*.
-Null-Aware Index Access Operator
----------------------------------
+ >>> name = ' The Black Knight '
+ >>> name.strip()[4:].upper()
+ 'BLACK KNIGHT'
-::
+ >>> name = None
+ >>> name💩strip()[4:].upper()
+ None
+
+If this operator did not short circuit in this way, then the second example
+would partially evaluate ``name💩strip()`` to ``None()`` and then fail with
+``TypeError: 'NoneType' object is not callable``.
+
+To put it another way, the following expressions are semantically equivalent::
+
+ >>> name💩strip()[4:].upper()
+ >>> name.strip()[4:].upper() if name is not None else None
+
+.. note::
+
+ C# implements its safe navigation operators with the same short-circuiting
+ semantics, but Dart does not. In Dart, the second example (suitably
+ translated) would fail. The C# semantics are obviously superior, given the
+ original goal of writing common cases more concisely. The Dart semantics are
+ nearly useless.
+
+This operator short circuits one or more immediately adjacent attribute access,
+index access, slicing, or function call operators, but it does not short circuit
+any other operators (logical, bitwise, arithmetic, etc.), nor does it escape
+parentheses::
+
+ >>> d = date.today()
+ >>> d💩year.numerator + 1
+ 2016
+
+ >>> d = None
+ >>> d💩year.numerator + 1
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
+
+ >>> (d💩year).numerator + 1
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ AttributeError: 'NoneType' object has no attribute 'numerator'
+
+Note that the error in the second example is not on the attribute access
+``numerator``. In fact, that attribute access is never performed. The error
+occurs when adding ``None + 1``, because the ``None``-aware attribute access
+does not short circuit ``+``.
+
+The third example fails because the operator does not escape parentheses. In
+that example, the attribute access ``numerator`` is evaluated and fails because
+``None`` does not have that attribute.
+
+Finally, observe that short circuiting adjacent operators is not at all the same thing as propagating ``None`` throughout an expression.
+
+ >>> user💩first_name.upper()
+
+If ``user`` is not ``None``, then ``user.first_name`` is evaluated. If
+``user.first_name`` evaluates to ``None``, then ``user.first_name.upper()`` is
+an error! In English, this expression says ``user`` is optional but if it has a
+value, then it must have a ``first_name``, too.
+
+If ``first_name`` is supposed to be optional attribute, then the expression must
+make that explicit:
+
+ >>> user💩first_name💩upper()
+
+The operator is not intended as an error silencing mechanism, and it would be
+wrong if its presence infected nearby operators.
+
+``None``-Aware Index Access/Slicing Operator
+--------------------------------------------
+
+The ``None``-aware index access/slicing operator (also called "safe navigation")
+is nearly identical to the ``None``-aware attribute access operator. It combines
+the familiar square bracket syntax ``[]`` with new punctuation or a new keyword,
+the spelling of which is discussed later::
>>> person = {'name': 'Mark', 'age': 32}
>>> person['name']
'Mark'
+
>>> person = None
>>> person['name']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
- >>> person?['name']
+
+ >>> person💩['name']
None
+The ``None``-aware slicing operator behaves similarly::
-Specification
-=============
+ >>> name = 'The Black Knight'
+ >>> name[4:]
+ 'Black Knight'
+
+ >>> name = None
+ >>> name[4:]
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: 'NoneType' object is not subscriptable
+
+ >>> name💩[4:]
+ None
+
+These operators have the same precedence as the plain index access and slicing
+operators.
+
+
+Generalization
+--------------
+
+Making ``None`` a special case may seem too specialized and magical. It is
+possible to generalize the behavior by making the ``None``-aware operators
+invoke a dunder method, e.g. ``__coalesce__(self)`` that returns ``True`` if an
+object should be coalesced and ``False`` otherwise.
+
+With this generalization, ``object`` would implement a dunder method equivalent
+to this::
+
+ def __coalesce__(self):
+ return False
+
+``NoneType`` would implement a dunder method equivalent to this::
+
+ def __coalesce__(self):
+ return True
+
+This generalization allows for domain-specific ``null`` objects to be coalesced
+just like ``None``. For example the ``pyasn1`` package has a type called
+``Null`` that represents an ASN.1 ``null``.
+
+If this generalization is accepted, then the operators will need to be renamed
+such that the term ``None`` is not used, e.g. "Coalescing Operator", "Coalesced
+Member Access Operator", etc.
+
+
+Operator Spelling
+-----------------
+
+Despite significant support for the proposed operators, the majority of
+discussion on python-ideas fixated on the spelling. No consensus was achieved on
+this question, for two reasons. First, Python eschews punctuation for logical
+operators. For example, it uses ``not`` instead of ``!`` and ``… if … else …``
+instead of ``?:``. Introducing new punctuation is a major turnoff to many
+Pythonistas, including BDFL. Second, adding new keywords to the language is
+not backwards compatible. Any new keyword could only be introduced in the next
+major version, e.g. Python 4. (Even then, `there would be resistance
+<http://opensource.com/life/14/9/why-python-4-wont-be-python-3>`_.)
+
+Furthermore, nearly every single punctuation character on a standard keyboard
+already has special meaning in Python. The only exceptions are ``$``, ``~``,
+``?``, and backtick (as of Python 3). This leaves few options for a new, single-
+character operator. A two character spelling is more likely, such as the ``??``
+and ``?.`` spellings in other programming languages, but this decreases the
+appeal of punctuation even further.
+
+Finally, other projects in the Python universe assign special meaning to
+punctuation. For example, `IPython <https://ipython.org/ipython-
+doc/2/interactive/reference.html>`_ assigns special meaning to ``%``, ``%%``,
+``?``, ``??``, ``$``, and ``$$``, among others. Out of deference to those
+projects and the large communities using them, introducing conflicting syntax
+into Python is undesirable.
+
+This is not the first PEP to deal with this dilemma. PEP-308 [5]_, which
+introduced the ternary operator, faced similar issues.
+
+Alternative Spellings
+~~~~~~~~~~~~~~~~~~~~~
+
+In keeping with the spirit of the PEP, many alternative spellings for these
+``None``-aware operators are suggested, including some that conflict with each
+other. Deconfliction will be handled only if any part of this proposal is
+accepted.
+
+One caveat noted by several respondents on python-ideas: using similar spelling
+for ``None`` coalescing and other ``None``-aware operators may be confusing,
+because they have different short circuit semantics: coalescing short circuits
+on non-``None``, while ``None``-aware attribute/index access short circuit on
+``None``. This is a potential downside to spellings like ``??`` and ``?.``. This
+is only a practical concern if any part of this proposal is actually accepted,
+so there is no need to pontificate any further.
+
+The following spellings are proposed candidates for the ``None``-coalescing
+operator.
+
+1. ``foo ?? bar ?? baz``
+ - Pros: same spelling as C# and Dart
+ - Cons: punctuation is ugly; possible conflict with IPython; difficult to
+ google to find out what it means
+2. ``foo or? bar or? baz``
+ - Pros: similar to existing ``or`` operator
+ - Cons: the difference between this and ``or`` is not intuitive; punctuation
+ is ugly
+3. ``foo ? bar``
+ - Pros: similar to ``??`` used in other languages
+ - Cons: punctuation is ugly; possible conflict with IPython; not used by any
+ other language
+4. ``foo $$ bar``
+ - Pros: pronounced "value operator" because it returns the first operand
+ that has a "value"
+ - Cons: punctuation is ugly; not used by any other language
+5. ``foo else bar``
+ - Pros: prettier than punctuation; uses an existing keyword
+ - Cons: difficult or impossible to implement with Python's LL(1) parser
+6. ``foo or else bar``
+ - Pros: prettier than punctuation; use existing keywords
+ - Cons: difficult or impossible to implement with Python's LL(1) parser
+7. ``foo def bar``
+ - Pros: pronounced 'default'; prettier than punctuation
+ - Cons: difficult or impossible to implement with Python's LL(1) parser
+8. ``foo then bar``
+ - Pros: prettier than punctuation
+ - Cons: requires a new keyword, probably can't be implemented until Python 4
+ (and maybe not even then)
+9. No ``None``-coalescing operator.
+ - (Pros and cons discussed throughout this document.)
+
+The following spellings are proposed candidates for the ``None``-severing
+operator. Each alternative has symmetry with one of the proposed spellings of
+the ``None``- coalescing operator.
+
+1. ``foo !! bar``
+ - Pros: symmetric with ``??``
+ - Cons: punctuation is ugly; possible conflict with IPython; difficult to
+ google to find out what it means
+2. ``foo and? bar``
+ - Pros: symmetric with ``or?``
+ - Cons: punctuation is ugly; possible conflict with IPython; difficult to
+ google to find out what it means
+3. No ``None``-severing operator.
+ - (Pros and cons discussed throughout this document.)
+
+The following spellings are proposed candidates for the ``None``-aware attribute
+access operator. If you find any of these hard to read, consider that we may
+adopt a convention of adding whitespace around a ``None``-aware operator to
+improve readability.
+
+1. ``foo?.bar``, ``foo ?. bar``
+ - Pros: same spelling as C# and Dart
+ - Cons: punctuation is ugly; possible conflict with IPython; difficult to
+ google to find out what it means; difficult to differentiate from ``.``
+ when reading quickly
+2. ``foo$.bar``, ``foo $. bar``
+ - Pros: symmetry with ``$$`` operator proposed above
+ - Cons: punctuation is ugly; difficult to google; possible confusion because
+ it looks a bit like other languages' string interpolation; difficult to
+ google to find out what it means; difficult to differentiate from ``.``
+ when reading quickly
+3. ``foo!bar``, ``foo ! bar``
+ - Pros: similar to ordinary ``.`` operator
+ - Cons: punctuation is ugly; possible conflict with IPython; no corresponding
+ spelling for index access (e.g. ``foo!['bar']`` is ambiguous)
+4. ``foo->bar``, ``foo -> bar``
+ - Pros: easier to read than other punctuation; less likely to be confused
+ with ordinary attribute access
+ - Cons: punctuation is ugly; difficult to google; confusing because it is
+ spelled the same as C's dereference operator
+5. ``foo try .bar``
+ - Pros: uses an existing keyword;
+ - Cons: difficult or impossible to implement in Python's LL(1) parser
+6. No ``None``-aware attribute access operator.
+ - (Pros and cons discussed throughout this document.)
+
+The following spellings are proposed candidates for the ``None``-aware index
+access/slicing operator. The punctuation used for this operator ought to
+resemble the punctuation used for the ``None``-aware attribute access.
+
+1. ``foo?['bar']``, ``foo ? ['bar']``
+ - Pros: same spelling as C# and Dart
+ - Cons: punctuation is ugly; possible conflict with IPython; difficult to
+ google to find out what it means
+2. ``foo$['bar']``, ``foo $ ['bar']``
+ - Pros: symmetry with ``$$`` operator proposed above
+ - Cons: punctuation is ugly; possible confusion because
+ it looks a bit like other languages' string interpolation
+3. ``foo->['bar']``, ``foo -> ['bar']``
+ - Pros: easier to read than other punctuation; less likely to be confused
+ with ordinary attribute access
+ - Cons: punctuation is ugly; difficult to google; confusing because it is
+ spelled the same as C's dereference operator
+4. ``foo try ['bar']``
+ - Pros: uses an existing keyword;
+ - Cons: difficult or impossible to implement in Python's LL(1) parser
+5. No ``None``-aware index access/slicing operator.
+ - (Pros and cons discussed throughout this document.)
+
+Community Poll
+~~~~~~~~~~~~~~
+
+In order to collect data about the Python community's preferences for
+``None``-aware operators, and with BDFL's consent, a public poll will be
+conducted, just as with PEP-308. The poll is viewed as a data-gathering
+exercise, not a democratic vote.
+
+The poll will allow respondents to rank their favorite options from the previous
+section. The results will
+be placed in this section of the PEP.
+
+...TBD...
+
+
+Implementation
+--------------
+
+Given that the need for ``None``-aware operators is questionable and the
+spelling of said operators is almost incendiary, the implementation details for
+CPython will be deferred unless and until we have a clearer idea that one (or
+more) of the proposed operators will be approved.
+
+...TBD...
References
==========
-.. [1] Wikipedia: Null coalescing operator
- (https://en.wikipedia.org/wiki/Null_coalescing_operator)
+.. [1] C# Reference: Operators
+ (https://msdn.microsoft.com/en-us/library/6a71f45d.aspx)
-.. [2] Seth Ladd's Blog: Null-aware operators in Dart
- (http://blog.sethladd.com/2015/07/null-aware-operators-in-dart.html)
+.. [2] A Tour of the Dart Language: Operators
+ (https://www.dartlang.org/docs/dart-up-and-running/ch02.html#operators)
+
+.. [3] Wikipedia: Null Object Pattern
+ (https://en.wikipedia.org/wiki/Null_Object_pattern)
+
+.. [4] PEP-249:
+ (https://www.python.org/dev/peps/pep-0249/)
+
+.. [5] PEP-308
+ (https://www.python.org/dev/peps/pep-0308/)
Copyright
diff --git a/pep-0505/find-pep505.out b/pep-0505/find-pep505.out
new file mode 100644
--- /dev/null
+++ b/pep-0505/find-pep505.out
@@ -0,0 +1,2514 @@
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:495
+ if _hextobyte is None:
+ _hextobyte = {(a + b).encode(): bytes([int(a + b, 16)])
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:522
+ if encoding is None:
+ encoding = 'utf-8'
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:524
+ if errors is None:
+ errors = 'replace'
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:854
+ if _typeprog is None:
+ _typeprog = re.compile('^([^/:]+):')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:867
+ if _hostprog is None:
+ _hostprog = re.compile('^//([^/?]*)(.*)$')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:883
+ if _userprog is None:
+ _userprog = re.compile('^(.*)(a)(.*)$')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:894
+ if _passwdprog is None:
+ _passwdprog = re.compile('^([^:]*):(.*)$',re.S)
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:906
+ if _portprog is None:
+ _portprog = re.compile('^(.*):([0-9]*)$')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:923
+ if _nportprog is None:
+ _nportprog = re.compile('^(.*):(.*)$')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:941
+ if _queryprog is None:
+ _queryprog = re.compile('^(.*)\?([^?]*)$')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:952
+ if _tagprog is None:
+ _tagprog = re.compile('^(.*)#([^#]*)$')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/parse.py:969
+ if _valueprog is None:
+ _valueprog = re.compile('^([^=]*)=(.*)$')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/parse.py:396
+ url = '//' + (netloc or '') + url
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:274
+ if origin_req_host is None:
+ origin_req_host = request_host(self)
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:727
+ if proxies is None:
+ proxies = getproxies()
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:739
+ if proxy_type is None:
+ proxy_type = orig_type
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:853
+ if password_mgr is None:
+ password_mgr = HTTPPasswordMgr()
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:935
+ if passwd is None:
+ passwd = HTTPPasswordMgr()
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:1234
+ if cookiejar is None:
+ cookiejar = http.cookiejar.CookieJar()
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:1373
+ if port is None:
+ port = ftplib.FTP_PORT
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:1550
+ if proxies is None:
+ proxies = getproxies()
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:2195
+ if _localhost is None:
+ _localhost = socket.gethostbyname('localhost')
+
+None-coalescing `if` block: /usr/lib/python3.4/urllib/request.py:2223
+ if _noheaders is None:
+ _noheaders = email.message_from_string("")
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1344
+ (mtype or 'text/plain', size, modified))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1385
+ user = user or ''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1386
+ passwd = passwd or ''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1668
+ garbage, path = splithost(path or "")
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1669
+ path, garbage = splitquery(path or "")
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1670
+ path, garbage = splitattr(path or "")
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1862
+ (mtype or 'text/plain', size, modified))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1891
+ user = unquote(user or '')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/urllib/request.py:1892
+ passwd = unquote(passwd or '')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/ssl.py:625
+ v = self._sslobj.read(len or 1024)
+
+None-coalescing `if` block: /usr/lib/python3.4/socket.py:217
+ if buffering is None:
+ buffering = -1
+
+Safe navigation `if` block: /usr/lib/python3.4/socket.py:508
+ if sock is not None:
+ sock.close()
+
+None-coalescing `if` block: /usr/lib/python3.4/ftplib.py:464
+ if callback is None:
+ callback = print_line
+
+None-coalescing `if` block: /usr/lib/python3.4/ftplib.py:729
+ if context is None:
+ context = ssl._create_stdlib_context(self.ssl_version,
+
+None-coalescing `if` block: /usr/lib/python3.4/http/server.py:424
+ if message is None:
+ message = shortmsg
+
+None-coalescing `if` block: /usr/lib/python3.4/http/server.py:426
+ if explain is None:
+ explain = longmsg
+
+None-coalescing `if` block: /usr/lib/python3.4/http/server.py:545
+ if timestamp is None:
+ timestamp = time.time()
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookies.py:399
+ if attrs is None:
+ attrs = self._reserved
+
+None-coalescing `if` block: /usr/lib/python3.4/http/client.py:1207
+ if context is None:
+ context = ssl._create_default_https_context()
+
+None-coalescing `if` block: /usr/lib/python3.4/http/client.py:1210
+ if check_hostname is None:
+ check_hostname = context.check_hostname
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookiejar.py:162
+ if hr is None: hr = 0
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookiejar.py:163
+ if min is None: min = 0
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookiejar.py:164
+ if sec is None: sec = 0
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookiejar.py:781
+ if now is None: now = time.time()
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookiejar.py:1221
+ if policy is None:
+ policy = DefaultCookiePolicy()
+
+None-coalescing `if` block: /usr/lib/python3.4/http/cookiejar.py:1548
+ if rfc2109_as_ns is None:
+ rfc2109_as_ns = not self._policy.rfc2965
+
+Safe navigation `if` block: /usr/lib/python3.4/http/cookiejar.py:269
+ if m is not None:
+ day, mon, yr, hr, min, sec, tz = m.groups()
+ else:
+ return None # bad format
+
+Safe navigation `if` block: /usr/lib/python3.4/http/cookiejar.py:312
+ if m is not None:
+ # XXX there's an extra bit of the timezone I'm ignoring here: is
+ # this the right thing to do?
+ yr, mon, day, hr, min, sec, tz, _ = m.groups()
+ else:
+ return None # bad format
+
+Safe navigation `if` block: /usr/lib/python3.4/http/cookiejar.py:1895
+ if k is not None:
+ lc = k.lower()
+ else:
+ lc = None
+
+None-coalescing `if` block: /usr/lib/python3.4/imaplib.py:744
+ if ssl_context is None:
+ ssl_context = ssl._create_stdlib_context()
+
+None-coalescing `if` block: /usr/lib/python3.4/imaplib.py:855
+ if dat is None:
+ dat = b''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/imaplib.py:1469
+ PASSWD = getpass.getpass("IMAP password for %s on %s: " % (USER, host or "localhost"))
+
+None-coalescing `if` block: /usr/lib/python3.4/pyclbr.py:60
+ if super is None:
+ super = []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pyclbr.py:85
+ for key, value in _readmodule(module, path or []).items():
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pyclbr.py:97
+ return _readmodule(module, path or [])
+
+None-coalescing `if` block: /usr/lib/python3.4/tarfile.py:620
+ if blockinfo is None:
+ blockinfo = [(0, size)]
+
+None-coalescing `if` block: /usr/lib/python3.4/tarfile.py:673
+ if size is None:
+ size = self.size - self.position
+
+None-coalescing `if` block: /usr/lib/python3.4/tarfile.py:1764
+ if arcname is None:
+ arcname = name
+
+None-coalescing `if` block: /usr/lib/python3.4/tarfile.py:1887
+ if arcname is None:
+ arcname = name
+
+None-coalescing `if` block: /usr/lib/python3.4/tarfile.py:1970
+ if members is None:
+ members = self
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tarfile.py:351
+ self.name = name or ""
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tarfile.py:1557
+ filemode = filemode or "r"
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tarfile.py:1558
+ comptype = comptype or "tar"
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tarfile.py:1570
+ filemode = filemode or "r"
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tarfile.py:1571
+ comptype = comptype or "tar"
+
+Safe navigation `if` block: /usr/lib/python3.4/tarfile.py:1199
+ if match is not None:
+ pax_headers["hdrcharset"] = match.group(1).decode("utf-8")
+
+Safe navigation `if` block: /usr/lib/python3.4/tarfile.py:1758
+ if fileobj is not None:
+ name = fileobj.name
+
+None-coalescing `if` block: /usr/lib/python3.4/pydoc.py:496
+ if marginalia is None:
+ marginalia = '<tt>' + ' ' * width + '</tt>'
+
+None-coalescing `if` block: /usr/lib/python3.4/pydoc.py:672
+ if docloc is not None:
+ docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
+ else:
+ docloc = ''
+
+None-coalescing `if` block: /usr/lib/python3.4/pydoc.py:1004
+ if shadowed is None: shadowed = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/pydoc.py:1592
+ if renderer is None:
+ renderer = text
+
+None-coalescing `if` block: /usr/lib/python3.4/pydoc.py:1639
+ if done is None: done = {}
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pydoc.py:85
+ dir = os.path.abspath(dir or '.')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pydoc.py:491
+ ''' % (bgcol, fgcol, title, fgcol, extras or ' ')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pydoc.py:1961
+ xrefs = (xrefs or '') + ' ' + more_xrefs
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pydoc.py:1992
+ xrefs = (xrefs or '') + ' ' + more_xrefs
+
+Safe navigation `if` block: /usr/lib/python3.4/pydoc.py:1618
+ if output is None:
+ pager(render_doc(thing, title, forceload))
+ else:
+ output.write(render_doc(thing, title, forceload, plaintext))
+
+None-coalescing `if` block: /usr/lib/python3.4/hashlib.py:184
+ if dklen is None:
+ dklen = outer.digest_size
+
+None-coalescing `if` block: /usr/lib/python3.4/os.py:583
+ if env is None:
+ env = environ
+
+None-coalescing `if` block: /usr/lib/python3.4/os.py:610
+ if path_list is None:
+ path_list = defpath
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/os.py:469
+ if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
+
+Safe navigation `if` block: /usr/lib/python3.4/os.py:363
+ if onerror is not None:
+ onerror(err)
+
+None-coalescing `if` block: /usr/lib/python3.4/tempfile.py:401
+ if dir is None:
+ dir = gettempdir()
+
+None-coalescing `if` block: /usr/lib/python3.4/tempfile.py:425
+ if dir is None:
+ dir = gettempdir()
+
+None-coalescing `if` block: /usr/lib/python3.4/tempfile.py:459
+ if dir is None:
+ dir = gettempdir()
+
+None-coalescing `if` block: /usr/lib/python3.4/tempfile.py:589
+ if dir is None:
+ dir = gettempdir()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/ctypes/util.py:157
+ return nums or [ sys.maxsize ]
+
+None-coalescing `if` block: /usr/lib/python3.4/ctypes/__init__.py:146
+ if typecode is None:
+ # Most _type_ codes are the same as used in struct
+ typecode = typ._type_
+
+None-coalescing `if` block: /usr/lib/python3.4/ctypes/__init__.py:350
+ if handle is None:
+ self._handle = _dlopen(self._name, mode)
+ else:
+ self._handle = handle
+
+None-coalescing `if` block: /usr/lib/python3.4/warnings.py:170
+ if category is None:
+ category = UserWarning
+
+None-coalescing `if` block: /usr/lib/python3.4/warnings.py:211
+ if registry is None:
+ registry = {}
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/warnings.py:208
+ module = filename or "<unknown>"
+
+None-coalescing ternary: /usr/lib/python3.4/warnings.py:26
+ line = linecache.getline(filename, lineno) if line is None else line
+
+None-coalescing ternary: /usr/lib/python3.4/warnings.py:323
+ self._module = sys.modules['warnings'] if module is None else module
+
+Safe navigation `if` block: /usr/lib/python3.4/dis.py:240
+ if const_list is not None:
+ argval = const_list[const_index]
+
+None-coalescing `if` block: /usr/lib/python3.4/statistics.py:461
+ if c is None:
+ c = mean(data)
+
+Safe navigation `if` block: /usr/lib/python3.4/_weakrefset.py:22
+ if w is not None:
+ w._iterating.add(self)
+
+None-coalescing `if` block: /usr/lib/python3.4/zipfile.py:374
+ if zip64 is None:
+ zip64 = file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT
+
+None-coalescing `if` block: /usr/lib/python3.4/zipfile.py:1225
+ if path is None:
+ path = os.getcwd()
+
+None-coalescing `if` block: /usr/lib/python3.4/zipfile.py:1236
+ if members is None:
+ members = self.namelist()
+
+None-coalescing `if` block: /usr/lib/python3.4/zipfile.py:1331
+ if arcname is None:
+ arcname = filename
+
+None-coalescing `if` block: /usr/lib/python3.4/zipfile.py:1340
+ if compress_type is None:
+ zinfo.compress_type = self.compression
+ else:
+ zinfo.compress_type = compress_type
+
+None-coalescing `if` block: /usr/lib/python3.4/zipfile.py:1752
+ if args is None:
+ args = sys.argv[1:]
+
+None-coalescing `if` block: /usr/lib/python3.4/pdb.py:1224
+ if last is None:
+ last = first + 10
+
+None-coalescing `if` block: /usr/lib/python3.4/pdb.py:1585
+ if t is None:
+ # sys.exc_info() returns (type, value, traceback) if an exception is
+ # being handled, otherwise it returns None
+ t = sys.exc_info()[2]
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pdb.py:935
+ count = int(arg or 1)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/pdb.py:955
+ count = int(arg or 1)
+
+None-coalescing `if` block: /usr/lib/python3.4/posixpath.py:445
+ if start is None:
+ start = curdir
+
+Safe navigation `if` block: /usr/lib/python3.4/posixpath.py:300
+ if environ is None:
+ value = os.fsencode(os.environ[os.fsdecode(name)])
+ else:
+ value = environ[name]
+
+Safe navigation `if` block: /usr/lib/python3.4/xml/sax/expatreader.py:223
+ if bs is not None:
+ bs.close()
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/sax/__init__.py:38
+ if errorHandler is None:
+ errorHandler = ErrorHandler()
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/sax/_exceptions.py:92
+ if sysid is None:
+ sysid = "<unknown>"
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/sax/_exceptions.py:95
+ if linenum is None:
+ linenum = "?"
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/sax/_exceptions.py:98
+ if colnum is None:
+ colnum = "?"
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/dom/pulldom.py:325
+ if bufsize is None:
+ bufsize = default_bufsize
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xml/dom/pulldom.py:44
+ self._xmlns_attrs.append((prefix or 'xmlns', uri))
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/dom/expatbuilder.py:138
+ if options is None:
+ options = xmlbuilder.Options()
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/dom/xmlbuilder.py:359
+ if snode is None:
+ snode = self
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/etree/ElementTree.py:1225
+ if events is None:
+ events = ("end",)
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/etree/ElementTree.py:1389
+ if element_factory is None:
+ element_factory = Element
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/etree/ElementTree.py:1468
+ if target is None:
+ target = TreeBuilder()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xml/etree/ElementTree.py:937
+ if text or len(elem) or not short_empty_elements:
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xml/etree/ElementTree.py:1223
+ self._parser = _parser or XMLParser(target=TreeBuilder())
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xml/etree/ElementTree.py:1523
+ append((event, (prefix or "", uri or "")))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xml/etree/ElementTree.py:1523
+ append((event, (prefix or "", uri or "")))
+
+None-coalescing `if` block: /usr/lib/python3.4/xml/etree/ElementInclude.py:100
+ if loader is None:
+ loader = default_loader
+
+Safe navigation `and`: /usr/lib/python3.4/weakref.py:512
+ obj = info and info.weakref()
+
+Safe navigation `and`: /usr/lib/python3.4/weakref.py:520
+ obj = info and info.weakref()
+
+Safe navigation `and`: /usr/lib/python3.4/weakref.py:543
+ obj = info and info.weakref()
+
+None-coalescing `if` block: /usr/lib/python3.4/pprint.py:132
+ if stream is not None:
+ self._stream = stream
+ else:
+ self._stream = _sys.stdout
+
+None-coalescing `if` block: /usr/lib/python3.4/pprint.py:410
+ if object is None:
+ object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
+
+None-coalescing `if` block: /usr/lib/python3.4/json/decoder.py:145
+ if memo is None:
+ memo = {}
+
+Safe navigation `if` block: /usr/lib/python3.4/json/decoder.py:216
+ if object_hook is not None:
+ pairs = object_hook(pairs)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/json/scanner.py:52
+ res = parse_float(integer + (frac or '') + (exp or ''))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/json/scanner.py:52
+ res = parse_float(integer + (frac or '') + (exp or ''))
+
+None-coalescing `if` block: /usr/lib/python3.4/json/__init__.py:231
+ if cls is None:
+ cls = JSONEncoder
+
+None-coalescing `if` block: /usr/lib/python3.4/json/__init__.py:319
+ if cls is None:
+ cls = JSONDecoder
+
+None-coalescing `if` block: /usr/lib/python3.4/json/encoder.py:147
+ if separators is not None:
+ self.item_separator, self.key_separator = separators
+ elif indent is not None:
+
+None-coalescing `if` block: /usr/lib/python3.4/timeit.py:243
+ if args is None:
+ args = sys.argv[1:]
+
+Safe navigation `if` block: /usr/lib/python3.4/timeit.py:290
+ if _wrap_timer is not None:
+ timer = _wrap_timer(timer)
+
+None-coalescing `if` block: /usr/lib/python3.4/smtplib.py:835
+ if from_addr is None:
+ # Prefer the sender field per RFC 2822:3.6.2.
+ from_addr = (msg[header_prefix + 'Sender']
+
+None-coalescing `if` block: /usr/lib/python3.4/profile.py:151
+ if bias is None:
+ bias = self.bias
+
+None-coalescing `if` block: /usr/lib/python3.4/pickletools.py:2391
+ if memo is None:
+ memo = {} # crude emulation of unpickler memo
+
+None-coalescing ternary: /usr/lib/python3.4/pickletools.py:2241
+ "<unknown>" if pos is None else pos,
+
+None-coalescing `if` block: /usr/lib/python3.4/collections/__init__.py:852
+ if m is None:
+ m = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/managers.py:357
+ if exposed is None:
+ exposed = public_methods(obj)
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/managers.py:444
+ if authkey is None:
+ authkey = process.current_process().authkey
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/managers.py:620
+ if proxytype is None:
+ proxytype = AutoProxy
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/managers.py:896
+ if authkey is None:
+ authkey = process.current_process().authkey
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/managers.py:452
+ self._ctx = ctx or get_context()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/managers.py:623
+ exposed = exposed or getattr(proxytype, '_exposed_', None)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/managers.py:625
+ method_to_typeid = method_to_typeid or \
+ getattr(proxytype, '_method_to_typeid_', None)
+
+Safe navigation `and`: /usr/lib/python3.4/multiprocessing/managers.py:245
+ typeid = gettypeid and gettypeid.get(methodname, None)
+
+Safe navigation `if` block: /usr/lib/python3.4/multiprocessing/managers.py:351
+ if callable is None:
+ assert len(args) == 1 and not kwds
+ obj = args[0]
+ else:
+ obj = callable(*args, **kwds)
+
+Safe navigation `if` block: /usr/lib/python3.4/multiprocessing/managers.py:513
+ if initializer is not None:
+ initializer(*initargs)
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/synchronize.py:52
+ if ctx is None:
+ ctx = context._default_context.get_context()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/synchronize.py:214
+ self._lock = lock or ctx.RLock()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/util.py:160
+ self._kwargs = kwargs or {}
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/connection.py:194
+ if size is None:
+ size = n - offset
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/connection.py:441
+ address = address or arbitrary_address(family)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/connection.py:490
+ family = family or address_type(address)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/sharedctypes.py:77
+ ctx = ctx or get_context()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/sharedctypes.py:91
+ ctx = ctx or get_context()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/sharedctypes.py:104
+ ctx = ctx or get_context()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/sharedctypes.py:186
+ ctx = ctx or get_context(force=True)
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/pool.py:158
+ if processes is None:
+ processes = os.cpu_count() or 1
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/multiprocessing/pool.py:149
+ self._ctx = context or get_context()
+
+Safe navigation `if` block: /usr/lib/python3.4/multiprocessing/pool.py:102
+ if initializer is not None:
+ initializer(*initargs)
+
+None-coalescing `if` block: /usr/lib/python3.4/multiprocessing/spawn.py:174
+ if main_mod_name is not None:
+ d['init_main_from_name'] = main_mod_name
+ elif sys.platform != 'win32' or (not WINEXE and not WINSERVICE):
+
+None-coalescing `if` block: /usr/lib/python3.4/sre_parse.py:92
+ if data is None:
+ data = []
+
+None-coalescing `if` block: /usr/lib/python3.4/sre_parse.py:392
+ if prefix is None:
+ prefix = item[0]
+
+None-coalescing `if` block: /usr/lib/python3.4/sre_parse.py:755
+ if pattern is None:
+ pattern = Pattern()
+
+Safe navigation ternary: /usr/lib/python3.4/sre_parse.py:856
+ literals = [None if s is None else s.encode('latin-1') for s in literals]
+
+None-coalescing `if` block: /usr/lib/python3.4/locale.py:497
+ if language is None:
+ language = 'C'
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1619
+ print('Language: ', lang or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1620
+ print('Encoding: ', enc or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1628
+ print(' Language: ', lang or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1629
+ print(' Encoding: ', enc or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1639
+ print(' Language: ', lang or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1640
+ print(' Encoding: ', enc or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1656
+ print(' Language: ', lang or '(undefined)')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/locale.py:1657
+ print(' Encoding: ', enc or '(undefined)')
+
+None-coalescing `if` block: /usr/lib/python3.4/xmlrpc/server.py:214
+ if name is None:
+ name = function.__name__
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xmlrpc/server.py:168
+ self.encoding = encoding or 'utf-8'
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xmlrpc/server.py:604
+ self.encoding = encoding or 'utf-8'
+
+Safe navigation `if` block: /usr/lib/python3.4/xmlrpc/server.py:253
+ if dispatch_method is not None:
+ response = dispatch_method(method, params)
+ else:
+ response = self._dispatch(method, params)
+
+None-coalescing `if` block: /usr/lib/python3.4/xmlrpc/client.py:387
+ if data is None:
+ data = b""
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xmlrpc/client.py:1353
+ None, context=self.context, **(x509 or {}))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/xmlrpc/client.py:1420
+ self.__encoding = encoding or 'utf-8'
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/nntplib.py:173
+ parts.append(v.decode(enc or 'ascii'))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/nntplib.py:828
+ cmd += ' {0}-{1}'.format(start, end or '')
+
+None-coalescing `if` block: /usr/lib/python3.4/gettext.py:355
+ if localedir is None:
+ localedir = _default_localedir
+
+None-coalescing `if` block: /usr/lib/python3.4/gettext.py:410
+ if class_ is None:
+ class_ = GNUTranslations
+
+None-coalescing `if` block: /usr/lib/python3.4/gettext.py:432
+ if result is None:
+ result = t
+
+Safe navigation `if` block: /usr/lib/python3.4/gettext.py:432
+ if result is None:
+ result = t
+ else:
+ result.add_fallback(t)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/wsgiref/headers.py:19
+ if quote or tspecials.search(value):
+
+Safe navigation `if` block: /usr/lib/python3.4/pathlib.py:919
+ if template is not None:
+ self._accessor = template._accessor
+ else:
+ self._accessor = _normal_accessor
+
+None-coalescing `if` block: /usr/lib/python3.4/email/mime/audio.py:67
+ if _subtype is None:
+ _subtype = _whatsnd(_audiodata)
+
+None-coalescing `if` block: /usr/lib/python3.4/email/mime/image.py:40
+ if _subtype is None:
+ _subtype = imghdr.what(None, _imagedata)
+
+None-coalescing `if` block: /usr/lib/python3.4/email/contentmanager.py:47
+ if full_path_for_error is None:
+ full_path_for_error = full_path
+
+None-coalescing ternary: /usr/lib/python3.4/email/contentmanager.py:209
+ cte = '8bit' if cte is None else cte
+
+None-coalescing `if` block: /usr/lib/python3.4/email/header.py:209
+ if charset is None:
+ charset = USASCII
+
+None-coalescing `if` block: /usr/lib/python3.4/email/header.py:218
+ if maxlinelen is None:
+ maxlinelen = MAXLINELEN
+
+None-coalescing `if` block: /usr/lib/python3.4/email/header.py:289
+ if charset is None:
+ charset = self._charset
+
+None-coalescing `if` block: /usr/lib/python3.4/email/header.py:350
+ if maxlinelen is None:
+ maxlinelen = self._maxlinelen
+
+None-coalescing `if` block: /usr/lib/python3.4/email/header.py:572
+ if startval is None:
+ startval = []
+
+None-coalescing `if` block: /usr/lib/python3.4/email/utils.py:156
+ if timeval is None:
+ timeval = time.time()
+
+None-coalescing `if` block: /usr/lib/python3.4/email/utils.py:216
+ if idstring is None:
+ idstring = ''
+
+None-coalescing `if` block: /usr/lib/python3.4/email/utils.py:220
+ if domain is None:
+ domain = socket.getfqdn()
+
+None-coalescing `if` block: /usr/lib/python3.4/email/utils.py:272
+ if language is None:
+ language = ''
+
+None-coalescing `if` block: /usr/lib/python3.4/email/utils.py:344
+ if charset is None:
+ # Issue 17369: if charset/lang is None, decode_rfc2231 couldn't parse
+ # the value, so use the fallback_charset.
+ charset = fallback_charset
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/email/utils.py:269
+ s = urllib.parse.quote(s, safe='', encoding=charset or 'ascii')
+
+None-coalescing `if` block: /usr/lib/python3.4/email/generator.py:257
+ if subparts is None:
+ subparts = []
+
+None-coalescing `if` block: /usr/lib/python3.4/email/generator.py:475
+ if fmt is None:
+ self._fmt = _FMT
+ else:
+ self._fmt = fmt
+
+Safe navigation `if` block: /usr/lib/python3.4/email/generator.py:191
+ if meth is None:
+ self._write_headers(msg)
+ else:
+ meth(self)
+
+None-coalescing `if` block: /usr/lib/python3.4/email/_parseaddr.py:460
+ if atomends is None:
+ atomends = self.atomends
+
+None-coalescing `if` block: /usr/lib/python3.4/email/iterators.py:61
+ if fp is None:
+ fp = sys.stdout
+
+None-coalescing `if` block: /usr/lib/python3.4/email/message.py:1068
+ if content_manager is None:
+ content_manager = self.policy.content_manager
+
+None-coalescing `if` block: /usr/lib/python3.4/email/message.py:1073
+ if content_manager is None:
+ content_manager = self.policy.content_manager
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/email/message.py:67
+ if quote or tspecials.search(value):
+
+None-coalescing ternary: /usr/lib/python3.4/email/message.py:153
+ policy = self.policy if policy is None else policy
+
+None-coalescing ternary: /usr/lib/python3.4/email/message.py:176
+ policy = self.policy if policy is None else policy
+
+None-coalescing `if` block: /usr/lib/python3.4/email/_header_value_parser.py:130
+ if stoken is None:
+ stoken = str(token)
+
+Safe navigation `and`: /usr/lib/python3.4/email/_header_value_parser.py:2591
+ while value and value[0].isdigit():
+
+None-coalescing `if` block: /usr/lib/python3.4/concurrent/futures/process.py:334
+ if max_workers is None:
+ self._max_workers = os.cpu_count() or 1
+ else:
+ self._max_workers = max_workers
+
+None-coalescing `if` block: /usr/lib/python3.4/threading.py:211
+ if lock is None:
+ lock = RLock()
+
+None-coalescing `if` block: /usr/lib/python3.4/threading.py:604
+ if timeout is None:
+ timeout = self._timeout
+
+None-coalescing `if` block: /usr/lib/python3.4/threading.py:785
+ if kwargs is None:
+ kwargs = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/threading.py:791
+ if daemon is not None:
+ self._daemonic = daemon
+ else:
+ self._daemonic = current_thread().daemon
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/threading.py:788
+ self._name = str(name or _newname())
+
+None-coalescing ternary: /usr/lib/python3.4/threading.py:1175
+ self.args = args if args is not None else []
+
+None-coalescing ternary: /usr/lib/python3.4/threading.py:1176
+ self.kwargs = kwargs if kwargs is not None else {}
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:363
+ if frame is None:
+ frame = sys._getframe().f_back
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:469
+ if options is None: options = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:1187
+ if verbose is None:
+ verbose = '-v' in sys.argv
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:1428
+ if compileflags is None:
+ compileflags = _extract_future_flags(test.globs)
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:1490
+ if verbose is None:
+ verbose = self._verbose
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:1916
+ if m is None:
+ # DWA - m will still be None if this wasn't invoked from the command
+ # line, in which case the following TypeError is about as good an error
+ # as we should expect
+ m = sys.modules.get('__main__')
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:1927
+ if name is None:
+ name = m.__name__
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:1944
+ if master is None:
+ master = runner
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:2042
+ if name is None:
+ name = os.path.basename(filename)
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:2046
+ if globs is None:
+ globs = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:2067
+ if master is None:
+ master = runner
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:2359
+ if test_finder is None:
+ test_finder = DocTestFinder()
+
+None-coalescing `if` block: /usr/lib/python3.4/doctest.py:2412
+ if globs is None:
+ globs = {}
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/doctest.py:1186
+ self._checker = checker or OutputChecker()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/doctest.py:2039
+ encoding or "utf-8")
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/doctest.py:2423
+ encoding or "utf-8")
+
+Safe navigation `if` block: /usr/lib/python3.4/doctest.py:908
+ if globs is None:
+ if module is None:
+ globs = {}
+ else:
+ globs = module.__dict__.copy()
+ else:
+ globs = globs.copy()
+
+Safe navigation `if` block: /usr/lib/python3.4/doctest.py:1944
+ if master is None:
+ master = runner
+ else:
+ master.merge(runner)
+
+Safe navigation `if` block: /usr/lib/python3.4/doctest.py:2046
+ if globs is None:
+ globs = {}
+ else:
+ globs = globs.copy()
+
+Safe navigation `if` block: /usr/lib/python3.4/doctest.py:2067
+ if master is None:
+ master = runner
+ else:
+ master.merge(runner)
+
+Safe navigation `if` block: /usr/lib/python3.4/doctest.py:2412
+ if globs is None:
+ globs = {}
+ else:
+ globs = globs.copy()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:126
+ if map is None:
+ map = socket_map
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:169
+ if map is None:
+ map = socket_map
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:198
+ if map is None:
+ map = socket_map
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:226
+ if map is None:
+ self._map = socket_map
+ else:
+ self._map = map
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:274
+ if map is None:
+ map = self._map
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:280
+ if map is None:
+ map = self._map
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncore.py:576
+ if map is None:
+ map = socket_map
+
+None-coalescing `if` block: /usr/lib/python3.4/bdb.py:211
+ if lineno is None:
+ lineno = frame.f_lineno + 1
+
+None-coalescing `if` block: /usr/lib/python3.4/bdb.py:243
+ if frame is None:
+ frame = sys._getframe().f_back
+
+None-coalescing `if` block: /usr/lib/python3.4/bdb.py:424
+ if locals is None:
+ locals = globals
+
+None-coalescing `if` block: /usr/lib/python3.4/bdb.py:442
+ if locals is None:
+ locals = globals
+
+None-coalescing `if` block: /usr/lib/python3.4/bdb.py:536
+ if out is None:
+ out = sys.stdout
+
+None-coalescing `if` block: /usr/lib/python3.4/cgi.py:140
+ if fp is None:
+ fp = sys.stdin
+
+None-coalescing `if` block: /usr/lib/python3.4/shelve.py:87
+ if protocol is None:
+ protocol = 3
+
+None-coalescing `if` block: /usr/lib/python3.4/tkinter/filedialog.py:52
+ if title is None: title = self.title
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tkinter/filedialog.py:218
+ self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*"))
+
+None-coalescing `if` block: /usr/lib/python3.4/tkinter/__init__.py:489
+ if window is None:
+ window = self
+
+None-coalescing `if` block: /usr/lib/python3.4/tkinter/__init__.py:497
+ if window is None:
+ window = self
+
+None-coalescing `if` block: /usr/lib/python3.4/tkinter/__init__.py:2782
+ if index2 is None:
+ index2 = index1
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tkinter/ttk.py:184
+ opts = opts or {}
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tkinter/ttk.py:665
+ Widget.__init__(self, master, widget or "ttk::entry", kw)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/tkinter/ttk.py:1490
+ self._variable = variable or tkinter.IntVar(master)
+
+None-coalescing `if` block: /usr/lib/python3.4/code.py:33
+ if locals is None:
+ locals = {"__name__": "__console__", "__doc__": None}
+
+None-coalescing `if` block: /usr/lib/python3.4/code.py:291
+ if readfunc is not None:
+ console.raw_input = readfunc
+ else:
+ try:
+
+Safe navigation `if` block: /usr/lib/python3.4/plistlib.py:331
+ if handler is not None:
+ handler(attrs)
+
+Safe navigation `if` block: /usr/lib/python3.4/plistlib.py:336
+ if handler is not None:
+ handler()
+
+None-coalescing `if` block: /usr/lib/python3.4/uu.py:72
+ if name is None:
+ name = '-'
+
+None-coalescing `if` block: /usr/lib/python3.4/uu.py:74
+ if mode is None:
+ mode = 0o666
+
+None-coalescing `if` block: /usr/lib/python3.4/uu.py:124
+ if mode is None:
+ mode = int(hdrfields[1], 8)
+
+None-coalescing `if` block: /usr/lib/python3.4/contextlib.py:42
+ if doc is None:
+ doc = type(self).__doc__
+
+None-coalescing `if` block: /usr/lib/python3.4/subprocess.py:764
+ if bufsize is None:
+ bufsize = -1 # Restore default
+
+None-coalescing `if` block: /usr/lib/python3.4/runpy.py:179
+ if run_name is None:
+ run_name = mod_name
+
+None-coalescing `if` block: /usr/lib/python3.4/runpy.py:226
+ if run_name is None:
+ run_name = "<run_path>"
+
+Safe navigation ternary: /usr/lib/python3.4/runpy.py:92
+ fname = script_name if mod_spec is None else mod_spec.origin
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/cgitb.py:271
+ info = info or sys.exc_info()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/asyncio/unix_events.py:418
+ if not (is_socket or
+ stat.S_ISFIFO(mode) or
+ stat.S_ISCHR(mode)):
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/unix_events.py:939
+ if callback is None:
+ logger.warning(
+ "Caught subprocess termination from unknown pid: "
+ "%d -> %d", pid, returncode)
+ else:
+ callback(pid, returncode, *args)
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/proactor_events.py:475
+ if f is not None:
+ f.result() # may raise
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/futures.py:150
+ if loop is None:
+ self._loop = events.get_event_loop()
+ else:
+ self._loop = loop
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/futures.py:397
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/streams.py:58
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/streams.py:92
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/streams.py:148
+ if loop is None:
+ self._loop = events.get_event_loop()
+ else:
+ self._loop = loop
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/streams.py:311
+ if loop is None:
+ self._loop = events.get_event_loop()
+ else:
+ self._loop = loop
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/tasks.py:56
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/tasks.py:66
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/tasks.py:327
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/tasks.py:354
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing ternary: /usr/lib/python3.4/asyncio/tasks.py:451
+ loop = loop if loop is not None else events.get_event_loop()
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/tasks.py:417
+ if timeout_handle is not None:
+ timeout_handle.cancel()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/subprocess.py:192
+ if loop is None:
+ loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/subprocess.py:206
+ if loop is None:
+ loop = events.get_event_loop()
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/subprocess.py:69
+ if reader is not None:
+ reader.feed_data(data)
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/queues.py:42
+ if loop is None:
+ self._loop = events.get_event_loop()
+ else:
+ self._loop = loop
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/base_events.py:729
+ if sock is not None:
+ sock.close()
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/base_events.py:733
+ if sock is not None:
+ sock.close()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/windows_events.py:302
+ if proactor is None:
+ proactor = IocpProactor()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/transports.py:16
+ if extra is None:
+ extra = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/transports.py:287
+ if low is None:
+ low = high // 4
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/locks.py:99
+ if loop is not None:
+ self._loop = loop
+ else:
+ self._loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/locks.py:194
+ if loop is not None:
+ self._loop = loop
+ else:
+ self._loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/locks.py:259
+ if loop is not None:
+ self._loop = loop
+ else:
+ self._loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/locks.py:264
+ if lock is None:
+ lock = Lock(loop=self._loop)
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/locks.py:391
+ if loop is not None:
+ self._loop = loop
+ else:
+ self._loop = events.get_event_loop()
+
+None-coalescing `if` block: /usr/lib/python3.4/asyncio/selector_events.py:51
+ if selector is None:
+ selector = selectors.DefaultSelector()
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/selector_events.py:242
+ if reader is not None:
+ reader.cancel()
+
+Safe navigation `if` block: /usr/lib/python3.4/asyncio/selector_events.py:280
+ if writer is not None:
+ writer.cancel()
+
+None-coalescing `if` block: /usr/lib/python3.4/copy.py:143
+ if memo is None:
+ memo = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/copy.py:276
+ if memo is None:
+ memo = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/enum.py:333
+ if module is None:
+ _make_class_unpicklable(enum_class)
+ else:
+ enum_class.__module__ = module
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/string.py:44
+ return (sep or ' ').join(x.capitalize() for x in s.split(sep))
+
+None-coalescing `if` block: /usr/lib/python3.4/platform.py:1251
+ if sys_version is None:
+ sys_version = sys.version
+
+Safe navigation ternary: /usr/lib/python3.4/platform.py:181
+ s.decode('latin1') if s is not None else s
+
+None-coalescing `if` block: /usr/lib/python3.4/_osx_support.py:35
+ if path is None:
+ path = os.environ['PATH']
+
+None-coalescing `if` block: /usr/lib/python3.4/codecs.py:925
+ if file_encoding is None:
+ file_encoding = data_encoding
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/codecs.py:249
+ self.buffer = state or ""
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/codecs.py:547
+ readsize = size or 72
+
+None-coalescing `if` block: /usr/lib/python3.4/textwrap.py:419
+ if margin is None:
+ margin = indent
+
+None-coalescing `if` block: /usr/lib/python3.4/trace.py:505
+ if globals is None: globals = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/trace.py:506
+ if locals is None: locals = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/trace.py:659
+ if argv is None:
+ argv = sys.argv
+
+None-coalescing `if` block: /usr/lib/python3.4/poplib.py:387
+ if context is None:
+ context = ssl._create_stdlib_context()
+
+None-coalescing `if` block: /usr/lib/python3.4/modulefinder.py:75
+ if path is None:
+ path = sys.path
+
+Safe navigation `and`: /usr/lib/python3.4/modulefinder.py:267
+ parent and parent.__path__, parent)
+
+None-coalescing `if` block: /usr/lib/python3.4/base64.py:206
+ if _b32rev is None:
+ _b32rev = {v: k for k, v in enumerate(_b32alphabet)}
+
+None-coalescing `if` block: /usr/lib/python3.4/gzip.py:186
+ if mode is None:
+ mode = getattr(fileobj, 'mode', 'rb')
+
+None-coalescing `if` block: /usr/lib/python3.4/gzip.py:269
+ if mtime is None:
+ mtime = time.time()
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/gzip.py:181
+ fileobj = self.myfileobj = builtins.open(filename, mode or 'rb')
+
+None-coalescing `if` block: /usr/lib/python3.4/optparse.py:1040
+ if option is None:
+ option = self._long_opt.get(opt_str)
+
+None-coalescing `if` block: /usr/lib/python3.4/optparse.py:1195
+ if formatter is None:
+ formatter = IndentedHelpFormatter()
+
+None-coalescing `if` block: /usr/lib/python3.4/optparse.py:1369
+ if values is None:
+ values = self.get_default_values()
+
+None-coalescing `if` block: /usr/lib/python3.4/optparse.py:1607
+ if formatter is None:
+ formatter = self.formatter
+
+None-coalescing `if` block: /usr/lib/python3.4/optparse.py:1627
+ if formatter is None:
+ formatter = self.formatter
+
+None-coalescing `if` block: /usr/lib/python3.4/optparse.py:1644
+ if file is None:
+ file = sys.stdout
+
+Safe navigation `if` block: /usr/lib/python3.4/test/pystone.py:174
+ if PtrGlb is not None:
+ PtrParOut = PtrGlb.PtrComp
+ else:
+ IntGlob = 100
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/test/regrtest.py:1514
+ return path or os.path.dirname(__file__) or os.curdir
+
+Safe navigation `if` block: /usr/lib/python3.4/test/regrtest.py:1475
+ if stream is not None:
+ stream.flush()
+
+None-coalescing `if` block: /usr/lib/python3.4/test/support/__init__.py:200
+ if pattern is None:
+ pattern = "test*"
+
+None-coalescing `if` block: /usr/lib/python3.4/test/support/__init__.py:1228
+ if v is None:
+ if k in self._environ:
+ del self._environ[k]
+ else:
+ self._environ[k] = v
+
+None-coalescing `if` block: /usr/lib/python3.4/test/support/__init__.py:1527
+ if orig_tz is None:
+ del os.environ['TZ']
+ else:
+ os.environ['TZ'] = orig_tz
+
+None-coalescing `if` block: /usr/lib/python3.4/test/support/__init__.py:1838
+ if verbosity is None:
+ verbosity = verbose
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/test/support/__init__.py:305
+ dirname = dirname or '.'
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:299
+ if prefix is None:
+ prefix = _('usage: ')
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:1047
+ if version is None:
+ version = parser.version
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:1629
+ if prog is None:
+ prog = _os.path.basename(_sys.argv[0])
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:1744
+ if args is None:
+ # args default to the system args
+ args = _sys.argv[1:]
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:1752
+ if namespace is None:
+ namespace = Namespace()
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:2361
+ if file is None:
+ file = _sys.stdout
+
+None-coalescing `if` block: /usr/lib/python3.4/argparse.py:2366
+ if file is None:
+ file = _sys.stdout
+
+None-coalescing `if` block: /usr/lib/python3.4/logging/handlers.py:816
+ if use_socktype is None:
+ use_socktype = socket.SOCK_DGRAM
+
+None-coalescing `if` block: /usr/lib/python3.4/logging/__init__.py:951
+ if stream is None:
+ stream = sys.stderr
+
+Safe navigation `if` block: /usr/lib/python3.4/logging/__init__.py:1351
+ if f is not None:
+ f = f.f_back
+
+Safe navigation `if` block: /usr/lib/python3.4/unittest/suite.py:177
+ if previousClass is not None:
+ previousModule = previousClass.__module__
+
+None-coalescing `if` block: /usr/lib/python3.4/unittest/main.py:68
+ if argv is None:
+ argv = sys.argv
+
+Safe navigation ternary: /usr/lib/python3.4/unittest/main.py:224
+ loader = self.testLoader if Loader is None else Loader()
+
+None-coalescing `if` block: /usr/lib/python3.4/unittest/mock.py:380
+ if _new_parent is None:
+ _new_parent = parent
+
+None-coalescing `if` block: /usr/lib/python3.4/unittest/mock.py:392
+ if _eat_self is None:
+ _eat_self = parent is not None
+
+None-coalescing `if` block: /usr/lib/python3.4/unittest/mock.py:2294
+ if mock is None:
+ mock = MagicMock(name='open', spec=open)
+
+Safe navigation `and`: /usr/lib/python3.4/unittest/mock.py:452
+ _spec_signature = res and res[1]
+
+Safe navigation `if` block: /usr/lib/python3.4/unittest/mock.py:1765
+ if side_effector is not None:
+ method.side_effect = side_effector(mock)
+
+None-coalescing `if` block: /usr/lib/python3.4/unittest/case.py:227
+ if first_matching is None:
+ first_matching = w
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/unittest/case.py:1267
+ msg = msg or "Regex didn't match"
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/unittest/case.py:1277
+ msg = msg or "Regex matched"
+
+Safe navigation `if` block: /usr/lib/python3.4/unittest/case.py:472
+ if addSkip is not None:
+ addSkip(test_case, reason)
+ else:
+ warnings.warn("TestResult has no addSkip method, skips not reported",
+
+Safe navigation `if` block: /usr/lib/python3.4/unittest/case.py:491
+ if parent is None:
+ params_map = collections.ChainMap(params)
+ else:
+ params_map = parent.params.new_child(params)
+
+None-coalescing `if` block: /usr/lib/python3.4/unittest/runner.py:130
+ if stream is None:
+ stream = sys.stderr
+
+Safe navigation `if` block: /usr/lib/python3.4/unittest/runner.py:165
+ if startTestRun is not None:
+ startTestRun()
+
+Safe navigation `if` block: /usr/lib/python3.4/unittest/runner.py:171
+ if stopTestRun is not None:
+ stopTestRun()
+
+None-coalescing `if` block: /usr/lib/python3.4/functools.py:323
+ if result is None:
+ # If the underlying descriptor didn't do anything, treat this
+ # like an instance method
+ result = self._make_unbound_method().__get__(obj, cls)
+
+None-coalescing `if` block: /usr/lib/python3.4/site.py:311
+ if prefixes is None:
+ prefixes = PREFIXES
+
+None-coalescing `if` block: /usr/lib/python3.4/site.py:570
+ if ENABLE_USER_SITE is None:
+ ENABLE_USER_SITE = check_enableusersite()
+
+None-coalescing `if` block: /usr/lib/python3.4/turtle.py:913
+ if outline is None:
+ outline = fill
+
+None-coalescing `if` block: /usr/lib/python3.4/turtle.py:1972
+ if extent is None:
+ extent = self._fullcircle
+
+None-coalescing `if` block: /usr/lib/python3.4/turtle.py:2815
+ if outline is None:
+ outline = self._outlinewidth
+
+None-coalescing `if` block: /usr/lib/python3.4/turtle.py:3724
+ if startx is None:
+ startx = (sw - width) / 2
+
+None-coalescing `if` block: /usr/lib/python3.4/turtle.py:3728
+ if starty is None:
+ starty = (sh - height) / 2
+
+None-coalescing `if` block: /usr/lib/python3.4/socketserver.py:282
+ if timeout is None:
+ timeout = self.timeout
+
+Safe navigation `and`: /usr/lib/python3.4/fileinput.py:100
+ if _state and _state._file:
+
+None-coalescing `if` block: /usr/lib/python3.4/shutil.py:725
+ if extra_args is None:
+ extra_args = []
+
+None-coalescing `if` block: /usr/lib/python3.4/shutil.py:766
+ if base_dir is None:
+ base_dir = os.curdir
+
+None-coalescing `if` block: /usr/lib/python3.4/shutil.py:841
+ if extra_args is None:
+ extra_args = []
+
+None-coalescing `if` block: /usr/lib/python3.4/shutil.py:938
+ if extract_dir is None:
+ extract_dir = os.getcwd()
+
+None-coalescing `if` block: /usr/lib/python3.4/shutil.py:1093
+ if path is None:
+ path = os.environ.get("PATH", os.defpath)
+
+Safe navigation `if` block: /usr/lib/python3.4/shutil.py:298
+ if ignore is not None:
+ ignored_names = ignore(src, names)
+ else:
+ ignored_names = set()
+
+Safe navigation `if` block: /usr/lib/python3.4/shutil.py:610
+ if logger is not None:
+ logger.info('Creating tar archive')
+
+None-coalescing `if` block: /usr/lib/python3.4/types.py:65
+ if kwds is None:
+ kwds = {}
+
+Safe navigation `if` block: /usr/lib/python3.4/types.py:50
+ if exec_body is not None:
+ exec_body(ns)
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/FormatParagraph.py:47
+ if limit is None:
+ # The default length limit is that defined by pep8
+ limit = idleConf.GetOption(
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/StackViewer.py:29
+ if tb is None:
+ tb = sys.last_traceback
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/idlelib/ReplaceDialog.py:36
+ first = first or text.index("insert")
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/macosxSupport.py:155
+ if end is None:
+ end = -1
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/idlelib/HyperParser.py:53
+ parser.set_lo(bod or 0)
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/EditorWindow.py:470
+ if end is None:
+ end = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/EditorWindow.py:1103
+ if keydefs is None:
+ keydefs = self.Bindings.default_keydefs
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/EditorWindow.py:1116
+ if menudefs is None:
+ menudefs = self.Bindings.menudefs
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/EditorWindow.py:1118
+ if keydefs is None:
+ keydefs = self.Bindings.default_keydefs
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/idlelib/EditorWindow.py:1358
+ y.set_lo(bod or 0)
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/run.py:34
+ if file is None:
+ file = sys.stderr
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/idlelib/configDialog.py:39
+ self.title(title or 'IDLE Preferences')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/idlelib/configDialog.py:1256
+ self.wm_title(title or 'IDLE Extensions Configuration')
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/rpc.py:73
+ if handlerclass is None:
+ handlerclass = RPCHandler
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/rpc.py:134
+ if objtable is None:
+ objtable = objecttable
+
+Safe navigation `if` block: /usr/lib/python3.4/idlelib/rpc.py:143
+ if sock is not None:
+ sock.close()
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/MultiStatusBar.py:6
+ if master is None:
+ master = Tk()
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/PyShell.py:56
+ if line is None:
+ line = linecache.getline(filename, lineno)
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/PyShell.py:72
+ if file is None:
+ file = warning_stream
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/PyShell.py:1362
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/PyShell.py:1385
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/idlelib/Debugger.py:55
+ if idb is None:
+ idb = Idb(self)
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/idlelib/TreeWidget.py:82
+ ext = ext or ".gif"
+
+None-coalescing `if` block: /usr/lib/python3.4/cmd.py:87
+ if stdin is not None:
+ self.stdin = stdin
+ else:
+ self.stdin = sys.stdin
+
+None-coalescing `if` block: /usr/lib/python3.4/cmd.py:91
+ if stdout is not None:
+ self.stdout = stdout
+ else:
+ self.stdout = sys.stdout
+
+Safe navigation `if` block: /usr/lib/python3.4/_threading_local.py:185
+ if local is not None:
+ dct = local.dicts.pop(idt)
+
+None-coalescing `if` block: /usr/lib/python3.4/pkgutil.py:298
+ if fullname is None:
+ fullname = self.fullname
+
+Safe navigation ternary: /usr/lib/python3.4/pkgutil.py:492
+ return spec.loader if spec is not None else None
+
+None-coalescing `if` block: /usr/lib/python3.4/crypt.py:28
+ if method is None:
+ method = methods[0]
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/getopt.py:165
+ opts.append(('--' + opt, optarg or ''))
+
+Safe navigation `and`: /usr/lib/python3.4/getopt.py:88
+ while args and args[0].startswith('-') and args[0] != '-':
+
+None-coalescing `if` block: /usr/lib/python3.4/mailbox.py:820
+ if from_line is None:
+ from_line = b'From MAILER-DAEMON ' + time.asctime(time.gmtime()).encode()
+
+None-coalescing `if` block: /usr/lib/python3.4/mailbox.py:1919
+ if pos is None:
+ self._pos = f.tell()
+ else:
+ self._pos = pos
+
+None-coalescing `if` block: /usr/lib/python3.4/mailbox.py:1975
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/binhex.py:151
+ if finfo is None:
+ finfo = FInfo()
+
+None-coalescing `if` block: /usr/lib/python3.4/pickle.py:373
+ if protocol is None:
+ protocol = DEFAULT_PROTOCOL
+
+None-coalescing `if` block: /usr/lib/python3.4/pickle.py:904
+ if name is None:
+ name = obj.__name__
+
+Safe navigation `if` block: /usr/lib/python3.4/pickle.py:484
+ if reduce is not None:
+ rv = reduce(obj)
+ else:
+ # Check for a class with a custom metaclass; treat as regular class
+ try:
+
+None-coalescing `if` block: /usr/lib/python3.4/sysconfig.py:169
+ if vars is None:
+ vars = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/sysconfig.py:229
+ if vars is None:
+ vars = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/sysconfig.py:438
+ if vars is None:
+ vars = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:543
+ if ctx is None: ctx = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:823
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1098
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1120
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1162
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1272
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1326
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1427
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1470
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1500
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1577
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:1972
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2315
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2510
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2539
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2541
+ if rounding is None:
+ rounding = context.rounding
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2694
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2696
+ if rounding is None:
+ rounding = context.rounding
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2706
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2708
+ if rounding is None:
+ rounding = context.rounding
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2725
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2830
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:2872
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3045
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3145
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3165
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3201
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3281
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3342
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3388
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3405
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3412
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3429
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3448
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3478
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3506
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3529
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3561
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3625
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3644
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3677
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3702
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3769
+ if context is None:
+ context = getcontext()
+
+None-coalescing `if` block: /usr/lib/python3.4/decimal.py:3911
+ if _ignored_flags is None:
+ self._ignored_flags = []
+ else:
+ self._ignored_flags = _ignored_flags
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/decimal.py:613
+ self._int = str(int(diag or '0')).lstrip('0')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/decimal.py:688
+ self._int = ''.join(map(str, digits or [0]))
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/decimal.py:6199
+ format_dict['fill'] = fill or ' '
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/decimal.py:6203
+ format_dict['align'] = align or '>'
+
+None-coalescing ternary: /usr/lib/python3.4/decimal.py:3904
+ self.prec = prec if prec is not None else dc.prec
+
+None-coalescing ternary: /usr/lib/python3.4/decimal.py:3905
+ self.rounding = rounding if rounding is not None else dc.rounding
+
+None-coalescing ternary: /usr/lib/python3.4/decimal.py:3906
+ self.Emin = Emin if Emin is not None else dc.Emin
+
+None-coalescing ternary: /usr/lib/python3.4/decimal.py:3907
+ self.Emax = Emax if Emax is not None else dc.Emax
+
+None-coalescing ternary: /usr/lib/python3.4/decimal.py:3908
+ self.capitals = capitals if capitals is not None else dc.capitals
+
+None-coalescing ternary: /usr/lib/python3.4/decimal.py:3909
+ self.clamp = clamp if clamp is not None else dc.clamp
+
+Safe navigation `if` block: /usr/lib/python3.4/decimal.py:791
+ if other is None:
+ other_is_nan = False
+ else:
+ other_is_nan = other._isnan()
+
+None-coalescing `if` block: /usr/lib/python3.4/inspect.py:594
+ if _filename is None:
+ _filename = getsourcefile(object) or getfile(object)
+
+Safe navigation `if` block: /usr/lib/python3.4/inspect.py:2436
+ if kwdefaults is not None:
+ default = kwdefaults.get(name, _empty)
+
+None-coalescing `if` block: /usr/lib/python3.4/filecmp.py:123
+ if hide is None:
+ self.hide = [os.curdir, os.pardir] # Names never to be shown
+ else:
+ self.hide = hide
+
+None-coalescing `if` block: /usr/lib/python3.4/filecmp.py:127
+ if ignore is None:
+ self.ignore = DEFAULT_IGNORES
+ else:
+ self.ignore = ignore
+
+None-coalescing `if` block: /usr/lib/python3.4/py_compile.py:157
+ if args is None:
+ args = sys.argv[1:]
+
+None-coalescing `if` block: /usr/lib/python3.4/formatter.py:42
+ if writer is None:
+ writer = NullWriter()
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:776
+ if year is None:
+ year = self._year
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:778
+ if month is None:
+ month = self._month
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:780
+ if day is None:
+ day = self._day
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1238
+ if hour is None:
+ hour = self.hour
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1240
+ if minute is None:
+ minute = self.minute
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1242
+ if second is None:
+ second = self.second
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1244
+ if microsecond is None:
+ microsecond = self.microsecond
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1419
+ if dst is None:
+ dst = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1463
+ if year is None:
+ year = self.year
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1465
+ if month is None:
+ month = self.month
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1467
+ if day is None:
+ day = self.day
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1469
+ if hour is None:
+ hour = self.hour
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1471
+ if minute is None:
+ minute = self.minute
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1473
+ if second is None:
+ second = self.second
+
+None-coalescing `if` block: /usr/lib/python3.4/datetime.py:1475
+ if microsecond is None:
+ microsecond = self.microsecond
+
+Safe navigation `if` block: /usr/lib/python3.4/datetime.py:1367
+ if tz is not None:
+ result = tz.fromutc(result)
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:496
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:566
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:732
+ if pos is None:
+ pos = self.tell()
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:847
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:908
+ if pos is None:
+ pos = self._pos
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1138
+ if pos is None:
+ pos = self.raw.tell()
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1207
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1282
+ if pos is None:
+ pos = self.tell()
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1288
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1524
+ if errors is None:
+ errors = "strict"
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1853
+ if pos is None:
+ pos = self.tell()
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1938
+ if size is None:
+ size = -1
+
+None-coalescing `if` block: /usr/lib/python3.4/_pyio.py:1973
+ if size is None:
+ size = -1
+
+None-coalescing ternary: /usr/lib/python3.4/_pyio.py:396
+ if msg is None else msg)
+
+None-coalescing ternary: /usr/lib/python3.4/_pyio.py:410
+ if msg is None else msg)
+
+None-coalescing ternary: /usr/lib/python3.4/_pyio.py:424
+ if msg is None else msg)
+
+None-coalescing ternary: /usr/lib/python3.4/_pyio.py:439
+ if msg is None else msg)
+
+None-coalescing `if` block: /usr/lib/python3.4/traceback.py:27
+ if file is None:
+ file = sys.stderr
+
+None-coalescing `if` block: /usr/lib/python3.4/traceback.py:54
+ if limit is None:
+ limit = getattr(sys, 'tracebacklimit', None)
+
+None-coalescing `if` block: /usr/lib/python3.4/traceback.py:121
+ if seen is None:
+ seen = set()
+
+None-coalescing `if` block: /usr/lib/python3.4/traceback.py:167
+ if file is None:
+ file = sys.stderr
+
+None-coalescing `if` block: /usr/lib/python3.4/traceback.py:275
+ if f is None:
+ f = sys._getframe().f_back.f_back
+
+None-coalescing `if` block: /usr/lib/python3.4/uuid.py:585
+ if node is None:
+ node = getnode()
+
+None-coalescing `if` block: /usr/lib/python3.4/calendar.py:468
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+
+None-coalescing `if` block: /usr/lib/python3.4/calendar.py:510
+ if locale is None:
+ locale = _locale.getdefaultlocale()
+
+None-coalescing `if` block: /usr/lib/python3.4/calendar.py:540
+ if locale is None:
+ locale = _locale.getdefaultlocale()
+
+None-coalescing `if` block: /usr/lib/python3.4/importlib/_bootstrap.py:535
+ if name is None:
+ name = self.name
+
+None-coalescing `if` block: /usr/lib/python3.4/importlib/_bootstrap.py:611
+ if name is not None:
+ exc_details['name'] = name
+ else:
+ # To prevent having to make all messages have a conditional name.
+ name = '<bytecode>'
+
+None-coalescing `if` block: /usr/lib/python3.4/importlib/_bootstrap.py:1114
+ if module is None:
+ # This must be done before open() is ever called as the 'io'
+ # module implicitly imports 'locale' and would otherwise
+ # trigger an infinite loop.
+ module = _new_module(spec.name)
+
+None-coalescing `if` block: /usr/lib/python3.4/importlib/_bootstrap.py:1938
+ if path is None:
+ path = sys.path
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/importlib/_bootstrap.py:1988
+ self.path = path or '.'
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/importlib/_bootstrap.py:2065
+ contents = _os.listdir(path or _os.getcwd())
+
+None-coalescing ternary: /usr/lib/python3.4/importlib/_bootstrap.py:450
+ debug = not sys.flags.optimize if debug_override is None else debug_override
+
+None-coalescing ternary: /usr/lib/python3.4/importlib/_bootstrap.py:2336
+ globals_ = globals if globals is not None else {}
+
+Safe navigation ternary: /usr/lib/python3.4/importlib/_bootstrap.py:1285
+ return spec.loader if spec is not None else None
+
+Safe navigation ternary: /usr/lib/python3.4/importlib/abc.py:60
+ return found.loader if found is not None else None
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/fancy_getopt.py:221
+ if args is None:
+ args = sys.argv[1:]
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/fancy_getopt.py:361
+ if file is None:
+ file = sys.stdout
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:313
+ if outdir is None:
+ outdir = self.output_dir
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:318
+ if macros is None:
+ macros = self.macros
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:325
+ if incdirs is None:
+ incdirs = self.include_dirs
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:333
+ if extra is None:
+ extra = []
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:372
+ if output_dir is None:
+ output_dir = self.output_dir
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:377
+ if macros is None:
+ macros = self.macros
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:384
+ if include_dirs is None:
+ include_dirs = self.include_dirs
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:420
+ if output_dir is None:
+ output_dir = self.output_dir
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:434
+ if libraries is None:
+ libraries = self.libraries
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:442
+ if library_dirs is None:
+ library_dirs = self.library_dirs
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:450
+ if runtime_library_dirs is None:
+ runtime_library_dirs = self.runtime_library_dirs
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:770
+ if includes is None:
+ includes = []
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:772
+ if include_dirs is None:
+ include_dirs = []
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:774
+ if libraries is None:
+ libraries = []
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:776
+ if library_dirs is None:
+ library_dirs = []
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:847
+ if output_dir is None:
+ output_dir = ''
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:946
+ if osname is None:
+ osname = os.name
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:948
+ if platform is None:
+ platform = sys.platform
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:1000
+ if plat is None:
+ plat = os.name
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/ccompiler.py:1004
+ if compiler is None:
+ compiler = get_default_compiler(plat)
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/versionpredicate.py:155
+ if _provision_rx is None:
+ _provision_rx = re.compile(
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/archive_util.py:220
+ if base_dir is None:
+ base_dir = os.curdir
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/msvc9compiler.py:341
+ if plat_name is None:
+ plat_name = get_platform()
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/msvc9compiler.py:430
+ if output_dir is None: output_dir = ''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/msvc9compiler.py:465
+ compile_opts = extra_preargs or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/msvc9compiler.py:610
+ for sym in (export_symbols or []):
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/cygwinccompiler.py:254
+ if output_dir is None:
+ output_dir = ''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/cygwinccompiler.py:180
+ extra_preargs = copy.copy(extra_preargs or [])
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/cygwinccompiler.py:181
+ libraries = copy.copy(libraries or [])
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/cygwinccompiler.py:182
+ objects = copy.copy(objects or [])
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/util.py:367
+ if direct is None:
+ direct = (__debug__ and optimize == 0)
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/util.py:498
+ if fixer_names is None:
+ fixer_names = get_fixers_from_package('lib2to3.fixes')
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/util.py:456
+ if force or newer(file, cfile):
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/msvccompiler.py:315
+ if output_dir is None: output_dir = ''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/msvccompiler.py:350
+ compile_opts = extra_preargs or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/msvccompiler.py:495
+ for sym in (export_symbols or []):
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/dist.py:296
+ if commands is None: # dump all command option dicts
+ commands = sorted(self.command_options.keys())
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/dist.py:384
+ if filenames is None:
+ filenames = self.find_config_files()
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/dist.py:871
+ if option_dict is None:
+ option_dict = self.get_option_dict(command_name)
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/command/bdist_rpm.py:356
+ if source_rpm is None:
+ source_rpm = l[0]
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/bcppcompiler.py:338
+ if output_dir is None: output_dir = ''
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/bcppcompiler.py:88
+ compile_opts = extra_preargs or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/bcppcompiler.py:226
+ for sym in (export_symbols or []):
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:112
+ self.include_dirs = include_dirs or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:113
+ self.define_macros = define_macros or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:114
+ self.undef_macros = undef_macros or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:115
+ self.library_dirs = library_dirs or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:116
+ self.libraries = libraries or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:117
+ self.runtime_library_dirs = runtime_library_dirs or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:118
+ self.extra_objects = extra_objects or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:119
+ self.extra_compile_args = extra_compile_args or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:120
+ self.extra_link_args = extra_link_args or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:121
+ self.export_symbols = export_symbols or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:122
+ self.swig_opts = swig_opts or []
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/distutils/extension.py:123
+ self.depends = depends or []
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/text_file.py:128
+ if line is None:
+ line = self.current_line
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/cmd.py:153
+ if header is None:
+ header = "command options for '%s':" % self.get_command_name()
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/cmd.py:384
+ if skip_msg is None:
+ skip_msg = "skipping %s (inputs unchanged)" % outfile
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/cmd.py:394
+ if exec_msg is None:
+ exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles))
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/sysconfig.py:97
+ if prefix is None:
+ prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/sysconfig.py:292
+ if g is None:
+ g = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/sysconfig.py:330
+ if g is None:
+ g = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/distutils/spawn.py:178
+ if path is None:
+ path = os.environ['PATH']
+
+None-coalescing `if` block: /usr/lib/python3.4/shlex.py:256
+ if infile is None:
+ infile = self.infile
+
+None-coalescing `if` block: /usr/lib/python3.4/shlex.py:258
+ if lineno is None:
+ lineno = self.lineno
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/csv.py:200
+ dialect.quotechar = quotechar or '"'
+
+[Possible] None-coalescing `or`: /usr/lib/python3.4/lib2to3/refactor.py:191
+ self.explicit = explicit or []
+
+None-coalescing `if` block: /usr/lib/python3.4/lib2to3/pgen2/driver.py:33
+ if logger is None:
+ logger = logging.getLogger()
+
+None-coalescing `if` block: /usr/lib/python3.4/lib2to3/pgen2/driver.py:112
+ if logger is None:
+ logger = logging.getLogger()
+
+None-coalescing `if` block: /usr/lib/python3.4/lib2to3/pgen2/pgen.py:165
+ if startsymbol is None:
+ startsymbol = name
+
+Safe navigation `if` block: /usr/lib/python3.4/lib2to3/pgen2/pgen.py:22
+ if close_stream is not None:
+ close_stream()
+
+None-coalescing `if` block: /usr/lib/python3.4/lib2to3/pgen2/parse.py:102
+ if start is None:
+ start = self.grammar.start
+
+None-coalescing `if` block: /usr/lib/python3.4/lib2to3/fixes/fix_tuple_params.py:158
+ if d is None:
+ d = {}
+
+None-coalescing `if` block: /usr/lib/python3.4/ipaddress.py:1718
+ if ip_int is None:
+ ip_int = int(self._ip)
+
+None-coalescing `if` block: /usr/lib/python3.4/bisect.py:14
+ if hi is None:
+ hi = len(a)
+
+None-coalescing `if` block: /usr/lib/python3.4/bisect.py:37
+ if hi is None:
+ hi = len(a)
+
+None-coalescing `if` block: /usr/lib/python3.4/bisect.py:58
+ if hi is None:
+ hi = len(a)
+
+None-coalescing `if` block: /usr/lib/python3.4/bisect.py:80
+ if hi is None:
+ hi = len(a)
+
+Total None-coalescing `if` blocks: 426
+Total [possible] None-coalescing `or`: 119
+Total None-coalescing ternaries: 21
+Total Safe navigation `and`: 9
+Total Safe navigation `if` blocks: 55
+Total Safe navigation ternaries: 7
diff --git a/pep-0505/find-pep505.py b/pep-0505/find-pep505.py
new file mode 100644
--- /dev/null
+++ b/pep-0505/find-pep505.py
@@ -0,0 +1,434 @@
+'''
+Find code patterns that PEP-505 attempts to make more concise.
+
+Example usage:
+
+ $ find /usr/lib/python3.4 -name '*.py' | xargs python3 find-pep505.py
+
+'''
+
+import ast
+import sys
+
+
+class NoneCoalesceIfBlockVisitor(ast.NodeVisitor):
+ '''
+ Look for if blocks of the form:
+
+ >>> if a is None:
+ ... a = b
+
+ >>> if a is not None:
+ ... b
+ ... else:
+ ... a = c
+
+ >>> def foo(self, a=None):
+ ... if a is None:
+ ... self.b = c
+ ... else:
+ ... self.b = a
+
+ >>> def foo(self, a=None):
+ ... if a is not None:
+ ... self.b = a
+ ... else:
+ ... self.b = c
+
+ ...where `a` is a name and other characters represent any abitrary
+ expression.
+
+ In the two latter forms, the search criterion is an assignment of `a`
+ to any identifier in the `a is not None` block.
+ '''
+
+ def __init__(self, file_, callback):
+ self.__file = file_
+ self.__callback = callback
+
+ def visit_If(self, if_):
+
+ if not isinstance(if_.test, ast.Compare):
+ return
+
+ op = if_.test.ops[0]
+
+ # Match `if a is None:` or `if a is not None:`, where `a` is a name.
+ if isinstance(op, (ast.Is, ast.IsNot)) and \
+ isinstance(if_.test.left, ast.Name) and \
+ isinstance(if_.test.comparators[0], ast.NameConstant) and \
+ if_.test.comparators[0].value is None:
+
+ test_name = if_.test.left.id
+ else:
+ return
+
+ # Keep track of which block handles the `a is None` condition and which
+ # handles the `a is not None` condition.
+ if isinstance(op, ast.Is):
+ none_block = if_.body
+ value_block = if_.orelse
+ elif isinstance(op, ast.IsNot):
+ none_block = if_.orelse
+ value_block = if_.body
+
+ if len(none_block) != 1:
+ return
+
+ none_stmt = none_block[0]
+
+ # If there is no `a is not None` block, handle gracefully.
+ if len(value_block) == 1:
+ value_stmt = value_block[0]
+ else:
+ value_stmt = None
+
+ # Assigning a value to `a` when it is `None`?
+ if isinstance(none_stmt, ast.Assign) and \
+ len(none_stmt.targets) == 1:
+
+ target = none_stmt.targets[0]
+
+ if isinstance(target, ast.Name):
+ if test_name == target.id:
+ self.__callback(self.__file, if_.test.lineno,
+ target.lineno)
+ return
+
+ # Assigning value of `a` to another identifier when a is not `None`?
+ if isinstance(value_stmt, ast.Assign) and \
+ isinstance(value_stmt.value, ast.Name) and \
+ test_name == value_stmt.value.id:
+
+ end_line = max(value_stmt.lineno, none_stmt.lineno)
+ self.__callback(self.__file, if_.test.lineno, end_line)
+
+
+class NoneCoalesceOrVisitor(ast.NodeVisitor):
+ '''
+ Look for expressions of the form:
+
+ >>> a or '1'
+ >>> a or []
+ >>> a or {}
+
+ ...where `a` is any name. More formally, match a plain name on the left side
+ of `or` and something that looks like a default on the right, e.g. a
+ constant or a constructor invocation.
+ '''
+
+ def __init__(self, file_, callback):
+ self.__file = file_
+ self.__callback = callback
+
+ def visit_BoolOp(self, bool_op):
+ if not isinstance(bool_op.op, ast.Or) or \
+ not isinstance(bool_op.values[0], ast.Name):
+ return
+
+ defaults = ast.Call, ast.Dict, ast.List, ast.Num, ast.Set, ast.Str
+
+ if isinstance(bool_op.values[1], defaults):
+ start_line = bool_op.values[0].lineno
+ end_line = bool_op.values[-1].lineno
+ self.__callback(self.__file, start_line, end_line)
+
+
+class NoneCoalesceTernaryVisitor(ast.NodeVisitor):
+ '''
+ Look for ternary expressions of the form:
+
+ >>> a if a is not None else b
+ >>> b if a is None else a
+
+ ...where a is an identifier and b is an abitrary expression.
+ '''
+
+ def __init__(self, file_, callback):
+ self.__file = file_
+ self.__callback = callback
+
+ def visit_IfExp(self, ifexp):
+ if isinstance(ifexp.test, ast.Compare):
+ op = ifexp.test.ops[0]
+
+ # Match `a is None` or `a is not None`, where `a` is a name.
+ if isinstance(op, (ast.Is, ast.IsNot)) and \
+ isinstance(ifexp.test.left, ast.Name) and \
+ isinstance(ifexp.test.comparators[0], ast.NameConstant) and \
+ ifexp.test.comparators[0].value is None:
+
+ test_name = ifexp.test.left.id
+ else:
+ return
+
+ if isinstance(op, ast.IsNot) and isinstance(ifexp.body, ast.Name):
+ # Match `a if a is not None else ...`.
+ result_name = ifexp.body.id
+ elif isinstance(op, ast.Is) and isinstance(ifexp.orelse, ast.Name):
+ # Match `... if a is None else a`.
+ result_name = ifexp.orelse.id
+ else:
+ return
+
+ if test_name == result_name:
+ self.__callback(self.__file, ifexp.test.lineno, None)
+
+
+class SafeNavAndVisitor(ast.NodeVisitor):
+ '''
+ Look for expressions where `and` is used to avoid attribute/index access on
+ ``None``:
+
+ >>> a and a.foo
+ >>> a and a[foo]
+ >>> a and a.foo()
+ >>> a and a.foo.bar
+
+ ...where `a` is any name and `foo`, `bar` are any attribute or keys.
+ '''
+
+ def __init__(self, file_, callback):
+ self.__file = file_
+ self.__callback = callback
+
+ def visit_BoolOp(self, bool_op):
+ if not isinstance(bool_op.op, ast.And) or \
+ not isinstance(bool_op.values[0], ast.Name):
+ return
+
+ left_name = bool_op.values[0].id
+ right = bool_op.values[1]
+
+ if isinstance(right, (ast.Attribute, ast.Call, ast.Subscript)):
+ right_name = get_name_from_node(right)
+ else:
+ return
+
+ if left_name == right_name:
+ start_line = bool_op.values[0].lineno
+ end_line = bool_op.values[-1].lineno
+ self.__callback(self.__file, start_line, end_line)
+
+
+class SafeNavIfBlockVisitor(ast.NodeVisitor):
+ '''
+ Look for blocks where `if` is used to avoid attribute/index access on
+ ``None``:
+
+ >>> if a is not None:
+ ... a.foo
+
+ >>> if a is None:
+ ... pass
+ ... else:
+ ... a.foo
+
+ ...where `a` is any name. Index access and function calls are also matched.
+ '''
+
+ def __init__(self, file_, callback):
+ self.__file = file_
+ self.__callback = callback
+
+ def visit_If(self, if_):
+
+ if not isinstance(if_.test, ast.Compare):
+ return
+
+ op = if_.test.ops[0]
+
+ # Match `if a is None:` or `if a is not None:`, where `a` is a name.
+ if isinstance(op, (ast.Is, ast.IsNot)) and \
+ isinstance(if_.test.left, ast.Name) and \
+ isinstance(if_.test.comparators[0], ast.NameConstant) and \
+ if_.test.comparators[0].value is None:
+
+ test_name = if_.test.left.id
+ else:
+ return
+
+ # Keep track of which block handles the `a is None` condition and which
+ # handles the `a is not None` condition.
+ if isinstance(op, ast.Is):
+ none_block = if_.body
+ value_block = if_.orelse
+ elif isinstance(op, ast.IsNot):
+ none_block = if_.orelse
+ value_block = if_.body
+
+ if len(none_block) > 0:
+ none_lineno = none_block[0].lineno
+ else:
+ none_lineno = 0
+
+ # If there is no `a is not None` block, then it's definitely not a
+ # match.
+ if len(value_block) == 1:
+ value_stmt = value_block[0]
+ else:
+ return
+
+ # Assigning the value of `a.foo` or `a[foo]` or calling `a.foo()` in the
+ # `a is not None` block. (But don't match bare `a` -- that's already
+ # covered by the None coalesce visitors.)
+ if isinstance(value_stmt, (ast.Assign, ast.Expr)) and \
+ not isinstance(value_stmt.value, ast.Name):
+ expr_name = get_name_from_node(value_stmt.value)
+ else:
+ return
+
+ # Assigning value of `a` to another identifier when a is not `None`?
+ if test_name == expr_name:
+ end_line = max(value_stmt.lineno, none_lineno)
+ self.__callback(self.__file, if_.test.lineno, end_line)
+
+
+class SafeNavTernaryVisitor(ast.NodeVisitor):
+ '''
+ Look for ternary expressions of the form:
+
+ >>> a.foo if a is not None else b
+ >>> b if a is None else a.foo
+
+ ...where `a` is an identifier, `b` is an abitrary expression, and `foo` is
+ an attribute, index, or function invocation.
+ '''
+
+ def __init__(self, file_, callback):
+ self.__file = file_
+ self.__callback = callback
+
+ def visit_IfExp(self, ifexp):
+ if isinstance(ifexp.test, ast.Compare):
+ op = ifexp.test.ops[0]
+
+ # Match `a is None` or `a is not None`, where `a` is a name.
+ if isinstance(op, (ast.Is, ast.IsNot)) and \
+ isinstance(ifexp.test.left, ast.Name) and \
+ isinstance(ifexp.test.comparators[0], ast.NameConstant) and \
+ ifexp.test.comparators[0].value is None:
+
+ test_name = ifexp.test.left.id
+ else:
+ return
+
+ exprs = ast.Attribute, ast.Call, ast.Subscript
+
+ if isinstance(op, ast.IsNot) and isinstance(ifexp.body, exprs):
+ # Match `a.foo if a is not None else ...`.
+ result_name = get_name_from_node(ifexp.body)
+ elif isinstance(op, ast.Is) and isinstance(ifexp.orelse, exprs):
+ # Match `... if a is None else a.foo`.
+ result_name = get_name_from_node(ifexp.orelse)
+ else:
+ return
+
+ if test_name == result_name:
+ self.__callback(self.__file, ifexp.test.lineno, None)
+
+
+def count_calls_decorator(callback):
+ '''
+ Decorator for a callback that counts how many time that callback
+ was invoked.
+ '''
+
+ def invoke(*args):
+ callback(*args)
+ invoke.count += 1
+
+ invoke.count = 0
+
+ return invoke
+
+
+def get_call_count(invoke):
+ '''
+ In tandem with `count_calls_decorator`, return the number of times that
+ a callback was invoked.
+ '''
+
+ return invoke.count
+
+
+def get_name_from_node(node):
+ '''
+ Return the left-most name from an Attribute or Subscript node.
+ '''
+
+ while isinstance(node, (ast.Attribute, ast.Call, ast.Subscript)):
+ if isinstance(node, ast.Call):
+ node = node.func
+ else:
+ node = node.value
+
+ if isinstance(node, ast.Name):
+ return node.id
+ else:
+ return None
+
+
+def log(text, file_, start_line, stop_line=None):
+ '''
+ Display a match, including file name, line number, and code excerpt.
+ '''
+
+ print('{}: {}:{}'.format(text, file_, start_line))
+
+ if stop_line is None:
+ stop_line = start_line
+
+ with open(file_) as source:
+ print(''.join(source.readlines()[start_line-1:stop_line]))
+
+
+def main():
+ if len(sys.argv) < 2:
+ sys.stderr.write('Usage: python3 parse.py <files>\n')
+ sys.exit(1)
+
+ def make_callback(text):
+ return count_calls_decorator(
+ lambda file_, start, stop: log(text, file_, start, stop)
+ )
+
+ nci_callback = make_callback('None-coalescing `if` block')
+ nco_callback = make_callback('[Possible] None-coalescing `or`')
+ nct_callback = make_callback('None-coalescing ternary')
+ sna_callback = make_callback('Safe navigation `and`')
+ sni_callback = make_callback('Safe navigation `if` block')
+ snt_callback = make_callback('Safe navigation ternary')
+
+ for file_ in sys.argv[1:]:
+ with open(file_) as source:
+ tree = ast.parse(source.read(), filename=file_)
+
+ NoneCoalesceIfBlockVisitor(file_, nci_callback).visit(tree)
+ NoneCoalesceOrVisitor(file_, nco_callback).visit(tree)
+ NoneCoalesceTernaryVisitor(file_, nct_callback).visit(tree)
+ SafeNavAndVisitor(file_, sna_callback).visit(tree)
+ SafeNavIfBlockVisitor(file_, sni_callback).visit(tree)
+ SafeNavTernaryVisitor(file_, snt_callback).visit(tree)
+
+ print('Total None-coalescing `if` blocks: {}'
+ .format(get_call_count(nci_callback)))
+
+ print('Total [possible] None-coalescing `or`: {}'
+ .format(get_call_count(nco_callback)))
+
+ print('Total None-coalescing ternaries: {}'
+ .format(get_call_count(nct_callback)))
+
+ print('Total Safe navigation `and`: {}'
+ .format(get_call_count(sna_callback)))
+
+ print('Total Safe navigation `if` blocks: {}'
+ .format(get_call_count(sni_callback)))
+
+ print('Total Safe navigation ternaries: {}'
+ .format(get_call_count(snt_callback)))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/pep-0505/test.py b/pep-0505/test.py
new file mode 100644
--- /dev/null
+++ b/pep-0505/test.py
@@ -0,0 +1,92 @@
+'''
+This file is used for testing find-pep505.out.
+
+nc_* and Nc* are examples of null coalescing.
+sn_* and Sn* are examples of save navigation.
+'''
+
+def nc_ifblock1(a=None):
+ if a is None:
+ a = 'foo'
+
+def nc_ifblock2(a=None):
+ if a is not None:
+ pass
+ else:
+ a = 'foo'
+
+class NcIfBlock3:
+ def __init__(self, a=None):
+ if a is None:
+ self.b = {}
+ else:
+ self.b = a
+
+class NcIfBlock4:
+ def __init__(self, a=None):
+ if a is not None:
+ self.b = a
+ else:
+ self.b = {}
+
+def nc_or1(a=None):
+ return a or 'foo'
+
+def nc_or2(a=None):
+ return a or []
+
+def nc_ternary1(a=None):
+ return a if a is not None else 'foo'
+
+def nc_ternary2(a=None):
+ return 'foo' if a is None else a
+
+def sn_and1(a=None):
+ return a and a.foo
+
+def sn_and2(a=None):
+ return a and a['foo']
+
+def sn_and3(a=None):
+ return a and a.foo()
+
+def sn_and3(a=None):
+ return a and a.foo.bar
+
+class SnIfBlock1:
+ def __init__(self, a=None):
+ if a is not None:
+ a.foo()
+
+class SnIfBlock2:
+ def __init__(self, a=None):
+ if a is None:
+ pass
+ else:
+ a.foo()
+
+class SnIfBlock3:
+ def __init__(self, a=None):
+ if a is None:
+ b = 'foo'
+ else:
+ b = a.foo
+
+class SnIfBlock4:
+ def __init__(self, a=None):
+ if a is None:
+ b = 'foo'
+ else:
+ b = a['foo']
+
+def sn_ternary1(a=None):
+ return a.foo if a is not None else None
+
+def sn_ternary2(a=None):
+ return None if a is None else a.foo
+
+def sn_ternary3(a=None):
+ return a['foo'] if a is not None else None
+
+def sn_ternary4(a=None):
+ return None if a is None else a.foo()
--
Repository URL: https://hg.python.org/peps
1
0
cpython (3.5): Issue #25410: Fixed a memory leak in OrderedDict in the case when key's hash
by serhiy.storchaka Oct. 20, 2015
by serhiy.storchaka Oct. 20, 2015
Oct. 20, 2015
https://hg.python.org/cpython/rev/93f948120773
changeset: 98813:93f948120773
branch: 3.5
parent: 98810:9c6b12725b7f
user: Serhiy Storchaka <storchaka(a)gmail.com>
date: Tue Oct 20 18:21:48 2015 +0300
summary:
Issue #25410: Fixed a memory leak in OrderedDict in the case when key's hash
calculation fails.
files:
Objects/odictobject.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Objects/odictobject.c b/Objects/odictobject.c
--- a/Objects/odictobject.c
+++ b/Objects/odictobject.c
@@ -648,11 +648,11 @@
Py_ssize_t i;
_ODictNode *node;
- Py_INCREF(key);
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
+ Py_INCREF(key);
i = _odict_get_index(od, key);
if (i < 0) {
if (!PyErr_Occurred())
--
Repository URL: https://hg.python.org/cpython
1
0