Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
3bc13cc8
Commit
3bc13cc8
authored
Jul 07, 2014
by
Serhiy Storchaka
Browse files
Options
Browse Files
Download
Plain Diff
Merge heads
parents
667abc7d
e50dafcd
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
223 additions
and
94 deletions
+223
-94
Doc/faq/design.rst
Doc/faq/design.rst
+0
-56
Doc/faq/programming.rst
Doc/faq/programming.rst
+56
-0
Doc/library/__main__.rst
Doc/library/__main__.rst
+1
-1
Doc/library/asyncio-eventloop.rst
Doc/library/asyncio-eventloop.rst
+8
-2
Doc/library/asyncio-task.rst
Doc/library/asyncio-task.rst
+4
-1
Lib/asyncio/coroutines.py
Lib/asyncio/coroutines.py
+6
-0
Lib/asyncio/futures.py
Lib/asyncio/futures.py
+6
-0
Lib/asyncio/proactor_events.py
Lib/asyncio/proactor_events.py
+1
-1
Lib/asyncio/queues.py
Lib/asyncio/queues.py
+1
-1
Lib/asyncio/selector_events.py
Lib/asyncio/selector_events.py
+3
-2
Lib/asyncio/tasks.py
Lib/asyncio/tasks.py
+2
-1
Lib/asyncio/unix_events.py
Lib/asyncio/unix_events.py
+2
-2
Lib/distutils/sysconfig.py
Lib/distutils/sysconfig.py
+2
-1
Lib/distutils/tests/test_sysconfig.py
Lib/distutils/tests/test_sysconfig.py
+22
-0
Lib/pathlib.py
Lib/pathlib.py
+7
-4
Lib/test/test_asyncio/test_futures.py
Lib/test/test_asyncio/test_futures.py
+6
-0
Lib/test/test_asyncio/test_tasks.py
Lib/test/test_asyncio/test_tasks.py
+4
-0
Lib/test/test_frame.py
Lib/test/test_frame.py
+52
-0
Lib/test/test_pathlib.py
Lib/test/test_pathlib.py
+14
-0
Misc/NEWS
Misc/NEWS
+12
-0
Modules/_io/_iomodule.c
Modules/_io/_iomodule.c
+5
-3
Objects/frameobject.c
Objects/frameobject.c
+1
-1
Objects/unicodeobject.c
Objects/unicodeobject.c
+8
-18
No files found.
Doc/faq/design.rst
View file @
3bc13cc8
...
@@ -664,62 +664,6 @@ before you write any of the actual code. Of course Python allows you to be
...
@@ -664,62 +664,6 @@ before you write any of the actual code. Of course Python allows you to be
sloppy and not write test cases at all.
sloppy and not write test cases at all.
Why are default values shared between objects?
----------------------------------------------
This type of bug commonly bites neophyte programmers. Consider this function::
def foo(mydict={}): # Danger: shared reference to one dict for all calls
... compute something ...
mydict[key] = value
return mydict
The first time you call this function, ``mydict`` contains a single item. The
second time, ``mydict`` contains two items because when ``foo()`` begins
executing, ``mydict`` starts out with an item already in it.
It is often expected that a function call creates new objects for default
values. This is not what happens. Default values are created exactly once, when
the function is defined. If that object is changed, like the dictionary in this
example, subsequent calls to the function will refer to this changed object.
By definition, immutable objects such as numbers, strings, tuples, and ``None``,
are safe from change. Changes to mutable objects such as dictionaries, lists,
and class instances can lead to confusion.
Because of this feature, it is good programming practice to not use mutable
objects as default values. Instead, use ``None`` as the default value and
inside the function, check if the parameter is ``None`` and create a new
list/dictionary/whatever if it is. For example, don't write::
def foo(mydict={}):
...
but::
def foo(mydict=None):
if mydict is None:
mydict = {} # create a new dict for local namespace
This feature can be useful. When you have a function that's time-consuming to
compute, a common technique is to cache the parameters and the resulting value
of each call to the function, and return the cached value if the same value is
requested again. This is called "memoizing", and can be implemented like this::
# Callers will never provide a third parameter for this function.
def expensive(arg1, arg2, _cache={}):
if (arg1, arg2) in _cache:
return _cache[(arg1, arg2)]
# Calculate the value
result = ... expensive computation ...
_cache[(arg1, arg2)] = result # Store result in the cache
return result
You could use a global variable containing a dictionary instead of the default
value; it's a matter of taste.
Why is there no goto?
Why is there no goto?
---------------------
---------------------
...
...
Doc/faq/programming.rst
View file @
3bc13cc8
...
@@ -352,6 +352,62 @@ the import inside the class but outside of any method still causes the import to
...
@@ -352,6 +352,62 @@ the import inside the class but outside of any method still causes the import to
occur when the module is initialized.
occur when the module is initialized.
Why are default values shared between objects?
----------------------------------------------
This type of bug commonly bites neophyte programmers. Consider this function::
def foo(mydict={}): # Danger: shared reference to one dict for all calls
... compute something ...
mydict[key] = value
return mydict
The first time you call this function, ``mydict`` contains a single item. The
second time, ``mydict`` contains two items because when ``foo()`` begins
executing, ``mydict`` starts out with an item already in it.
It is often expected that a function call creates new objects for default
values. This is not what happens. Default values are created exactly once, when
the function is defined. If that object is changed, like the dictionary in this
example, subsequent calls to the function will refer to this changed object.
By definition, immutable objects such as numbers, strings, tuples, and ``None``,
are safe from change. Changes to mutable objects such as dictionaries, lists,
and class instances can lead to confusion.
Because of this feature, it is good programming practice to not use mutable
objects as default values. Instead, use ``None`` as the default value and
inside the function, check if the parameter is ``None`` and create a new
list/dictionary/whatever if it is. For example, don't write::
def foo(mydict={}):
...
but::
def foo(mydict=None):
if mydict is None:
mydict = {} # create a new dict for local namespace
This feature can be useful. When you have a function that's time-consuming to
compute, a common technique is to cache the parameters and the resulting value
of each call to the function, and return the cached value if the same value is
requested again. This is called "memoizing", and can be implemented like this::
# Callers will never provide a third parameter for this function.
def expensive(arg1, arg2, _cache={}):
if (arg1, arg2) in _cache:
return _cache[(arg1, arg2)]
# Calculate the value
result = ... expensive computation ...
_cache[(arg1, arg2)] = result # Store result in the cache
return result
You could use a global variable containing a dictionary instead of the default
value; it's a matter of taste.
How can I pass optional or keyword parameters from one function to another?
How can I pass optional or keyword parameters from one function to another?
---------------------------------------------------------------------------
---------------------------------------------------------------------------
...
...
Doc/library/__main__.rst
View file @
3bc13cc8
...
@@ -12,7 +12,7 @@ standard input, a script, or from an interactive prompt.
...
@@ -12,7 +12,7 @@ standard input, a script, or from an interactive prompt.
A module can discover whether or not it is running in the main scope by
A module can discover whether or not it is running in the main scope by
checking its own ``__name__``, which allows a common idiom for conditionally
checking its own ``__name__``, which allows a common idiom for conditionally
executing code in a module when it is run as a script or with ``python
executing code in a module when it is run as a script or with ``python
-m`` but not when it is imported:
-m`` but not when it is imported:
:
if __name__ == "__main__":
if __name__ == "__main__":
# execute only if run as a script
# execute only if run as a script
...
...
Doc/library/asyncio-eventloop.rst
View file @
3bc13cc8
...
@@ -651,7 +651,10 @@ Print ``Hello World`` every two seconds, using a callback::
...
@@ -651,7 +651,10 @@ Print ``Hello World`` every two seconds, using a callback::
loop = asyncio.get_event_loop()
loop = asyncio.get_event_loop()
loop.call_soon(print_and_repeat, loop)
loop.call_soon(print_and_repeat, loop)
loop.run_forever()
try:
loop.run_forever()
finally:
loop.close()
.. seealso::
.. seealso::
...
@@ -679,5 +682,8 @@ Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`::
...
@@ -679,5 +682,8 @@ Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`::
print("Event loop running forever, press CTRL+c to interrupt.")
print("Event loop running forever, press CTRL+c to interrupt.")
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
loop.run_forever()
try:
loop.run_forever()
finally:
loop.close()
Doc/library/asyncio-task.rst
View file @
3bc13cc8
...
@@ -89,7 +89,10 @@ Print ``"Hello World"`` every two seconds using a coroutine::
...
@@ -89,7 +89,10 @@ Print ``"Hello World"`` every two seconds using a coroutine::
yield from asyncio.sleep(2)
yield from asyncio.sleep(2)
loop = asyncio.get_event_loop()
loop = asyncio.get_event_loop()
loop.run_until_complete(greet_every_two_seconds())
try:
loop.run_until_complete(greet_every_two_seconds())
finally:
loop.close()
.. seealso::
.. seealso::
...
...
Lib/asyncio/coroutines.py
View file @
3bc13cc8
...
@@ -64,6 +64,12 @@ class CoroWrapper:
...
@@ -64,6 +64,12 @@ class CoroWrapper:
self
.
gen
=
gen
self
.
gen
=
gen
self
.
func
=
func
self
.
func
=
func
self
.
_source_traceback
=
traceback
.
extract_stack
(
sys
.
_getframe
(
1
))
self
.
_source_traceback
=
traceback
.
extract_stack
(
sys
.
_getframe
(
1
))
# __name__, __qualname__, __doc__ attributes are set by the coroutine()
# decorator
def
__repr__
(
self
):
return
(
'<%s %s>'
%
(
self
.
__class__
.
__name__
,
_format_coroutine
(
self
)))
def
__iter__
(
self
):
def
__iter__
(
self
):
return
self
return
self
...
...
Lib/asyncio/futures.py
View file @
3bc13cc8
...
@@ -316,6 +316,12 @@ class Future:
...
@@ -316,6 +316,12 @@ class Future:
# So-called internal methods (note: no set_running_or_notify_cancel()).
# So-called internal methods (note: no set_running_or_notify_cancel()).
def
_set_result_unless_cancelled
(
self
,
result
):
"""Helper setting the result only if the future was not cancelled."""
if
self
.
cancelled
():
return
self
.
set_result
(
result
)
def
set_result
(
self
,
result
):
def
set_result
(
self
,
result
):
"""Mark the future done and set its result.
"""Mark the future done and set its result.
...
...
Lib/asyncio/proactor_events.py
View file @
3bc13cc8
...
@@ -38,7 +38,7 @@ class _ProactorBasePipeTransport(transports._FlowControlMixin,
...
@@ -38,7 +38,7 @@ class _ProactorBasePipeTransport(transports._FlowControlMixin,
self
.
_server
.
attach
(
self
)
self
.
_server
.
attach
(
self
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
if
waiter
is
not
None
:
if
waiter
is
not
None
:
self
.
_loop
.
call_soon
(
waiter
.
set_result
,
None
)
self
.
_loop
.
call_soon
(
waiter
.
_set_result_unless_cancelled
,
None
)
def
_set_extra
(
self
,
sock
):
def
_set_extra
(
self
,
sock
):
self
.
_extra
[
'pipe'
]
=
sock
self
.
_extra
[
'pipe'
]
=
sock
...
...
Lib/asyncio/queues.py
View file @
3bc13cc8
...
@@ -173,7 +173,7 @@ class Queue:
...
@@ -173,7 +173,7 @@ class Queue:
# run, we need to defer the put for a tick to ensure that
# run, we need to defer the put for a tick to ensure that
# getters and putters alternate perfectly. See
# getters and putters alternate perfectly. See
# ChannelTest.test_wait.
# ChannelTest.test_wait.
self
.
_loop
.
call_soon
(
putter
.
set_result
,
None
)
self
.
_loop
.
call_soon
(
putter
.
_set_result_unless_cancelled
,
None
)
return
self
.
_get
()
return
self
.
_get
()
...
...
Lib/asyncio/selector_events.py
View file @
3bc13cc8
...
@@ -481,7 +481,7 @@ class _SelectorSocketTransport(_SelectorTransport):
...
@@ -481,7 +481,7 @@ class _SelectorSocketTransport(_SelectorTransport):
self
.
_loop
.
add_reader
(
self
.
_sock_fd
,
self
.
_read_ready
)
self
.
_loop
.
add_reader
(
self
.
_sock_fd
,
self
.
_read_ready
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
if
waiter
is
not
None
:
if
waiter
is
not
None
:
self
.
_loop
.
call_soon
(
waiter
.
set_result
,
None
)
self
.
_loop
.
call_soon
(
waiter
.
_set_result_unless_cancelled
,
None
)
def
pause_reading
(
self
):
def
pause_reading
(
self
):
if
self
.
_closing
:
if
self
.
_closing
:
...
@@ -690,7 +690,8 @@ class _SelectorSslTransport(_SelectorTransport):
...
@@ -690,7 +690,8 @@ class _SelectorSslTransport(_SelectorTransport):
self
.
_loop
.
add_reader
(
self
.
_sock_fd
,
self
.
_read_ready
)
self
.
_loop
.
add_reader
(
self
.
_sock_fd
,
self
.
_read_ready
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
if
self
.
_waiter
is
not
None
:
if
self
.
_waiter
is
not
None
:
self
.
_loop
.
call_soon
(
self
.
_waiter
.
set_result
,
None
)
self
.
_loop
.
call_soon
(
self
.
_waiter
.
_set_result_unless_cancelled
,
None
)
def
pause_reading
(
self
):
def
pause_reading
(
self
):
# XXX This is a bit icky, given the comment at the top of
# XXX This is a bit icky, given the comment at the top of
...
...
Lib/asyncio/tasks.py
View file @
3bc13cc8
...
@@ -487,7 +487,8 @@ def as_completed(fs, *, loop=None, timeout=None):
...
@@ -487,7 +487,8 @@ def as_completed(fs, *, loop=None, timeout=None):
def
sleep
(
delay
,
result
=
None
,
*
,
loop
=
None
):
def
sleep
(
delay
,
result
=
None
,
*
,
loop
=
None
):
"""Coroutine that completes after a given time (in seconds)."""
"""Coroutine that completes after a given time (in seconds)."""
future
=
futures
.
Future
(
loop
=
loop
)
future
=
futures
.
Future
(
loop
=
loop
)
h
=
future
.
_loop
.
call_later
(
delay
,
future
.
set_result
,
result
)
h
=
future
.
_loop
.
call_later
(
delay
,
future
.
_set_result_unless_cancelled
,
result
)
try
:
try
:
return
(
yield
from
future
)
return
(
yield
from
future
)
finally
:
finally
:
...
...
Lib/asyncio/unix_events.py
View file @
3bc13cc8
...
@@ -269,7 +269,7 @@ class _UnixReadPipeTransport(transports.ReadTransport):
...
@@ -269,7 +269,7 @@ class _UnixReadPipeTransport(transports.ReadTransport):
self
.
_loop
.
add_reader
(
self
.
_fileno
,
self
.
_read_ready
)
self
.
_loop
.
add_reader
(
self
.
_fileno
,
self
.
_read_ready
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
if
waiter
is
not
None
:
if
waiter
is
not
None
:
self
.
_loop
.
call_soon
(
waiter
.
set_result
,
None
)
self
.
_loop
.
call_soon
(
waiter
.
_set_result_unless_cancelled
,
None
)
def
_read_ready
(
self
):
def
_read_ready
(
self
):
try
:
try
:
...
@@ -353,7 +353,7 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
...
@@ -353,7 +353,7 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
self
.
_loop
.
call_soon
(
self
.
_protocol
.
connection_made
,
self
)
if
waiter
is
not
None
:
if
waiter
is
not
None
:
self
.
_loop
.
call_soon
(
waiter
.
set_result
,
None
)
self
.
_loop
.
call_soon
(
waiter
.
_set_result_unless_cancelled
,
None
)
def
get_write_buffer_size
(
self
):
def
get_write_buffer_size
(
self
):
return
sum
(
len
(
data
)
for
data
in
self
.
_buffer
)
return
sum
(
len
(
data
)
for
data
in
self
.
_buffer
)
...
...
Lib/distutils/sysconfig.py
View file @
3bc13cc8
...
@@ -179,7 +179,8 @@ def customize_compiler(compiler):
...
@@ -179,7 +179,8 @@ def customize_compiler(compiler):
# version and build tools may not support the same set
# version and build tools may not support the same set
# of CPU architectures for universal builds.
# of CPU architectures for universal builds.
global
_config_vars
global
_config_vars
if
not
_config_vars
.
get
(
'CUSTOMIZED_OSX_COMPILER'
,
''
):
# Use get_config_var() to ensure _config_vars is initialized.
if
not
get_config_var
(
'CUSTOMIZED_OSX_COMPILER'
):
import
_osx_support
import
_osx_support
_osx_support
.
customize_compiler
(
_config_vars
)
_osx_support
.
customize_compiler
(
_config_vars
)
_config_vars
[
'CUSTOMIZED_OSX_COMPILER'
]
=
'True'
_config_vars
[
'CUSTOMIZED_OSX_COMPILER'
]
=
'True'
...
...
Lib/distutils/tests/test_sysconfig.py
View file @
3bc13cc8
"""Tests for distutils.sysconfig."""
"""Tests for distutils.sysconfig."""
import
os
import
os
import
shutil
import
shutil
import
subprocess
import
sys
import
textwrap
import
unittest
import
unittest
from
distutils
import
sysconfig
from
distutils
import
sysconfig
...
@@ -174,6 +177,25 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
...
@@ -174,6 +177,25 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
self
.
assertIsNotNone
(
vars
[
'SO'
])
self
.
assertIsNotNone
(
vars
[
'SO'
])
self
.
assertEqual
(
vars
[
'SO'
],
vars
[
'EXT_SUFFIX'
])
self
.
assertEqual
(
vars
[
'SO'
],
vars
[
'EXT_SUFFIX'
])
def
test_customize_compiler_before_get_config_vars
(
self
):
# Issue #21923: test that a Distribution compiler
# instance can be called without an explicit call to
# get_config_vars().
with
open
(
TESTFN
,
'w'
)
as
f
:
f
.
writelines
(
textwrap
.
dedent
(
'''
\
from distutils.core import Distribution
config = Distribution().get_command_obj('config')
# try_compile may pass or it may fail if no compiler
# is found but it should not raise an exception.
rc = config.try_compile('int x;')
'''
))
p
=
subprocess
.
Popen
([
str
(
sys
.
executable
),
TESTFN
],
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
,
universal_newlines
=
True
)
outs
,
errs
=
p
.
communicate
()
self
.
assertEqual
(
0
,
p
.
returncode
,
"Subprocess failed: "
+
outs
)
def
test_suite
():
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
=
unittest
.
TestSuite
()
...
...
Lib/pathlib.py
View file @
3bc13cc8
...
@@ -749,17 +749,20 @@ class PurePath(object):
...
@@ -749,17 +749,20 @@ class PurePath(object):
"""Return a new path with the file name changed."""
"""Return a new path with the file name changed."""
if
not
self
.
name
:
if
not
self
.
name
:
raise
ValueError
(
"%r has an empty name"
%
(
self
,))
raise
ValueError
(
"%r has an empty name"
%
(
self
,))
drv
,
root
,
parts
=
self
.
_flavour
.
parse_parts
((
name
,))
if
(
not
name
or
name
[
-
1
]
in
[
self
.
_flavour
.
sep
,
self
.
_flavour
.
altsep
]
or
drv
or
root
or
len
(
parts
)
!=
1
):
raise
ValueError
(
"Invalid name %r"
%
(
name
))
return
self
.
_from_parsed_parts
(
self
.
_drv
,
self
.
_root
,
return
self
.
_from_parsed_parts
(
self
.
_drv
,
self
.
_root
,
self
.
_parts
[:
-
1
]
+
[
name
])
self
.
_parts
[:
-
1
]
+
[
name
])
def
with_suffix
(
self
,
suffix
):
def
with_suffix
(
self
,
suffix
):
"""Return a new path with the file suffix changed (or added, if none)."""
"""Return a new path with the file suffix changed (or added, if none)."""
# XXX if suffix is None, should the current suffix be removed?
# XXX if suffix is None, should the current suffix be removed?
drv
,
root
,
parts
=
self
.
_flavour
.
parse_parts
((
suffix
,))
f
=
self
.
_flavour
if
drv
or
root
or
len
(
parts
)
!=
1
:
if
f
.
sep
in
suffix
or
f
.
altsep
and
f
.
altsep
in
suffix
:
raise
ValueError
(
"Invalid suffix %r"
%
(
suffix
))
raise
ValueError
(
"Invalid suffix %r"
%
(
suffix
))
suffix
=
parts
[
0
]
if
suffix
and
not
suffix
.
startswith
(
'.'
)
or
suffix
==
'.'
:
if
not
suffix
.
startswith
(
'.'
):
raise
ValueError
(
"Invalid suffix %r"
%
(
suffix
))
raise
ValueError
(
"Invalid suffix %r"
%
(
suffix
))
name
=
self
.
name
name
=
self
.
name
if
not
name
:
if
not
name
:
...
...
Lib/test/test_asyncio/test_futures.py
View file @
3bc13cc8
...
@@ -343,6 +343,12 @@ class FutureTests(test_utils.TestCase):
...
@@ -343,6 +343,12 @@ class FutureTests(test_utils.TestCase):
message
=
m_log
.
error
.
call_args
[
0
][
0
]
message
=
m_log
.
error
.
call_args
[
0
][
0
]
self
.
assertRegex
(
message
,
re
.
compile
(
regex
,
re
.
DOTALL
))
self
.
assertRegex
(
message
,
re
.
compile
(
regex
,
re
.
DOTALL
))
def
test_set_result_unless_cancelled
(
self
):
fut
=
asyncio
.
Future
(
loop
=
self
.
loop
)
fut
.
cancel
()
fut
.
_set_result_unless_cancelled
(
2
)
self
.
assertTrue
(
fut
.
cancelled
())
class
FutureDoneCallbackTests
(
test_utils
.
TestCase
):
class
FutureDoneCallbackTests
(
test_utils
.
TestCase
):
...
...
Lib/test/test_asyncio/test_tasks.py
View file @
3bc13cc8
...
@@ -211,6 +211,10 @@ class TaskTests(test_utils.TestCase):
...
@@ -211,6 +211,10 @@ class TaskTests(test_utils.TestCase):
coro
=
(
'%s() at %s:%s'
coro
=
(
'%s() at %s:%s'
%
(
coro_qualname
,
code
.
co_filename
,
code
.
co_firstlineno
))
%
(
coro_qualname
,
code
.
co_filename
,
code
.
co_firstlineno
))
# test repr(CoroWrapper)
if
coroutines
.
_DEBUG
:
self
.
assertEqual
(
repr
(
gen
),
'<CoroWrapper %s>'
%
coro
)
# test pending Task
# test pending Task
t
=
asyncio
.
Task
(
gen
,
loop
=
self
.
loop
)
t
=
asyncio
.
Task
(
gen
,
loop
=
self
.
loop
)
t
.
add_done_callback
(
Dummy
())
t
.
add_done_callback
(
Dummy
())
...
...
Lib/test/test_frame.py
View file @
3bc13cc8
import
gc
import
gc
import
sys
import
sys
import
types
import
unittest
import
unittest
import
weakref
import
weakref
...
@@ -109,6 +110,57 @@ class ClearTest(unittest.TestCase):
...
@@ -109,6 +110,57 @@ class ClearTest(unittest.TestCase):
self
.
assertIs
(
None
,
wr
())
self
.
assertIs
(
None
,
wr
())
class
FrameLocalsTest
(
unittest
.
TestCase
):
"""
Tests for the .f_locals attribute.
"""
def
make_frames
(
self
):
def
outer
():
x
=
5
y
=
6
def
inner
():
z
=
x
+
2
1
/
0
t
=
9
return
inner
()
try
:
outer
()
except
ZeroDivisionError
as
e
:
tb
=
e
.
__traceback__
frames
=
[]
while
tb
:
frames
.
append
(
tb
.
tb_frame
)
tb
=
tb
.
tb_next
return
frames
def
test_locals
(
self
):
f
,
outer
,
inner
=
self
.
make_frames
()
outer_locals
=
outer
.
f_locals
self
.
assertIsInstance
(
outer_locals
.
pop
(
'inner'
),
types
.
FunctionType
)
self
.
assertEqual
(
outer_locals
,
{
'x'
:
5
,
'y'
:
6
})
inner_locals
=
inner
.
f_locals
self
.
assertEqual
(
inner_locals
,
{
'x'
:
5
,
'z'
:
7
})
def
test_clear_locals
(
self
):
# Test f_locals after clear() (issue #21897)
f
,
outer
,
inner
=
self
.
make_frames
()
outer
.
clear
()
inner
.
clear
()
self
.
assertEqual
(
outer
.
f_locals
,
{})
self
.
assertEqual
(
inner
.
f_locals
,
{})
def
test_locals_clear_locals
(
self
):
# Test f_locals before and after clear() (to exercise caching)
f
,
outer
,
inner
=
self
.
make_frames
()
outer
.
f_locals
inner
.
f_locals
outer
.
clear
()
inner
.
clear
()
self
.
assertEqual
(
outer
.
f_locals
,
{})
self
.
assertEqual
(
inner
.
f_locals
,
{})
def
test_main
():
def
test_main
():
support
.
run_unittest
(
__name__
)
support
.
run_unittest
(
__name__
)
...
...
Lib/test/test_pathlib.py
View file @
3bc13cc8
...
@@ -540,6 +540,10 @@ class _BasePurePathTest(object):
...
@@ -540,6 +540,10 @@ class _BasePurePathTest(object):
self
.
assertRaises
(
ValueError
,
P
(
''
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
''
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'.'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'.'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'/'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'/'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_name
,
''
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_name
,
'/c'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_name
,
'c/'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_name
,
'c/d'
)
def
test_with_suffix_common
(
self
):
def
test_with_suffix_common
(
self
):
P
=
self
.
cls
P
=
self
.
cls
...
@@ -547,6 +551,9 @@ class _BasePurePathTest(object):
...
@@ -547,6 +551,9 @@ class _BasePurePathTest(object):
self
.
assertEqual
(
P
(
'/a/b'
).
with_suffix
(
'.gz'
),
P
(
'/a/b.gz'
))
self
.
assertEqual
(
P
(
'/a/b'
).
with_suffix
(
'.gz'
),
P
(
'/a/b.gz'
))
self
.
assertEqual
(
P
(
'a/b.py'
).
with_suffix
(
'.gz'
),
P
(
'a/b.gz'
))
self
.
assertEqual
(
P
(
'a/b.py'
).
with_suffix
(
'.gz'
),
P
(
'a/b.gz'
))
self
.
assertEqual
(
P
(
'/a/b.py'
).
with_suffix
(
'.gz'
),
P
(
'/a/b.gz'
))
self
.
assertEqual
(
P
(
'/a/b.py'
).
with_suffix
(
'.gz'
),
P
(
'/a/b.gz'
))
# Stripping suffix
self
.
assertEqual
(
P
(
'a/b.py'
).
with_suffix
(
''
),
P
(
'a/b'
))
self
.
assertEqual
(
P
(
'/a/b'
).
with_suffix
(
''
),
P
(
'/a/b'
))
# Path doesn't have a "filename" component
# Path doesn't have a "filename" component
self
.
assertRaises
(
ValueError
,
P
(
''
).
with_suffix
,
'.gz'
)
self
.
assertRaises
(
ValueError
,
P
(
''
).
with_suffix
,
'.gz'
)
self
.
assertRaises
(
ValueError
,
P
(
'.'
).
with_suffix
,
'.gz'
)
self
.
assertRaises
(
ValueError
,
P
(
'.'
).
with_suffix
,
'.gz'
)
...
@@ -554,9 +561,12 @@ class _BasePurePathTest(object):
...
@@ -554,9 +561,12 @@ class _BasePurePathTest(object):
# Invalid suffix
# Invalid suffix
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'gz'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'gz'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'/'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'/'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'.'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'/.gz'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'/.gz'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'c/d'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'c/d'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'.c/.d'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'.c/.d'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'./.d'
)
self
.
assertRaises
(
ValueError
,
P
(
'a/b'
).
with_suffix
,
'.d/.'
)
def
test_relative_to_common
(
self
):
def
test_relative_to_common
(
self
):
P
=
self
.
cls
P
=
self
.
cls
...
@@ -950,6 +960,10 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
...
@@ -950,6 +960,10 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
self
.
assertRaises
(
ValueError
,
P
(
'c:'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:/'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:/'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'//My/Share'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'//My/Share'
).
with_name
,
'd.xml'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:a/b'
).
with_name
,
'd:'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:a/b'
).
with_name
,
'd:e'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:a/b'
).
with_name
,
'd:/e'
)
self
.
assertRaises
(
ValueError
,
P
(
'c:a/b'
).
with_name
,
'//My/Share'
)
def
test_with_suffix
(
self
):
def
test_with_suffix
(
self
):
P
=
self
.
cls
P
=
self
.
cls
...
...
Misc/NEWS
View file @
3bc13cc8
...
@@ -27,6 +27,15 @@ Core and Builtins
...
@@ -27,6 +27,15 @@ Core and Builtins
Library
Library
-------
-------
- Issue #20639: calling Path.with_suffix('') allows removing the suffix
again. Patch by July Tikhonov.
- Issue #21714: Disallow the construction of invalid paths using
Path.with_name(). Original patch by Antony Lee.
- Issue #21897: Fix a crash with the f_locals attribute with closure
variables when frame.clear() has been called.
- Issue #21151: Fixed a segfault in the winreg module when ``None`` is passed
- Issue #21151: Fixed a segfault in the winreg module when ``None`` is passed
as a ``REG_BINARY`` value to SetValueEx. Patch by John Ehresman.
as a ``REG_BINARY`` value to SetValueEx. Patch by John Ehresman.
...
@@ -133,6 +142,9 @@ Library
...
@@ -133,6 +142,9 @@ Library
-
Issue
#
21801
:
Validate
that
__signature__
is
None
or
an
instance
of
Signature
.
-
Issue
#
21801
:
Validate
that
__signature__
is
None
or
an
instance
of
Signature
.
-
Issue
#
21923
:
Prevent
AttributeError
in
distutils
.
sysconfig
.
customize_compiler
due
to
possible
uninitialized
_config_vars
.
Build
Build
-----
-----
...
...
Modules/_io/_iomodule.c
View file @
3bc13cc8
...
@@ -465,11 +465,13 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
...
@@ -465,11 +465,13 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds)
error:
error:
if
(
result
!=
NULL
)
{
if
(
result
!=
NULL
)
{
PyObject
*
exc
,
*
val
,
*
tb
;
PyObject
*
exc
,
*
val
,
*
tb
,
*
close_result
;
PyErr_Fetch
(
&
exc
,
&
val
,
&
tb
);
PyErr_Fetch
(
&
exc
,
&
val
,
&
tb
);
if
(
_PyObject_CallMethodId
(
result
,
&
PyId_close
,
NULL
)
!=
NULL
)
close_result
=
_PyObject_CallMethodId
(
result
,
&
PyId_close
,
NULL
);
if
(
close_result
!=
NULL
)
{
Py_DECREF
(
close_result
);
PyErr_Restore
(
exc
,
val
,
tb
);
PyErr_Restore
(
exc
,
val
,
tb
);
else
{
}
else
{
PyObject
*
exc2
,
*
val2
,
*
tb2
;
PyObject
*
exc2
,
*
val2
,
*
tb2
;
PyErr_Fetch
(
&
exc2
,
&
val2
,
&
tb2
);
PyErr_Fetch
(
&
exc2
,
&
val2
,
&
tb2
);
PyErr_NormalizeException
(
&
exc
,
&
val
,
&
tb
);
PyErr_NormalizeException
(
&
exc
,
&
val
,
&
tb
);
...
...
Objects/frameobject.c
View file @
3bc13cc8
...
@@ -786,7 +786,7 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
...
@@ -786,7 +786,7 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
PyObject
*
key
=
PyTuple_GET_ITEM
(
map
,
j
);
PyObject
*
key
=
PyTuple_GET_ITEM
(
map
,
j
);
PyObject
*
value
=
values
[
j
];
PyObject
*
value
=
values
[
j
];
assert
(
PyUnicode_Check
(
key
));
assert
(
PyUnicode_Check
(
key
));
if
(
deref
)
{
if
(
deref
&&
value
!=
NULL
)
{
assert
(
PyCell_Check
(
value
));
assert
(
PyCell_Check
(
value
));
value
=
PyCell_GET
(
value
);
value
=
PyCell_GET
(
value
);
}
}
...
...
Objects/unicodeobject.c
View file @
3bc13cc8
...
@@ -1372,9 +1372,8 @@ PyUnicode_CopyCharacters(PyObject *to, Py_ssize_t to_start,
...
@@ -1372,9 +1372,8 @@ PyUnicode_CopyCharacters(PyObject *to, Py_ssize_t to_start,
how_many
=
Py_MIN
(
PyUnicode_GET_LENGTH
(
from
),
how_many
);
how_many
=
Py_MIN
(
PyUnicode_GET_LENGTH
(
from
),
how_many
);
if
(
to_start
+
how_many
>
PyUnicode_GET_LENGTH
(
to
))
{
if
(
to_start
+
how_many
>
PyUnicode_GET_LENGTH
(
to
))
{
PyErr_Format
(
PyExc_SystemError
,
PyErr_Format
(
PyExc_SystemError
,
"Cannot write %"
PY_FORMAT_SIZE_T
"i characters at %"
"Cannot write %zi characters at %zi "
PY_FORMAT_SIZE_T
"i in a string of %"
"in a string of %zi characters"
,
PY_FORMAT_SIZE_T
"i characters"
,
how_many
,
to_start
,
PyUnicode_GET_LENGTH
(
to
));
how_many
,
to_start
,
PyUnicode_GET_LENGTH
(
to
));
return
-
1
;
return
-
1
;
}
}
...
@@ -4083,9 +4082,7 @@ unicode_decode_call_errorhandler_wchar(
...
@@ -4083,9 +4082,7 @@ unicode_decode_call_errorhandler_wchar(
if
(
newpos
<
0
)
if
(
newpos
<
0
)
newpos
=
insize
+
newpos
;
newpos
=
insize
+
newpos
;
if
(
newpos
<
0
||
newpos
>
insize
)
{
if
(
newpos
<
0
||
newpos
>
insize
)
{
PyErr_Format
(
PyExc_IndexError
,
PyErr_Format
(
PyExc_IndexError
,
"position %zd from error handler out of bounds"
,
newpos
);
"position %"
PY_FORMAT_SIZE_T
"d from error handler out of bounds"
,
newpos
);
goto
onError
;
goto
onError
;
}
}
...
@@ -4178,9 +4175,7 @@ unicode_decode_call_errorhandler_writer(
...
@@ -4178,9 +4175,7 @@ unicode_decode_call_errorhandler_writer(
if
(
newpos
<
0
)
if
(
newpos
<
0
)
newpos
=
insize
+
newpos
;
newpos
=
insize
+
newpos
;
if
(
newpos
<
0
||
newpos
>
insize
)
{
if
(
newpos
<
0
||
newpos
>
insize
)
{
PyErr_Format
(
PyExc_IndexError
,
PyErr_Format
(
PyExc_IndexError
,
"position %zd from error handler out of bounds"
,
newpos
);
"position %"
PY_FORMAT_SIZE_T
"d from error handler out of bounds"
,
newpos
);
goto
onError
;
goto
onError
;
}
}
...
@@ -6443,9 +6438,7 @@ unicode_encode_call_errorhandler(const char *errors,
...
@@ -6443,9 +6438,7 @@ unicode_encode_call_errorhandler(const char *errors,
if
(
*
newpos
<
0
)
if
(
*
newpos
<
0
)
*
newpos
=
len
+
*
newpos
;
*
newpos
=
len
+
*
newpos
;
if
(
*
newpos
<
0
||
*
newpos
>
len
)
{
if
(
*
newpos
<
0
||
*
newpos
>
len
)
{
PyErr_Format
(
PyExc_IndexError
,
PyErr_Format
(
PyExc_IndexError
,
"position %zd from error handler out of bounds"
,
*
newpos
);
"position %"
PY_FORMAT_SIZE_T
"d from error handler out of bounds"
,
*
newpos
);
Py_DECREF
(
restuple
);
Py_DECREF
(
restuple
);
return
NULL
;
return
NULL
;
}
}
...
@@ -8468,9 +8461,7 @@ unicode_translate_call_errorhandler(const char *errors,
...
@@ -8468,9 +8461,7 @@ unicode_translate_call_errorhandler(const char *errors,
else
else
*
newpos
=
i_newpos
;
*
newpos
=
i_newpos
;
if
(
*
newpos
<
0
||
*
newpos
>
PyUnicode_GET_LENGTH
(
unicode
))
{
if
(
*
newpos
<
0
||
*
newpos
>
PyUnicode_GET_LENGTH
(
unicode
))
{
PyErr_Format
(
PyExc_IndexError
,
PyErr_Format
(
PyExc_IndexError
,
"position %zd from error handler out of bounds"
,
*
newpos
);
"position %"
PY_FORMAT_SIZE_T
"d from error handler out of bounds"
,
*
newpos
);
Py_DECREF
(
restuple
);
Py_DECREF
(
restuple
);
return
NULL
;
return
NULL
;
}
}
...
@@ -9752,8 +9743,7 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
...
@@ -9752,8 +9743,7 @@ PyUnicode_Join(PyObject *separator, PyObject *seq)
item
=
items
[
i
];
item
=
items
[
i
];
if
(
!
PyUnicode_Check
(
item
))
{
if
(
!
PyUnicode_Check
(
item
))
{
PyErr_Format
(
PyExc_TypeError
,
PyErr_Format
(
PyExc_TypeError
,
"sequence item %"
PY_FORMAT_SIZE_T
"sequence item %zd: expected str instance,"
"d: expected str instance,"
" %.80s found"
,
" %.80s found"
,
i
,
Py_TYPE
(
item
)
->
tp_name
);
i
,
Py_TYPE
(
item
)
->
tp_name
);
goto
onError
;
goto
onError
;
...
@@ -14452,7 +14442,7 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
...
@@ -14452,7 +14442,7 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx,
default:
default:
PyErr_Format
(
PyExc_ValueError
,
PyErr_Format
(
PyExc_ValueError
,
"unsupported format character '%c' (0x%x) "
"unsupported format character '%c' (0x%x) "
"at index %
"
PY_FORMAT_SIZE_T
"
d"
,
"at index %
z
d"
,
(
31
<=
arg
->
ch
&&
arg
->
ch
<=
126
)
?
(
char
)
arg
->
ch
:
'?'
,
(
31
<=
arg
->
ch
&&
arg
->
ch
<=
126
)
?
(
char
)
arg
->
ch
:
'?'
,
(
int
)
arg
->
ch
,
(
int
)
arg
->
ch
,
ctx
->
fmtpos
-
1
);
ctx
->
fmtpos
-
1
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment