mirror of
https://github.com/python/cpython.git
synced 2024-11-24 18:34:43 +08:00
Merge heads
This commit is contained in:
commit
c366117820
@ -38,6 +38,16 @@ There are a few functions specific to Python functions.
|
||||
object, the argument defaults and closure are set to *NULL*.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
|
||||
|
||||
As :c:func:`PyFunction_New`, but also allows to set the function object's
|
||||
``__qualname__`` attribute. *qualname* should be a unicode object or NULL;
|
||||
if NULL, the ``__qualname__`` attribute is set to the same value as its
|
||||
``__name__`` attribute.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyFunction_GetCode(PyObject *op)
|
||||
|
||||
Return the code object associated with the function object *op*.
|
||||
|
@ -17,7 +17,7 @@ any other object.
|
||||
|
||||
Create a memoryview object from an object that provides the buffer interface.
|
||||
If *obj* supports writable buffer exports, the memoryview object will be
|
||||
readable and writable, other it will be read-only.
|
||||
readable and writable, otherwise it will be read-only.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyMemoryView_FromBuffer(Py_buffer *view)
|
||||
@ -33,7 +33,7 @@ any other object.
|
||||
Create a memoryview object to a contiguous chunk of memory (in either
|
||||
'C' or 'F'ortran *order*) from an object that defines the buffer
|
||||
interface. If memory is contiguous, the memoryview object points to the
|
||||
original memory. Otherwise copy is made and the memoryview points to a
|
||||
original memory. Otherwise, a copy is made and the memoryview points to a
|
||||
new bytes object.
|
||||
|
||||
|
||||
|
@ -465,6 +465,11 @@ PyFunction_New:PyObject*::+1:
|
||||
PyFunction_New:PyObject*:code:+1:
|
||||
PyFunction_New:PyObject*:globals:+1:
|
||||
|
||||
PyFunction_NewWithQualName:PyObject*::+1:
|
||||
PyFunction_NewWithQualName:PyObject*:code:+1:
|
||||
PyFunction_NewWithQualName:PyObject*:globals:+1:
|
||||
PyFunction_NewWithQualName:PyObject*:qualname:+1:
|
||||
|
||||
PyFunction_SetClosure:int:::
|
||||
PyFunction_SetClosure:PyObject*:op:0:
|
||||
PyFunction_SetClosure:PyObject*:closure:+1:
|
||||
|
@ -989,6 +989,32 @@ What does 'UnicodeDecodeError' or 'UnicodeEncodeError' error mean?
|
||||
See the :ref:`unicode-howto`.
|
||||
|
||||
|
||||
What is the most efficient way to concatenate many strings together?
|
||||
--------------------------------------------------------------------
|
||||
|
||||
:class:`str` and :class:`bytes` objects are immutable, therefore concatenating
|
||||
many strings together is inefficient as each concatenation creates a new
|
||||
object. In the general case, the total runtime cost is quadratic in the
|
||||
total string length.
|
||||
|
||||
To accumulate many :class:`str` objects, the recommended idiom is to place
|
||||
them into a list and call :meth:`str.join` at the end::
|
||||
|
||||
chunks = []
|
||||
for s in my_strings:
|
||||
chunks.append(s)
|
||||
result = ''.join(chunks)
|
||||
|
||||
(another reasonably efficient idiom is to use :class:`io.StringIO`)
|
||||
|
||||
To accumulate many :class:`bytes` objects, the recommended idiom is to extend
|
||||
a :class:`bytearray` object using in-place concatenation (the ``+=`` operator)::
|
||||
|
||||
result = bytearray()
|
||||
for b in my_bytes_objects:
|
||||
result += b
|
||||
|
||||
|
||||
Sequences (Tuples/Lists)
|
||||
========================
|
||||
|
||||
|
@ -544,6 +544,24 @@ Glossary
|
||||
for piece in food:
|
||||
print(piece)
|
||||
|
||||
qualified name
|
||||
A dotted name showing the "path" from a module's global scope to a
|
||||
class, function or method defined in that module, as defined in
|
||||
:pep:`3155`. For top-level functions and classes, the qualified name
|
||||
is the same as the object's name::
|
||||
|
||||
>>> class C:
|
||||
... class D:
|
||||
... def meth(self):
|
||||
... pass
|
||||
...
|
||||
>>> C.__qualname__
|
||||
'C'
|
||||
>>> C.D.__qualname__
|
||||
'C.D'
|
||||
>>> C.D.meth.__qualname__
|
||||
'C.D.meth'
|
||||
|
||||
reference count
|
||||
The number of references to an object. When the reference count of an
|
||||
object drops to zero, it is deallocated. Reference counting is
|
||||
|
@ -653,7 +653,7 @@ Window Objects
|
||||
--------------
|
||||
|
||||
Window objects, as returned by :func:`initscr` and :func:`newwin` above, have
|
||||
the following methods:
|
||||
the following methods and attributes:
|
||||
|
||||
|
||||
.. method:: window.addch([y, x,] ch[, attr])
|
||||
@ -834,6 +834,16 @@ the following methods:
|
||||
event.
|
||||
|
||||
|
||||
.. attribute:: window.encoding
|
||||
|
||||
Encoding used to encode method arguments (Unicode strings and characters).
|
||||
The encoding attribute is inherited from by parent window when a subwindow
|
||||
is created, for example with :meth:`window.subwin`. By default, the locale
|
||||
encoding is used (see :func:`locale.getpreferredencoding`).
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
|
||||
.. method:: window.erase()
|
||||
|
||||
Clear the window.
|
||||
|
@ -968,15 +968,18 @@ Notes:
|
||||
If *k* is ``None``, it is treated like ``1``.
|
||||
|
||||
(6)
|
||||
.. impl-detail::
|
||||
Concatenating immutable strings always results in a new object. This means
|
||||
that building up a string by repeated concatenation will have a quadratic
|
||||
runtime cost in the total string length. To get a linear runtime cost,
|
||||
you must switch to one of the alternatives below:
|
||||
|
||||
If *s* and *t* are both strings, some Python implementations such as
|
||||
CPython can usually perform an in-place optimization for assignments of
|
||||
the form ``s = s + t`` or ``s += t``. When applicable, this optimization
|
||||
makes quadratic run-time much less likely. This optimization is both
|
||||
version and implementation dependent. For performance sensitive code, it
|
||||
is preferable to use the :meth:`str.join` method which assures consistent
|
||||
linear concatenation performance across versions and implementations.
|
||||
* if concatenating :class:`str` objects, you can build a list and use
|
||||
:meth:`str.join` at the end;
|
||||
|
||||
* if concatenating :class:`bytes` objects, you can similarly use
|
||||
:meth:`bytes.join`, or you can do in-place concatenation with a
|
||||
:class:`bytearray` object. :class:`bytearray` objects are mutable and
|
||||
have an efficient overallocation mechanism.
|
||||
|
||||
|
||||
.. _string-methods:
|
||||
@ -2821,6 +2824,13 @@ types, where they are relevant. Some of these are not reported by the
|
||||
The name of the class or type.
|
||||
|
||||
|
||||
.. attribute:: class.__qualname__
|
||||
|
||||
The :term:`qualified name` of the class or type.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
|
||||
.. attribute:: class.__mro__
|
||||
|
||||
This attribute is a tuple of classes that are considered when looking for
|
||||
|
@ -448,6 +448,11 @@ Callable types
|
||||
+-------------------------+-------------------------------+-----------+
|
||||
| :attr:`__name__` | The function's name | Writable |
|
||||
+-------------------------+-------------------------------+-----------+
|
||||
| :attr:`__qualname__` | The function's | Writable |
|
||||
| | :term:`qualified name` | |
|
||||
| | | |
|
||||
| | .. versionadded:: 3.3 | |
|
||||
+-------------------------+-------------------------------+-----------+
|
||||
| :attr:`__module__` | The name of the module the | Writable |
|
||||
| | function was defined in, or | |
|
||||
| | ``None`` if unavailable. | |
|
||||
|
@ -189,6 +189,65 @@ inspection of exception attributes::
|
||||
print("You are not allowed to read document.txt")
|
||||
|
||||
|
||||
PEP 3155: Qualified name for classes and functions
|
||||
==================================================
|
||||
|
||||
:pep:`3155` - Qualified name for classes and functions
|
||||
PEP written and implemented by Antoine Pitrou.
|
||||
|
||||
Functions and class objects have a new ``__qualname__`` attribute representing
|
||||
the "path" from the module top-level to their definition. For global functions
|
||||
and classes, this is the same as ``__name__``. For other functions and classes,
|
||||
it provides better information about where they were actually defined, and
|
||||
how they might be accessible from the global scope.
|
||||
|
||||
Example with (non-bound) methods::
|
||||
|
||||
>>> class C:
|
||||
... def meth(self):
|
||||
... pass
|
||||
>>> C.meth.__name__
|
||||
'meth'
|
||||
>>> C.meth.__qualname__
|
||||
'C.meth'
|
||||
|
||||
Example with nested classes::
|
||||
|
||||
>>> class C:
|
||||
... class D:
|
||||
... def meth(self):
|
||||
... pass
|
||||
...
|
||||
>>> C.D.__name__
|
||||
'D'
|
||||
>>> C.D.__qualname__
|
||||
'C.D'
|
||||
>>> C.D.meth.__name__
|
||||
'meth'
|
||||
>>> C.D.meth.__qualname__
|
||||
'C.D.meth'
|
||||
|
||||
Example with nested functions::
|
||||
|
||||
>>> def outer():
|
||||
... def inner():
|
||||
... pass
|
||||
... return inner
|
||||
...
|
||||
>>> outer().__name__
|
||||
'inner'
|
||||
>>> outer().__qualname__
|
||||
'outer.<locals>.inner'
|
||||
|
||||
The string representation of those objects is also changed to include the
|
||||
new, more precise information::
|
||||
|
||||
>>> str(C.D)
|
||||
"<class '__main__.C.D'>"
|
||||
>>> str(C.D.meth)
|
||||
'<function C.D.meth at 0x7f46b9fe31e0>'
|
||||
|
||||
|
||||
Other Language Changes
|
||||
======================
|
||||
|
||||
@ -274,6 +333,11 @@ function to the :mod:`crypt` module.
|
||||
curses
|
||||
------
|
||||
|
||||
* If the :mod:`curses` module is linked to the ncursesw library, use Unicode
|
||||
functions when Unicode strings or characters are passed (e.g.
|
||||
:c:func:`waddwstr`), and bytes functions otherwise (e.g. :c:func:`waddstr`).
|
||||
* Use the locale encoding instead of ``utf-8`` to encode Unicode strings.
|
||||
* :class:`curses.window` has a new :attr:`curses.window.encoding` attribute.
|
||||
* The :class:`curses.window` class has a new :meth:`~curses.window.get_wch`
|
||||
method to get a wide character
|
||||
* The :mod:`curses` module has a new :meth:`~curses.unget_wch` function to
|
||||
|
@ -31,6 +31,7 @@ typedef struct {
|
||||
PyObject *func_weakreflist; /* List of weak references */
|
||||
PyObject *func_module; /* The __module__ attribute, can be anything */
|
||||
PyObject *func_annotations; /* Annotations, a dict or NULL */
|
||||
PyObject *func_qualname; /* The qualified name */
|
||||
|
||||
/* Invariant:
|
||||
* func_closure contains the bindings for func_code->co_freevars, so
|
||||
@ -44,6 +45,7 @@ PyAPI_DATA(PyTypeObject) PyFunction_Type;
|
||||
#define PyFunction_Check(op) (Py_TYPE(op) == &PyFunction_Type)
|
||||
|
||||
PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyFunction_NewWithQualName(PyObject *, PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
|
||||
|
@ -418,7 +418,7 @@ typedef struct _heaptypeobject {
|
||||
a given operator (e.g. __getitem__).
|
||||
see add_operators() in typeobject.c . */
|
||||
PyBufferProcs as_buffer;
|
||||
PyObject *ht_name, *ht_slots;
|
||||
PyObject *ht_name, *ht_slots, *ht_qualname;
|
||||
/* here are optional user slots, followed by the members. */
|
||||
} PyHeapTypeObject;
|
||||
|
||||
|
@ -76,6 +76,7 @@ extern "C" {
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
WINDOW *win;
|
||||
char *encoding;
|
||||
} PyCursesWindowObject;
|
||||
|
||||
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)
|
||||
|
@ -166,7 +166,7 @@ def visiblename(name, all=None, obj=None):
|
||||
if name in {'__builtins__', '__doc__', '__file__', '__path__',
|
||||
'__module__', '__name__', '__slots__', '__package__',
|
||||
'__cached__', '__author__', '__credits__', '__date__',
|
||||
'__version__'}:
|
||||
'__version__', '__qualname__'}:
|
||||
return 0
|
||||
# Private names are hidden, but special names are displayed.
|
||||
if name.startswith('__') and name.endswith('__'): return 1
|
||||
|
@ -108,8 +108,13 @@ class _RandomNameSequence:
|
||||
|
||||
characters = "abcdefghijklmnopqrstuvwxyz0123456789_"
|
||||
|
||||
def __init__(self):
|
||||
self.rng = _Random()
|
||||
@property
|
||||
def rng(self):
|
||||
cur_pid = _os.getpid()
|
||||
if cur_pid != getattr(self, '_rng_pid', None):
|
||||
self._rng = _Random()
|
||||
self._rng_pid = cur_pid
|
||||
return self._rng
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
@ -578,8 +583,13 @@ class SpooledTemporaryFile:
|
||||
def tell(self):
|
||||
return self._file.tell()
|
||||
|
||||
def truncate(self):
|
||||
self._file.truncate()
|
||||
def truncate(self, size=None):
|
||||
if size is None:
|
||||
self._file.truncate()
|
||||
else:
|
||||
if size > self._max_size:
|
||||
self.rollover()
|
||||
self._file.truncate(size)
|
||||
|
||||
def write(self, s):
|
||||
file = self._file
|
||||
|
@ -16,7 +16,7 @@ cellvars: ('x',)
|
||||
freevars: ()
|
||||
nlocals: 2
|
||||
flags: 3
|
||||
consts: ('None', '<code object g>')
|
||||
consts: ('None', '<code object g>', "'f.<locals>.g'")
|
||||
|
||||
>>> dump(f(4).__code__)
|
||||
name: g
|
||||
|
@ -267,24 +267,42 @@ def test_issue6243(stdscr):
|
||||
def test_unget_wch(stdscr):
|
||||
if not hasattr(curses, 'unget_wch'):
|
||||
return
|
||||
ch = 'a'
|
||||
curses.unget_wch(ch)
|
||||
read = stdscr.get_wch()
|
||||
read = chr(read)
|
||||
if read != ch:
|
||||
raise AssertionError("%r != %r" % (read, ch))
|
||||
for ch in ('a', '\xe9', '\u20ac', '\U0010FFFF'):
|
||||
curses.unget_wch(ch)
|
||||
read = stdscr.get_wch()
|
||||
read = chr(read)
|
||||
if read != ch:
|
||||
raise AssertionError("%r != %r" % (read, ch))
|
||||
|
||||
ch = ord('a')
|
||||
curses.unget_wch(ch)
|
||||
read = stdscr.get_wch()
|
||||
if read != ch:
|
||||
raise AssertionError("%r != %r" % (read, ch))
|
||||
code = ord(ch)
|
||||
curses.unget_wch(code)
|
||||
read = stdscr.get_wch()
|
||||
if read != code:
|
||||
raise AssertionError("%r != %r" % (read, code))
|
||||
|
||||
def test_issue10570():
|
||||
b = curses.tparm(curses.tigetstr("cup"), 5, 3)
|
||||
assert type(b) is bytes
|
||||
curses.putp(b)
|
||||
|
||||
def test_encoding(stdscr):
|
||||
import codecs
|
||||
encoding = stdscr.encoding
|
||||
codecs.lookup(encoding)
|
||||
try:
|
||||
stdscr.encoding = 10
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("TypeError not raised")
|
||||
stdscr.encoding = encoding
|
||||
try:
|
||||
del stdscr.encoding
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("TypeError not raised")
|
||||
|
||||
def main(stdscr):
|
||||
curses.savetty()
|
||||
try:
|
||||
@ -295,6 +313,7 @@ def main(stdscr):
|
||||
test_issue6243(stdscr)
|
||||
test_unget_wch(stdscr)
|
||||
test_issue10570()
|
||||
test_encoding(stdscr)
|
||||
finally:
|
||||
curses.resetty()
|
||||
|
||||
|
@ -4492,9 +4492,14 @@ class DictProxyTests(unittest.TestCase):
|
||||
self.assertEqual(type(C.__dict__), type(B.__dict__))
|
||||
|
||||
def test_repr(self):
|
||||
# Testing dict_proxy.__repr__
|
||||
dict_ = {k: v for k, v in self.C.__dict__.items()}
|
||||
self.assertEqual(repr(self.C.__dict__), 'dict_proxy({!r})'.format(dict_))
|
||||
# Testing dict_proxy.__repr__.
|
||||
# We can't blindly compare with the repr of another dict as ordering
|
||||
# of keys and values is arbitrary and may differ.
|
||||
r = repr(self.C.__dict__)
|
||||
self.assertTrue(r.startswith('dict_proxy('), r)
|
||||
self.assertTrue(r.endswith(')'), r)
|
||||
for k, v in self.C.__dict__.items():
|
||||
self.assertIn('{!r}: {!r}'.format(k, v), r)
|
||||
|
||||
|
||||
class PTypesLongInitTest(unittest.TestCase):
|
||||
|
@ -339,6 +339,7 @@ Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
|
||||
Constants:
|
||||
0: None
|
||||
1: <code object f at (.*), file "(.*)", line (.*)>
|
||||
2: 'tricky.<locals>.f'
|
||||
Variable names:
|
||||
0: x
|
||||
1: y
|
||||
|
@ -2,6 +2,15 @@ from test import support
|
||||
import types
|
||||
import unittest
|
||||
|
||||
|
||||
def global_function():
|
||||
def inner_function():
|
||||
class LocalClass:
|
||||
pass
|
||||
return LocalClass
|
||||
return lambda: inner_function
|
||||
|
||||
|
||||
class FuncAttrsTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
class F:
|
||||
@ -96,6 +105,24 @@ class FunctionPropertiesTest(FuncAttrsTest):
|
||||
self.assertEqual(self.fi.a.__name__, 'a')
|
||||
self.cannot_set_attr(self.fi.a, "__name__", 'a', AttributeError)
|
||||
|
||||
def test___qualname__(self):
|
||||
# PEP 3155
|
||||
self.assertEqual(self.b.__qualname__, 'FuncAttrsTest.setUp.<locals>.b')
|
||||
self.assertEqual(FuncAttrsTest.setUp.__qualname__, 'FuncAttrsTest.setUp')
|
||||
self.assertEqual(global_function.__qualname__, 'global_function')
|
||||
self.assertEqual(global_function().__qualname__,
|
||||
'global_function.<locals>.<lambda>')
|
||||
self.assertEqual(global_function()().__qualname__,
|
||||
'global_function.<locals>.inner_function')
|
||||
self.assertEqual(global_function()()().__qualname__,
|
||||
'global_function.<locals>.inner_function.<locals>.LocalClass')
|
||||
self.b.__qualname__ = 'c'
|
||||
self.assertEqual(self.b.__qualname__, 'c')
|
||||
self.b.__qualname__ = 'd'
|
||||
self.assertEqual(self.b.__qualname__, 'd')
|
||||
# __qualname__ must be a string
|
||||
self.cannot_set_attr(self.b, '__qualname__', 7, TypeError)
|
||||
|
||||
def test___code__(self):
|
||||
num_one, num_two = 7, 8
|
||||
def a(): pass
|
||||
|
@ -159,6 +159,7 @@ Use a __prepare__ method that returns an instrumented dict.
|
||||
... bar = 123
|
||||
...
|
||||
d['__module__'] = 'test.test_metaclass'
|
||||
d['__qualname__'] = 'C'
|
||||
d['foo'] = 4
|
||||
d['foo'] = 42
|
||||
d['bar'] = 123
|
||||
@ -177,12 +178,12 @@ Use a metaclass that doesn't derive from type.
|
||||
... b = 24
|
||||
...
|
||||
meta: C ()
|
||||
ns: [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
|
||||
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
|
||||
kw: []
|
||||
>>> type(C) is dict
|
||||
True
|
||||
>>> print(sorted(C.items()))
|
||||
[('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
|
||||
[('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
|
||||
>>>
|
||||
|
||||
And again, with a __prepare__ attribute.
|
||||
@ -199,11 +200,12 @@ And again, with a __prepare__ attribute.
|
||||
...
|
||||
prepare: C () [('other', 'booh')]
|
||||
d['__module__'] = 'test.test_metaclass'
|
||||
d['__qualname__'] = 'C'
|
||||
d['a'] = 1
|
||||
d['a'] = 2
|
||||
d['b'] = 3
|
||||
meta: C ()
|
||||
ns: [('__module__', 'test.test_metaclass'), ('a', 2), ('b', 3)]
|
||||
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 2), ('b', 3)]
|
||||
kw: [('other', 'booh')]
|
||||
>>>
|
||||
|
||||
|
@ -129,8 +129,8 @@ class ReprTests(unittest.TestCase):
|
||||
self.assertIn(s.find("..."), [12, 13])
|
||||
|
||||
def test_lambda(self):
|
||||
self.assertTrue(repr(lambda x: x).startswith(
|
||||
"<function <lambda"))
|
||||
r = repr(lambda x: x)
|
||||
self.assertTrue(r.startswith("<function ReprTests.test_lambda.<locals>.<lambda"), r)
|
||||
# XXX anonymous functions? see func_repr
|
||||
|
||||
def test_builtin_function(self):
|
||||
@ -278,13 +278,14 @@ class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
''')
|
||||
from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
|
||||
# Unbound methods first
|
||||
self.assertTrue(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod).startswith(
|
||||
'<function amethod'))
|
||||
r = repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod)
|
||||
self.assertTrue(r.startswith('<function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod'), r)
|
||||
# Bound method next
|
||||
iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
|
||||
self.assertTrue(repr(iqux.amethod).startswith(
|
||||
r = repr(iqux.amethod)
|
||||
self.assertTrue(r.startswith(
|
||||
'<bound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod of <%s.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa object at 0x' \
|
||||
% (qux.__name__,) ))
|
||||
% (qux.__name__,) ), r)
|
||||
|
||||
def test_builtin_function(self):
|
||||
# XXX test built-in functions and methods with really long names
|
||||
|
@ -730,7 +730,7 @@ class SizeofTest(unittest.TestCase):
|
||||
check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
|
||||
# function
|
||||
def func(): pass
|
||||
check(func, size(h + '11P'))
|
||||
check(func, size(h + '12P'))
|
||||
class c():
|
||||
@staticmethod
|
||||
def foo():
|
||||
@ -828,7 +828,7 @@ class SizeofTest(unittest.TestCase):
|
||||
# type
|
||||
# (PyTypeObject + PyNumberMethods + PyMappingMethods +
|
||||
# PySequenceMethods + PyBufferProcs)
|
||||
s = size(vh + 'P2P15Pl4PP9PP11PI') + size('16Pi17P 3P 10P 2P 2P')
|
||||
s = size(vh + 'P2P15Pl4PP9PP11PI') + size('16Pi17P 3P 10P 2P 3P')
|
||||
check(int, s)
|
||||
# class
|
||||
class newstyleclass(object): pass
|
||||
|
@ -1,6 +1,7 @@
|
||||
# tempfile.py unit tests.
|
||||
import tempfile
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import re
|
||||
import warnings
|
||||
@ -135,6 +136,37 @@ class test__RandomNameSequence(TC):
|
||||
except:
|
||||
self.failOnException("iteration")
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'fork'),
|
||||
"os.fork is required for this test")
|
||||
def test_process_awareness(self):
|
||||
# ensure that the random source differs between
|
||||
# child and parent.
|
||||
read_fd, write_fd = os.pipe()
|
||||
pid = None
|
||||
try:
|
||||
pid = os.fork()
|
||||
if not pid:
|
||||
os.close(read_fd)
|
||||
os.write(write_fd, next(self.r).encode("ascii"))
|
||||
os.close(write_fd)
|
||||
# bypass the normal exit handlers- leave those to
|
||||
# the parent.
|
||||
os._exit(0)
|
||||
parent_value = next(self.r)
|
||||
child_value = os.read(read_fd, len(parent_value)).decode("ascii")
|
||||
finally:
|
||||
if pid:
|
||||
# best effort to ensure the process can't bleed out
|
||||
# via any bugs above
|
||||
try:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
except EnvironmentError:
|
||||
pass
|
||||
os.close(read_fd)
|
||||
os.close(write_fd)
|
||||
self.assertNotEqual(child_value, parent_value)
|
||||
|
||||
|
||||
test_classes.append(test__RandomNameSequence)
|
||||
|
||||
|
||||
@ -846,6 +878,27 @@ class test_SpooledTemporaryFile(TC):
|
||||
pass
|
||||
self.assertRaises(ValueError, use_closed)
|
||||
|
||||
def test_truncate_with_size_parameter(self):
|
||||
# A SpooledTemporaryFile can be truncated to zero size
|
||||
f = tempfile.SpooledTemporaryFile(max_size=10)
|
||||
f.write(b'abcdefg\n')
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
self.assertFalse(f._rolled)
|
||||
self.assertEqual(f._file.getvalue(), b'')
|
||||
# A SpooledTemporaryFile can be truncated to a specific size
|
||||
f = tempfile.SpooledTemporaryFile(max_size=10)
|
||||
f.write(b'abcdefg\n')
|
||||
f.truncate(4)
|
||||
self.assertFalse(f._rolled)
|
||||
self.assertEqual(f._file.getvalue(), b'abcd')
|
||||
# A SpooledTemporaryFile rolls over if truncated to large size
|
||||
f = tempfile.SpooledTemporaryFile(max_size=10)
|
||||
f.write(b'abcdefg\n')
|
||||
f.truncate(20)
|
||||
self.assertTrue(f._rolled)
|
||||
if has_stat:
|
||||
self.assertEqual(os.fstat(f.fileno()).st_size, 20)
|
||||
|
||||
test_classes.append(test_SpooledTemporaryFile)
|
||||
|
||||
|
@ -1816,20 +1816,10 @@ class UnicodeTest(string_tests.CommonTest,
|
||||
b' 3.14 ')
|
||||
self.assertRaises(UnicodeEncodeError,
|
||||
unicode_encodedecimal, "123\u20ac", "strict")
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac", "replace"),
|
||||
b'123?')
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac", "ignore"),
|
||||
b'123')
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac", "xmlcharrefreplace"),
|
||||
b'123€')
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac", "backslashreplace"),
|
||||
b'123\\u20ac')
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac\N{EM SPACE}", "replace"),
|
||||
b'123? ')
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac\u20ac", "replace"),
|
||||
b'123??')
|
||||
self.assertEqual(unicode_encodedecimal("123\u20ac\u0660", "replace"),
|
||||
b'123?0')
|
||||
self.assertRaisesRegex(
|
||||
ValueError,
|
||||
"^'decimal' codec can't encode character",
|
||||
unicode_encodedecimal, "123\u20ac", "replace")
|
||||
|
||||
def test_transform_decimal(self):
|
||||
from _testcapi import unicode_transformdecimaltoascii as transform_decimal
|
||||
|
18
Misc/NEWS
18
Misc/NEWS
@ -14,6 +14,12 @@ Core and Builtins
|
||||
on POSIX systems supporting anonymous memory mappings. Patch by
|
||||
Charles-François Natali.
|
||||
|
||||
- Issue #13452: PyUnicode_EncodeDecimal() doesn't support error handlers
|
||||
different than "strict" anymore. The caller was unable to compute the
|
||||
size of the output buffer: it depends on the error handler.
|
||||
|
||||
- PEP 3155 / issue #13448: Qualified name for classes and functions.
|
||||
|
||||
- Issue #13436: Fix a bogus error message when an AST object was passed
|
||||
an invalid integer value.
|
||||
|
||||
@ -386,10 +392,20 @@ Core and Builtins
|
||||
- Issue #12380: The rjust, ljust and center methods of bytes and bytearray
|
||||
now accept a bytearray argument.
|
||||
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
- Issue #12567: The curses module uses Unicode functions for Unicode arguments
|
||||
when it is linked to the ncurses library. It encodes also Unicode strings to
|
||||
the locale encoding instead of UTF-8.
|
||||
|
||||
- Issue #12856: Ensure child processes do not inherit the parent's random
|
||||
seed for filename generation in the tempfile module. Patch by Brian
|
||||
Harring.
|
||||
|
||||
- Issue #9957: SpooledTemporaryFile.truncate() now accepts an optional size
|
||||
parameter, as other file-like objects. Patch by Ryan Kelly.
|
||||
|
||||
- Issue #13458: Fix a memory leak in the ssl module when decoding a
|
||||
certificate with a subjectAltName. Patch by Robert Xiao.
|
||||
|
||||
|
@ -121,6 +121,10 @@ extern int setupterm(char *,int,int *);
|
||||
#include <term.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_NCURSES_H) && (defined(sgi) || defined(__sun) || defined(SCO5))
|
||||
#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */
|
||||
typedef chtype attr_t; /* No attr_t type is available */
|
||||
@ -143,6 +147,8 @@ static int initialised = FALSE;
|
||||
/* Tells whether start_color() has been called to initialise color usage. */
|
||||
static int initialisedcolors = FALSE;
|
||||
|
||||
static char *screen_encoding = NULL;
|
||||
|
||||
/* Utility Macros */
|
||||
#define PyCursesSetupTermCalled \
|
||||
if (initialised_setupterm != TRUE) { \
|
||||
@ -175,7 +181,7 @@ static int initialisedcolors = FALSE;
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
PyCursesCheckERR(int code, char *fname)
|
||||
PyCursesCheckERR(int code, const char *fname)
|
||||
{
|
||||
if (code != ERR) {
|
||||
Py_INCREF(Py_None);
|
||||
@ -190,28 +196,193 @@ PyCursesCheckERR(int code, char *fname)
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert an object to a byte (an integer of type chtype):
|
||||
|
||||
- int
|
||||
- bytes of length 1
|
||||
- str of length 1
|
||||
|
||||
Return 1 on success, 0 on error (invalid type or integer overflow). */
|
||||
static int
|
||||
PyCurses_ConvertToChtype(PyObject *obj, chtype *ch)
|
||||
PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch)
|
||||
{
|
||||
if (PyLong_CheckExact(obj)) {
|
||||
int overflow;
|
||||
/* XXX should the truncation by the cast also be reported
|
||||
as an error? */
|
||||
*ch = (chtype) PyLong_AsLongAndOverflow(obj, &overflow);
|
||||
if (overflow)
|
||||
long value;
|
||||
if(PyBytes_Check(obj) && PyBytes_Size(obj) == 1) {
|
||||
value = (unsigned char)PyBytes_AsString(obj)[0];
|
||||
}
|
||||
else if (PyUnicode_Check(obj)) {
|
||||
if (PyUnicode_GetLength(obj) != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"expect bytes or str of length 1, or int, "
|
||||
"got a str of length %zi",
|
||||
PyUnicode_GET_LENGTH(obj));
|
||||
return 0;
|
||||
} else if(PyBytes_Check(obj)
|
||||
&& (PyBytes_Size(obj) == 1)) {
|
||||
*ch = (chtype) *PyBytes_AsString(obj);
|
||||
} else if (PyUnicode_Check(obj) && PyUnicode_GET_LENGTH(obj) == 1) {
|
||||
Py_UCS4 ucs = PyUnicode_READ(PyUnicode_KIND(obj),
|
||||
PyUnicode_DATA(obj),
|
||||
0);
|
||||
*ch = (chtype)ucs;
|
||||
} else {
|
||||
}
|
||||
value = PyUnicode_READ_CHAR(obj, 0);
|
||||
if (128 < value) {
|
||||
PyObject *bytes;
|
||||
const char *encoding;
|
||||
if (win)
|
||||
encoding = win->encoding;
|
||||
else
|
||||
encoding = screen_encoding;
|
||||
bytes = PyUnicode_AsEncodedObject(obj, encoding, NULL);
|
||||
if (bytes == NULL)
|
||||
return 0;
|
||||
if (PyBytes_GET_SIZE(bytes) == 1)
|
||||
value = (unsigned char)PyBytes_AS_STRING(bytes)[0];
|
||||
else
|
||||
value = -1;
|
||||
Py_DECREF(bytes);
|
||||
if (value < 0)
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
else if (PyLong_CheckExact(obj)) {
|
||||
int long_overflow;
|
||||
value = PyLong_AsLongAndOverflow(obj, &long_overflow);
|
||||
if (long_overflow)
|
||||
goto overflow;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"expect bytes or str of length 1, or int, got %s",
|
||||
Py_TYPE(obj)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
*ch = (chtype)value;
|
||||
if ((long)*ch != value)
|
||||
goto overflow;
|
||||
return 1;
|
||||
|
||||
overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"byte doesn't fit in chtype");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert an object to a byte (chtype) or a character (cchar_t):
|
||||
|
||||
- int
|
||||
- bytes of length 1
|
||||
- str of length 1
|
||||
|
||||
Return:
|
||||
|
||||
- 2 if obj is a character (written into *wch)
|
||||
- 1 if obj is a byte (written into *ch)
|
||||
- 0 on error: raise an exception */
|
||||
static int
|
||||
PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj,
|
||||
chtype *ch
|
||||
#ifdef HAVE_NCURSESW
|
||||
, cchar_t *wch
|
||||
#endif
|
||||
)
|
||||
{
|
||||
int ret = 0;
|
||||
long value;
|
||||
#ifdef HAVE_NCURSESW
|
||||
wchar_t buffer[2];
|
||||
#endif
|
||||
|
||||
if (PyUnicode_Check(obj)) {
|
||||
#ifdef HAVE_NCURSESW
|
||||
if (PyUnicode_AsWideChar(obj, buffer, 2) != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"expect bytes or str of length 1, or int, "
|
||||
"got a str of length %zi",
|
||||
PyUnicode_GET_LENGTH(obj));
|
||||
return 0;
|
||||
}
|
||||
memset(wch->chars, 0, sizeof(wch->chars));
|
||||
wch->chars[0] = buffer[0];
|
||||
return 2;
|
||||
#else
|
||||
return PyCurses_ConvertToChtype(win, obj, ch);
|
||||
#endif
|
||||
}
|
||||
else if(PyBytes_Check(obj) && PyBytes_Size(obj) == 1) {
|
||||
value = (unsigned char)PyBytes_AsString(obj)[0];
|
||||
ret = 1;
|
||||
}
|
||||
else if (PyLong_CheckExact(obj)) {
|
||||
int overflow;
|
||||
value = PyLong_AsLongAndOverflow(obj, &overflow);
|
||||
if (overflow) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"int doesn't fit in long");
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_NCURSESW
|
||||
ret = 2;
|
||||
#else
|
||||
ret = 1;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"expect bytes or str of length 1, or int, got %s",
|
||||
Py_TYPE(obj)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_NCURSESW
|
||||
if (ret == 2) {
|
||||
memset(wch->chars, 0, sizeof(wch->chars));
|
||||
wch->chars[0] = (wchar_t)value;
|
||||
if ((long)wch->chars[0] != value) {
|
||||
PyErr_Format(PyExc_OverflowError,
|
||||
"character doesn't fit in wchar_t");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
*ch = (chtype)value;
|
||||
if ((long)*ch != value || value < 0 || value > 255) {
|
||||
PyErr_Format(PyExc_OverflowError,
|
||||
"byte doesn't fit in chtype");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Convert an object to a byte string (char*) or a wide character string
|
||||
(wchar_t*). Return:
|
||||
|
||||
- 2 if obj is a character string (written into *wch)
|
||||
- 1 if obj is a byte string (written into *bytes)
|
||||
- 0 on error: raise an exception */
|
||||
static int
|
||||
PyCurses_ConvertToString(PyCursesWindowObject *win, PyObject *obj,
|
||||
PyObject **bytes, wchar_t **wstr)
|
||||
{
|
||||
if (PyUnicode_Check(obj)) {
|
||||
#ifdef HAVE_NCURSESW
|
||||
assert (wstr != NULL);
|
||||
*wstr = PyUnicode_AsWideCharString(obj, NULL);
|
||||
if (*wstr == NULL)
|
||||
return 0;
|
||||
return 2;
|
||||
#else
|
||||
assert (wstr == NULL);
|
||||
*bytes = PyUnicode_AsEncodedObject(obj, win->encoding, NULL);
|
||||
if (*bytes == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
else if (PyBytes_Check(obj)) {
|
||||
Py_INCREF(obj);
|
||||
*bytes = obj;
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError, "expect bytes or str, got %s",
|
||||
Py_TYPE(obj)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function versions of the 3 functions for testing whether curses has been
|
||||
@ -357,13 +528,37 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
|
||||
/* Allocation and deallocation of Window Objects */
|
||||
|
||||
static PyObject *
|
||||
PyCursesWindow_New(WINDOW *win)
|
||||
PyCursesWindow_New(WINDOW *win, const char *encoding)
|
||||
{
|
||||
PyCursesWindowObject *wo;
|
||||
|
||||
if (encoding == NULL) {
|
||||
#if defined(MS_WINDOWS)
|
||||
char *buffer[100];
|
||||
UINT cp;
|
||||
cp = GetConsoleOutputCP();
|
||||
if (cp != 0) {
|
||||
PyOS_snprintf(buffer, sizeof(buffer), "cp%u", cp);
|
||||
encoding = buffer;
|
||||
}
|
||||
#elif defined(CODESET)
|
||||
const char *codeset = nl_langinfo(CODESET);
|
||||
if (codeset != NULL && codeset[0] != 0)
|
||||
encoding = codeset;
|
||||
#endif
|
||||
if (encoding == NULL)
|
||||
encoding = "utf-8";
|
||||
}
|
||||
|
||||
wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type);
|
||||
if (wo == NULL) return NULL;
|
||||
wo->win = win;
|
||||
wo->encoding = strdup(encoding);
|
||||
if (wo->encoding == NULL) {
|
||||
Py_DECREF(wo);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *)wo;
|
||||
}
|
||||
|
||||
@ -371,6 +566,8 @@ static void
|
||||
PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
|
||||
{
|
||||
if (wo->win != stdscr) delwin(wo->win);
|
||||
if (wo->encoding != NULL)
|
||||
free(wo->encoding);
|
||||
PyObject_DEL(wo);
|
||||
}
|
||||
|
||||
@ -380,29 +577,34 @@ static PyObject *
|
||||
PyCursesWindow_AddCh(PyCursesWindowObject *self, PyObject *args)
|
||||
{
|
||||
int rtn, x, y, use_xy = FALSE;
|
||||
PyObject *temp;
|
||||
chtype ch = 0;
|
||||
PyObject *chobj;
|
||||
int type;
|
||||
chtype ch;
|
||||
#ifdef HAVE_NCURSESW
|
||||
cchar_t wch;
|
||||
#endif
|
||||
attr_t attr = A_NORMAL;
|
||||
long lattr;
|
||||
const char *funcname;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args, "O;ch or int", &temp))
|
||||
if (!PyArg_ParseTuple(args, "O;ch or int", &chobj))
|
||||
return NULL;
|
||||
break;
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &temp, &lattr))
|
||||
if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &chobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &temp))
|
||||
if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &chobj))
|
||||
return NULL;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args,"iiOl;y,x,ch or int, attr",
|
||||
&y, &x, &temp, &lattr))
|
||||
&y, &x, &chobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_xy = TRUE;
|
||||
@ -412,17 +614,33 @@ PyCursesWindow_AddCh(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 or 3 must be a ch or an int");
|
||||
#ifdef HAVE_NCURSESW
|
||||
type = PyCurses_ConvertToCchar_t(self, chobj, &ch, &wch);
|
||||
if (type == 2) {
|
||||
funcname = "add_wch";
|
||||
wch.attr = attr;
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwadd_wch(self->win,y,x, &wch);
|
||||
else {
|
||||
rtn = wadd_wch(self->win, &wch);
|
||||
}
|
||||
}
|
||||
else
|
||||
#else
|
||||
type = PyCurses_ConvertToCchar_t(self, chobj, &ch);
|
||||
#endif
|
||||
if (type == 1) {
|
||||
funcname = "addch";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddch(self->win,y,x, ch | attr);
|
||||
else {
|
||||
rtn = waddch(self->win, ch | attr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddch(self->win,y,x, ch | attr);
|
||||
else {
|
||||
rtn = waddch(self->win, ch | attr);
|
||||
}
|
||||
return PyCursesCheckERR(rtn, "addch");
|
||||
return PyCursesCheckERR(rtn, funcname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -430,29 +648,34 @@ PyCursesWindow_AddStr(PyCursesWindowObject *self, PyObject *args)
|
||||
{
|
||||
int rtn;
|
||||
int x, y;
|
||||
char *str;
|
||||
int strtype;
|
||||
PyObject *strobj, *bytesobj;
|
||||
#ifdef HAVE_NCURSESW
|
||||
wchar_t *wstr = NULL;
|
||||
#endif
|
||||
attr_t attr = A_NORMAL , attr_old = A_NORMAL;
|
||||
long lattr;
|
||||
int use_xy = FALSE, use_attr = FALSE;
|
||||
const char *funcname;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args,"s;str", &str))
|
||||
if (!PyArg_ParseTuple(args,"O;str", &strobj))
|
||||
return NULL;
|
||||
break;
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args,"sl;str,attr", &str, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"Ol;str,attr", &strobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_attr = TRUE;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args,"iis;int,int,str", &y, &x, &str))
|
||||
if (!PyArg_ParseTuple(args,"iiO;int,int,str", &y, &x, &strobj))
|
||||
return NULL;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args,"iisl;int,int,str,attr", &y, &x, &str, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"iiOl;int,int,str,attr", &y, &x, &strobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_xy = use_attr = TRUE;
|
||||
@ -461,47 +684,74 @@ PyCursesWindow_AddStr(PyCursesWindowObject *self, PyObject *args)
|
||||
PyErr_SetString(PyExc_TypeError, "addstr requires 1 to 4 arguments");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NCURSESW
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr);
|
||||
#else
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL);
|
||||
#endif
|
||||
if (strtype == 0)
|
||||
return NULL;
|
||||
if (use_attr == TRUE) {
|
||||
attr_old = getattrs(self->win);
|
||||
(void)wattrset(self->win,attr);
|
||||
}
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddstr(self->win,y,x,str);
|
||||
#ifdef HAVE_NCURSESW
|
||||
if (strtype == 2) {
|
||||
funcname = "addwstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddwstr(self->win,y,x,wstr);
|
||||
else
|
||||
rtn = waddwstr(self->win,wstr);
|
||||
PyMem_Free(wstr);
|
||||
}
|
||||
else
|
||||
rtn = waddstr(self->win,str);
|
||||
#endif
|
||||
{
|
||||
char *str = PyBytes_AS_STRING(bytesobj);
|
||||
funcname = "addstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddstr(self->win,y,x,str);
|
||||
else
|
||||
rtn = waddstr(self->win,str);
|
||||
Py_DECREF(bytesobj);
|
||||
}
|
||||
if (use_attr == TRUE)
|
||||
(void)wattrset(self->win,attr_old);
|
||||
return PyCursesCheckERR(rtn, "addstr");
|
||||
return PyCursesCheckERR(rtn, funcname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesWindow_AddNStr(PyCursesWindowObject *self, PyObject *args)
|
||||
{
|
||||
int rtn, x, y, n;
|
||||
char *str;
|
||||
int strtype;
|
||||
PyObject *strobj, *bytesobj;
|
||||
#ifdef HAVE_NCURSESW
|
||||
wchar_t *wstr = NULL;
|
||||
#endif
|
||||
attr_t attr = A_NORMAL , attr_old = A_NORMAL;
|
||||
long lattr;
|
||||
int use_xy = FALSE, use_attr = FALSE;
|
||||
const char *funcname;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args,"si;str,n", &str, &n))
|
||||
if (!PyArg_ParseTuple(args,"Oi;str,n", &strobj, &n))
|
||||
return NULL;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args,"sil;str,n,attr", &str, &n, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"Oil;str,n,attr", &strobj, &n, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_attr = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args,"iisi;y,x,str,n", &y, &x, &str, &n))
|
||||
if (!PyArg_ParseTuple(args,"iiOi;y,x,str,n", &y, &x, &strobj, &n))
|
||||
return NULL;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
case 5:
|
||||
if (!PyArg_ParseTuple(args,"iisil;y,x,str,n,attr", &y, &x, &str, &n, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"iiOil;y,x,str,n,attr", &y, &x, &strobj, &n, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_xy = use_attr = TRUE;
|
||||
@ -510,18 +760,41 @@ PyCursesWindow_AddNStr(PyCursesWindowObject *self, PyObject *args)
|
||||
PyErr_SetString(PyExc_TypeError, "addnstr requires 2 to 5 arguments");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef HAVE_NCURSESW
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr);
|
||||
#else
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL);
|
||||
#endif
|
||||
if (strtype == 0)
|
||||
return NULL;
|
||||
|
||||
if (use_attr == TRUE) {
|
||||
attr_old = getattrs(self->win);
|
||||
(void)wattrset(self->win,attr);
|
||||
}
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddnstr(self->win,y,x,str,n);
|
||||
#ifdef HAVE_NCURSESW
|
||||
if (strtype == 2) {
|
||||
funcname = "addnwstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddnwstr(self->win,y,x,wstr,n);
|
||||
else
|
||||
rtn = waddnwstr(self->win,wstr,n);
|
||||
PyMem_Free(wstr);
|
||||
}
|
||||
else
|
||||
rtn = waddnstr(self->win,str,n);
|
||||
#endif
|
||||
{
|
||||
char *str = PyBytes_AS_STRING(bytesobj);
|
||||
funcname = "addnstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddnstr(self->win,y,x,str,n);
|
||||
else
|
||||
rtn = waddnstr(self->win,str,n);
|
||||
Py_DECREF(bytesobj);
|
||||
}
|
||||
if (use_attr == TRUE)
|
||||
(void)wattrset(self->win,attr_old);
|
||||
return PyCursesCheckERR(rtn, "addnstr");
|
||||
return PyCursesCheckERR(rtn, funcname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -547,10 +820,8 @@ PyCursesWindow_Bkgd(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &bkgd)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 or 3 must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(self, temp, &bkgd))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyCursesCheckERR(wbkgd(self->win, bkgd | attr), "bkgd");
|
||||
}
|
||||
@ -605,10 +876,8 @@ PyCursesWindow_BkgdSet(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &bkgd)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(self, temp, &bkgd))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wbkgdset(self->win, bkgd | attr);
|
||||
return PyCursesCheckERR(0, "bkgdset");
|
||||
@ -633,11 +902,8 @@ PyCursesWindow_Border(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
|
||||
for(i=0; i<8; i++) {
|
||||
if (temp[i] != NULL && !PyCurses_ConvertToChtype(temp[i], &ch[i])) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"argument %i must be a ch or an int", i+1);
|
||||
if (temp[i] != NULL && !PyCurses_ConvertToChtype(self, temp[i], &ch[i]))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wborder(self->win,
|
||||
@ -782,7 +1048,7 @@ PyCursesWindow_DerWin(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win);
|
||||
return (PyObject *)PyCursesWindow_New(win, NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -810,10 +1076,8 @@ PyCursesWindow_EchoChar(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(self, temp, &ch))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef WINDOW_HAS_FLAGS
|
||||
if (self->win->_flags & _ISPAD)
|
||||
@ -1034,11 +1298,8 @@ PyCursesWindow_Hline(PyCursesWindowObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
if (code != ERR) {
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 or 3 must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(self, temp, &ch))
|
||||
return NULL;
|
||||
}
|
||||
return PyCursesCheckERR(whline(self->win, ch | attr, n), "hline");
|
||||
} else
|
||||
return PyCursesCheckERR(code, "wmove");
|
||||
@ -1079,11 +1340,8 @@ PyCursesWindow_InsCh(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 or 3 must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(self, temp, &ch))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwinsch(self->win,y,x, ch | attr);
|
||||
@ -1154,29 +1412,34 @@ PyCursesWindow_InsStr(PyCursesWindowObject *self, PyObject *args)
|
||||
{
|
||||
int rtn;
|
||||
int x, y;
|
||||
char *str;
|
||||
int strtype;
|
||||
PyObject *strobj, *bytesobj;
|
||||
#ifdef HAVE_NCURSESW
|
||||
wchar_t *wstr = NULL;
|
||||
#endif
|
||||
attr_t attr = A_NORMAL , attr_old = A_NORMAL;
|
||||
long lattr;
|
||||
int use_xy = FALSE, use_attr = FALSE;
|
||||
const char *funcname;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args,"s;str", &str))
|
||||
if (!PyArg_ParseTuple(args,"O;str", &strobj))
|
||||
return NULL;
|
||||
break;
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args,"sl;str,attr", &str, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"Ol;str,attr", &strobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_attr = TRUE;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args,"iis;y,x,str", &y, &x, &str))
|
||||
if (!PyArg_ParseTuple(args,"iiO;y,x,str", &y, &x, &strobj))
|
||||
return NULL;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args,"iisl;y,x,str,attr", &y, &x, &str, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"iiOl;y,x,str,attr", &y, &x, &strobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_xy = use_attr = TRUE;
|
||||
@ -1186,46 +1449,75 @@ PyCursesWindow_InsStr(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NCURSESW
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr);
|
||||
#else
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL);
|
||||
#endif
|
||||
if (strtype == 0)
|
||||
return NULL;
|
||||
|
||||
if (use_attr == TRUE) {
|
||||
attr_old = getattrs(self->win);
|
||||
(void)wattrset(self->win,attr);
|
||||
}
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwinsstr(self->win,y,x,str);
|
||||
#ifdef HAVE_NCURSESW
|
||||
if (strtype == 2) {
|
||||
funcname = "inswstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwins_wstr(self->win,y,x,wstr);
|
||||
else
|
||||
rtn = wins_wstr(self->win,wstr);
|
||||
PyMem_Free(wstr);
|
||||
}
|
||||
else
|
||||
rtn = winsstr(self->win,str);
|
||||
#endif
|
||||
{
|
||||
char *str = PyBytes_AS_STRING(bytesobj);
|
||||
funcname = "insstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwinsstr(self->win,y,x,str);
|
||||
else
|
||||
rtn = winsstr(self->win,str);
|
||||
Py_DECREF(bytesobj);
|
||||
}
|
||||
if (use_attr == TRUE)
|
||||
(void)wattrset(self->win,attr_old);
|
||||
return PyCursesCheckERR(rtn, "insstr");
|
||||
return PyCursesCheckERR(rtn, funcname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesWindow_InsNStr(PyCursesWindowObject *self, PyObject *args)
|
||||
{
|
||||
int rtn, x, y, n;
|
||||
char *str;
|
||||
int strtype;
|
||||
PyObject *strobj, *bytesobj;
|
||||
#ifdef HAVE_NCURSESW
|
||||
wchar_t *wstr = NULL;
|
||||
#endif
|
||||
attr_t attr = A_NORMAL , attr_old = A_NORMAL;
|
||||
long lattr;
|
||||
int use_xy = FALSE, use_attr = FALSE;
|
||||
const char *funcname;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args,"si;str,n", &str, &n))
|
||||
if (!PyArg_ParseTuple(args,"Oi;str,n", &strobj, &n))
|
||||
return NULL;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args,"sil;str,n,attr", &str, &n, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"Oil;str,n,attr", &strobj, &n, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_attr = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args,"iisi;y,x,str,n", &y, &x, &str, &n))
|
||||
if (!PyArg_ParseTuple(args,"iiOi;y,x,str,n", &y, &x, &strobj, &n))
|
||||
return NULL;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
case 5:
|
||||
if (!PyArg_ParseTuple(args,"iisil;y,x,str,n,attr", &y, &x, &str, &n, &lattr))
|
||||
if (!PyArg_ParseTuple(args,"iiOil;y,x,str,n,attr", &y, &x, &strobj, &n, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_xy = use_attr = TRUE;
|
||||
@ -1235,17 +1527,41 @@ PyCursesWindow_InsNStr(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NCURSESW
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, &wstr);
|
||||
#else
|
||||
strtype = PyCurses_ConvertToString(self, strobj, &bytesobj, NULL);
|
||||
#endif
|
||||
if (strtype == 0)
|
||||
return NULL;
|
||||
|
||||
if (use_attr == TRUE) {
|
||||
attr_old = getattrs(self->win);
|
||||
(void)wattrset(self->win,attr);
|
||||
}
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwinsnstr(self->win,y,x,str,n);
|
||||
#ifdef HAVE_NCURSESW
|
||||
if (strtype == 2) {
|
||||
funcname = "insn_wstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwins_nwstr(self->win,y,x,wstr,n);
|
||||
else
|
||||
rtn = wins_nwstr(self->win,wstr,n);
|
||||
PyMem_Free(wstr);
|
||||
}
|
||||
else
|
||||
rtn = winsnstr(self->win,str,n);
|
||||
#endif
|
||||
{
|
||||
char *str = PyBytes_AS_STRING(bytesobj);
|
||||
funcname = "insnstr";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwinsnstr(self->win,y,x,str,n);
|
||||
else
|
||||
rtn = winsnstr(self->win,str,n);
|
||||
Py_DECREF(bytesobj);
|
||||
}
|
||||
if (use_attr == TRUE)
|
||||
(void)wattrset(self->win,attr_old);
|
||||
return PyCursesCheckERR(rtn, "insnstr");
|
||||
return PyCursesCheckERR(rtn, funcname);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -1528,7 +1844,7 @@ PyCursesWindow_SubWin(PyCursesWindowObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win);
|
||||
return (PyObject *)PyCursesWindow_New(win, self->encoding);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -1604,16 +1920,51 @@ PyCursesWindow_Vline(PyCursesWindowObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
if (code != ERR) {
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 or 3 must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(self, temp, &ch))
|
||||
return NULL;
|
||||
}
|
||||
return PyCursesCheckERR(wvline(self->win, ch | attr, n), "vline");
|
||||
} else
|
||||
return PyCursesCheckERR(code, "wmove");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
PyCursesWindow_get_encoding(PyCursesWindowObject *self, void *closure)
|
||||
{
|
||||
return PyUnicode_FromString(self->encoding);
|
||||
}
|
||||
|
||||
static int
|
||||
PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value)
|
||||
{
|
||||
PyObject *ascii;
|
||||
char *encoding;
|
||||
|
||||
/* It is illegal to del win.encoding */
|
||||
if (value == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"encoding may not be deleted");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!PyUnicode_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"setting encoding to a non-string");
|
||||
return -1;
|
||||
}
|
||||
ascii = PyUnicode_AsASCIIString(value);
|
||||
if (ascii == NULL)
|
||||
return -1;
|
||||
encoding = strdup(PyBytes_AS_STRING(ascii));
|
||||
if (encoding == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
free(self->encoding);
|
||||
self->encoding = encoding;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef PyCursesWindow_Methods[] = {
|
||||
{"addch", (PyCFunction)PyCursesWindow_AddCh, METH_VARARGS},
|
||||
{"addnstr", (PyCFunction)PyCursesWindow_AddNStr, METH_VARARGS},
|
||||
@ -1701,6 +2052,13 @@ static PyMethodDef PyCursesWindow_Methods[] = {
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyGetSetDef PyCursesWindow_getsets[] = {
|
||||
{"encoding",
|
||||
(getter)PyCursesWindow_get_encoding,
|
||||
(setter)PyCursesWindow_set_encoding,
|
||||
"the typecode character used to create the array"}
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------*/
|
||||
|
||||
PyTypeObject PyCursesWindow_Type = {
|
||||
@ -1733,6 +2091,8 @@ PyTypeObject PyCursesWindow_Type = {
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
PyCursesWindow_Methods, /*tp_methods*/
|
||||
0, /* tp_members */
|
||||
PyCursesWindow_getsets, /* tp_getset */
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
@ -1956,7 +2316,7 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream)
|
||||
PyErr_SetString(PyCursesError, catchall_NULL);
|
||||
return NULL;
|
||||
}
|
||||
return PyCursesWindow_New(win);
|
||||
return PyCursesWindow_New(win, NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -2034,10 +2394,11 @@ static PyObject *
|
||||
PyCurses_InitScr(PyObject *self)
|
||||
{
|
||||
WINDOW *win;
|
||||
PyCursesWindowObject *winobj;
|
||||
|
||||
if (initialised == TRUE) {
|
||||
wrefresh(stdscr);
|
||||
return (PyObject *)PyCursesWindow_New(stdscr);
|
||||
return (PyObject *)PyCursesWindow_New(stdscr, NULL);
|
||||
}
|
||||
|
||||
win = initscr();
|
||||
@ -2129,7 +2490,9 @@ PyCurses_InitScr(PyObject *self)
|
||||
SetDictInt("LINES", LINES);
|
||||
SetDictInt("COLS", COLS);
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win);
|
||||
winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL);
|
||||
screen_encoding = winobj->encoding;
|
||||
return (PyObject *)winobj;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -2331,7 +2694,7 @@ PyCurses_NewPad(PyObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win);
|
||||
return (PyObject *)PyCursesWindow_New(win, NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -2363,7 +2726,7 @@ PyCurses_NewWindow(PyObject *self, PyObject *args)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)PyCursesWindow_New(win);
|
||||
return (PyObject *)PyCursesWindow_New(win, NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -2680,10 +3043,8 @@ PyCurses_UnCtrl(PyObject *self, PyObject *args)
|
||||
|
||||
if (!PyArg_ParseTuple(args,"O;ch or int",&temp)) return NULL;
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a ch or an int");
|
||||
if (!PyCurses_ConvertToChtype(NULL, temp, &ch))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyBytes_FromString(unctrl(ch));
|
||||
}
|
||||
@ -2696,12 +3057,11 @@ PyCurses_UngetCh(PyObject *self, PyObject *args)
|
||||
|
||||
PyCursesInitialised;
|
||||
|
||||
if (!PyArg_ParseTuple(args,"O;ch or int",&temp)) return NULL;
|
||||
|
||||
if (!PyCurses_ConvertToChtype(temp, &ch)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a ch or an int");
|
||||
if (!PyArg_ParseTuple(args,"O;ch or int",&temp))
|
||||
return NULL;
|
||||
|
||||
if (!PyCurses_ConvertToChtype(NULL, temp, &ch))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyCursesCheckERR(ungetch(ch), "ungetch");
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "structmember.h"
|
||||
|
||||
PyObject *
|
||||
PyFunction_New(PyObject *code, PyObject *globals)
|
||||
PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
|
||||
{
|
||||
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject,
|
||||
&PyFunction_Type);
|
||||
@ -54,6 +54,11 @@ PyFunction_New(PyObject *code, PyObject *globals)
|
||||
Py_INCREF(module);
|
||||
op->func_module = module;
|
||||
}
|
||||
if (qualname)
|
||||
op->func_qualname = qualname;
|
||||
else
|
||||
op->func_qualname = op->func_name;
|
||||
Py_INCREF(op->func_qualname);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
@ -61,6 +66,12 @@ PyFunction_New(PyObject *code, PyObject *globals)
|
||||
return (PyObject *)op;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyFunction_New(PyObject *code, PyObject *globals)
|
||||
{
|
||||
return PyFunction_NewWithQualName(code, globals, NULL);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyFunction_GetCode(PyObject *op)
|
||||
{
|
||||
@ -333,6 +344,32 @@ func_set_name(PyFunctionObject *op, PyObject *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
func_get_qualname(PyFunctionObject *op)
|
||||
{
|
||||
Py_INCREF(op->func_qualname);
|
||||
return op->func_qualname;
|
||||
}
|
||||
|
||||
static int
|
||||
func_set_qualname(PyFunctionObject *op, PyObject *value)
|
||||
{
|
||||
PyObject *tmp;
|
||||
|
||||
/* Not legal to del f.__qualname__ or to set it to anything
|
||||
* other than a string object. */
|
||||
if (value == NULL || !PyUnicode_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__qualname__ must be set to a string object");
|
||||
return -1;
|
||||
}
|
||||
tmp = op->func_qualname;
|
||||
Py_INCREF(value);
|
||||
op->func_qualname = value;
|
||||
Py_DECREF(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
func_get_defaults(PyFunctionObject *op)
|
||||
{
|
||||
@ -441,6 +478,7 @@ static PyGetSetDef func_getsetlist[] = {
|
||||
(setter)func_set_annotations},
|
||||
{"__dict__", (getter)func_get_dict, (setter)func_set_dict},
|
||||
{"__name__", (getter)func_get_name, (setter)func_set_name},
|
||||
{"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -561,6 +599,7 @@ func_dealloc(PyFunctionObject *op)
|
||||
Py_XDECREF(op->func_dict);
|
||||
Py_XDECREF(op->func_closure);
|
||||
Py_XDECREF(op->func_annotations);
|
||||
Py_XDECREF(op->func_qualname);
|
||||
PyObject_GC_Del(op);
|
||||
}
|
||||
|
||||
@ -568,7 +607,7 @@ static PyObject*
|
||||
func_repr(PyFunctionObject *op)
|
||||
{
|
||||
return PyUnicode_FromFormat("<function %U at %p>",
|
||||
op->func_name, op);
|
||||
op->func_qualname, op);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -584,6 +623,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
|
||||
Py_VISIT(f->func_dict);
|
||||
Py_VISIT(f->func_closure);
|
||||
Py_VISIT(f->func_annotations);
|
||||
Py_VISIT(f->func_qualname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -242,6 +242,19 @@ type_name(PyTypeObject *type, void *context)
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
type_qualname(PyTypeObject *type, void *context)
|
||||
{
|
||||
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
|
||||
PyHeapTypeObject* et = (PyHeapTypeObject*)type;
|
||||
Py_INCREF(et->ht_qualname);
|
||||
return et->ht_qualname;
|
||||
}
|
||||
else {
|
||||
return type_name(type, context);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
type_set_name(PyTypeObject *type, PyObject *value, void *context)
|
||||
{
|
||||
@ -286,6 +299,25 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
type_set_qualname(PyTypeObject *type, PyObject *value, void *context)
|
||||
{
|
||||
PyHeapTypeObject* et;
|
||||
|
||||
if (!PyUnicode_Check(value)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"can only assign string to %s.__qualname__, not '%s'",
|
||||
type->tp_name, Py_TYPE(value)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
et = (PyHeapTypeObject*)type;
|
||||
Py_INCREF(value);
|
||||
Py_DECREF(et->ht_qualname);
|
||||
et->ht_qualname = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
type_module(PyTypeObject *type, void *context)
|
||||
{
|
||||
@ -631,6 +663,7 @@ type___subclasscheck__(PyObject *type, PyObject *inst)
|
||||
|
||||
static PyGetSetDef type_getsets[] = {
|
||||
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
|
||||
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
|
||||
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
|
||||
{"__module__", (getter)type_module, (setter)type_set_module, NULL},
|
||||
{"__abstractmethods__", (getter)type_abstractmethods,
|
||||
@ -652,7 +685,7 @@ type_repr(PyTypeObject *type)
|
||||
Py_DECREF(mod);
|
||||
mod = NULL;
|
||||
}
|
||||
name = type_name(type, NULL);
|
||||
name = type_qualname(type, NULL);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -1955,7 +1988,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *name, *bases, *dict;
|
||||
static char *kwlist[] = {"name", "bases", "dict", 0};
|
||||
PyObject *slots, *tmp, *newslots;
|
||||
PyObject *qualname, *slots, *tmp, *newslots;
|
||||
PyTypeObject *type, *base, *tmptype, *winner;
|
||||
PyHeapTypeObject *et;
|
||||
PyMemberDef *mp;
|
||||
@ -2032,6 +2065,18 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check for a __qualname__ variable in dict */
|
||||
qualname = PyDict_GetItemString(dict, "__qualname__");
|
||||
if (qualname == NULL) {
|
||||
qualname = name;
|
||||
}
|
||||
else {
|
||||
if (PyDict_DelItemString(dict, "__qualname__") < 0) {
|
||||
Py_DECREF(bases);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for a __slots__ sequence variable in dict, and count it */
|
||||
slots = PyDict_GetItemString(dict, "__slots__");
|
||||
nslots = 0;
|
||||
@ -2185,7 +2230,9 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
||||
/* Keep name and slots alive in the extended type object */
|
||||
et = (PyHeapTypeObject *)type;
|
||||
Py_INCREF(name);
|
||||
Py_INCREF(qualname);
|
||||
et->ht_name = name;
|
||||
et->ht_qualname = qualname;
|
||||
et->ht_slots = slots;
|
||||
|
||||
/* Initialize tp_flags */
|
||||
@ -2369,6 +2416,8 @@ PyObject* PyType_FromSpec(PyType_Spec *spec)
|
||||
res->ht_name = PyUnicode_FromString(spec->name);
|
||||
if (!res->ht_name)
|
||||
goto fail;
|
||||
res->ht_qualname = res->ht_name;
|
||||
Py_INCREF(res->ht_qualname);
|
||||
res->ht_type.tp_name = _PyUnicode_AsString(res->ht_name);
|
||||
if (!res->ht_type.tp_name)
|
||||
goto fail;
|
||||
@ -2568,6 +2617,7 @@ type_dealloc(PyTypeObject *type)
|
||||
*/
|
||||
PyObject_Free((char *)type->tp_doc);
|
||||
Py_XDECREF(et->ht_name);
|
||||
Py_XDECREF(et->ht_qualname);
|
||||
Py_XDECREF(et->ht_slots);
|
||||
Py_TYPE(type)->tp_free((PyObject *)type);
|
||||
}
|
||||
@ -2983,7 +3033,7 @@ object_repr(PyObject *self)
|
||||
Py_DECREF(mod);
|
||||
mod = NULL;
|
||||
}
|
||||
name = type_name(type, NULL);
|
||||
name = type_qualname(type, NULL);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
if (mod != NULL && PyUnicode_CompareWithASCIIString(mod, "builtins"))
|
||||
|
@ -8839,15 +8839,8 @@ PyUnicode_EncodeDecimal(Py_UNICODE *s,
|
||||
char *output,
|
||||
const char *errors)
|
||||
{
|
||||
PyObject *errorHandler = NULL;
|
||||
PyObject *exc = NULL;
|
||||
PyObject *unicode;
|
||||
const char *encoding = "decimal";
|
||||
const char *reason = "invalid decimal Unicode string";
|
||||
/* the following variable is used for caching string comparisons
|
||||
* -1=not initialized, 0=unknown, 1=strict, 2=replace, 3=ignore, 4=xmlcharrefreplace */
|
||||
int known_errorHandler = -1;
|
||||
Py_ssize_t i, j;
|
||||
Py_ssize_t i;
|
||||
enum PyUnicode_Kind kind;
|
||||
void *data;
|
||||
|
||||
@ -8860,15 +8853,20 @@ PyUnicode_EncodeDecimal(Py_UNICODE *s,
|
||||
if (unicode == NULL)
|
||||
return -1;
|
||||
|
||||
if (PyUnicode_READY(unicode) < 0)
|
||||
goto onError;
|
||||
if (PyUnicode_READY(unicode) < 0) {
|
||||
Py_DECREF(unicode);
|
||||
return -1;
|
||||
}
|
||||
kind = PyUnicode_KIND(unicode);
|
||||
data = PyUnicode_DATA(unicode);
|
||||
|
||||
for (i=0; i < length; ) {
|
||||
Py_UCS4 ch = PyUnicode_READ(kind, data, i);
|
||||
PyObject *exc;
|
||||
Py_UCS4 ch;
|
||||
int decimal;
|
||||
Py_ssize_t startpos, endpos;
|
||||
Py_ssize_t startpos;
|
||||
|
||||
ch = PyUnicode_READ(kind, data, i);
|
||||
|
||||
if (Py_UNICODE_ISSPACE(ch)) {
|
||||
*output++ = ' ';
|
||||
@ -8886,113 +8884,20 @@ PyUnicode_EncodeDecimal(Py_UNICODE *s,
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
/* All other characters are considered unencodable */
|
||||
|
||||
startpos = i;
|
||||
endpos = i+1;
|
||||
for (; endpos < length; endpos++) {
|
||||
ch = PyUnicode_READ(kind, data, endpos);
|
||||
if ((0 < ch && ch < 256) ||
|
||||
Py_UNICODE_ISSPACE(ch) ||
|
||||
0 <= Py_UNICODE_TODECIMAL(ch))
|
||||
break;
|
||||
}
|
||||
/* cache callback name lookup
|
||||
* (if not done yet, i.e. it's the first error) */
|
||||
if (known_errorHandler==-1) {
|
||||
if ((errors==NULL) || (!strcmp(errors, "strict")))
|
||||
known_errorHandler = 1;
|
||||
else if (!strcmp(errors, "replace"))
|
||||
known_errorHandler = 2;
|
||||
else if (!strcmp(errors, "ignore"))
|
||||
known_errorHandler = 3;
|
||||
else if (!strcmp(errors, "xmlcharrefreplace"))
|
||||
known_errorHandler = 4;
|
||||
else
|
||||
known_errorHandler = 0;
|
||||
}
|
||||
switch (known_errorHandler) {
|
||||
case 1: /* strict */
|
||||
raise_encode_exception(&exc, encoding, unicode, startpos, endpos, reason);
|
||||
goto onError;
|
||||
case 2: /* replace */
|
||||
for (j=startpos; j < endpos; j++)
|
||||
*output++ = '?';
|
||||
i = endpos;
|
||||
break;
|
||||
case 3: /* ignore */
|
||||
i = endpos;
|
||||
break;
|
||||
case 4: /* xmlcharrefreplace */
|
||||
/* generate replacement */
|
||||
for (j=startpos; j < endpos; j++) {
|
||||
ch = PyUnicode_READ(kind, data, i);
|
||||
output += sprintf(output, "&#%d;", (int)ch);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
PyObject *repunicode;
|
||||
Py_ssize_t repsize, newpos, k;
|
||||
enum PyUnicode_Kind repkind;
|
||||
void *repdata;
|
||||
|
||||
repunicode = unicode_encode_call_errorhandler(errors, &errorHandler,
|
||||
encoding, reason, unicode, &exc,
|
||||
startpos, endpos, &newpos);
|
||||
if (repunicode == NULL)
|
||||
goto onError;
|
||||
if (!PyUnicode_Check(repunicode)) {
|
||||
/* Byte results not supported, since they have no decimal property. */
|
||||
PyErr_SetString(PyExc_TypeError, "error handler should return unicode");
|
||||
Py_DECREF(repunicode);
|
||||
goto onError;
|
||||
}
|
||||
if (PyUnicode_READY(repunicode) < 0) {
|
||||
Py_DECREF(repunicode);
|
||||
goto onError;
|
||||
}
|
||||
repkind = PyUnicode_KIND(repunicode);
|
||||
repdata = PyUnicode_DATA(repunicode);
|
||||
|
||||
/* generate replacement */
|
||||
repsize = PyUnicode_GET_SIZE(repunicode);
|
||||
for (k=0; k<repsize; k++) {
|
||||
ch = PyUnicode_READ(repkind, repdata, k);
|
||||
if (Py_UNICODE_ISSPACE(ch))
|
||||
*output++ = ' ';
|
||||
else {
|
||||
decimal = Py_UNICODE_TODECIMAL(ch);
|
||||
if (decimal >= 0)
|
||||
*output++ = '0' + decimal;
|
||||
else if (0 < ch && ch < 256)
|
||||
*output++ = (char)ch;
|
||||
else {
|
||||
Py_DECREF(repunicode);
|
||||
raise_encode_exception(&exc, encoding,
|
||||
unicode, startpos, endpos,
|
||||
reason);
|
||||
goto onError;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = newpos;
|
||||
Py_DECREF(repunicode);
|
||||
}
|
||||
}
|
||||
exc = NULL;
|
||||
raise_encode_exception(&exc, "decimal", unicode,
|
||||
startpos, startpos+1,
|
||||
"invalid decimal Unicode string");
|
||||
Py_XDECREF(exc);
|
||||
Py_DECREF(unicode);
|
||||
return -1;
|
||||
}
|
||||
/* 0-terminate the output string */
|
||||
*output++ = '\0';
|
||||
Py_XDECREF(exc);
|
||||
Py_XDECREF(errorHandler);
|
||||
Py_DECREF(unicode);
|
||||
return 0;
|
||||
|
||||
onError:
|
||||
Py_XDECREF(exc);
|
||||
Py_XDECREF(errorHandler);
|
||||
Py_DECREF(unicode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* --- Helpers ------------------------------------------------------------ */
|
||||
|
@ -2687,9 +2687,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||
int kwdefaults = (oparg>>8) & 0xff;
|
||||
int num_annotations = (oparg >> 16) & 0x7fff;
|
||||
|
||||
w = POP(); /* qualname */
|
||||
v = POP(); /* code object */
|
||||
x = PyFunction_New(v, f->f_globals);
|
||||
x = PyFunction_NewWithQualName(v, f->f_globals, w);
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
|
||||
if (x != NULL && opcode == MAKE_CLOSURE) {
|
||||
v = POP();
|
||||
|
139
Python/compile.c
139
Python/compile.c
@ -90,6 +90,13 @@ struct fblockinfo {
|
||||
basicblock *fb_block;
|
||||
};
|
||||
|
||||
enum {
|
||||
COMPILER_SCOPE_MODULE,
|
||||
COMPILER_SCOPE_CLASS,
|
||||
COMPILER_SCOPE_FUNCTION,
|
||||
COMPILER_SCOPE_COMPREHENSION,
|
||||
};
|
||||
|
||||
/* The following items change on entry and exit of code blocks.
|
||||
They must be saved and restored when returning to a block.
|
||||
*/
|
||||
@ -97,6 +104,9 @@ struct compiler_unit {
|
||||
PySTEntryObject *u_ste;
|
||||
|
||||
PyObject *u_name;
|
||||
PyObject *u_qualname; /* dot-separated qualified name (lazy) */
|
||||
int u_scope_type;
|
||||
|
||||
/* The following fields are dicts that map objects to
|
||||
the index of them in co_XXX. The index is used as
|
||||
the argument for opcodes that refer to those collections.
|
||||
@ -149,7 +159,7 @@ struct compiler {
|
||||
PyArena *c_arena; /* pointer to memory allocation arena */
|
||||
};
|
||||
|
||||
static int compiler_enter_scope(struct compiler *, identifier, void *, int);
|
||||
static int compiler_enter_scope(struct compiler *, identifier, int, void *, int);
|
||||
static void compiler_free(struct compiler *);
|
||||
static basicblock *compiler_new_block(struct compiler *);
|
||||
static int compiler_next_instr(struct compiler *, basicblock *);
|
||||
@ -457,6 +467,7 @@ compiler_unit_free(struct compiler_unit *u)
|
||||
}
|
||||
Py_CLEAR(u->u_ste);
|
||||
Py_CLEAR(u->u_name);
|
||||
Py_CLEAR(u->u_qualname);
|
||||
Py_CLEAR(u->u_consts);
|
||||
Py_CLEAR(u->u_names);
|
||||
Py_CLEAR(u->u_varnames);
|
||||
@ -467,8 +478,8 @@ compiler_unit_free(struct compiler_unit *u)
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_enter_scope(struct compiler *c, identifier name, void *key,
|
||||
int lineno)
|
||||
compiler_enter_scope(struct compiler *c, identifier name,
|
||||
int scope_type, void *key, int lineno)
|
||||
{
|
||||
struct compiler_unit *u;
|
||||
|
||||
@ -479,6 +490,7 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
|
||||
return 0;
|
||||
}
|
||||
memset(u, 0, sizeof(struct compiler_unit));
|
||||
u->u_scope_type = scope_type;
|
||||
u->u_argcount = 0;
|
||||
u->u_kwonlyargcount = 0;
|
||||
u->u_ste = PySymtable_Lookup(c->c_st, key);
|
||||
@ -566,6 +578,59 @@ compiler_exit_scope(struct compiler *c)
|
||||
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
compiler_scope_qualname(struct compiler *c)
|
||||
{
|
||||
Py_ssize_t stack_size, i;
|
||||
_Py_static_string(dot, ".");
|
||||
_Py_static_string(locals, "<locals>");
|
||||
struct compiler_unit *u;
|
||||
PyObject *capsule, *name, *seq, *dot_str, *locals_str;
|
||||
|
||||
u = c->u;
|
||||
if (u->u_qualname != NULL) {
|
||||
Py_INCREF(u->u_qualname);
|
||||
return u->u_qualname;
|
||||
}
|
||||
|
||||
seq = PyList_New(0);
|
||||
if (seq == NULL)
|
||||
return NULL;
|
||||
|
||||
stack_size = PyList_GET_SIZE(c->c_stack);
|
||||
for (i = 0; i < stack_size; i++) {
|
||||
capsule = PyList_GET_ITEM(c->c_stack, i);
|
||||
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
|
||||
assert(u);
|
||||
if (u->u_scope_type == COMPILER_SCOPE_MODULE)
|
||||
continue;
|
||||
if (PyList_Append(seq, u->u_name))
|
||||
goto _error;
|
||||
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) {
|
||||
locals_str = _PyUnicode_FromId(&locals);
|
||||
if (locals_str == NULL)
|
||||
goto _error;
|
||||
if (PyList_Append(seq, locals_str))
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
u = c->u;
|
||||
if (PyList_Append(seq, u->u_name))
|
||||
goto _error;
|
||||
dot_str = _PyUnicode_FromId(&dot);
|
||||
if (dot_str == NULL)
|
||||
goto _error;
|
||||
name = PyUnicode_Join(dot_str, seq);
|
||||
Py_DECREF(seq);
|
||||
u->u_qualname = name;
|
||||
Py_XINCREF(name);
|
||||
return name;
|
||||
|
||||
_error:
|
||||
Py_XDECREF(seq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate a new block and return a pointer to it.
|
||||
Returns NULL on error.
|
||||
*/
|
||||
@ -862,9 +927,9 @@ opcode_stack_effect(int opcode, int oparg)
|
||||
case CALL_FUNCTION_VAR_KW:
|
||||
return -NARGS(oparg)-2;
|
||||
case MAKE_FUNCTION:
|
||||
return -NARGS(oparg) - ((oparg >> 16) & 0xffff);
|
||||
return -1 -NARGS(oparg) - ((oparg >> 16) & 0xffff);
|
||||
case MAKE_CLOSURE:
|
||||
return -1 - NARGS(oparg) - ((oparg >> 16) & 0xffff);
|
||||
return -2 - NARGS(oparg) - ((oparg >> 16) & 0xffff);
|
||||
#undef NARGS
|
||||
case BUILD_SLICE:
|
||||
if (oparg == 3)
|
||||
@ -1194,7 +1259,7 @@ compiler_mod(struct compiler *c, mod_ty mod)
|
||||
return NULL;
|
||||
}
|
||||
/* Use 0 for firstlineno initially, will fixup in assemble(). */
|
||||
if (!compiler_enter_scope(c, module, mod, 0))
|
||||
if (!compiler_enter_scope(c, module, COMPILER_SCOPE_MODULE, mod, 0))
|
||||
return NULL;
|
||||
switch (mod->kind) {
|
||||
case Module_kind:
|
||||
@ -1270,11 +1335,15 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
|
||||
compiler_make_closure(struct compiler *c, PyCodeObject *co, int args, PyObject *qualname)
|
||||
{
|
||||
int i, free = PyCode_GetNumFree(co);
|
||||
if (qualname == NULL)
|
||||
qualname = co->co_name;
|
||||
|
||||
if (free == 0) {
|
||||
ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
|
||||
ADDOP_O(c, LOAD_CONST, qualname, consts);
|
||||
ADDOP_I(c, MAKE_FUNCTION, args);
|
||||
return 1;
|
||||
}
|
||||
@ -1311,6 +1380,7 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
|
||||
}
|
||||
ADDOP_I(c, BUILD_TUPLE, free);
|
||||
ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
|
||||
ADDOP_O(c, LOAD_CONST, qualname, consts);
|
||||
ADDOP_I(c, MAKE_CLOSURE, args);
|
||||
return 1;
|
||||
}
|
||||
@ -1452,7 +1522,7 @@ static int
|
||||
compiler_function(struct compiler *c, stmt_ty s)
|
||||
{
|
||||
PyCodeObject *co;
|
||||
PyObject *first_const = Py_None;
|
||||
PyObject *qualname, *first_const = Py_None;
|
||||
arguments_ty args = s->v.FunctionDef.args;
|
||||
expr_ty returns = s->v.FunctionDef.returns;
|
||||
asdl_seq* decos = s->v.FunctionDef.decorator_list;
|
||||
@ -1478,7 +1548,8 @@ compiler_function(struct compiler *c, stmt_ty s)
|
||||
return 0;
|
||||
assert((num_annotations & 0xFFFF) == num_annotations);
|
||||
|
||||
if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s,
|
||||
if (!compiler_enter_scope(c, s->v.FunctionDef.name,
|
||||
COMPILER_SCOPE_FUNCTION, (void *)s,
|
||||
s->lineno))
|
||||
return 0;
|
||||
|
||||
@ -1500,14 +1571,19 @@ compiler_function(struct compiler *c, stmt_ty s)
|
||||
VISIT_IN_SCOPE(c, stmt, st);
|
||||
}
|
||||
co = assemble(c, 1);
|
||||
qualname = compiler_scope_qualname(c);
|
||||
compiler_exit_scope(c);
|
||||
if (co == NULL)
|
||||
if (qualname == NULL || co == NULL) {
|
||||
Py_XDECREF(qualname);
|
||||
Py_XDECREF(co);
|
||||
return 0;
|
||||
}
|
||||
|
||||
arglength = asdl_seq_LEN(args->defaults);
|
||||
arglength |= kw_default_count << 8;
|
||||
arglength |= num_annotations << 16;
|
||||
compiler_make_closure(c, co, arglength);
|
||||
compiler_make_closure(c, co, arglength, qualname);
|
||||
Py_DECREF(qualname);
|
||||
Py_DECREF(co);
|
||||
|
||||
/* decorators */
|
||||
@ -1542,7 +1618,8 @@ compiler_class(struct compiler *c, stmt_ty s)
|
||||
*/
|
||||
|
||||
/* 1. compile the class body into a code object */
|
||||
if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, s->lineno))
|
||||
if (!compiler_enter_scope(c, s->v.ClassDef.name,
|
||||
COMPILER_SCOPE_CLASS, (void *)s, s->lineno))
|
||||
return 0;
|
||||
/* this block represents what we do in the new scope */
|
||||
{
|
||||
@ -1572,6 +1649,21 @@ compiler_class(struct compiler *c, stmt_ty s)
|
||||
return 0;
|
||||
}
|
||||
Py_DECREF(str);
|
||||
/* store the __qualname__ */
|
||||
str = compiler_scope_qualname(c);
|
||||
if (!str) {
|
||||
compiler_exit_scope(c);
|
||||
return 0;
|
||||
}
|
||||
ADDOP_O(c, LOAD_CONST, str, consts);
|
||||
Py_DECREF(str);
|
||||
str = PyUnicode_InternFromString("__qualname__");
|
||||
if (!str || !compiler_nameop(c, str, Store)) {
|
||||
Py_XDECREF(str);
|
||||
compiler_exit_scope(c);
|
||||
return 0;
|
||||
}
|
||||
Py_DECREF(str);
|
||||
/* compile the body proper */
|
||||
if (!compiler_body(c, s->v.ClassDef.body)) {
|
||||
compiler_exit_scope(c);
|
||||
@ -1608,7 +1700,7 @@ compiler_class(struct compiler *c, stmt_ty s)
|
||||
ADDOP(c, LOAD_BUILD_CLASS);
|
||||
|
||||
/* 3. load a function (or closure) made from the code object */
|
||||
compiler_make_closure(c, co, 0);
|
||||
compiler_make_closure(c, co, 0, NULL);
|
||||
Py_DECREF(co);
|
||||
|
||||
/* 4. load class name */
|
||||
@ -1659,6 +1751,7 @@ static int
|
||||
compiler_lambda(struct compiler *c, expr_ty e)
|
||||
{
|
||||
PyCodeObject *co;
|
||||
PyObject *qualname;
|
||||
static identifier name;
|
||||
int kw_default_count = 0, arglength;
|
||||
arguments_ty args = e->v.Lambda.args;
|
||||
@ -1678,7 +1771,8 @@ compiler_lambda(struct compiler *c, expr_ty e)
|
||||
}
|
||||
if (args->defaults)
|
||||
VISIT_SEQ(c, expr, args->defaults);
|
||||
if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
|
||||
if (!compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION,
|
||||
(void *)e, e->lineno))
|
||||
return 0;
|
||||
|
||||
/* Make None the first constant, so the lambda can't have a
|
||||
@ -1696,13 +1790,15 @@ compiler_lambda(struct compiler *c, expr_ty e)
|
||||
ADDOP_IN_SCOPE(c, RETURN_VALUE);
|
||||
}
|
||||
co = assemble(c, 1);
|
||||
qualname = compiler_scope_qualname(c);
|
||||
compiler_exit_scope(c);
|
||||
if (co == NULL)
|
||||
if (qualname == NULL || co == NULL)
|
||||
return 0;
|
||||
|
||||
arglength = asdl_seq_LEN(args->defaults);
|
||||
arglength |= kw_default_count << 8;
|
||||
compiler_make_closure(c, co, arglength);
|
||||
compiler_make_closure(c, co, arglength, qualname);
|
||||
Py_DECREF(qualname);
|
||||
Py_DECREF(co);
|
||||
|
||||
return 1;
|
||||
@ -2916,11 +3012,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
|
||||
{
|
||||
PyCodeObject *co = NULL;
|
||||
expr_ty outermost_iter;
|
||||
PyObject *qualname = NULL;
|
||||
|
||||
outermost_iter = ((comprehension_ty)
|
||||
asdl_seq_GET(generators, 0))->iter;
|
||||
|
||||
if (!compiler_enter_scope(c, name, (void *)e, e->lineno))
|
||||
if (!compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION,
|
||||
(void *)e, e->lineno))
|
||||
goto error;
|
||||
|
||||
if (type != COMP_GENEXP) {
|
||||
@ -2953,12 +3051,14 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
|
||||
}
|
||||
|
||||
co = assemble(c, 1);
|
||||
qualname = compiler_scope_qualname(c);
|
||||
compiler_exit_scope(c);
|
||||
if (co == NULL)
|
||||
if (qualname == NULL || co == NULL)
|
||||
goto error;
|
||||
|
||||
if (!compiler_make_closure(c, co, 0))
|
||||
if (!compiler_make_closure(c, co, 0, qualname))
|
||||
goto error;
|
||||
Py_DECREF(qualname);
|
||||
Py_DECREF(co);
|
||||
|
||||
VISIT(c, expr, outermost_iter);
|
||||
@ -2968,6 +3068,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
|
||||
error_in_scope:
|
||||
compiler_exit_scope(c);
|
||||
error:
|
||||
Py_XDECREF(qualname);
|
||||
Py_XDECREF(co);
|
||||
return 0;
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ typedef unsigned short mode_t;
|
||||
tag: cpython-32
|
||||
Python 3.2a2 3180 (add DELETE_DEREF)
|
||||
Python 3.3a0 3190 __class__ super closure changed
|
||||
Python 3.3a0 3200 (__qualname__ added)
|
||||
*/
|
||||
|
||||
/* MAGIC must change whenever the bytecode emitted by the compiler may no
|
||||
@ -115,7 +116,7 @@ typedef unsigned short mode_t;
|
||||
#define STRIFY(name) QUOTE(name)
|
||||
#define MAJOR STRIFY(PY_MAJOR_VERSION)
|
||||
#define MINOR STRIFY(PY_MINOR_VERSION)
|
||||
#define MAGIC (3190 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
||||
#define MAGIC (3200 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
||||
#define TAG "cpython-" MAJOR MINOR;
|
||||
#define CACHEDIR "__pycache__"
|
||||
/* Current magic word and string tag as globals. */
|
||||
|
Loading…
Reference in New Issue
Block a user