[issue46085] OrderedDict iterator allocates di_result unnecessarily
New submission from Kevin Shweh : The OrderedDict iterator caches a di_result tuple for use with iter(od.items()). It's *supposed* to only do that for the items() case, but the code does if (kind & (_odict_ITER_KEYS | _odict_ITER_VALUES)) to test for this case. This is the wrong test. It should be if ((kind & _odict_ITER_KEYS) && (kind &_odict_ITER_VALUES)) The current test allocates di_result for key and value iterators as well as items iterators. -- components: Library (Lib) messages: 408616 nosy: Kevin Shweh priority: normal severity: normal status: open title: OrderedDict iterator allocates di_result unnecessarily type: resource usage versions: Python 3.10, Python 3.11, Python 3.8, Python 3.9 ___ Python tracker <https://bugs.python.org/issue46085> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue46085] OrderedDict iterator allocates di_result unnecessarily
Kevin Shweh added the comment: Almost - C's weird bitwise operator precedence means it has to be parenthesized as if ((kind & _odict_ITER_ITEMS) == _odict_ITER_ITEMS) -- ___ Python tracker <https://bugs.python.org/issue46085> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue46726] Thread spuriously marked dead after interrupting a join call
New submission from Kevin Shweh : This code in Thread._wait_for_tstate_lock: try: if lock.acquire(block, timeout): lock.release() self._stop() except: if lock.locked(): # bpo-45274: lock.acquire() acquired the lock, but the function # was interrupted with an exception before reaching the # lock.release(). It can happen if a signal handler raises an # exception, like CTRL+C which raises KeyboardInterrupt. lock.release() self._stop() raise has a bug. The "if lock.locked()" check doesn't check whether this code managed to acquire the lock. It checks if *anyone at all* is holding the lock. The lock is almost always locked, so this code will perform a spurious call to self._stop() if it gets interrupted while trying to acquire the lock. Thread.join uses this method to wait for a thread to finish, so a thread will spuriously be marked dead if you interrupt a join call with Ctrl-C while it's trying to acquire the lock. Here's a reproducer: import time import threading event = threading.Event() def target(): event.wait() print('thread done') t = threading.Thread(target=target) t.start() print('joining now') try: t.join() except KeyboardInterrupt: pass print(t.is_alive()) event.set() Interrupt this code with Ctrl-C during the join(), and print(t.is_alive()) will print False. -- components: Library (Lib) messages: 413106 nosy: Kevin Shweh priority: normal severity: normal status: open title: Thread spuriously marked dead after interrupting a join call type: behavior versions: Python 3.10, Python 3.11, Python 3.9 ___ Python tracker <https://bugs.python.org/issue46726> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue46726] Thread spuriously marked dead after interrupting a join call
Kevin Shweh added the comment: Issue 45274 was a subtly different issue. That was a problem that happened if the thread got interrupted *between* the acquire and the release, causing it to *not* release the lock and *not* perform end-of-thread cleanup. The fix for that issue caused this issue, which happens if the thread gets interrupted *during* the acquire, in which case it *does* release the lock (that someone else is holding) and *does* perform end-of-thread cleanup even though it's not supposed to do either of those things. -- ___ Python tracker <https://bugs.python.org/issue46726> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue46726] Thread spuriously marked dead after interrupting a join call
Kevin Shweh added the comment: The PR you submitted doesn't work, unfortunately. It essentially reintroduces issue 45274. If this line: if locked := lock.acquire(block, timeout): gets interrupted between the acquire and the assignment, locked is still False. That's rare, but so is an interruption between the acquire and the release, which is the original form of issue 45274. -- ___ Python tracker <https://bugs.python.org/issue46726> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue46722] Different behavior for functiools.partial between inspect.isfunction() and other inspect.is*function()
Kevin Shweh added the comment: Frankly, it doesn't make sense that isgeneratorfunction or iscoroutinefunction unwrap partials at all. The original justification for making them do that back in https://bugs.python.org/issue34890 was invalid - the original argument was that isfunction unwraps partials, but it doesn't, and I don't think it ever did. isfunction is supposed to be a very specific check for Python function objects. It rejects all sorts of other callables, like sum (a built-in function), super (a type), or method objects (which wrap functions in a very similar way to partial). Having it be a check for *either* a Python function object *or* a partial object wrapping a Python function object seems to just make it less useful. ------ nosy: +Kevin Shweh ___ Python tracker <https://bugs.python.org/issue46722> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue38908] Troubles with @runtime_checkable protocols
Kevin Shweh added the comment: It seems like the straightforward, minimal fix would be to just add if (getattr(cls, '_is_protocol', False) and not getattr(cls, '_is_runtime_protocol', False) and not _allow_reckless_class_cheks()): raise TypeError(...) to _ProtocolMeta.__instancecheck__. Does that fail on some edge case (that the current implementation works on)? It's a little weird that _ProtocolMeta.__instancecheck__ doesn't explicitly check that the protocol is runtime-checkable. -- nosy: +Kevin Shweh ___ Python tracker <https://bugs.python.org/issue38908> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue44921] dict subclassing is slow
Kevin Shweh added the comment: Of course it's reasonable to support dict subclasses. We already have a bunch of dict subclasses in the standard library, like collections.defaultdict and collections.Counter, and collections.Counter is significantly slower than it could be because of this issue. (collections.defaultdict seems to be unaffected due to differences between classes implemented in C and Python.) dict.__getitem__ even has dedicated support for a __missing__ hook, which is only useful for subclasses. -- nosy: +Kevin Shweh ___ Python tracker <https://bugs.python.org/issue44921> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue45104] Error in __new__ docs
New submission from Kevin Shweh : The data model docs for __new__ say "If __new__() is invoked during object construction and it returns an instance or subclass of cls, then the new instance’s __init__() method will be invoked..." "instance or subclass of cls" is incorrect - if for some reason __new__ returns a subclass of cls, __init__ will not be invoked, unless the subclass also happens to be an instance of cls (which can happen with metaclasses). This should probably say something like "instance of cls (including subclass instances)", or "instance of cls or of a subclass of cls", or just "instance of cls". -- assignee: docs@python components: Documentation messages: 401065 nosy: Kevin Shweh, docs@python priority: normal severity: normal status: open title: Error in __new__ docs versions: Python 3.10, Python 3.11, Python 3.8, Python 3.9 ___ Python tracker <https://bugs.python.org/issue45104> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue38947] dataclass defaults behave inconsistently for init=True/init=False when default is a descriptor
New submission from Kevin Shweh : The following code: from dataclasses import dataclass, field from typing import Callable @dataclass class Foo: callback: Callable[[int], int] = lambda x: x**2 @dataclass class Bar: callback: Callable[[int], int] = field(init=False, default=lambda x: x**2) print(Foo().callback(2)) print(Bar().callback(2)) prints 4 for the first print, but throws a TypeError for the second. This is because Foo() stores the default callback in the instance dict, while Bar() only has it in the class dict. Bar().callback triggers the descriptor protocol and produces a method object instead of the original callback. There does not seem to be any indication in the dataclasses documentation that these fields will behave differently. It seems like they should behave the same, and/or the documentation should be clearer about how the default value/non-init field interaction behaves. -- components: Library (Lib) messages: 357669 nosy: Kevin Shweh priority: normal severity: normal status: open title: dataclass defaults behave inconsistently for init=True/init=False when default is a descriptor type: behavior versions: Python 3.7, Python 3.8 ___ Python tracker <https://bugs.python.org/issue38947> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue42190] global declarations affect too much inside exec or compile
New submission from Kevin Shweh : A global declaration inside a function is only supposed to affect assignments inside that function, but in code executed with exec, a global declaration affects assignments outside the function: >>> gdict = {} >>> ldict = {} >>> exec('x = 1', gdict, ldict) >>> 'x' in gdict False >>> 'x' in ldict True >>> >>> gdict = {} >>> ldict = {} >>> exec(''' ... x = 1 ... def f(): global x''', gdict, ldict) >>> 'x' in gdict True >>> 'x' in ldict False Here, we can see that the presence of a "global x" declaration inside f causes the "x = 1" outside of f to assign to globals instead of locals. This also affects code objects compiled with compile(). -- components: Interpreter Core messages: 379855 nosy: Kevin Shweh priority: normal severity: normal status: open title: global declarations affect too much inside exec or compile type: behavior versions: Python 3.8 ___ Python tracker <https://bugs.python.org/issue42190> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36951] Wrong types for PyMemberDefs in Objects/typeobject.c
New submission from Kevin Shweh : In Objects/typeobject.c, the PyMemberDefs for __flags__, __weakrefoffset__, and __dictoffset__ all use T_LONG: {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY}, {"__weakrefoffset__", T_LONG, offsetof(PyTypeObject, tp_weaklistoffset), READONLY}, ... {"__dictoffset__", T_LONG, offsetof(PyTypeObject, tp_dictoffset), READONLY}, {"__weakrefoffset__", T_LONG, offsetof(PyTypeObject, tp_weaklistoffset), READONLY}, but in Include/object.h or Include/cpython/object.h, the corresponding struct members have types unsigned long, Py_ssize_t, and Py_ssize_t respectively: /* Flags to define presence of optional/expanded features */ unsigned long tp_flags; ... /* weak reference enabler */ Py_ssize_t tp_weaklistoffset; ... Py_ssize_t tp_dictoffset; These uses of T_LONG should be changed to T_ULONG and T_PYSSIZE_T. This was checked on 3.7.3 and master. -- components: Interpreter Core messages: 342759 nosy: Kevin Shweh priority: normal severity: normal status: open title: Wrong types for PyMemberDefs in Objects/typeobject.c type: behavior versions: Python 3.7, Python 3.8 ___ Python tracker <https://bugs.python.org/issue36951> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36951] Wrong types for PyMemberDefs in Objects/typeobject.c
Kevin Shweh added the comment: Looks like I accidentally doubled the PyMemberDef for __weakrefoffset__ while editing. There's no double definition in the actual file. -- ___ Python tracker <https://bugs.python.org/issue36951> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue31127] Abstract classes derived from built-in classes don't block instance creation
New submission from Kevin Shweh: The only check that prevents instantiating abstract classes is in object.__new__, but most built-in classes never actually call object.__new__. That means you can do stuff like import abc class Foo(list, metaclass=abc.ABCMeta): @abc.abstractmethod def abstract(self): pass Foo() and the Foo() call will silently succeed. Ideally, the Foo() call should fail. Other options include having the Foo class definition itself fail, or just making a note in the documentation describing the limitation. (As far as I can see, this is currently undocumented.) -- assignee: docs@python components: Documentation, Library (Lib) messages: 299810 nosy: Kevin Shweh, docs@python priority: normal severity: normal status: open title: Abstract classes derived from built-in classes don't block instance creation type: behavior versions: Python 2.7, Python 3.6 ___ Python tracker <http://bugs.python.org/issue31127> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue14385] Support other types than dict for __builtins__
Kevin Shweh added the comment: The patch for this issue changed LOAD_GLOBAL to use PyObject_GetItem when globals() is a dict subclass, but LOAD_NAME, STORE_GLOBAL, and DELETE_GLOBAL weren't changed. (LOAD_NAME uses PyObject_GetItem for builtins now, but not for globals.) This means that global lookup doesn't respect overridden __getitem__ inside a class statement (unless you explicitly declare the name global with a global statement, in which case LOAD_GLOBAL gets used instead of LOAD_NAME). I don't have a strong opinion on whether STORE_GLOBAL or DELETE_GLOBAL should respect overridden __setitem__ or __delitem__, but the inconsistency between LOAD_GLOBAL and LOAD_NAME seems like a bug that should be fixed. For reference, in the following code, the first 3 exec calls successfully print 5, and the last exec call fails, due to the LOAD_GLOBAL/LOAD_NAME inconsistency: class Foo(dict): def __getitem__(self, index): return 5 if index == 'y' else super().__getitem__(index) exec('print(y)', Foo()) exec('global y; print(y)', Foo()) exec(''' class UsesLOAD_NAME: global y print(y)''', Foo()) exec(''' class UsesLOAD_NAME: print(y)''', Foo()) -- nosy: +Kevin Shweh ___ Python tracker <https://bugs.python.org/issue14385> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue36220] LOAD_NAME and LOAD_GLOBAL handle dict subclasses for globals() differently
New submission from Kevin Shweh : LOAD_NAME and LOAD_GLOBAL don't treat dict subclasses for globals() the same way. If globals() is a dict subclass, LOAD_GLOBAL will respect overridden __getitem__, but LOAD_NAME will use PyDict_GetItem. This causes global lookup to behave differently in class statements; for example, in the following code, the final exec is the only one where print(y) causes a NameError: class Foo(dict): def __getitem__(self, index): return 5 if index == 'y' else super().__getitem__(index) exec('print(y)', Foo()) exec('global y; print(y)', Foo()) exec(''' class UsesLOAD_NAME: global y print(y)''', Foo()) exec(''' class UsesLOAD_NAME: print(y)''', Foo()) STORE_GLOBAL and DELETE_GLOBAL also go straight for PyDict_SetItem and PyDict_DelItem; I don't know whether those should be considered bugs as well, but the inconsistency between LOAD_NAME and LOAD_GLOBAL definitely seems wrong. (For reference, the change that introduced the inconsistency was made for issue #14385, which was intended to support non-dict __builtins__.) -- components: Interpreter Core messages: 337356 nosy: Kevin Shweh priority: normal severity: normal status: open title: LOAD_NAME and LOAD_GLOBAL handle dict subclasses for globals() differently type: behavior versions: Python 3.7, Python 3.8 ___ Python tracker <https://bugs.python.org/issue36220> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue15606] re.VERBOSE whitespace behavior not completely documented
Kevin Shweh added the comment: It looks to me like there are more situations than the patch lists where whitespace still separates tokens. For example, *? is a reluctant quantifier and * ? is a syntax error, even in verbose mode. -- nosy: +Kevin Shweh ___ Python tracker <https://bugs.python.org/issue15606> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue29581] __init_subclass__ causes TypeError when used with standard library metaclasses (such as ABCMeta)
Kevin Shweh added the comment: Doesn't that ignore_extra_args thing prevent InitX.__init_subclass__ from receiving the x argument it wanted? It doesn't seem like a solution. -- nosy: +Kevin Shweh ___ Python tracker <http://bugs.python.org/issue29581> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue7406] int arithmetic relies on C signed overflow behaviour
Kevin Shweh added the comment: It looks like the fast paths for INPLACE_ADD and INPLACE_SUBTRACT in Python 2 don't have the cast-to-unsigned fix, so they're still relying on undefined behavior. For example, in INPLACE_ADD: /* INLINE: int + int */ register long a, b, i; a = PyInt_AS_LONG(v); b = PyInt_AS_LONG(w); i = a + b; if ((i^a) < 0 && (i^b) < 0) goto slow_iadd; -- nosy: +Kevin Shweh ___ Python tracker <http://bugs.python.org/issue7406> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com
[issue25843] lambdas on the same line may incorrectly share code objects
Kevin Shweh added the comment: A type-based check runs into problems with 0.0 vs -0.0. For example, on Python 2.7.11: >>> x, y = lambda: 0.0, lambda: -0.0 >>> y() 0.0 I wasn't able to reproduce the -0.0 problem with Python 3.4 on Ideone; y.__code__.co_consts seems to have an unused 0.0 in it on 3.4. I don't have access to Python 3.5, so I don't know what the situation is like on that version. -- nosy: +Kevin Shweh ___ Python tracker <http://bugs.python.org/issue25843> ___ ___ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com