#internals-and-peps
1 messages · Page 33 of 1
Hii everyone
hey
You could do gc.get_referrers(obj) and then try to un-bind the references to objon each of them
And then you don't explicitly kill the object. So if you successfully killed all the references, it's going to die due to normal garbage collection. Otherwise, it keeps on living
like a best-effort thing
though that seems like a huge footgun with unclear benefits
maybe global del could del the reference, and error out if the object still has references leftover. That should still let you have predictable lifetimes for objects where it's relevant.
that's not enough because the GC doesn't necessarily know about all references
eventually we may get a protocol that identifies all references of an object for some concurrency-related things
Hi I need help
hey
if only this was possible
if case (_, _) = all_length:
if let moment
Hi, does anyone with a JIT build want to help figuring out whether lafleur found a real JIT bug?
What’s the bug?
I've just reported it as https://github.com/python/cpython/issues/140104, but any confirmation would be nice because I'm still worried I did something wrong 😅
there seems to be a documentation rendering with it not removing the module name for the deco role in https://docs.python.org/3/library/warnings.html#warnings.deprecated
you mean the "@~typing.overload" part right?
yeah that looks wrong, maybe open an issue on CPython? if it's a sphinx bug somebody will redirect it
@~deco seems like some cool syntax.
it's meant to render without the module name
can someone help me ?
This is not the appropriate channel for that, see #❓|how-to-get-help
please no advertising
Alright
Why does ast.fix_missing_locations return the modified node, if it mutates it as well? Is that just a historical accident?
same with ast.copy_location and ast.increment_lineno
i thought all this does is apply the line numbers?
Its an annoyance u have to do when modifying the ast or generating code from scratch with AST and go to dump it
probably no good reason
reminds me of Javascript behaviour
3.13
>>> Union[int, str] | 'complex'
typing.Union[int, str, ForwardRef('complex')]
3.14
>>> Union[int, str] | 'complex'
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
Union[int, str] | 'complex'
~~~~~~~~~~~~~~~~^~~~~~~~~~~
TypeError: unsupported operand type(s) for |: 'typing.Union' and 'str'
is this a bug, or is the change mentioned somewhere?
I was reading it here, but didn't see a mention of it https://docs.python.org/3/whatsnew/3.14.html#typing
that's a bug
is it filed anywhere, or should I go report it?
(I'm assuming its already been filed tbh)
please report it
done!
In python, a function typically either mutates an object and returns None, or returns a copy and returns that. See list.sort and sorted
i dont think I understood the question lol, sorry.
Can you give me some tips on the best way to learn Python?
ast.fix_missing_locations mutates the argument, but also returns it. If you use it like this: py my_node = ... fixed_node = ast.fix_missing_locations(my_node) you might think that fixed_node is a new object, but it's the same as my_node
the typical convention is to return None if you're mutating the argument, so I was surprised
yeah I see now ur question, thank you 🙂 . I agree it is surprising
Maybe it's just easier to chain?
On discourse, does github issue status when previewing adjust to the UI language of the message author? Or am I tripping
See opened on the left and відкрито on the right
sure looks like it
must be I guess. when you write the comment some JS runs that prefetches it?
strange feature for sure
mostly for the 99% of readers who don't know what відкрито means
should I post about it on the meta topic?
Hm... https://github.blog/news-insights/the-library/github-in-your-language/
apparently github doesn't support non-English languages anymore?
Edit (11/18/2016): GitHub no longer supports languages other than English.
weird, it should have called _type_convert on the string when fast path failed
assuming that the comment is right saying that it's is_unionable that is the problem
oooh, it's not this code path
interesting.
working on a fix
yeah, i see the problem. contrary to how casting is done in unionbuilder_add_single, we don't call type_check() on the _Py_union_type_or because we want to adhere to the operator protocol and return NotImplemented instead of raising an error that each arg must be a type
if it was any different, that would break the liskov principle, sort-of
in some parallel scheme of things, PEP 604 could have specified that | on types has its own rules though. that would perhaps simplify things a bit, but wouldn't allow good semantics with custom proxies that would want custom behavior on being |-ed with Unions. ...perhaps?
@feral island will you rewrite wrapping in ForwardRef to C or resort to Python's _type_convert?
index c4ece0fe09f..e5342dd5faf 100644
--- a/Objects/unionobject.c
+++ b/Objects/unionobject.c
@@ -256,13 +256,8 @@ is_unionable(PyObject *obj)
PyObject *
_Py_union_type_or(PyObject* self, PyObject* other)
{
- if (!is_unionable(self) || !is_unionable(other)) {
- Py_RETURN_NOTIMPLEMENTED;
- }
-
unionbuilder ub;
- // unchecked because we already checked is_unionable()
- if (!unionbuilder_init(&ub, false)) {
+ if (!unionbuilder_init(&ub, true)) {
return NULL;
}
if (!unionbuilder_add_single(&ub, self) ||
``` is what I have but haven't tested yet
oh so that would probably introduce new semantics and never return NOT_IMPLEMENTED
because we're resorting to _type_convert and not really reinterpreting the error to NOT_IMPLEMENTED
or am i mistaken
yeah I need to think through the implications more but this would restore 3.13 behavior and allow some other things
i'll check
in particular int | str | "float" would become legal
but not int | "float" which is somewhat dubious
python 3.13 was very loose, yeah
❯ ./python
Python 3.13.9+ (heads/3.13:d7473f7a476, Oct 20 2025, 21:01:02) [GCC 15.2.1 20250808 (Red Hat 15.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import Union
>>> Union['str', 4] | object() | type('', (), {})
typing.Union[ForwardRef('str'), 4, <object object at 0x7f9b75f09c30>, __main__.]
>>> Union['str', object(), type('', (), {})]
typing.Union[ForwardRef('str'), <object object at 0x7f9b75f09c90>, __main__.]
but it still does check whether the types are conceptually correctly placed
>>> Union['str', 4] | object() | type('', (), {}) | ClassVar[int]
Traceback (most recent call last):
...
TypeError: typing.ClassVar[int] is not valid as type argument
TIL!
well i guess i meant type('', (), {})() and not type('', (), {}) which is a valid class by all means in terms of runtime
yeah that's typing._type_check, it just rejects a couple of special things
definitely +1 on restoring the old behavior i guess
runtime processing engines have the most to care about here
in some parallel scheme of things, PEP 604 could have specified that | on types has its own rules though.
so it seems that it did!
yep there we go https://peps.python.org/pep-0604/#incompatible-changes
the proposed change would be the one compatible with the pep ^
no... not too fast
the pep just doesn't seem to specify this case
that PEP is extremely low on detail
yeah
I'm still sort of surprised that was enough back in 3.10 days
@feral island btw had a different take on https://github.com/python/cpython/issues/84644,
perhaps you'd want to take a look?
we're just popping "return" from type hints
https://github.com/python/cpython/pull/140255
it's a pre-work for supporting dispatching on type after typing.Self, although not a must-have to fix that independently
i hope nobody relied on return-type dispatching
left a comment
thanks, very useful! i'll close this and look for something more general then. :-)
oh the issue also already discusses the same thing (the issue is not just with return types, but more generally we don't necessarily look at the right annotation)
yeah but my thing doesn't find the first one, just discards the obvious return annotation
I think the right approach is to first look at inspect.signature to find the right parameter name to use, then grab that one from the annotations dictionary
or I guess straight from the signature
found a different edge case as well
>>> @foo.register
... def x(*args: Unpack[tuple[str, int]], **kwargs):
... print("x called")
...
Traceback (most recent call last):
File "<python-input-9>", line 1, in <module>
@foo.register
^^^^^^^^^^^^
File "/home/bswck/Python/cpython/Lib/functools.py", line 913, in register
raise TypeError(
...<2 lines>...
)
TypeError: Invalid annotation for 'args'. typing.Unpack[tuple[str, int]] is not a class.
this should perhaps find str...
but that's very deep in the woods
at this point you can just pass str
and we can report that special forms aren't supported or something
unless Annotated? are Annotated types supported at all?
oh ok they seem to be
should try but I think the current logic uses get_type_hints which strips Annotated
nice.
I wouldn't worry about that
not sure about *args: T though
because args can be a ()
therefore i think we should raise on a variadic param being registered
but again
edge case.
nooo that would break things
and someone might have a valid use case, and in their code *args could always be 1+ in size just by convention. let's not touch that
i'm seeing skip_bound_arg in _signature_from_callable. it's not public API but definitely of use here?
no, not much. at this point it's always a function, not a bound method. :/
so yeah, inspect.signature would be great primarily as a source of truth
hm yes, maybe there isn't a simple way to recognize the self argument
the problem lies in an edge case of custom descriptors, right
something registered to singledispatchmethod must be a callable belonging to the class
plain function is obvious, classmethod is obvious, and if we specialcase staticmethod to understand the first param as non-self that solves 99% of problematic cases
the rest is an open question
perhaps we can just change the error message to recommend using verbose type API (.register(cls)) if the descriptor is ambiguous?
oh, the thing is more complicated in singledispatchmethod
weird inconsistency in the error messages, is this worth fixing?
>>> class T:
... def __init__(self, a, b): pass
...
>>> T(a=1, **{"a": 2, "b": 3})
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
T(a=1, **{"a": 2, "b": 3})
~^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: __main__.T() got multiple values for keyword argument 'a'
>>> T(c=3)
Traceback (most recent call last):
File "<python-input-5>", line 1, in <module>
T(c=3)
~^^^^^
TypeError: T.__init__() got an unexpected keyword argument 'c'
maybe it's because the multiple kwargs thing gets raised earlier
i'd fix it because the latter is more helpful if both __init__ and __new__ are present and perhaps not uniform:
>>> class T:
... def __init__(self, **kwargs): pass
... def __new__(cls, *, a, b): return object.__new__(cls)
...
>>> T(a=1, **{"a": 2, "b": 3})
Traceback (most recent call last):
File "<python-input-11>", line 1, in <module>
T(a=1, **{"a": 2, "b": 3})
~^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: __main__.T() got multiple values for keyword argument 'a'
>>> T(c=3)
Traceback (most recent call last):
File "<python-input-12>", line 1, in <module>
T(c=3)
~^^^^^
TypeError: T.__new__() got an unexpected keyword argument 'c'
unless in that specific case there is no access to what exactly is the target
maybe .T() is just type.__call__?
it's in ceval so it can't be fixed? we don't know what T will be
Python/ceval.c lines 1725 to 1732
kw_found:
if (PyStackRef_AsPyObjectBorrow(localsplus[j]) != NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"%U() got multiple values for argument '%S'",
func->func_qualname, keyword);
goto kw_fail;
}
localsplus[j] = value_stackref;```
calls with more than one of the same kwarg are always invalid
yeah
maybe the weird thing is that T() is mentioned at all
yes!
that shouldn't be there
>>> (lambda: 1/0)(a=1, **{"a": 2, "b": 3})
Traceback (most recent call last):
File "<python-input-14>", line 1, in <module>
(lambda: 1/0)(a=1, **{"a": 2, "b": 3})
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: __main__.<lambda>() got multiple values for keyword argument 'a'
but perhaps it can be helpful because it's resolved at the time of call
so we know what we tried to call... although the problem isn't calling what, it's calling how
target may be a very weird and unrelated thing if it's improperly wrapped
and that can be confusing
the whole focus should be on the call itself
nice.
>>> SimpleNamespace(__qualname__=1 .__truediv__)(a=1, **{"a": 2})
Traceback (most recent call last):
File "<python-input-23>", line 1, in <module>
SimpleNamespace(__qualname__=1 .__truediv__)(a=1, **{"a": 2})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
TypeError: <method-wrapper '__truediv__' of int object at 0x00007FFFA373D3A8>() got multiple values for keyword argument 'a'
probably should be as close as possible to
>>> whatever(a=1, a=2)
File "<python-input-24>", line 1
whatever(a=1, a=2)
^^^
SyntaxError: keyword argument repeated: a
but not a syntax error, of course
hm it also looks like the callable has no qualname it raises a KeyError?
no
the exception from qualname replaces the TypeError though ```>>> class X:
... def getattr(self, attr):
... if attr == "qualname": raise ZeroDivisionError
... raise AttributeError(attr)
...
X()(a=1, **{"a": 2})
Traceback (most recent call last):
File "<python-input-6>", line 1, in <module>
X()(a=1, **{"a": 2})
~~~^^^^^^^^^^^^^^^^^
File "<python-input-5>", line 3, in getattr
if attr == "qualname": raise ZeroDivisionError
^^^^^^^^^^^^^^^^^^^^^^^
ZeroDivisionError
smart! __qualname__ could only have been patched this way -- not through class assignment, because that one is eagerly validated
it should have falled back to format() like in cases when __qualname__ isn't present
breaks if __str__ is incorrect as well:
>>> type("", (), {"__str__": lambda _: 1})()(a=1, **{"a": 2})
Traceback (most recent call last):
File "<python-input-50>", line 1, in <module>
type("", (), {"__str__": lambda _: 1})()(a=1, **{"a": 2})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
TypeError: __str__ returned non-string (type int)
or, to make it less obvious
>>> mysterious(a=1, **{"a": 2})
Traceback (most recent call last):
File "<python-input-52>", line 1, in <module>
mysterious(a=1, **{"a": 2})
~~~~~~~~~~^^^^^^^^^^^^^^^^^
TypeError: __str__ returned non-string (type int)
i think that, in principle, raising an exception in ceval should be free of side effects
or maybe shouldn't :-)?
__qualname__ is also used for missing arguments, too many positional arguments, positional passed as keyword, non-string keywords and unexpected keyword
(the last one overlaps with where the call is correct but the signature is incompatible)
while __qualname__ isn't likely to fail, __str__ is much more likely to overtake exceptions, particularly if the instance they operate on is partially initialized (AttributeErrors)
but i think it's rare for an object to be only partially initialized if it's being called.
and still, that is only relevant for objects that implement __call__ on their own. most of the time we're simply calling functions and classes.
waht is this channel about
Description is in the top ribbon on the discord display
https://github.com/python/cpython/blob/b3b0d750697e931e46b004122bde7b7987769a87/Lib/test/test_capi/test_float.py#L205
what a bizarre way to write 1 - signaling
Lib/test/test_capi/test_float.py line 205
quiet = int(not signaling)```
it is clear!
If signaling was a bool, then I'd agree it's clear... But it's 0 or 1, not bool. not non_boolean_here is not clearer
well booleans are ints so
it kinda makes sense
Searching around the Python forum in Ideas didn't lead me to anywhere.... anyone know if there's ever been a proposal/discussion around slicing dictionaries by keys? Basically if I have {"a": 1, "b": 2, "c": 3} and, say, ["a", "b"] , to get {"a": 1, "b": 2} without resorting to a comprehension call. Feels like there should be a method on dicts for this
>>> dict_a = {"a": 1, "b": 2, "c": 3}
>>> dict_b = {"c": 4, "d": 5}
>>> list(dict_a.keys() | dict_b.keys())
['a', 'c', 'b', 'd']
>>> list(dict_a.items() | dict_b.items())
[('d', 5), ('b', 2), ('c', 4), ('a', 1), ('c', 3)]
>>> dict_a | dict_b
{'a': 1, 'b': 2, 'c': 4, 'd': 5}
>>> dict_a - dict_b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
>>> dict_a.keys() | dict_b.keys()
{'a', 'c', 'b', 'd'}
>>> dict_a.keys() - dict_b.keys()
{'a', 'b'}
like we're so close to something interesting here IMO! I don't ... I don't think - is really a great operator in this case for this but I do think a method would make a lot of sense
also in terms of del... like wiping a set of keys in one go
(I might just bem issing a method on dict, been staring at the docs and not seeing the thing)
just to mention, dict.items() supports -, but as an operation over a set of (key, value) tuples, so it only removes if both the key and value are the same
>>> x = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> y = {'c': -1, 'd': 4}
>>> dict(x.items() - y.items())
{'a': 1, 'c': 3, 'b': 2}
actual slicing (via the slicing syntax) wouldn't work since dictionaries can store slices as of 3.12 though, dict[:] = ... will literally store that slice object (slice(None, None, None) in this case) as a key
To add:
my_dict["a", "b"] is just indexing using a tuple and tuples are valid keys
(because it's a comma that makes a tuple, not parentheses - those are only needed in empty tuple and when comma can has a different meaning, e.g. in function calls or when defining a dict literal with a tuple key)
Curios if anyone has any advice or an opinion on this-
A while back someone filed a github issue to update asyncio's CancelledError to inherit from BaseException so that it doesn't get caught by generic try/except loops. At first it was rejected, but the Python maintainers came around and updated the inheritance in 3.8.
There's another class named CancelledError in Python from concurrent.futures. Both represent a cancelled task, so it makes sense to me that both would inherit from BaseException. I'm wondering if this was just a miss when they updated asyncio's CancelledError, or if this was intentional. I'm considering trying to make a similar PR to cPython, but it would be my first one.
did that inheriting from Exception cause an actual bug for you, or is this speculation?
I’d expect the places where concurrent.futures.CancelledError can be raised to be pretty different than where asyncio.CancelledError can be raised
yeah tbh it feels very hard/impossible to imagine something that you could index on for dicts given their universal nature. I don't mind a named method, just want something
a fun fact i've learned today is that you can subtract keysview from valuesview, likely because of __rsub__:
>>> {None: []}.values() - {}.keys()
Traceback (most recent call last):
File "<python-input-20>", line 1, in <module>
{None: []}.values() - {}.keys()
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
TypeError: unhashable type: 'list'
(likely because of __rsub__ because you can't subtract valuesview from valuesview)
It caused an actual bug- but it was on me for having a generic try/except block
Is it a bug in CPython that running round(2**31, -2**31) seems to never complete? what even does it mean to round to a negative number of digits?
I think there was an issue about this recently that tried to make it fast, but it was rejected
from memory, it errors out, but spends time proportional to the size of the negative number or something
interestingly I’m also coming at this as fallout from devdanzin’s fuzzing campaign
>>> round(123.456, 2)
123.46
>>> round(123.456, 0)
123.0
>>> round(123.456, -2)
100.0
I'd say round(x, y) is equivalent to round(x * 10**y, 0) / 10**y, whenever it's for positive or negative y
maybe that should be documented in the round docs. Right now it just says negative ndigits is accepted but doesn’t explain what it does. Thanks for experimenting!
thank you!
sounds reasonable, but I would make an ideas thread regarding this. i’m worried that we’ll be breaking things here; asyncio had only been around for 3 years when they changed CancelledError, but concurrent.futures has been around for over a decade (since 3.2)
yes this cannot really be changed in a backwards-compatible way
maybe it's worth the disruption but 🤷♀️
FWIW this is where I landed on this for NumPy: https://github.com/numpy/numpy/pull/30071
c.f. https://huntr.com/bounties/49928a2c-c6bb-4c1c-80ec-5d7bf708bf28 where this almost led to a CVE getting reported against NumPy.
Addresses one of the issues reported in #28829.
For those who are...
you say INT_MIN == -INT_MAX - 1 but C doesn't guarantee two's complement, right?
doesn't really affect your fix though
I was talking a little loosely
fair
rephrased a little more precisely
looks good to me. disappointing that numpy won't support 2**16-bit floats though 😛
that’s a problem for numpy of the fuuuuutuuuuure
that's how we get a new y2k problem
iirc overflow of signed ints is undefined in C/C++, while overflow of unsigned ints is two's complement, or something like that
Here's a doozy: https://github.com/jburgy/skean/pull/2 is my (currently unsuccessful) attempt at upgrading a PEP-523 hack past 3.10. The PyFrameObject/_PyInterpreterFrame split which happened in 3.11 broke most of the things and I am under the grand delusion that I fixed all but one. Who's foolish enough to help me with that last issue (accessing locals of the current _PyInterpreterFrame not the closest "complete" PyFrameObject)?
I don't follow what you mean by "complete"... You say:
PyEval_GetFrame and PyThreadState_GetFrame only return complete frames. The relevant frame is, by definition, incomplete since we're in the middle of evaluating it!
But by that definition, every frame on the stack is incomplete... every frame on the stack is still being evaluated - that's literally what it means for a frame to be on the stack, that it will eventually be returned to and continue executing
All of which is to say, PyEval_GetFrame can certainly return a frame that's still being evaluated
My statement comes from observing that PyFrame_GetLocals(PyThreadState_GetFrame(tstate))) and PyCode_GetVarnames(PyUnstable_InterpreterFrame_GetCode(iframe)) don't line up during my test. The former contains fibonacci while the latter contains n which leads me to believe PyThreadState_GetFrame(tstate) represents the caller and iframe the callee. This jives with the following bit of cpython:
/* Determine whether a frame is incomplete.
* A frame is incomplete if it is part way through
* creating cell objects or a generator or coroutine.
*
* Frames on the frame stack are incomplete until the
* first RESUME instruction.
* Frames owned by a generator are always complete.
*
* NOTE: We allow racy accesses to the instruction pointer
* from other threads for sys._current_frames() and similar APIs.
*/
static inline bool _Py_NO_SANITIZE_THREAD
_PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
{
if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {
return true;
}
return frame->owner != FRAME_OWNED_BY_GENERATOR &&
frame->instr_ptr < _PyFrame_GetBytecode(frame) +
_PyFrame_GetCode(frame)->_co_firsttraceable;
}
static inline _PyInterpreterFrame *
_PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)
{
while (frame && _PyFrame_IsIncomplete(frame)) {
frame = frame->previous;
}
return frame;
}
static inline _PyInterpreterFrame *
_PyThreadState_GetFrame(PyThreadState *tstate)
{
return _PyFrame_GetFirstComplete(tstate->current_frame);
}
PyEval_GetFrame calls _PyEval_GetFrame which, in turns, calls _PyThreadState_GetFrame. Only difference is you don't need to pass a thread state, it will use _PyThreadState_GET
Even PyFrameObject *_PyFrame_GetFrameObject(_PyInterpreterFrame *frame) (which I can't access because it's static inline) asserts that !_PyFrame_IsIncomplete(frame) before returning _PyFrame_MakeAndSetFrameObject so that wouldn't help either. I believe I need to address the interpreter frame's locals directly but don't know how
Oh, I just found something completely evil and disgusting to access .localplus: <PyObject **>((<char *>_frame) + 72). (72 because, in 3.12, _PyInterpreterFrame contains 8 pointers, an int (stacktop), an unsigned short (return_offset), a char (owner), and padding to the next double word before localsplus)
The hack above can be made marginally less disgusting if you squint hard enough and remember struct padding and flexible array members in C: (<PyObject **>_frame) + 9. Forget that _PyInterpreterFrame is a struct with an array of PyObject * inline at the end. Think of it as an array of PyObject * where the first few (9 to be specific in 3.12 and 3.13) entries represent a header. Then skip over that header.
PyO3 (finally) moved from static to multi-phase initialization for pymodules: https://github.com/PyO3/pyo3/pull/5525
TIL. I gotta say... I find that - operation totally surprising
I also don't even really understand how that can work, there's no guarantee that value is hashable at all, so if this is the case, it can only work quadratically
unless I'm missing something
it only supports dict_items objects is how it manages
sorry, don't think I followed that
the - operation is performed "over a set of (key, value)" items
Yeah, and you are given the (key,value) pairs from a source that ensures that the key is hashable
but not the value
>>> a = [1, 2, 3]
>>> d = {'x': a}
>>> d.items() - d.items()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> d = {'x': tuple(a)}
>>> d.items() - d.items()
set()
Oh interesting!
okay, erroring is at least better than silently using quadratic behavior, thanks for pointing that out
I definitely still think having a - operator here is a mistake though, personally
you don't need the value to be hashable
i.e. dict_items is not really a set of tuples as far as I know, it (internally) supports O(1) access by key
I thought it used the keys' hash and then compared values only on key collision, this is definitely funny behavior
I'm talking about the specific example laid out by etrotta
and as we can see, in that case you do need the value to be hashable
for normal dictionary behaviour, yes
for dictionary items - operation, feels unlikely to be the case
anyhow - back to the operator existing to start with
I suspect if you told 100 python devs who didn't already know that d1.items() - d2.items() was valid and asked them to guess the behavior
a huge fraction if not the majority would get it wrong
and it's rather niche to start with - IMHO would be better if it didn't exist
I guess I just find the set-like behavior a unexpected
well, there's two semi-reasonable behaviors, and both are "set-like"
but yeah, I expected subtraction just on key
I mean I actually expected subtraction to just not work at all
I always saw the point of .items() as producing something for iteration, random iterable things don't generally support subtraction
interestingly this doesn't happen for ==
i.e. d1.items() == d2.items() will run, evenif the values are not hashable
which makes me think it's silently degrading to N^2 behavior
I think it's still O(N)
dict view's rich compare just runs a loop for whether everything in self is in other
and dict_items' contains is O(1)
it won't be O(N) if you have the same set of keys
.items() is supposed to behave like a set of (key, value)
but a set of (key, value) will always do == in O(min(N1, N2))
the comparison for the value will take time... but a dict_items object can retrieve the (k, v) pair for a given k in O(1) time
hmm I guess you're right actually
Why i have this error plz: Traceback (most recent call last): File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\plugins\cpython_frontend\cp_front.py", line 39, in init self._send_msg(ToplevelCommand("get_environment_info")) File "C:\Program Files (x86)\Thonny\lib\site-packages\thonny\running.py", line 1157, in _send_msg self._proc.stdin.write(serialize_message(msg) + "\n") OSError: [Errno 22] Invalid argument
Process ended with exit code 0
@devout estuary
Open a help thread. This isn't the place for that. #❓|how-to-get-help
So I've noticed that python 3.8-3.13 had signed git tags for their releases, but starting with python 3.14 and continuing into python 3.15, there aren't signatures on the git tags or other information confirming that 3.14 and 3.15 are signed by who they are said to be signed by
PSF made a terrible decision oh well
Interesting. I will say release commit signing doesn't provide much benefit since Python doesn't require commit signing for all commits.
3.14 and 3.15 have a new RM (Hugo), so it could just be that he doesn't have commit/tag signing set up
hugo vk?
Yes
helo
it must be difficult to be well out of step with the rest of the community
If its about moving Python forward as a Technology stack I'm on board. If it's about something else than software technology then we are hurting the Python effort.
there have been a number of times in the last decade or so where people wrung their hands and said, "this hurts Python overall," and then Python kept growing in popularity and influence.
Given the current funding shortfall that is well publicized it was decision for ideology not Python technology stack. A disservice to all who want to see Python continue to advance.
I'm sure you would not be in favor of taking money no matter what the preconditions were. So it's just a question of what values we place above money.
Python is software. A Technology. It's bits and bytes of code. The PSF should be focused on that. Not anything else. So the decision was disservice to us who care about the technology and seeing it get better.
so if an explicitly white nationalist organization offered the PSF $1.5M to improve the technology as long as they agreed to have no black people on the board of directors, you'd say we should take the money?
(the PSF supports the Python Community, not solely the Python language)
Why make a racist comment.
I'm trying to illustrate a situation where "just technology" isn't enough to consider.
Split the board into two Technology / Community that way we are not harming the technology stack
(that is why the Steering Council exists)
i know it's an unpleasant scenario. But what would you do in that situation? Take the money, or refuse it?
My focus is the Technology Stack nothing else
easy to say. If you were on the board, would you take that money or refuse it?
Anyhow the decision was made so be it
these are hard questions, and it is easy to avoid them when you are not in the position to make the decision.
@crisp locust btw, we also have yet to see that this decision harms the tech stack. People are stepping up to support the PSF because of this decision.
I'm out of the loop - what decision are we debating the merits of?
In January 2025, the PSF submitted a proposal to the US government National Science Foundation under the Safety, Security, and Privacy of Op...
it makes sense given that the PSF's explicit goal is to foster the community
I think even independent of the PSF's goals and values this decision was a no-brainer, given that the terms were so overreaching, applied to all activity of the PSF and would have allowed the NSF to unilaterally claw back money that was already sent, if they decided the PSF didn't do enough (against its own stated values).
It's hard to think of a PSF decision in the last years that should be less controversial.
disappointing to have people on the sidelines bemoaning the decision but not willing to actually look at the hard choices.
Yeah, seems like a no-brainer to me. If they took the money, would they have to stop having the Charlas track at PyCon, for instance? Would they need to stop providing travel grants? Would they need to stop funding PyLadies? I think the answer to all of those is "yes"
Mostly it comes down to the uncertainty about what the US administration would consider a violation of the law. They'd rug-pull the money and the PSF would have no recourse except to sue the federal govt, which would be costly, time-consuming, and unlikely to result in the money being returned soon enough to matter.
And looking at the current administration, I think they would consider many activities like you've mentioned to be violations.
Heck, the government could argue that the stenographers captioning the talks at PyCon are a form of DEI
I misread as steganographers, and was wondering what that'd look like.
The live feed has secret messages hidden in the pixels!
sure, that's where the brainwashing happens....
I think it's unlikely that the administration would try to claw back the funds unless Trump personally had a reason to want to punish the PSF for the spectacle. But I think the PSF is wise not to open themselves up to that risk
Are you kidding me? I would expect them to pull back the funds because of a security issue in a government script that was written in python and blame Python for it
I am so glad psf didn't take it
Actually I expect them to do this anyhow
I work for a federally funded company. Trump is a monster, but there are (at least for now) people in government trying to get things done.
I don't have faith in the US government anymore but that's not really related to this channel typically, aside from it being related to the topic at hand
i wonder how trump didn’t put pressure on rust given the biden administration’s endorsement of it
this is probably getting off topic
Hello
Hey everyone, just read through the thread — really interesting points from both sides. I get where Brother Richard is coming from about focusing on the tech, but I also think the PSF made the right call here. If funding comes with strings that could limit inclusion or independence, that’s not worth the risk. Better to keep the community and the language aligned than compromise for short-term money.
what is the use of co_nlocals? Isn't it just len(co_varnames)?
would have to check but it may be different if nonlocals are involved
doesn't it include cellvars and freevars
oh, it doesn't
co_varnames is only populated lazily for backwards compatibility. On free-threaded, co_varnames is kept in a thread-local cache (_PyCoCached), and only populated lazily from localsplus (which are locals, cell vars aka variables referenced in nested scopes, and free vars aka variables defined in an outer scope). co_localsplusnames is used instead of co_varnames in the core interpreter loop e.g. https://github.com/python/cpython/blob/07912f86323dc5a13f4d070b7e3f2c3cb2850d8b/Python/ceval.c#L1656
Python/ceval.c line 1656
co_varnames = ((PyTupleObject *)(co->co_localsplusnames))->ob_item;```
Agreed the clawback clause is a showstopper. Almost regardless of the terms attached to it, it would be a massive risk hanging over PSF's head. How on earth are you meant to deploy funds if they could be demanded back at any time?
But how did nlocals start to exist? In 3.10 co_varnames was already explicitly defined. I get that in 3.11 it might have performance effects but in 3.10 I cannot see the same reason
Unfortunately I don't know the history there, I'm only familiar with the more recent interpreter loop implementation. I would recommend looking at history of codeobject.c for clues if no one else replies
Isn't co_nlocals way older than 3.10?
Yep, both co_nlocals and co_varnames were introduced in the same commit (884afd65) in 1995; that's Python 1.x days.
Yes, but I just took a recent version as an example. Anyway if it's from 1995 I'll just assume it was left in for backwards compatibility
Fun fact: the US government has the unique power in US law to unilaterally cancel contracts. Things I learned this year.
Oof, I shouldn't be surprised but that's still painful to hear.
in the past, political and oversight consideration have prevented governments from abusing that too hard - now we have an executive that doesn’t care about that stuff
didn't you or someone write a blog about this?
like the PSF refusing the 1.5M
the PSF has a blog post about it.
no the blog was not from PSF
someone on the board i think
perhaps Simon Willison? https://simonwillison.net/2025/Oct/27/psf-withdrawn-proposal/
ah yes
i saw it in my RSS feed
So the PSF board by saying NO they will allow violations of Federal anti-discrimination laws
No, they're saying they won't stop doing things that are intended to include people.
I don't know how familiar you are with the current US administration and its stance toward diversity initiatives.
US federal law is often written in a vague way that gives the executive leeway to apply the law however they want. And then people who disagree with the executive's application challenge it all the way to the supreme court, who rule in favor of the administration if they were appointed by a member of the administration's political party, else against.
tbh, all laws are vague to differing degrees, which is why we have juries and judges, appeals, etc.
Yes, but US laws are especially so, because the threshold to pass laws is unusually high (60 votes in the most lopsided legislative chamber on earth) and the two parties are especially uncooperative
I hope this clears things up for you. Last time we talked about it, you disengaged when uncomfortable scenarios were being considered. These aren't easy efforts and they aren't easy decisions. I'm proud of the PSF leadership for how they have handled this.
I read the blog article just think its an interesting position to take stance against based on what he said. Everyone is entitled to their opinions agree or disagree
what position do you find interesting?
We were forced to withdraw our application and turn down the funding, thanks to new language that was added to the agreement requiring us to affirm that we "do not, and will not during the term of this financial assistance award, operate any programs that advance or promote DEI, or discriminatory equity ideology in violation of Federal anti-discrimination laws."
do you understand how subjective laws can be? In this case, the funding isn't even subject to prosecution for violating laws. The administration could simply say, "you are violating a law" and take back the money.
"you can't promote diversity, equity, and inclusion; you can't discriminate"
These are ostensibly exact opposites.
Statement by the government
“The federal government must ensure that taxpayer money is used lawfully and for the public good,” said Assistant Attorney General Harmeet K. Dhillon. “The very foundation of our anti-discrimination laws rests on the principle that every American deserves equal opportunity, regardless of race, color, national origin, sex, religion, or other protected characteristics.”
that doesn't answer my question: do you understand that there's a great deal of subjectivity here? And also that the funding wouldn't be subject to conviction of breaking a law, but simply an administration official claiming there was a law broken?
Federal antidiscrimination laws prohibit discrimination on the basis of protected characteristics, including race, color, religion, sex, and national origin. The U.S. Supreme Court has consistently held that policies or practices based upon protected characteristics are subject to rigorous judicial scrutiny. Race-based classifications are subject to strict scrutiny, requiring a compelling governmental interest and narrowly tailored means to achieve that interest. Sex-based classifications are subject to heightened scrutiny, requiring an exceedingly persuasive justification
and substantial relation to an important governmental objective. Discrimination based on other protected characteristics, such as religion, is also evaluated under analogous standards. Entities receiving federal funds must comply with applicable civil rights laws, including:Title VI of the Civil Rights Act of 1964: Prohibits discrimination based on race, color, or national origin in any program or activity receiving federal financial assistance. This includes most educational institutions, healthcare providers, and state and local government agencies.
Title VII of the Civil Rights Act of 1964: Prohibits employment discrimination based on, or motivated by, race, color, religion, sex, or national origin, in any terms, conditions, or privileges of employment, including hiring, promotion, demotion, termination, compensation, job transfers, training, or access to employment privileges and benefits.
Title IX of the Education Amendments of 1972: Prohibits discrimination based on sex in education programs or activities receiving federal financial assistance. Title IX protections extend beyond athletics and include addressing sexual harassment, sex-based harassment, admissions policies, and equal access to resources and programs.
we don't need the text of the laws.
Nothing subjective about the law
isn't "subject to rigorous judicial scrutiny" subjective?
I can provide real life examples unlawful practices
yes, i'm sure there are examples of unlawful practices.
saying so doesn't make it true
do you understand that the funding isn't subject to conviction of breaking a law, but merely an official claiming a law was broken?
what scrutiny is needed if there is nothing subjective?
Overblown no proof
@crisp locust do you think those were 1500 prosecutions and convictions?
Because they are practicing discrimination
who determined they were practicing it?
The law is clear
answer the question: who determined it?
and laws are not clear-cut.
By refusing to acknowledge the law I can't help you
I see the laws. I think they are open to interpretation.
Nope, that's what happened with the last administration
if the PSF funds email outreach to women to encourage them to submit talk proposals to PyCon, is that a violation of the law?
NO
so you acknowledge that different administrations can apply laws differently.
No, the laws which I listed were written before group think came about
you just said, "Nope, that's what happened with the last administration": referring to laws being open to interpretation, right?
I think the current administration would say that emails sent only to women would be a violation of the law.
We are never going to agree. Have a nice day.
again, bowing out. got it.
I don't understand this:
"do not, and will not during the term of this financial assistance award, operate any programs that advance or promote DEI, or discriminatory equity ideology in violation of Federal anti-discrimination laws."
what don't you understand about it?
operate any programs that advance or promote DEI, or discriminatory equity ideology isnt that a violation of federal law?
and how could the NSF even say this?
like "stop promoting equality" for 1.5M
who would stop the NSF from saying this?
NSF is a part or governement no?
yes
i'm confused: where in that text is the NSF telling someone to break the law?
"operate any programs that advance or promote DEI, or discriminatory equity ideology" isnt that breaking a law?
to not promote "discriminatory equity ideology"
or is it just saying don't promote it, but dont be racist
The NSF is saying grant recipients cannot run programs promoting DEI.
i'm not sure what you are uncertain about.
I still don't understand why they would say that though
because the current administration doesn't like diversity programs.
they will say that diversity programs are fundamentally discriminatory. that's where the subjectivity comes in.
I don't want to say anything to that
ok
Dear PEP 810 authors. The Steering Council is happy to unanimously[1] accept “PEP 810, Explicit lazy imports”. Congratulations! We appreciate the way you were able to build on and improve the previously discussed (and rejected) attempt at lazy imports as proposed in PEP 690. We have recommendations about some of the PEP’s details, a fe...
Who has the backport?
oh, one of the steering council members was the PEP author
I wonder what happens if a PEP is co-authored by 4/5 members or 5/5 members?
PEP 798 also got accepted
!pep 798
^ with a single change, no yield from
No chain.from_iterable
I think SC members avoid putting themselves in that situation
nice
Big
Gotta be like one of the fastest peps I've seen accepted
what a glorious day
ok lazy imports are really good
I like the point that is made about typing-only imports
actually, can anyone confirm whether a type statement will reify a lazy import?
type statements are lazily evaluted, so no
however, using a lazy import in a field annotation in a dataclass will reify it
that makes sense. Assuming that is because the dataclass evaluates the annotation for purposes of generating the class init?
I feel like we might need to think about a way to address that
it's primarily for figuring out whether they're ClassVars
or InitVars
ah... tricky
Why is that needed? I thought you can't put ClassVar in a type statement
(from the type system perspective)
the situation is this
@dataclass
class MyData:
x: ClassVar[int] = 1
Oh, you're talking about not reifying dataclass attributes
The problem is that they must reify to check whether they are a typing.ClassVar or not.
Checking whether they are a dataclasses.InitVaris a non-issue IMO because are using dataclass there anyways
In the PEP 810 demo at https://lazy-import-demo.pages.dev/ you can put this example to see what happens
import sys
from dataclasses import dataclass
lazy import lazy_demo.utils
@dataclass
class Foo:
x: lazy_demo.utils.T
print("After lazy imports:")
print(f" 'lazy_demo.heavy' loaded? {'lazy_demo.heavy' in sys.modules}")
print(f" 'lazy_demo.utils' loaded? {'lazy_demo.utils' in sys.modules}")
print()
Python Lazy Imports - Interactive WASM Demo
is it appropriate to try and change the implementation of dataclasses such that it does not evaluate the annotations?
I don't see any attributions to any company in it (unlike abc), so I would assume so? I am not versed in contributing to cpython
do you mean change it and commit it to CPython?
yes, not me specifically, but yes
are we talking in two channels about this?
what
or #python-discussion has stopped I guess.
python discussion was just "hey people look, cool new thing"
it sounds like not evaluating annotations would be a big change, but maybe I'm missing something.
you would need to parse the string representation of an annotation to see whether it is a typing.ClassVar or dataclasses.InitVar.
As far as I have been thinking, that would require that dataclasses.dataclass analyzes the code that is is imported into.
This is because it is possible to define those names yourself and not be the actual types that the dataclass decorator needs to check for.
Sounds bad.
I sort of feel like we should try to fix this but can't think of a very elegant way to do it. You could look for whether ClassVar appears in the string version of the annotation or something but that's arguably not enough, users could alias it
(that was what I was getting at 👍)
the general answer to this is that contributions are possible to any module in CPython
what's the non-general answer
though whether the contribution will be accepted is always uncertain
A cursed fact about ClassVar: normally ClassVar[Final[X]] and Final[ClassVar[X]] are not allowed in a class. Unless it's a dataclass, in which case it's the only way to create a final classvar (both orders are possible)
So whether x: Final[int] = ... defines a classvar depends on whether it's a dataclass or not
guess I was just being verbose, all modules are the same in this regard
only difference might be that some modules could have an owner with a strong sense of ownership
good lucking contributing to something like antigravity, lol
such as Google?
there might be some random notices on some modules but that's just for historical reasons
that means "abstract base class", not google's parent company
they're referring to "# Copyright 2007 Google, Inc. All Rights Reserved."
oh
though I wonder how much of that module's code is still what Google contributed
I wonder if that comment is compatible with cpython's current license
@faint river contribution can be difficult, but it's never because some company owns a module.
they retain the copyright but gave a license the PSF, I think that's how all contributions work in general
I wonder if the license is technically revokable
I hope not, would be very impractical if it was
the PSF owns the IP of the code.
splendid
well, technically I don't think this is true. The contributor agreement grants the PSF an irrevecobale, perpetual license to redistribute contributions under any license approved by the PSF. However e.g. here there is wording:
PSF understands and agrees that Contributor retains copyright in its Contributions
!pep 798 question on this
someone should give emma her core team role
oh yeah I was gonna ask about this
[(*it if cond else it) for it in its]
is something like this (or similar, with a syntax chance) possible? Essentially, conditional flattening
i guess i didn't use the correct terms. my point was that the PSF can do what they want with the code.
no. you'd have write something like *(it if cond else [it])
effectively yes, I agree. Note that since the copyright is owned by the contributor I'm not sure if the PSF can defend the copyright? I'm no lawyer though
ok, so it retains the error from the non-generator/comprehension version, which is for example [*x if x else y] or [x if x else *y]
>>> [x if x else *y]
File "<stdin>", line 1
[x if x else *y]
^
SyntaxError: cannot unpack only part of a conditional expression
I asked in the partners channel for someone to give you the role
!pep 810
the lazy imports method can only be set once, it would be nice if it could be set for a module such as setuptools and therefore all imports within the setuptools namespace would use that filter method
eg sys.set_lazy_filter_namespaced('setuptools', method)
dataclasses not evaluating is a tricky one, there's already some extra fiddling for string annotations recognising ClassVar and InitVar. It actually looks like the type comparison for string annotations as it is now will be broken if ClassVar is lazily imported 🤔
Yes, dataclasses pulls from the module dict directly so it retrieves the lazy import object.
So combining lazy import typing with from __future__ import annotations and a typing.ClassVar annotation doesn't work correctly with @dataclass.
Well, the future annotations import does nothing in 3.14+ anyways
No, it still switches things to string annotations
from __future__ import annotations
from dataclasses import dataclass
lazy import typing
@dataclass
class X:
a: typing.ClassVar[str] = "H2G2"
b: int = 42
print(X())
The ClassVar annotation has no effect currently due to how the comparison is implemented.
That's not true, it does pick it up as a ClassVar
I think it does a string match
I just tried it
with the current lazy build
it checks for "typing" in sys.modules
which it isn't
yeah the new repl imports half the stdlib
old repl might also import typing, can't remember
I don't think so, that one wasn't written in Python
The check isn't for a string match either it's more fiddly than that
Guess this comment isn't true any more
# If typing has not been imported, then it's impossible for any
# annotation to be a ClassVar. So, only look for ClassVar if
# typing has been imported by any module (not necessarily cls's
# module).
That's a good catch
(I'll note that for my own dataclass-like implementation I do just check for the string ClassVar and document it as such)
yes I feel like that would make life easier
Too late to change that now though
I suppose compatibility makes it hard for us in CPython to change yes
I don't know whether anyone is doing shenanigans like having a utility module that does from typing import ClassVar as MyFancyName and then use that in a dataclass
But I saw the hoops dataclasses was jumping through and decided against it 😆
I've heard people might use from typing import ClassVar as CV, but I'm not sure I've seen that actually used anywhere other than to test that the aliases work for dataclasses.
Technically that one should still work
and also maybe the string ClassVar as (to detect multiline imports)
Either way it's not a guarantee we can remove
the lazy imports method can only be set once, it would be nice if it could be set for a module such as setuptools and therefore all imports within the setuptools namespace would use that filter method
eg sys.set_lazy_filter_namespaced('setuptools', method)
Where can I suggest/raise this?
Oh right discuss.python.org
Anyone know of an existing thread? I haven't used dpo
(carry on)
ok I was looking into removing the documentation for curses.__version__ because it doesn't exist and hasn't since at least 3.8
but now I'm trying to determine why that is
Modules/_cursesmodule.c lines 5447 to 5451
rc = PyDict_SetItemString(module_dict, "__version__", curses_version);
Py_CLEAR(curses_version);
if (rc < 0) {
return -1;
}```
that doesn't add up
the rc must be derefed at some point before that line is run, hm
it's on _curses not curses
>>> import _curses
>>> _curses.__version__
b'2.2'
huh
oh my god
its because its not in __all__
when did that change, then.... thanks jelle
not exactly, _curses has no __all__. It's because import * doesn't pick up underscored names by default
right yeah I meant that but went to the other part
its underscored, and because __all__ doesn't exist/contain it, it doesn't exist in curses
!d curses.version
curses.__version__```
A bytes object representing the current version of the module.
python/cpython#140606
I sort of suspect this has always been broken
oh same probably
not motivated enough to build a Python 2 to check though 🙂
I think the proper way to do this is to remove the docstring and the _curses.__version__ string and then remove just the docs for a backport in a seperate pr
this would be my first pull to python 🙂
that sounds right
is there a devguide page on making pull requests?
not sure. it's gh-<number>: Descriptive title where number is the issue number
so in this case something like Remove _curses.__version__
should this be reopened since its not quite a duplicate?
or keep the tracking to the other issue about version attributes
seems close enough to keep the same issue
I spent two minutes on this but https://github.com/python/cpython/issues/76007 looks to be generally "wrong/misleading __version__ in the stdlib" which this is an example of
BPO 31826 Nosy @warsaw, @rhettinger, @ncoghlan, @pitrou, @merwok, @encukou, @serhiy-storchaka, @abukaj, @cryvate PRs #17977 Note: these values reflect the state of the issue at the time it was migr...
it's just removing some lines, right? shouldn't be too hard
this diff seems wrong in terms of memory management
oh yeah keep the Py_CLEAR
PyCLEAR(curses_version) should probably be called here if I'm reading this right
and then I should probably be able to remove Py_DECREF
you mean on the line above? that should stay
otherwise it's leaked in that error path
No no like this
rc = PyDict_SetItemString(module_dict, "version", curses_version);
Py_CLEAR(curses_version);
if (rc < 0) {
return -1;
}
What's the difference between Py_CLEAR/Py_DECREF| where could I find that?
I have to check but I believe its referring to the ncurses version used to build this module
not the code here
I see
it's a bytes object which sort of suggests nobody since the Python 3 change has cared about it
I believe CLEAR is DECREF + set to NULL
nope it should be deprecated
this is almost certainly documented in C API docs, if you google like site:docs.python.org Py_CLEAR you should be able to find it
I can likely safely remove __version__, or do I need to deprecate the definition in _ncurses
it would only be usable with _curses.__version__ and has never been documented as such
I guess I just make the pull and put that in the body
yeah since it's only on the private module I feel it's OK to remove, another core dev might want a deprecation cycle though
I'll do it with no deprecation but someone can ask for it in which case I'll figure out how
thanks jelle!
!d Py_CLEAR
void Py_CLEAR(PyObject *o)```
Release a [strong reference](https://docs.python.org/3/glossary.html#term-strong-reference) for object *o*. The object may be `NULL`, in which case the macro has no effect; otherwise the effect is the same as for [`Py_DECREF()`](https://docs.python.org/3/c-api/refcounting.html#c.Py_DECREF), except that the argument is also set to `NULL`. The warning for [`Py_DECREF()`](https://docs.python.org/3/c-api/refcounting.html#c.Py_DECREF) does not apply with respect to the object passed because the macro carefully uses a temporary variable and sets the argument to `NULL` before releasing the reference.
It is a good idea to use this macro whenever releasing a reference to an object that might be traversed during garbage collection.
Changed in version 3.12: The macro argument is now only evaluated once. If the argument has side effects, these are no longer duplicated.
I think I did it right python/cpython#141052
You can use backticks to avoid turning double underscores into bold text:
`curses.__version__`
And you'll need to click that "sign CLA" button
already signed, and thanks for the description update
python/cpython#141052
yay its merged python/cpython#141052
thank you, @limpid forum, @feral island, and @raven ridge, for your help with this change!
congrats!
<@&831776746206265384> crossposting ad
!kick 495204443323760661 You've just been told not to spam
:incoming_envelope: :ok_hand: applied kick to @glad aurora permanently.
Is there some centralized list of __dunder__ methods? Right now some of them are on the Data Model page but some (like __replace__) are not
object.__replace__(self, /, **changes)```
This method should create a new object of the same type, replacing fields with values from *changes*.
Added in version 3.13.
Huh!
I really wish there was.... Hm
I did find this https://www.pythonmorsels.com/every-dunder-method/
Can probably throw something together shortly as a bash script
!d copy.replace calls it, and it was added in 3.13
copy.replace(obj, /, **changes)```
Creates a new object of the same type as *obj*, replacing fields with values from *changes*.
Added in version 3.13.
yeah, the destroyer of covariant frozen datclasses
Why do I forget what covariant means again
hello hello, small typo fix :-) https://github.com/python/cpython/pull/140248
thank you from the mountain (a different way of saying thank you in advance)
CC @ZeroIntensity we can skip issue and skip news here
a covariant type G means that if TSub is a subtype of T, then G[TSub] is a subtype of G[T].
this takes place for immutable containers, for instance a Sequence[bool] is assignable to Sequence[int], whereas a mutable list[bool] is not assignable to list[int] due to invariance.
!e ```py
import hello, traceback
traceback._print_exception_bltin = lambda exc, file=None, /: hello.main()
1 / 0
:x: Your 3.14 eval job has completed with return code 1.
Hello world!
investigating linecache line availability when source files are deleted
:x: Your 3.14 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File [35m"/home/main.py"[0m, line [35m7[0m, in [35m<module>[0m
003 | [31mrunpy.run_path[0m[1;31m(str(p))[0m
004 | [31m~~~~~~~~~~~~~~[0m[1;31m^^^^^^^^[0m
005 | File [35m"<frozen runpy>"[0m, line [35m287[0m, in [35mrun_path[0m
006 | File [35m"<frozen runpy>"[0m, line [35m98[0m, in [35m_run_module_code[0m
007 | File [35m"<frozen runpy>"[0m, line [35m88[0m, in [35m_run_code[0m
008 | File [35m"t.py"[0m, line [35m1[0m, in [35m<module>[0m
009 | [1;35mZeroDivisionError[0m: [35mdivision by zero[0m
k i'll use ci runners... it's platform-specific things
FYI there have been mixed opinions on fixing such typos in tests.
what mixed opinions? i can smuggle it in as part of a different PR touching tests if that's necessary
or do you mean there were opinions that it's unnecessary to fix those typos
there's quite a few on https://docs.python.org/3/genindex-_.html, but this list does include other stuff
Yes, we don’t have a set process documented in the devguide though, so it’s up to the core devs discretion.
thanks! I'll not open pure typo fix PRs in non-user-facing code in the future then.
@feral island does typeshed have checks to discover stdlib modules that aren't present? or is the process organic, like, someone comes and opens up a PR to add a new module?
for stdlib there's both pure and non-pure modules, so it seems best to validate our stubs against sys.stdlib_module_names of a particular version.
i think i'll just add this to that new project of specialized runtime checks of typeshed.
let me know if there are any other runtime checks typeshed could use
hm. we don't have quite a few things, but some of them are not meant to be user-facing i guess.
https://github.com/bswck/run-stuff/actions/runs/19194103121/job/54872570087#step:5:64
i guess we would want profiling for sure (checked against newest typeshed, profiling is missing).
adding an issue to track
stubtest might catch it? Regarding profiling, we don't tend to add stuff for new versions until the beta phase
cool! good to know, will wait until beta, thanks
I think I made an issue years ago with all missing standard library modules
There's a few left perhaps but it tends to be internal stuff that probably shouldn't be in typeshed anyway
Yeah, i think typeshed is pretty complete these days for public, documented modules
https://github.com/python/typeshed/issues/4545 is the most recent iteration of this. I think since then this hasn't really been needed because stubtest tells us
I don't completely understand what LOAD_FAST_AND_CLEAR is used for. This is the code of its implementation: https://github.com/python/cpython/blob/3.12/Python/bytecodes.c#L197C1-L201C10
I am trying to "emulate" this opcode using other opcodes. Is there some way to get the same behaviour without this specific opcode? Can someone explain why it's used?
Python/bytecodes.c line 197
inst(LOAD_FAST_AND_CLEAR, (-- value)) {```
one way I think I could emulate it is doing LOAD_FAST_CHECK, catching a possible UnboundLocalError triggered if the local var doesn't exist yet and push NULL
but that seems like it would impact performance a lot + I would have to keep the NULL behaviour. I'd like to emulate whatever this opcode is used for without using NULL as it does not exist in 3.10
It's used for inlined comprehensions (PEP 709). Looks like it's basically LOAD_FAST + del
I'm not sure what you're trying to do with the bytecode so hard to say how you should handle it
I'm trying to "compile" 3.12 bytecode to different versions, but specifically 3.10 and 3.11.
https://github.com/python/cpython/pull/101441
In the implementation of this PEP they brought up that you would have to remove the assert in the LOAD_FAST as it can never load NULL.
However I feel like the only feasable solution that can work for 3.10 and 3.11 is to "unline" the comprehension
back into a separate function
but that seems hard to recognize
I don't have a good enough mental model of how the fast storage works, especially as it changed between versions. As far as I understand they need this opcode to keep the locals of the comprehension separate from the locals of the code the comprehension is in? Can you confirm that?
yes, that's right
How does this opcode achieve that though? It's still using the same "table" of locals, it just loads a possibly NULL value and clears it afterwards. How does this keep it separate?
thanks for indulging my weird question btw
yes, it uses the same table, but as I recall we can now have two different locals with the same name
how does it know which one to use? do you have any documentation or pull requests on that?
I've noticed documentation of internals like this is rather sparse. The pull requests usually have the hidden gem information 😄
Yeah it's all going to be in the source. This is all intentionally undocumented implementation details
Looks like what happens is that when we enter the comprehension, we stash the outer local of the same name on the stack
Then put it back when the comprehension is done
... x = 1
... y = [x for x in [2]]
... return x * y
...
>>> dis.dis(f)
1 RESUME 0
2 LOAD_SMALL_INT 1
STORE_FAST 0 (x)
3 LOAD_CONST 1 ((2,))
GET_ITER
LOAD_FAST_AND_CLEAR 0 (x)
SWAP 2
L1: BUILD_LIST 0
SWAP 2
L2: FOR_ITER 4 (to L3)
STORE_FAST_LOAD_FAST 0 (x, x)
LIST_APPEND 2
JUMP_BACKWARD 6 (to L2)
L3: END_FOR
POP_ITER
L4: STORE_FAST 1 (y)
STORE_FAST 0 (x)
4 LOAD_FAST_CHECK 0 (x)
LOAD_FAST_BORROW 1 (y)
BINARY_OP 5 (*)
RETURN_VALUE
-- L5: SWAP 2
POP_TOP
3 SWAP 2
STORE_FAST 0 (x)
RERAISE 0
ExceptionTable:
L1 to L4 -> L5 [2]
so technically that means this inlining could also be supported in 3.10
yeah I'm not actually sure anything would go badly wrong if you just replace LOAD_FAST_AND_CLEAR with LOAD_FAST
maybe the worst thing is that some reference gets kept alive too long?
this examples helps clear stuff up a lot though, thanks
where is that assert?
ah it seems like it only exists in 3.12: https://github.com/python/cpython/blob/a183a11db8bc2520c52814635de2df118d2d7e8c/Python/bytecodes.c#L193
Python/bytecodes.c line 193
assert(value != NULL);```
in 3.11 and 3.10 it throws the UnboundLocalError
okay okay I finally understand how to handle this
it just pushes NULL to the stack to save it after the comprehension, but if I do some logic then I can avoid re-assigning x if it never existed before the comprehension
how about typos in internaldocs?
is it welcomed that external contributors fix them?
where do you mean?
a couple in https://github.com/python/cpython/blob/3ce2d57b2f02030353af314d89c5f6215d2f5c96/InternalDocs/interpreter.md#L36-L43, perhaps more
- unclosed lparen from line 36 in line 37
- a link without href in line 40 (
[`_PyEval_EvalFrameDefault()`]) -- judging by https://devguide.python.org/internals/interpreter/, i'm assuming that that document isn't rendered anywhere else than github, so there's no crossref magic and the link just misses a href - some links point to wrong places:
[`_PyEval_EvalFrame()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode)-- i don't think_PyEval_EvalFrameis equivalent toPyEval_EvalCode-- there's publicPyEval_EvalFramebelow it: https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalFrame, and these things seem to do very different things in the code
InternalDocs/interpreter.md lines 36 to 43
(this is used in the implementation of
[`gen.throw`](https://docs.python.org/3.14/reference/expressions.html#generator.throw).
By default, [`_PyEval_EvalFrame()`](https://docs.python.org/3.14/c-api/veryhigh.html#c.PyEval_EvalCode)
simply calls [`_PyEval_EvalFrameDefault()`] to execute the frame. However, as per
[`PEP 523`](https://peps.python.org/pep-0523/) this is configurable by setting
`interp->eval_frame`. In the following, we describe the default function,
`_PyEval_EvalFrameDefault()`.```
so just asking if one or a bunch of PRs to fix these are welcome
I think fixing those kinds of things would be accepted.
thanks!
if you make a PR and get resistance, ping me on it.
@uneven raptor i think we could also check if internaldocs can earn more links while working through https://github.com/python/cpython/issues/141004
LGTM too
We haven’t really been fixing references in the docs…
you can fix refs if you want, I don't have much of a preference there
!pep 814
New pep just dropped
Seems like we're not going to get a HAMT in the stdlib after all 😔
I thought we have a HAMT in the stdlib, it's just not exposed to Python land
(PEP 603 is not rejected though)
rpds-py is a thing…
IMO python needs a first-class way of marking variables as mutable a la rust but frozen types will help too
That's not how you're supposed to play the game!
sorry, was this a joke? if it is I don’t get the reference but if it isn’t I don’t understand
it's a meme, yeah.
I’m officially an old
how would that actually work though once you start aliasing things
this sort of thing is just kind of messy in GC languages, which is why you don't really see it much
the closest thing I can think of is D, but that's not exactly a super popular language, and I don't remember all the details of their system
makes sense, the other side is that in the type system you really want the mutability to show up in the type, so things get messy if types can go through transitions from mutable to immutable - this showed up in the discussion around freeze
the lower hanging fruit is just to use a lot more frozen or at least read only types. but that's kind of hard because python has really committed itself to dict, list, and set
a good example of a language that does this without making things very elaborate is Kotlin.
in Kotlin when you do the equivalent of a list comprehension, you get List, not MutableList, as the result.
so, in general there's just a lot less mutation floating around in a Kotlin program than in a python program.
don’t have to tell me that… all the mutable cython cdef classes that need passes to work on the free-threaded build without allowing new kinds of thread safety issues is kind of daunting
hah, yeah
I wasted hours or maybe even days a couple years ago because I made the mistake of having a dataclass with with a nested member and didn't use default_factory
this is back when datacalsses allowed that
some_member: Foo = Foo()
and then the program was using a thread pool or something; bad things ensued
attrs makes sure the default is hashable
I thought dataclasses did that also
I think it does now but didn't always?
correct
I don't know in which exact version they started doing it
maybe 3.11 or so
I fixed that particular bug when it happened of course but at some point later, we upgraded python version and we had to fix this in a couple dozen other places
I knew to use default_factory for list/dict/set but it didn't really occur to me for nested dataclasses for whatever reason
that defining a type with some defaulted members is so error prone and unintuitive in python is definitely not one of the bright spots
I don't actually do the check for this in my own implementation. I'm not really happy with the use of hashability as a proxy as it can be wrong in both directions.
That said it's probably right more often than not.
yeah, it's not an ideal situation
it's just generally a problem though in several contexts
don’t look at how numpy dtypes are hashed
you have the same problem in dicts in general
it’s bad
and not just in python, most GC languages have this issue
mostly they each try to do something that heuristically prevents the most common issues
>>> np.dtype('float64')
dtype('float64')
>>> np.dtype('float64') == 'float64'
True
this is not good but mostly it doesn't matter in practice
you might have bad times if you make dtypes the keys of a dictionary along with strings
oof
Yeah
I don't think I've ever mixed them. I can definitely imagine a dict with dtypes as keys, and probably even written it at some point. but not a mixture.
Is that not also something about how equality is defined, let alone hashing?
it’s both, because equality and hashing are related
Isn't it that two equal items should have the same hash but that two items with the same has aren't necessarily equal? I'm just surprised the equality check ignores the type.
there's a ton of code that implicitly relies on this behavior so changing it is an enormous headache
lol:
>>> np.dtype(None) == 'float64'
True
because the default dtype is float64
I'm Chinese, nice to chat with you.
not outright in the stdlib
it's in Python/hamt.c and it's used internally by contextvars
and you can reach it through _testinternalcapi
!e
s = str(encoding='utf-8', errors='strict')
assert s == ""
``` This is weird... why is `str` callable with just these kwargs?
:warning: Your 3.14 eval job has completed with return code 0.
[No output]
it's callable with no args: str() -> ''
yeah I know
unicode encoding?
!d str
class str(*, encoding='utf-8', errors='strict')``````py
class str(object)``````py
class str(object, encoding, errors='strict')```
Return a [string](https://docs.python.org/3/library/stdtypes.html#textseq) version of *object*. If *object* is not provided, returns the empty string. Otherwise, the behavior of `str()` depends on whether *encoding* or *errors* is given, as follows.
If neither *encoding* nor *errors* is given, `str(object)` returns [`type(object).__str__(object)`](https://docs.python.org/3/reference/datamodel.html#object.__str__), which is the “informal” or nicely printable string representation of *object*. For string objects, this is the string itself. If *object* does not have a [`__str__()`](https://docs.python.org/3/reference/datamodel.html#object.__str__) method, then [`str()`](https://docs.python.org/3/library/stdtypes.html#str) falls back to returning [`repr(object)`](https://docs.python.org/3/library/functions.html#repr).
Yeah, but in this case there's nothing to decode
Introduction We (@emmatyping, @eclips4) propose introducing the Rust programming language to CPython. Rust will initially only be allowed for writing optional extension modules, but eventually will become a required dependency of CPython and allowed to be used throughout the CPython code base. Motivation Rust has established itself as a popular...
RiiR 😉
I kid I kid, that’s not what’s proposed
As someone who maintains the Python ecosystem at a large company (but speaking for myself, not for the company) I really hope this doesn't happen. We don't have a great story for ownership and maintenance of the Rust toolchain right now, and it'll be a big extra burden on my team if we need to ensure Rust is available and usable internally as a prerequisite for Python being available and usable internally
I'd much rather see CPython start using C++ than start using Rust. C++ is much safer than C, and everyone who has a C11 toolchain can easily install a C++11 toolchain too
Well, it will be optional for at least a couple of years, so hopefully that would be time enough to develop a deployment plan? Would be very interested in your thoughts!
If it's optional but required for building some of the built-in modules, that's really not optional
It's not an option for us to ship an interpreter where some of the built-in modules don't work, even if they're newly added modules
I should add a section about C++. It may be safer than C, but large C++ projects like Chrome and Firefox are still seeing significant memory safety improvements with Rust over C++
First class rust support but c++ and Fortran still need 3rd party?
Doesn't seem right
It wouldn't be the end of the world for us, we would definitely manage, but it would be much more disruptive for us than the change to start requiring C99 and then C11 were, and much more work for us to catch up and stay caught up
Thank you for that context!
I would prefer to avoid having the build system need to manage 4 or even 5 implementation languages
(though C++ would probably come almost for free 😉)
you can point gcc at a .cpp file and it does the right thing. I'm pretty sure that's true for clang as well. Not sure about MSVC, but if it does that too, that's all 3 of the main platforms...
what do you do about cryptography needing rust to build now?
or polars or…
we use the upstream wheels
but you do your own Python builds?
yep. we build the interpreter from source, but don't currently build 3rd party libs from source.
makes sense why it hasn’t been a big pain until now
and we build the interpreter from source in a company-wide integration build environment that is, to put it mildly, challenging to keep up to date with new toolchains
or i guess not now but maybe the future
this is all a big backdoor campaign to get rust compilers available in BigCo build environments 😉
you can't upgrade gcc without fixing everyone's janky old code that won't build with the new gcc. I shudder to think we'd wind up in the same situation for Rust, especially given that my team likely doesn't have the Rust expertise to shepherd through one of those upgrades.
FWIW I expect Python would choose a rather conservative version of Rust to build with if integrated
I hope that would make your life a bit easier?
sure, better than the bleeding edge. but it doesn't really solve the problem around ownership and maintainership. It just kicks the can down the road for us. Eventually you'll want to upgrade to a newer Rust, and we'll need to have figured out some way to get rustc upgraded by then
none of the core devs want it - some definitely want Rust
honestly the writing is on the wall for that anyway, and I think one day we'll have it a supported story around it. But we don't have it today, so adding it today will make 3.15 a pain for me, heh
apparently Guido is on board
Well, again, I would say it should be totally fine not to build _base64, it is merely a performance improvement
(though it seems you have your own requirements for such things, and if so, sorry :/)
@crimson hatch if I can intrigue you into working on https://github.com/mesonbuild/meson-python/issues/721 that would unblock a lot of interesting possible Rust work in scientific packages. I know that at one point there was a discussion about using meson/muon instead of autotools in the cpython build.
Link to reproducible example: https://github.com/medley56/python_rust When using meson-python to package a Rust extension, I get the following error when running pip install . ../meson.build:10:14:...
Yes, I actually was originally planning on working on re-designing the build system before introducing Rust but decided it was too big of a task to take on right now
that's the wrong way to look at this... You're comparing a 3.15 with _base64 to a 3.15 without _base64, and saying that it's an optimization. Your users will be comparing a 3.14 with _base64 to a 3.15 without _base64 (because they had the 3.14 _base64 build dependencies but not the 3.15 ones). To them, it's a performance regression introduced when upgrading.
There is no _base64 at the moment. It is a new module that is purely designed to speed up the existing base64 implementation. So in 3.15 without _base64 it's the same as the current performance of base64 in 3.14
ah. ok, I stand corrected on that one. But what I said would apply for "upgrading" any of the existing optimization modules to Rust
yes, and I think for 3.15 we probably won't do that
ok, I think you're right that if it is only brand new modules, we could probably kick the can down the road a little further.
as long as the modules are new, and there is a pure-Python fallback for them
A side note: I think the 3.15 timeline might be a bit tight. Considering the current SC term is about to end, and we'll be voting in new SC members. 3.16 is definitely doable (assuming acceptance).
(I've just been saying "3.15" without paying any particular attention to what version this is proposed for inclusion in, heh)
Yeah, I am hopeful we can at least get a warning in for 3.15. If not, that's okay, but I'd certainly like to start testing this sooner rather than later to give us plenty of time to iterate on things
At the risk of over-explaining, I think the two "extra" requirements we've got are to not cause any performance regressions by upgrading (so no swapping an optimized 3.N module with an unoptimized 3.N+1 module), and to ensure that the interpreter we ship provides all of the publicly documented modules (thus the requirement for a pure-Python fallback for any Rust module that we might skip building)
we probably have some wiggle room on the latter, if necessary, but it'd put us in an awkward situation to say "Yes, we know that the release notes talk about the great new foobar module, but you can't use it at our company."
not over-explaining at all, I appreciate the context!
Plenty of time, Emma got zstd from PEP to discussion to SC acceptance to implemented before the beta freeze, in exactly a month!
Though I'd prefer to never do that again 😅
@crimson hatch where should I look in your PoC for the bindgen bindings? I’m curious how awful it would be to use it instead of pyo3-ffi in pyo3’s internals? or at least expose something that works like pyo3-ffi. I’m not particularly enthused about going through the CPython headers by hand for 3.15
I’m also a little curious how you’re handling some API details that the pyo3 ffi tests handle in hacky ways when they use bindgen
The bindgen bindings are generated at compile time. Also DM incoming :)
But yeah the bindings will end up in target/[debug,release]/deps/cpython-sys-<hash>/out/c_api.rs
thanks!
Rust in cpython now, Rust is everywhere :P
(I'm probably going to cry at what will become of the build system once that happens, this probably spells the end of my attempt to help the MinGW-w64 team with "porting" the Interpreter given I can never seem to get the hang of Rust)
Unless... Any talk of improving the build system that I've missed lately?
Prior to this work, I was hoping to improve the build system as a pre-requisite to Rust, but I felt that was an even more impossible change with a lot more work, so I decided to shelve it
can anyone help me?
I am learning python language. I am very beginner in it. I am having the problem with terminal portion part. I can't able to run the python file from there and even can't ble to install Pip.
Please help.
I think where most people can agree on is to use rust in extensions, but not the core, like the interpreter
which makes sense
It's a smaller/'safer' step. Like if a mistake is made in this change, it won't be that bad since it's mostly just an extension, but if a bug was introduced into the interpreter because of rust, then people would definitely point fingers at this change, even though it's not necessarily because of it, if ykw I mean
Plz in #python-discussion or open a help thread : #❓|how-to-get-help
I have a high performance app making heavy use of memoryview objects. I was excited to discover that Python 3.14 added an index method to memoryview; however, when testing this, I found it's much slower to use memoryview.index() than it is to first convert the memoryview to bytes, and then call bytes.index(). I don't suppose anyone has also noticed this and/or might know why?
The line in question is:
idx = self.data.index(NEW_LINE, beg, len(self.data))
My overall program is 4.5x slower when leaving self.data as a memoryview instead of converting it to a bytes. This is very counter intuitive!
memoryview's search is linear whereas bytes's search uses an optimized string search algorithm
I would expect memchr to be used in this case.
this is because bytes has only one dimension and one format and it's reasonable to use an optimized string search algorithm for it
however since memoryview only has one dimensional .index() i don't see why a fast path shouldn't be implemented
Hmm... something is going on. I just tried creating a small reproducible example, and I'm not seeing any timing differences now. But in my real code, simply changing:
self.data = self.buffer[: partial_length + num_read]
to
self.data = bytes(self.buffer[: partial_length + num_read])
provides a 4.5x speedup. It's just counter intuitive that copying the memoryview to a bytes makes it much faster :) There must be some strange interaction in my program.
Got it !!!
import time
def main(obj):
data = bytes(obj) # removing bytes() => 860x slower !!!
for _ in range(10_000):
assert data.index(10, 100) == len(data) - 1
if __name__ == '__main__':
data = memoryview(bytearray(64 * 1024))
data[-1] = 10
start = time.perf_counter()
main(data)
stop = time.perf_counter()
print(f'time = {stop-start:.3f}')
I created a Discourse post
True. I'm wondering how easy interop Rust and C would be. C and C++ code can be both used in a program's codebase very easily, but not sure for Rust. I assume Rust has the same compile-link model that C and C++ has, but I don't know for sure given my acute lack of knowledge for Rust
Hey if you ever come back round to doing that again, let me know, I'd be very happy to help!
Does anyone happen to know what changed in Python 3.14 that broke this somewhat cursed function that dynamcally rewrites Python functions on the fly? https://github.com/guidance-ai/guidance/blob/fc9958930a9dd083877498e872e95d2051bca405/guidance/_utils.py#L104-L150
it works on Python 3.13 and older but on 3.14 somehow the signature ends up corrupted
a little more context: https://github.com/guidance-ai/guidance/issues/1393
I was trying to figure out why I can't get this function to work. Seems like it assumes that the function has at least one decorator applied (with @ specifically) for some reason
fwiw here’s the fix: https://github.com/guidance-ai/guidance/pull/1395/files
that str(type(_)) thing was cursed yeah
it's in the implementation of a decorator so I guess that makes sense
I'd expect py @foo def bar(): ... to be the same as ```py
def bar(): ...
bar = foo(bar)
me too! I guess no one has noticed the limitation you found until now
Yeah, it's not a big deal I suppose
this project is a reverse dependency of vLLM - my current project is to get vLLM running on the free-threaded build
I'm not sure why the function needs to strip decorators tbh
It also won't work if the first decorator spans multiple lines```py
@decorator_factory(
param1=1, param2=2)
@strip_multiline_string_indents
def banana():
...
since it literally removes the first line of source code, not the first decorator through the AST
neither do i! but the principle of chesterton's fence applies to basically everything I'm doing lately...
sorry if I'm piling on with this function, I just don't like this kind of hasty meta-programming
Thankfully I'm not responsible. This is not the craziest I've seen on this project. There was a unit test that was basically doing:
for i in range(sys.getrefcount(None)):
...
And no one noticed that in Python 3.12 the test started taking 15 minutes to complete instead of being near-instant
because of immortals?
yeah, the immortal refcount is several billion
in 3.14 it's not 2^32 -1 anymore but it's large
@strip_multiline_string_indents
def banana(x, y, z):
return f" {x} {y} {z} "
print(banana(1, 2, 3)) # 123
``` 😩
who needs f-strings anyway
I believe it steers next-token probability distributions in LLMs to fit a certain schema (e.g. JSON)
I think maybe because annotations now add another code object
so that loop might be finding the wrong one
if that's true I feel I've done something good for the world by breaking that function
TIL context variable tokens are also context managers in 3.14, no need to define a boilerplate decorator anymore
What are those?
@boreal umbra you can think of a context variable as a souped-up thread-local that is “context-local”. You can use them to store state in a context manager.
before python 3.14 you had to write:
import contextvars
import contextlib
v = contextvars.ContextVar("test", default='default')
@contextlib.contextmanager
def test_context(value):
token = v.set(value)
try:
yield
finally:
v.reset(token)
print(v.get())
with test_context("context variable has a value!"):
print(v.get())
now you can write:
import contextvars
v = contextvars.ContextVar("test", default='default')
print(v.get())
with v.set("context variable has a value!"):
print(v.get())
man it is really hard to do something right
look at my web extension
like i dont know how to market it lol
@grand river that's not what this channel is for
sorry big council
would u like check it out?
!rule 6
cool! this makes sense
thanks for sharing
Is there a pyupgrade rule for this?
no idea
hello, anyone interested in internals of GIL removal
definitely cool but the JIT rn is more interesting to me
!clban 1417610459980234862 only here to advertise
:incoming_envelope: :ok_hand: applied ban to @high kite permanently.
yes that too but it's premature
still results are promising
where
my own benchmarks on my local machine (might not be as accurate)
There's this too https://doesjitgobrrr.com/ and
https://raw.githubusercontent.com/facebookexperimental/free-threading-benchmarking/refs/heads/main/results/bm-20251108-3.15.0a1%2B-7e2bc1d-JIT/bm-20251108-vultr-x86_64-Fidget%252dSpinner-tracing_jit-3.15.0a1%2B-7e2bc1d-vs-base.svg
-# It's in code block cuz discord messes up the link lol
yeah it's very clean
dare I ask why the prior value of sys.getrefcount(None) was meaningful in context?
Anyone helo me pls dm me
ask in #python-discussion and provide details. Or try #❓|how-to-get-help
@spark magnet ok i am new
no problem.
@spark magnet sir can I ask u thing
you can ask me in #python-discussion
Was digging through the build system's code and found a rather amusing comment that when the GIL is disabled the entire JIT is thrown into the trashcan 😆
it's not thread safe
But I am curious though how does simply disabling the GIL result in the entire JIT not being used at all? I'd get if the JIT doesn't work properly with the GIL, but I don't think I've ever seen a system just mysteriously decide to silently not do anything at all if another is disabled/enabled
JIT has dynamic code generation and ref coutning and a lot of stuff
Oop didn't manage to ask my question in time, sorry
I did see that issue, what I got from it was that the compiler just straight up doesn't get used
(Normally you'd expect the compiler to fail spectacularly on free threading, not silently just check out and call it a day, which is a little amusing to me)
there’s a PR open to fix that, I think
numba is also working on supporting the free-threaded build
you’re right that the whole topic is fraught - populating global caches in a scalable and thread-safe manner is tricky and a JIT is a pile of global caches
I see
I wonder if the second Interpreter (Forgot the name) is affected by this as well, I do recall that it uses the same configure option as the JIT does
python has a lot of interpreters for different compilers, but do you mean tail-calling?
It has like 2 tiers of Interpreters from what I remember? Not referring to tail calls or computed goto, I think the lower tier one was the profiling one and the higher tier one is supposed to be faster?
I really forgot everything about Python's internals, jeez
Tier 2 is the JIT I think tier one is specialising interpreter I think?
hmm
I very vaguely recall Python had 3 executors planned when the project to make it faster was started, the baseline interpreter (This was the one that can select between switch, computed goto and tail calls I think), a faster interpreter and the JIT being the fastest
Hold on lemme check the docs
are you thinking of subinterpreters?
i think each interpreter has its own JIT but not 100% on that
That's the tier 2 interpreter. In reality we use it only for debugging the JIT. It's much slower than the base interpreter right now.
hmm I always thought tier 2 was the JIT, when you set the flag to enable the JIT, tier 2 is used? not sure if im getting this right
the tier2 macro has multiple levels you can also pass --enable-experimental-jit=intepreter which sets the tier 2 interpreter to be used but not the jit
How many people use AI to complete programming for their related work tasks
What does that have to do with #internals-and-peps ?
Am wondering where to ask
!ot
Please read our off-topic etiquette before participating in conversations.
Thank you for that then
In 3.10 the END_ASYNC_FOR opcode pops 7 values from the stack. Why is this 7 values? I understand that when an exception is triggered this is put on the stack, which in 3.10 is 3 values. So then we also have the iterator on the stack, so we should pop 4 values. After a lot of reading it seems like there are 2 exceptions on the stack somehow, can anyone clarify this?
Should we refer to classes that conform to the __str__, __int__, etc. protocols as strables and intables respectably?
I'm thinking because at the current point the signature of print is print(*objects, sep=' ', end='\n', file=None, flush=False), but it's not clear what objects can actually be printed.
If we can change it to print(*strable, sep=' ', end='\n', file=None, flush=False) would it be clearer?
Every object is strable
unless you go out of your way to define __str__ such that it raises an exception, which is arguably just a bad idea
i would write that the object is convertible to str or int
speaking of which it should be about time that the typing hints in typing become built-ins in my opinion
I don’t see how that’s related to what I said
My bad. I didn't do my research but my point stands for say int()
never mind i think i was confused
But then again every object has some kind of __repr__ unless you go out of your way to change it
they are built-in, there's just not much incentive to put them in the no-module namespace
yeah, let's not put even more stuff in the builtins namespace
we already have enough stinkers, like id
there's things in the stdlib other than the typing module that can be argued to have more use in builtins too
do you think it makes sense to document that this is not thread-safe?
https://docs.python.org/3/library/codecs.html#module-encodings
well, search_function to be precise
hmm, i'll generally look around and see what is and isn't thread-safe in the encodings module
cc @uneven raptor
if the search function isn't thread-safe then .encode() might not be thread-safe as well...?
hmmm
although no
there would have to be different mods in the call of search_function for it to be a threat
that's a non-issue, nvm
what isn’t thread-safe?
like, what is the nature of the thread-unsafety?
not clear just from the docs
Research the concept on the internet
ngoldbaum knows how to research things on the internet. they're asking Bartosz to clarify the scope of their question.
!warn 280050413833682944 The last two interactions you've had in this channel have both been rude (first reacting to someone's question about AI usage in the workplace with a vomiting emoji, and now telling someone to Google something). You should re-read our #code-of-conduct if you plan on continuing to engage with this server.
:incoming_envelope: :ok_hand: applied warning to @crisp locust.
@uneven raptor in this PR https://github.com/python/cpython/pull/140690, why is HAVE_THREAD_LOCAL unconditionally defined? Shouldn't it only be defined if Py_BUILD_CORE is set? Tom Caswell noticed building numpy with cpython main that this change breaks numpy's definitions for thread-locals: https://github.com/numpy/numpy/blob/fb0578d3973e926eee2e68ce9fd9996459b8534b/numpy/_core/include/numpy/npy_common.h#L128-L140
in NumPy those HAVE_ variables are set at build time based on configure checks that meson does. I guess I could rename them to be e.g. NPY_HAVE_ to avoid problems like this too.
it broke mypyc, take a look at the discussion in that PR
mypyc defines Py_BUILD_CORE after pyport.h is included, so that would break in headers that assumed _Py_thread_local was available (by removing HAVE_THREAD_LOCAL checks)
I guess we could remove HAVE_THREAD_LOCAL entirely and that would fix it?
well, at least numpy relied on that macro being unset, no idea if anything else depends on it
could you create an issue? I guess the best fix is to only define that when Py_BUILD_CORE is set (but define _Py_thread_local unconditionally)
in NumPy we're dropping Python 3.11 support. Among other things, this lets us use the skip_file_prefixes keyword argument in warning.warns. I wrote a comment explaining why I think it's a good idea to wholesale switch over: https://github.com/numpy/numpy/issues/30311#issuecomment-3602664034. Anyone happen to be aware of cases where you'd ever want to use stacklevel instead of skip_file_prefixes?
what's an unraisable warning?
Like when a file gets deleted without using .close()
The warning gets spat on the floor and pretty arbitrarily signed a module
so a warning generated by a GC pass, I guess that's similar to a callback or a coroutine in that the runtime is calling it
NumPy has some C warning code that's a little gnarly but I don't think any of the Python implementation has any patterns like that.
GC doesn't insert a frame so it's whatever is on the stack when the GC runs
Does PCbuild have LTO on by default (Or does it even have LTO support at all)?
build.bat -h says nothing about LTO
MSVC supports LTO, I believe PGO and LTO are done in release builds
Ah it's an LTO is on when PGO is on and off otherwise sorta deal?
(Guessing because there is no LTO flag, only PGO)
walaikum assalam.
how's life?
Normal
fax
İ from azerbaycan
azerbaijan?
How are you
Yeah
im doing normal too
my finals are almost over.
I am dont racist
got it
I love this server, please introduce yourself.
aight hold on
This isnt the place, use #ot0-psvm’s-eternal-disapproval for chitchat
ok
Please react with ✅ to upload your file(s) to our paste bin, which is more accessible for some users.
Wrong channel, #ot2-never-nester’s-nightmare
mb i thought it was the career discussion thing
I joined server 2 days ago why am I muted in group call channels
Are paramspecs supported in __call__? I'm getting type errors when attempting to migrate a class to Python 3.12 (PEP 695) syntax
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
It works fine with an explicit ParamSpec, but says expected "def (*Never, **Never) -> Never" with the 3.12 syntax...