#internals-and-peps

1 messages ยท Page 155 of 1

verbal escarp
#

grml. x = min((actual_values[k] for k in K if k in actual_values), default=0) why can't python figure out x = min(actual_values[k] for k in K if k in actual_values, default=0)?

#

k in actual_values, default=0 isn't even valid syntax

radiant garden
#

probably since the other form (f(a, b for c in d)) is an easy footgun and allowing unparenthesized genexps in expression position only sometimes is a bit messy

visual shadow
#

This is breaking me a little...what happened here.

radiant garden
#

also might be confused for unpacking the genexp

grave jolt
lusty scroll
#

finally always gets the last laugh

#

I'n surprised that "worked", though

grave jolt
lusty scroll
#

!e

def foo():
  try:
    1/0
  finally:
    return
foo()```
fallen slateBOT
#

@lusty scroll :warning: Your eval job has completed with return code 0.

[No output]
sour thistle
#

ok what

lusty scroll
#

don't need a catch all block :p

#

somehow the pending exception must get cleared

#

!e

def foo():
  try:
    1/0
  finally:
    try:
        1/0
    finally:
        raise SystemExit(2)
foo()```
fallen slateBOT
#

@lusty scroll :warning: Your eval job has completed with return code 2.

[No output]
lusty scroll
#

well that's funny, it looked like a successful exit in my terminal

lusty scroll
native flame
#

looks like continue swallows the exc too

grave jolt
#

yep

#

in JS as well

lusty scroll
#

it's funny because in the C API I think python will raise a fatal error if you do certain things with an exception pending

#

you are supposed to call PyErr_Clear() or PyErr_Occurred() (i think that's what they were called)

#

so seems that something is "erasing" the exception

full marsh
#

what does this statement mean im paranoid that discord would leak my data
Related Companies: We may also share your information with our Related Companies for purposes consistent with this Privacy Policy.

#

its from discord tos

#

im trying to understand but can not

lusty scroll
#

as I understand it, anything you give discord (e.g. profile info) could be given to third parties

swift imp
#

Idk how I feel about pep 677 rejection.

#

I think it pretty much solidifies what the future lambda pep syntax would be

sour thistle
swift imp
#

They should have just never introduced typing

#

They don't want it becoming its own dsl but it's also bound to be forever cumbersome when they reject stuff like that

visual shadow
#

link please? im having a hard time finding the rejection notice on the page

swift imp
#

On #mailing-lists [Python-Dev] PEP 677 (Callable Type Syntax): Rejection notice.

visual shadow
#

ah ty. so the site isnt updated yet

raven ridge
lusty scroll
#

wow, neat

#

I don't think it works in java but I'm too lazy to check

#

nevermind

#
class Test {
  public static void main(String... argv) {
    for (int i=0; i<10; ++i) {
      System.out.println(i);
      try {
        throw new RuntimeException();
      } finally {
        continue;
      }
    }
  }
}```

$ java Test
0
1
2
3
4
5
6
7
8
9```

#

thinking how cursed it could probably be made using generators ...

#

!e who needs try/finally

class T:
  @staticmethod
  def __enter__(): pass
  @staticmethod
  def __exit__(_, _1, _2): return True

with T():
  1/0```
fallen slateBOT
#

@lusty scroll :warning: Your eval job has completed with return code 0.

[No output]
lusty scroll
#

Why is it showing a yellow triangle? ๐Ÿค”

astral gazelle
#

There wasnt any output

lusty scroll
#

ah, gotcha

lusty scroll
#

I just learned you can do this

echo 'a = b' | python -m dis```
peak spoke
#

I think the main reason would be that it's dynamic

#

"properly" compiling it would be more complex, and probably with not that much gain

flat gazelle
#

generating assembly is complicated, and requires doing several times over to do portably. In contrast, a bytecode VM is generally not slower unless you actually have an optimising compiler, which python doesnt really tend itself towards (these days, you could probably get one working, but 20 years ago, no), while writing a portable bytecode VM is as simple as writing it in C (though python isnt 100% ISO C, it is good enough for most platforms)

magic nova
#

yeah and as mentioned languages with a lot of dynamicism and introspection like Python don't really lend themselves to good optimized ahead-of-time compilation

#

you can't get a lot of information at just compile time, e.g consider what machine code you would generate for this Python snippet

#
def sum(a, b):
  return a + b
#

vs this C snippet

#
int sum(int a, int b) {
  return a + b;
}
raven ridge
#

Not only are the types of arguments not known at compile time, even the definitions of functions aren't known at compile time, because they can change after the function was originally defined.

native flame
#

Is there any non-esoteric use case for that?

peak spoke
#

decorators?

native flame
#

Oh

#

I was thinking of the f.__code__ manipulations

raven ridge
#

In C, if you wrote, say,

double squared(double x) {
    return x*x;
}

double area_of_circle(double radius) {
    return 3.1415926535 * squared(radius);
}
``` the compiler is likely to inline one of those function definitions into the other. If you wrote equivalent Python code like ```py
def squared(x):
    return x*x

def area_of_circle(radius):
    return 3.1415926535 * squared(radius)
``` a compiler couldn't perform the same optimization, because a user of the module could legally do something like: ```py
import mod
mod.squared = print
mod.area_of_circle(1)
raven ridge
native flame
#

Hmm

flat gazelle
#

I believe there are also some stdlib functions that replace their python implementation with an optimised C impl, but keep the python impl for readability

raven ridge
#

Yep, many of them.

#

But modification of a module from outside that module is rare except for tests

flat gazelle
#

I mean, even that already breaks function inlining

peak spoke
#

compile/eval/exec also don't help things

raven ridge
#

Also, note that in Python, (almost) everything happens at import time.

sacred yew
#

are there even any dynamically typed languages that compile AOT?

flat gazelle
#

julia compiles all the way to native

#

though whether it's AOT is debatable

raven ridge
#

The interpreter imports your main module, your main module imports some other stuff and then runs some stuff, and then your main module ends and Python is done importing it and it starts to tear down the interpreter and join outstanding threads and do a final GC pass.

#

That is, python myscript.py behaves almost exactly like python -c "import myscript"

#

Which is pretty weird ๐Ÿ˜„

past pilot
#

Does this a pythonic way?

from tkinter import Tk, Menu, Frame, StringVar, Button, Toplevel, Label, filedialog
#

Or it's better?

import tkinter
spice pecan
#

import tkinter as tk would be ideal IMO, but IIRC it's one of the (VERY) few libraries that suggest using from tkinter import *

#

Also, this question is not really suitable for this channel's topic

past pilot
#

ok

boreal umbra
#

I don't like that only subclasses of BaseException can be raised. I feel like it should be based on having a __raise__ method, or something.

raven ridge
#

Why?

#

For contrast, C++ allows you to throw any type of object, and it's widely regarded as a huge misfeature

boreal umbra
# raven ridge Why?

consistency with the rest of the language. the way that other user-defined types interface with the grammar is through dunder methods.

boreal umbra
raven ridge
boreal umbra
#

as if I've ever made a metaclass.

verbal escarp
#

i'd agree with @boreal umbra

#

consistency is important

raven ridge
#

I pointed out that it's not inconsistent, though. There's other places where a particular object needs a certain base class to be used in a certain context

verbal escarp
#

shrug it doesn't feel right, but i can't make a reasonable point why it should be different, too early in the morning ^^

raven ridge
#

As things stand today, you can except: to catch everything, or except Exception: to catch everything except things that should (almost) never be caught. If arbitrary objects were able to be raised, what would you replace except Exception: with to achieve the equivalent behavior?

verbal escarp
#

hmm.. the issue is that we assume a hierarchy, which is only feasibly realizable with subclassing, but if we had something token-based, a set of objects, we could filter based on that

#

with a token-based filter, it would be possible to add or remove basically keywords

#

the objects in the set should be something of an enum

#

that way it could be discoverable

raven ridge
#

So... What would use code look like, in the case where we want to catch everything except stuff that derives from BaseException and not from Exception?

#

Taking your set metaphor and running with it, we could get ```py
except ~(BaseException - Exception):

native flame
verbal escarp
#

lmao

raven ridge
#

s/excepts/accepts

#

Otherwise, exactly. ๐Ÿ˜„

native flame
#

hah

boreal umbra
white nexus
#

guido will win

boreal umbra
#

I lift weights and am decades younger than him, so that's doubtful. In theory I'll be in the same room as him at PyCon, though I haven't decided what I have to do if he wins. And I already wanted to use my fist fight victory wish to get function composition.

boreal umbra
#

is it currently just based on an isinstance check?

raven ridge
#

Yes

#

For there to be a dunder method on the class that decides if it can accept a particular exception instance, the class would need to have a custom metaclass

#

Otherwise, you'd need to provide an instance, rather than a type, to except

radiant garden
#

From a practical perspective, instantiating / manipulating traceback objects manually is a pain (and is only implemented in 3.7+) so user-implemented __raise__ would be bug-prone and annoying to work with.
However, since it can be done manually, you could in theory make some cursed DSL that uses a custom __raise__ dunder to implement structural exception handling.

verbal escarp
#

i have an ache that might need a pep

#

then people started to actually use the thing and poked me that there needs to be a way to add more complex rules, like the ones you see in textbooks as tables

#

so i've tried to really make it work with code, but all i could come up with is this monster

#
def rule_from_table(table: str, references: dict):
    """Turn a (2D) string table into a Rule of fuzzy sets.

    ATTENTION: This will eval() all strings in the table.
    This can pose a potential security risk if the table originates from an untrusted source.

    Using a table will considerably reduce the amount of required text to describe all rules,
    but there are two critical drawbacks: Tables are limited to 2 input variables (2D) and they are strings,
    with no IDE support. It is strongly recommended to check the Rule output for consistency.
    For example, a trailing "." will result in a SyntaxError when eval()ed.
    """
    import io
    from itertools import product

    import pandas as pd

    df = pd.read_table(io.StringIO(table), delim_whitespace=True)
    D = {}
    for x, y in product(range(len(df.index)), range(len(df.columns))):
        D[(eval(df.index[x].strip(), references), eval(df.columns[y].strip(), references))] = eval(
            df.iloc[x, y], references
        )
    return Rule(D)
#

only to be able to parse things like

table = """
            hum.dry             hum.wet
temp.cold   very(motor.slow)    motor.slow
temp.hot    motor.fast          very(motor.fast)
"""
#

there has to be a better way!

vast saffron
verbal escarp
#

if it has the same drawbacks as this approach.. :/

#

or is it possible to make it IDE-able (as in give autocompletion)?

#

i really can't think of a way to make it feel/work like a table but with valid python syntax so that it doesn't need eval()

#

i wouldn't mind if the table needs to be in a seperate file to work, as long as an IDE identifies it as valid python for completion

flat gazelle
#

it is true that exceptions are one of the very few things in python that require a base class (metaclasses just use the callable protocol, they dont have to derive from type), the only other example I can think of is changing module types, where it must derive from a module type. But with exceptions, I do think it makes sense, since the exception caries some information about the error that occurred, and IMO it makes more sense to just have that rather than using a dunder and storing it elsewhere

raven ridge
#

That would also catch SystemExit. The question was how to avoid that while still catching things that should be caught.

flat gazelle
unkempt rock
#

can you execute arbitrary code when you instantiate a namedtuple because it uses eval?

    code = f'lambda _cls, {arg_list}: _tuple_new(_cls, ({arg_list}))'
    __new__ = eval(code, namespace)

i was trying to think how you'd get it to print something but I couldn't figure out a way

fallen slateBOT
#

Lib/collections/__init__.py lines 380 to 382

if not name.isidentifier():
    raise ValueError('Type names and field names must be valid '
                     f'identifiers: {name!r}')```
unkempt rock
#

right I ran into that. but people always say eval is unsafe, but I couldn't find even a toy example of exploiting this

spark magnet
#

otherwise you'd have to find code that used data as the names for the namedtuple? I guess that might exist, but it seems unlikely.

peak spoke
#

eval is unsafe if it's running in a context that has higher privileges than the user and the user can give it unsafe code to execute

#

while the second point is probably not true with the check, the first one definitely is not

spark magnet
#

typically, the problem is eval'ing data

white nexus
#

yes

lime locust
#

pls meme

boreal umbra
lusty scroll
peak spoke
#

this seems confusing, why doesn't it raise some error?

In [43]: def f():
    ...:     ...

In [44]: copy.copy(f) is copy.copy(f)
Out[44]: True
boreal umbra
#

Hmm, there is no types.FunctionType.__copy__. What does copy.copy do, in that case?

fallen slateBOT
#

Lib/copy.py lines 107 to 108

def _copy_immutable(x):
    return x```
fallen slateBOT
#

Lib/copy.py lines 105 to 116

_copy_dispatch = d = {}

def _copy_immutable(x):
    return x
for t in (type(None), int, float, bool, complex, str, tuple,
          bytes, frozenset, type, range, slice, property,
          types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented),
          types.FunctionType, weakref.ref):
    d[t] = _copy_immutable
t = getattr(types, "CodeType", None)
if t is not None:
    d[t] = _copy_immutable```
raven ridge
peak spoke
#

probably not expect, but I also wouldn't be surprised by it

raven ridge
#

what about copy.deepcopy([1, 2, 3]) ?

peak spoke
#

copy being an identity func seems weird

white nexus
#

-gs copy.deepcopy

#

I forget this isn't my guild lmao

peak spoke
fallen slateBOT
#

Lib/copy.py lines 182 to 183

def _deepcopy_atomic(x, memo):
    return x```
`Lib/copy.py` line 197
```py
d[types.FunctionType] = _deepcopy_atomic```
peak spoke
#

but functions are mutable so I guess the code predates that change?

raven ridge
#

to keep backwards compatibility we'd need the current behavior by default, so you'd want to introduce a new flag called raise_if_immutable=False or something?

#

and if you set that flag, then a deepcopy of any object that (recursively) contains a string or int or float would fail?

#

seems... questionable. ๐Ÿ™‚

peak spoke
#

I don't know how it actually works but I meant the flag being set to True in deepcopy and false by default otherwise. This of course is not possible now but it feels like it would help prevent errors where the behaviour like the function copying not actually copying is not caught

raven ridge
#

hm. immutable objects are supposed to be interchangeable - the interpreter is allowed to, as an implementation detail, replace any pair of immutable but equal objects with a single object.

white nexus
#

๐Ÿ‘€ that's uh. fun. i may need to change some code

raven ridge
#

it does that as an implementation detail for strings and integers and tuples in some places

peak spoke
#

Well in this case it looks like a mistake with the list not being updated, but I think there could also be cases where they would be passed by accident

raven ridge
#

it would be allowed to do it in more places if it wanted to. If you've assumed that two equal immutable objects will not be is identical, you've probably made an unsafe assumption.

peak spoke
#

though that would probably be caught at an another place

raven ridge
#

since functions are mutable, it probably should make a new function, in the case you originally brought up

#

I do agree with you there - that seems to be worth a bug report.

peak spoke
#

now if I could log into the bug tracker

raven ridge
#

if it hasn't already been ๐Ÿ™‚

verbal escarp
#

i wished there was a way to write such a table in python syntax to describe matrices

#

the numpy people probably would agree

#

pandas even

grave charm
#

What does ... Mean?

quick snow
lusty scroll
#

can one subclass the ellipsis

#

!e no you can't.

class MyEllipsis(type(...)):
  def __repr__(self):
    return repr(super()) * 2
fallen slateBOT
#

@lusty scroll :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | TypeError: type 'ellipsis' is not an acceptable base type
lusty scroll
#
if (!_PyType_HasFeature(base_i, (1UL << 10))) {
      PyErr_Format(PyExc_TypeError,
                   "type '%.100s' is not an acceptable base type",
                   base_i->tp_name);
      return NULL;
}```
#

so, basically, if you really wanted to subclass ellipsis, you could set
type(...) 's tp_flags &= 0x7ffffffffffffbff

#

oh , that flag isn't set on this python. hmm.

#

well even with tp_flags = 0 it still doesn't work ?

grave jolt
wise plover
#

wow

spice pecan
#

does that mean that we may be able to do webdev with python instead of the language we don't talk about?

rich cradle
#

I checked with Christian Heimes (I hope I didn't butcher that name) but it's still compiled normally, I don't believe that the Python is converted to wasm.

#

That is, CPython can run in the browser, but the Python doesn't have access to all the Web APIs.

#

It's the interpreter that becomes a wasm file.

spice pecan
#

Ooh, gotcha

#

I assumed that python code was cross-compiled, not the interpreter

rich cradle
flat gazelle
#

you can already use python instead of JS using brython

rich cradle
#

Unless I'm completely misunderstanding the whole process.

spice pecan
#

I've used brython a bunch in the past

#

Out of all "Python-programmed web" implementation, I like that one the most

#

It has a really interesting (not sure if I'd call it pythonic, but it's definitely convenient and unique) approach to DOM interactions and is overall fairly pleasant. IIRC it's not very hard to integrate with frameworks like Vue/React either, and probably even easier to integrate with svelte, but I've tried neither svelte nor calling it from brython

grave jolt
#

I wonder why this didn't work:

#

!e

from fishhook import hook

@hook(type)
def __len__(cls):
    return 42

for x in list:
    print(x)
fallen slateBOT
#

@grave jolt :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 7, in <module>
003 | TypeError: 'type' object is not iterable
grave jolt
#

Shouldn't this print list[0], list[1] etc.?

verbal escarp
grave jolt
#

I just thought it'd be a fun abuse of generics

verbal escarp
#

hehe

#

i'm taking my first dive into brython atm.. somehow getting lost along the way

peak spoke
#

isn't that the only thing it needs?

feral cedar
#

it should have that for typehinting right?

peak spoke
#

The types use __class_getitem__ afaik

grave jolt
#

try list[0]

#

Ah, it might be that ot only uses __getitem__ lemon_pensive

#

I guess it makes sense, since it's a legacy protocol

quick snow
#

!e

from fishhook import hook

@hook(type)
def __len__(cls):
    return 3

@hook(type)
def __getitem__(self, item):
    return self.__class_getitem__(item)

for x in list:
    print(x)โ€Š
fallen slateBOT
#

@quick snow :x: Your eval job has completed with return code 143 (SIGTERM).

001 | list[0]
002 | list[1]
003 | list[2]
004 | list[3]
005 | list[4]
006 | list[5]
007 | list[6]
008 | list[7]
009 | list[8]
010 | list[9]
011 | list[10]
... (truncated - too many lines)

Full output: too long to upload

lusty scroll
#

__getitem__ ?

raven ridge
#

nah, legacy iteration

#

a collection is iterable if it provides only __len__ and __getitem__ - the interpreter will basically do iter(c[i] for i in range(len(c)))

lusty scroll
#

ohh

#

!e

class OldCollection:
    def __init__(self, *items): self._data = items
    __len__ = lambda self: self._data.__len__
    __getitem__ = lambda self,i: self._data.__getitem__(i)

oc = OldCollection(1, 2, 3, 4, 5)
for _ in oc:
    print(_)```
fallen slateBOT
#

@lusty scroll :white_check_mark: Your eval job has completed with return code 0.

001 | 1
002 | 2
003 | 3
004 | 4
005 | 5
lusty scroll
#

how about that

raven ridge
#

yeah - "legacy" because it predates __iter__

#

it was the original way to implement custom iterables, IIUC

lusty scroll
#

it gives a <class 'iterator'> instance

feral cedar
raven ridge
#

aha

lusty scroll
#

seriously?

raven ridge
#

!e ```py
class OldCollection:
def init(self, *items): self._data = items
getitem = lambda self,i: self._data.getitem(i)

oc = OldCollection(1, 2, 3, 4, 5)
for _ in oc:
print(_)

fallen slateBOT
#

@raven ridge :white_check_mark: Your eval job has completed with return code 0.

001 | 1
002 | 2
003 | 3
004 | 4
005 | 5
raven ridge
#

Yep.

#

LeGaCy

lusty scroll
#

I kmew StopIteration is part of the protocol

#

but not IndexError

raven ridge
#

StopIteration is part of the modern iteration protocol, but not the legacy one

lusty scroll
#

so they didn't originally use StopIteration

raven ridge
#

I don't think so

lusty scroll
#

huh, interesting

raven ridge
#

There wouldn't have been a need for it before custom iterables

#

Though I'm just conjecturing. Could be wrong.

olive marsh
#

Anyone here used this type? ๐Ÿ™„

unkempt rock
#

Implementing dunder len lets you iterate in reverse ,however, so reversed(OldCollection(1, 2, 3, 4, 5)) wouldn't fail

olive marsh
rose schooner
#

!e ```py
def f(x):
return x + 2**111023331924844412

f.code = f.code.replace(co_code=b'|\0d\1\x17\0S\0')
print(f(67))

fallen slateBOT
#

@rose schooner :white_check_mark: Your eval job has completed with return code 0.

69
prime estuary
#

You can introspect a code object (directly or via inspect.signature()) to fetch the signature of a function, which is neat if you want to do "smart" behaviours. I'm personally doing it for a bunch of callback functions, to allow you to reorder or omit parameters, but have the calling code figure out the right calls.

#

Constructing them is useful if you're generating code, and want to do things that aren't syntactically possible or want to try and optimise further.

glacial frigate
#

#bot-commands

lusty scroll
#

the code type __init__ was not in possession of a signature itself, iirc

olive marsh
#

@lusty scroll my mentor extracted some useful info from code object of traceback to improve the logger.

lusty scroll
olive marsh
lusty scroll
#

there is a package called snoop that kinda does it as well

#

and birdseye which is kind of a visual version

olive marsh
#

Cool, good to know. Will check that.

surreal sun
#

I personally use __code__ objects for mostly "cursed" things

#

like editing bytecode instrs and what not

#

I don't think I've ever had to use it directly in real code thanks to inspect

spark magnet
#

The code in my eval-crashing blog post is for 2.7: https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html For 3.10, the line in the middle has to be 0,0,0,0,0,0,b"KABOOM",(),(),(),"","",0,b"". For 3.11, it needs 4 more arguments, but when I make it 0,0,0,0,0,0,b"KABOOM",(),(),(),"","","",0,b"",b"",b"",b"",(),() (which I think is right), it doesn't crash....

magic nova
#

amusingly enough your bogus bytecode has now become valid, K is now opcode 75 aka RETURN_GENERATOR. In python built with assertions this causes a

#
>>> c = types.CodeType(0,0,0,0,0,0,b"KABOOM",(),(),(),"","","",0,b"",b"",b"",b"",(),())
>>> eval(c)
python: Objects/genobject.c:917: _Py_MakeCoro: Assertion `coro_flags' failed.
spark magnet
#

@magic nova ah, that's why ๐Ÿ™‚

#

ok, changing it to QABOOM crashes ๐Ÿ™‚

white nexus
#

interesting

spark magnet
#

(I just guessed at another opcode to use, I don't know if any of that was carefully chosen...)

white nexus
#

I'm quite curious, what kind of code can crash ast.parse that isn't incredibly long

magic nova
#

there shouldn't be any really

#

ast.literal_eval is marked to be safe to use except for resource constraints

white nexus
#

I'm using ast.parse on untrusted user input, basically

magic nova
#

so ast.parse (which ast.literal_eval uses) itself should not crash

white nexus
#

but the input is hard limited to around 30k characters

magic nova
#

you can still crash that with some tactical nesting

white nexus
#

yeah

#

but that requires a lot of characters iirc

spark magnet
#

a lot of characters fit into 30k

#

@white nexus what user input are you parsing with ast.parse?

white nexus
#

code that's been pasted to a pastebin

magic nova
#

yeah that should be fine assuming you avoid cpu/ram consumption issues (cgroups is probably the best way on Linux), we do fuzz ast.literal_eval in CPython and note it to be safe for untrusted inputs

spark magnet
#

@white nexus can you tell me more? What are you doing with the code?

white nexus
#

essentially parsing it for now to see if it is valid python code, and then might add some libcst walking to scan for different sorts of labels and similar. Not entirely sure yet, as I want to make sure that the ast parsing can't it down

spark magnet
#

but what will you do with it eventually? An obvious possibility would be to run it.

white nexus
#

i doubt i'll do that, i'm just curious if i should plan for the possibilty of someone crashing it -- but it seems super safe

spark magnet
#

ok, what will you do with the code? Why is someone sending you code, just so you can see if it's valid Python? I don't understand the big picture here of what you are building.

white nexus
#

same tbh, i just like integrating as many things as i can with other things right now

#

this phase will probably pass

spark magnet
#

@white nexus I can tell you from experience that it does not ๐Ÿ˜„

safe heron
#
>>> re.escape(" ")
'\\ '

just why

white nexus
#

then move on to AI

sturdy timber
#

Assume that bug would apply to ast.literal_eval too since it's with the parser

white nexus
#

hmm, fun

#

so that's basically blocking any ast.parse

#

or well

#

any ast parse on 3.10 in an async context needs to be run in an executor

spark magnet
safe heron
#

i looked thru the code already, thanks

spark magnet
neat delta
#

does anyone know if there's a plan in the future to make assert a function as happened to print?
below pep is draft but implies maybe so

#

!pep 679

fallen slateBOT
#
**PEP 679 - Allow parentheses in assert statements**
Status

Draft

Python-Version

3.11

Created

07-Jan-2022

Type

Standards Track

rose schooner
#

the pep describes py assert (expr, "message") becoming the same as py assert expr, "message" to support this ```py
assert (
some_very_long_expr_that_has_to_be +
broken,
"some very long message that has to"
"be broken",
)

neat delta
#

yeah, requiring the parens would break loooots of tests. can see why they wouldn't do it

boreal umbra
#

Part of me doesn't want this, just to inconvenience those who treat assert as a function. But other than that I'm for it.

#

!e

assert (2 == 4, "hi")
print("bye")
fallen slateBOT
#

@boreal umbra :white_check_mark: Your eval job has completed with return code 0.

001 | <string>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
002 | bye
boreal umbra
#

Remove the syntax warning ๐Ÿ˜ 

white nexus
#

!e assert(2 == 4, "hi")

fallen slateBOT
#

@white nexus :white_check_mark: Your eval job has completed with return code 0.

<string>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?
white nexus
#

interesting, i didn't know the space was not required

native flame
#

if parentheses became valid, how would you assert a tuple

#

not that there's ever a reason to do that

#

but seems odd to have no syntax to express it at all pithink

dusk comet
#

assert a # a is tuple - old behavior
assert a,b - old behavior
assert (a,b) - new behavior (there are no builded tuples, it works same as old form without pars)

spice pecan
native flame
#

hmm

dusk comet
#

hmm

#

!e
assert ()
assert (a,b,c)
assert (a,)
assert (a)

fallen slateBOT
#

@dusk comet :x: Your eval job has completed with return code 1.

001 | <string>:2: SyntaxWarning: assertion is always true, perhaps remove parentheses?
002 | <string>:3: SyntaxWarning: assertion is always true, perhaps remove parentheses?
003 | Traceback (most recent call last):
004 |   File "<string>", line 1, in <module>
005 | AssertionError
verbal escarp
#

!d help

fallen slateBOT
#

help([object])```
Invoke the built-in help system. (This function is intended for interactive use.) If no argument is given, the interactive help system starts on the interpreter console. If the argument is a string, then the string is looked up as the name of a module, function, class, method, keyword, or documentation topic, and a help page is printed on the console. If the argument is any other kind of object, a help page on the object is generated.

Note that if a slash(/) appears in the parameter list of a function when invoking [`help()`](https://docs.python.org/3/library/functions.html#help "help"), it means that the parameters prior to the slash are positional-only. For more info, see [the FAQ entry on positional-only parameters](https://docs.python.org/3/faq/programming.html#faq-positional-only-arguments).

This function is added to the built-in namespace by the [`site`](https://docs.python.org/3/library/site.html#module-site "site: Module responsible for site-specific configuration.") module.
verbal escarp
#

is there a trick on how to make help() spit out specific docs when envoked on certain objects?

spice pecan
#

I'm pretty sure it just yoinks the docstring, you may have success by adding a "__doc__" attribute

#

!e ```py
from site import help

class Example: pass

instance = Example()
instance.doc = "Hey!"
help(instance)

#

ah, right, hold on

fallen slateBOT
#

@spice pecan :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | ImportError: cannot import name 'help' from 'site' (/usr/local/lib/python3.10/site.py)
spice pecan
#

I can never remember the correct way to import it, smh

white nexus
#

it's

spice pecan
#

That's one way to do it, yeah

#

!e now let's see how wrong my assumption was

from pydoc import help 

class Example: pass

instance = Example() 
instance.__doc__ = "Hey!" 
help(instance) โ€Š
fallen slateBOT
#

@spice pecan :white_check_mark: Your eval job has completed with return code 0.

001 | Help on Example in module __main__:
002 | 
003 | <__main__.Example object>
004 |     Hey!
river remnant
paper echo
#

otherwise i think i saw (maybe participated in?) a github issue about it where they said "it's WIP and pending pep 646"

#

!pep 646

fallen slateBOT
#
**PEP 646 - Variadic Generics**
Status

Accepted

Python-Version

3.11

Created

16-Sep-2020

Type

Standards Track

languid pier
#

Not sure if this is the place, but what is the first instinct (or the natural answer) of resulting thing when you face

>>> list(enumerate(['a', 'b', 'c'], [1, 2, 3]))

?

  1. [(0, ['a', 'b', 'c']), (1, [1, 2, 3])] (i.e. treat as a list)
  2. [(0, ('a', 1)), (1, ('b', 2)), (2, ('c', 3))] (i.e. treat as a zip)
  3. [((0, 0), ('a', 1)), ((0, 1), ('a', 2)), ((0, 2), ('a', 3)), ..., ((2, 1), ('c', 2)), ((2, 2), ('c', 3))] (i.e. treat as a cartesian product)

Just a random idea. 3 seems most useful since you can just loop with both indexes... but I'm not sure which is the most natural one

feral cedar
#
  1. it should error
#

making any of those behaviors implicit is kinda weird

river remnant
paper echo
river remnant
#

Perfect!
I thought it was related to PEP 484 so asked.

#

Shall ask there from the next time!
Thanks again!

somber veldt
#

I want to level up my programing skills, can anyone give some reference work or some problem set?

fresh musk
#

is cpython's dict lookup implementation intentionally not vectorized or is it just that nobody's gotten around to it yet

magic nova
#

afaik no one has looked into it (or at least not posted about it on the bug tracker or mailing lists), I'm sure if it's done portably and has a good speedup vs complexity benefit it would be accepted

true ridge
prime estuary
#

Part of the problem might be that vectorising requires non-standard C code?

prime estuary
#

Well compilers can optimise by using them, but there's no operator/standard C function for the necessary instructions. Could be done by writing individual implementations for different instruction sets with a C fallback, but would be a bit of a pain.

swift imp
#

My understanding of vectorization is making sure to be able to write the loops such that the compiler can unroll then in some way to take advantage of the fact that say the target processor has 4 ALUs in parallel

fresh musk
#

i don't think compilers are very good at vectorizing array indexing, though

#

so you would need something like #include <immintrin.h>

frosty stratus
#

hu

#

hi

#

can someone help me in making my server better

#

??

fossil blade
#

what's the main difference between a package structure and a module structure?

#

and when should I choose which?

spice pecan
fallen slateBOT
#

Here's how to format Python code on Discord:

```py
print('Hello world!')
```

These are backticks, not quotes. Check this out if you can't find the backtick key.

timber charm
fossil blade
#

what's a good way to implement

#

@classmethod
def from_class():

lusty scroll
fossil blade
#
@classmethod
def from_class(cls, config):
  return cls(**{name: value if not name.startswith('__') for name, value in config.__dict__.items })
lusty scroll
#

ohhh

#

so it initializes a new instance from a dict

fossil blade
#

yse

#

yes

#

but the code above seems kinda hacky

lusty scroll
#

yea

#

i got a couple tiny ideas

fossil blade
#

gib

lusty scroll
#

would it be possiblle that an object with __slots__ gets passed in

#

that wouldn't have instance dict, that is

fossil blade
#

I don't know that yet yert

lusty scroll
#

ok

#

I always like inspect.getmembers

#

it returns tuples of key, value

#

so you dont even need items()

#

and it gets attributes from base classes and stuff

#

not sure if that makes sense

#

is config a dict or another regular object with attributes?

fossil blade
#

class Config:
owo = "smth"

lusty scroll
#

ok

#

oh that is a class attribute, yes?

fossil blade
#

Yep

lusty scroll
#

is config an instance of that, or the class itself

fossil blade
#

Class itself

lusty scroll
#

ok

#

nevermind what i saud abt instance dict

#

and you will always have __dict__ on type objects

#

so that's not a concern

#

the one question would be, do ou want attributes from base classes or not

fossil blade
#

Wdym?

lusty scroll
#

will this classmethod be returning a newly geberated class

fossil blade
#

Yes

lusty scroll
#

dayum

fossil blade
#

Oh wait

#

Not a class

#

An instance of the class

lusty scroll
#

oh ok phew

#

but Config is literally a type object right

#

<class 'Config'>

fossil blade
#

Yep

lusty scroll
#

ok

fossil blade
#

Greyblue do be writing a thesis

lusty scroll
#

!e This is my interpretation of it - I wanted a nice repr so I thought of using namedtuple

from collections import namedtuple
import builtins
class Config:
    owo = "Smith"
    other = 113
class NewClass:
    pass
def from_class(cls: type, config: type):
    o = cls()
    orig = set(o.__dict__)
    o.__dict__ |= vars(config)
    diff = { k:vars(o)[k] for k in set(vars(o)) - orig if k[0:2] != k[-2:] != "__"  }
    ntc = namedtuple(cls.__name__, diff.keys())
    return ntc(**diff)
print(from_class(NewClass, Config))```
fallen slateBOT
#

@lusty scroll :white_check_mark: Your eval job has completed with return code 0.

NewClass(owo='Smith', other=113)
lusty scroll
#

lol yeah sorry

#

my original thought was way simpler

lusty scroll
#

what I think is strange about this is that config is a type, not an instance

#

I could see either an object (for type conversion/auto-mapping) or a dict (like from json)

#

or maybe types.SimpleNamespace

#

I wanted to make the namedtuple inherit the NewClass but couldn't see how easily and got tired of tweaking it

swift imp
fossil blade
#

what's unbound?

#

[Pyright reportUnboundVariable] [E] "CLIENT" is unbound

white nexus
#

is this a new github feature?

#

okay so i think they're testing some new features....

#

as the first issue isn't actually #1

#

thonk apparently mannequins have been around for years

flat gazelle
elder blade
white nexus
#

yeah, i was more talking about the tools on github that are allowing that

#

since that repo where they're testing it out started on a high issue number

elder blade
#

They have probably skipped numbers so that it matches the ID on bugs.python

white nexus
#

& that i commented on an issue without actually commenting

white nexus
undone hare
#

that's weird, it is written for 3.9 but still a draft

solemn moat
#

Does anyone know why contextlib.suppress does not error if you don't specify any Exceptions to suppress? Do you think it should? I'm trying to think of a valid reason why it does this bahavior?

cooper@home1:~$ python3.11
Python 3.11.0a5+ (main, Feb 21 2022, 08:52:10) [GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import contextlib
>>> with contextlib.suppress():
...   print("Foo")
...
Foo
>>>

Just wondering and opened: https://bugs.python.org/issue46819

peak spoke
#

could be useful if you're collecting exception types from somewhere dynamically I guess, though that doesn't seem particularly common

quick snow
#

Tbh. the current behaviour seems reasonable. Literally contextlib.suppress() might be pointless, but contextlib.suppress(*exceptions) with potentially empty exceptions isn't.

grave jolt
#

yeah, just like sum([]) is 0

white nexus
#

I'd be more interested in does it suppress if nothing is provided

grave jolt
#

!e

import contextlib

with contextlib.suppress():
    1 / 0
fallen slateBOT
#

@grave jolt :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 4, in <module>
003 | ZeroDivisionError: division by zero
grave jolt
#

as expected, it suppresses all the exceptions you pass in ๐Ÿ™‚

white nexus
#

<

#

I was typing that out but I'm on mobile lol

grave jolt
#

Just like with sum, all and any, this bring about some nice properties, like these being equivalent ```py
with contextlib.suppress(*a):
with contextlib.suppress(*b):
...

with contextlib.suppress(*a, *b):
...

white nexus
#

if you put code where all of these ... were they they would be very different ```py
with contextlib.suppress(*a):
...
with contextlib.suppress(*b):
...
...

grave jolt
#

That's why the code doesn't have anything in there ๐Ÿ™‚

boreal umbra
#
In [1]: nums = list(range(10_000_000))

In [2]: arr = np.array(nums)

In [3]: %timeit sum(nums)
128 ms ยฑ 155 ยตs per loop (mean ยฑ std. dev. of 7 runs, 10 loops each)

In [4]: %timeit arr.sum()
2.39 ms ยฑ 3.11 ยตs per loop (mean ยฑ std. dev. of 7 runs, 100 loops each)

I assume one of the reasons numpy can do this 53 times faster is that it doesn't have to account for heterogeny, whereas I assume Python has to repeatedly do type checking to make sure x.__add__(y) or y.__radd__(x) works (and to access those methods in the first place). Could cpython optimize builtin functions/methods that involve lists if the c struct for the list had a is_homogenous flag with optimized behavior for homogenous lists of primitive-like types?

#

Also, some potentially interesting supplemental information:

In [7]: s = pd.Series(arr)

In [9]: %timeit s.sum()
4.65 ms ยฑ 5.29 ยตs per loop (mean ยฑ std. dev. of 7 runs, 100 loops each)

In [10]: s2 = s.astype(object)

In [11]: %timeit s2.sum()
312 ms ยฑ 1.12 ms per loop (mean ยฑ std. dev. of 7 runs, 1 loop each)
raven ridge
#

I suspect, of those effects, accumulating into a C int is by far the most impactful in terms of the performance.

boreal umbra
#

also, when you say a fixed precision int, do you mean size?

raven ridge
boreal umbra
#

ints are discrete, yes? how can the concept of precision apply?

raven ridge
#

Python ints have variable range, C ints have a fixed range

boreal umbra
#

but isn't that just a matter of how many bits the int is allowed to take up? I don't think that's necessarily the same as precision

raven ridge
#

not just how many bits it can take up, but also what those bits represent. Sure, maybe "precision" isn't the best word.

peak spoke
#

I've always assumed that

for line in file:
    ...

is mostly a shortcut for

while line := file.readline():
    ...

but that doesn't seem to be the case as I just got

    self._last_file_pos = journal_file.tell()
OSError: telling position disabled by next() call

where the tell was under a loop over a file. What is it doing that this has to be diabled?

prime estuary
#

Here's where the flag is set: https://github.com/python/cpython/blob/cff4d5c5d29528299ec1ac5b3b3a6f7735577c01/Lib/_pyio.py#L2553
It looks like it's an optimisation - since chunks are being fetched from the binary file, there's going to be fragments being stored to be returned in the next read call. If you use readline() I think it then takes extra work to keep track of how much was used of the binary data so tell() can rewind appropriately, but if next() is called it assumes you're going through the file continuously so it can skip figuring that out.

fallen slateBOT
#

Lib/_pyio.py line 2553

self._telling = False```
prime estuary
#

You can always use iter(file.readline, '') to force calls to readline instead.

vast saffron
#

pep680 doesn't sit right with me, currently mostly because of the unintuitive name and not being able to write. It feels like a pep sized band-aid.

Generally:

  • It is needed to be in the stdlib
  • it fulfills the bare minimum
  • I take what I can get but it feels really defensive and the way it is now done does worry a bit for the future (only implementing the minimum really late, because it is already aimed at nobody will want to maintain it)

with the name of the channel in mind, what are your general thoughts? I know it is done and accepted, but it seems like a nice starting point for a discussion.

raven ridge
#

!pep 680

fallen slateBOT
#
**PEP 680 - tomllib: Support for Parsing TOML in the Standard Library**
Status

Accepted

Python-Version

3.11

Created

01-Jan-2022

Type

Standards Track

white nexus
#

i agree that it should be in the stdlib

#

i also think that they should have done it long ago??

#

Any existing third-party module named tomllib will break, as import tomllib will import the standard library module.

#

doesn't the import system check for third parties before stdlib?

raven ridge
#

It's pretty weird that we standardized on pyproject.toml as the main config file for developing, maintaining, and building Python libraries and applications before we had any way to parse TOML in the stdlib, so I agree it's overdue.

#

And since TOML files are generally written by hand but parsed by machine, I don't mind that it's read-only for now. Targeting a minimal viable surface also makes sense, since the stdlib is where modules go to die

distant lance
#

setuptools is way behind though, but they are making strides

white nexus
native flame
#

new releases get tied to python's release schedule

raven ridge
#

Only one feature release per year, a much higher barrier of entry for contribution than the average open source project, and extremely strict backwards compatibility requirements really stymie the evolution of modules once they become part of the standard library

spice pecan
#

That's part of the reason why numpy is not in stdlib, despite being an essential package

raven ridge
#

The fact that a backwards incompatible change to the standard library generally takes 3 years, for instance, means that even when something is recognized as a mistake, it often doesn't get fixed, because fixing it would often cost more (in terms of time, effort, and developer goodwill) than leaving the mistake around

white nexus
#

ah, that makes sense

swift imp
#

I guess its bc y'all has security issues and json is tough to write by hand

#

Ini doesn't provide enough features

peak spoke
#

yaml also has a bit too much going on for something like pyproject imo

#

I really like toml for what it is as an advancement for ini, as ini is mostly useless with requiring some custom parsing for basic structures

swift imp
#

Yeah but the syntax is the best imo

swift imp
peak spoke
#

I think there was some issue for making that better, but you can use inline tables in most cases where you would need a structure like that

fossil blade
#

What's the norm for caching? Is using a dict fine

flat gazelle
#

it depends on what you are caching. For caching function calls, a dict or just functools.cache is fine. But for caching web requests, you may want something more elaborate, e.g. redis

lusty scroll
#

yaml has a lot of complexity. If you look at the spec, it'is quite monolithic

vast saffron
#

Yeah yamk can be a pain, toml is ini with extra, but the resemblance to toml can make easier to understand.

Yaml can get quite weird and is relatively alien

last marsh
#

yaml is nicer and easier to parse

flat gazelle
#

unless toml got way more complex in recent revisions, yaml is definitely the more complex format here. 8 different variants of multiline strings, variable substitution, etc.
I am not saying that complexity isn't sometimes useful, but for describing python projects... toml is more than adequate

fossil blade
#

What do I need to know to be able to be an expert in python

boreal umbra
#

Generally, I'd say that understanding things like dunder methods and the method resolution order show an "advanced" understanding of the language.

fossil blade
#

Just want to get knowledge for in-depth python and possibly how is it built

boreal umbra
feral cedar
#

the book "cpython internals" is good

grave jolt
#

building a language is a complex social, technical and economical process ๐Ÿ™‚

elder blade
#

How does import_module()'s relative importing work?

#

I have a file, and I want to import a sibling next to it (from .friend import ...), but import_module() (and more specifically resolve_name()) seems to producing current_file.friend when I use ('.friend', __name__) for the arguments

#

I want to produce friend because in this case, the "main" point where absolute imports base around is the same folder.

frigid trout
fallen slateBOT
#

Lib/importlib/_bootstrap.py lines 902 to 908

def _resolve_name(name, package, level):
    """Resolve a relative module name to an absolute one."""
    bits = package.rsplit('.', level - 1)
    if len(bits) < level:
        raise ImportError('attempted relative import beyond top-level package')
    base = bits[0]
    return '{}.{}'.format(base, name) if name else base```
surreal sun
#

I have the book and it is awesome

verbal escarp
#

import always checks the cwd first, then goes through sys.path etc

#

so if you know where the thing lives you want to import, do ```py
orig_cwd = Path.cwd()
os.chdir(installation_path)
try:
importlib.import_module(module_name)
except ImportError:
pass
finally:
os.chdir(orig_cwd)

#

that's the safest approach

raven ridge
#

That wouldn't be thread safe...

verbal escarp
#

put it behind a lock if you must :p

#

it's the approach that the import system was about to take but then they introduced the sys.path hack

#

i've seen code comments in the source that lamented this

#

in justuse we do this consistently without manipulating sys.path, so i know it works

white nexus
#

what underlying methods do all of the weird shortcut operators call?
for example:
a |= b
~c
d | f

white nexus
#

I've not seen |= much before, but extremely curious how to abuse use it in practice

verbal escarp
#

i.. means inplace

white nexus
#

what is neg?

verbal escarp
#

d | f is just or

white nexus
#

isn't that a bitwise or?

verbal escarp
white nexus
#

is there a place where these are all documented, which symbol to what method?

verbal escarp
#

the page i linked

#

or cpython source

#

none of those operations are bitwise per se, it depends on the implementation. the operations you can't change are not, and, or

white nexus
verbal escarp
#

you can

#

but you can't change or

white nexus
#

ah, yeah

verbal escarp
#

True or False

white nexus
#

but thankfully I already love or, and, not

#

they're already overpowered :)

#

and is so useful for protecting attribute access against a possibly nullable attribute

verbal escarp
#

i tried to overwrite or, and, not when i tried to implement fuzzy logic by overloading booleans.. >.>

white nexus
#

:-:

verbal escarp
#

well, i had to settle for ~hot & ~cold, but that's not too bad either

white nexus
#

no, it's not

verbal escarp
#

but it's good to know there is a big difference between those symbols and the keywords, even though they are called the same colloquially

white nexus
#

yeah

#

bro I didn't even know half of these things existed

#

like <<=

verbal escarp
#

dunders are very powerful and should be taught fairly early imo

white nexus
#

well, I know most dunders (I think) , just didn't realise that there was a <<= and other related in place edits

verbal escarp
#

well, if you've never seen them, you also don't get any ideas on how to (ab)use them ^^

white nexus
#

oh I already have the ideas :3

verbal escarp
#

which is a shame, since they can provide a very nice intuitive API if applied sparingly

white nexus
#

sparingly
and now it's time to go

verbal escarp
#

hrhrhr

#

have fun making your coworker's heads spin ๐Ÿ˜‰

white nexus
#

essentially there's a bunch of bitmasks that I need to represent, and using some of these operators would make it a lot easier

verbal escarp
#

couldn't you use numpy arrays for that?

white nexus
#

ehh, can't introduce numpy as a dependency

verbal escarp
#

too bad

white nexus
#

right now the current system has a function definition for each flag (why??) and a decorator to collect them

verbal escarp
#

that sounds overly convoluted

#

could it be the code is older than enum?

white nexus
#

idk how much python has progressed in the past 7 years but it was implemented on 3.6

#

so not sure

verbal escarp
#

enum was introduced in 3.4 afaik

#

so, no excuse ๐Ÿ˜‰

white nexus
#

maybe it was implemented before then blobthinking

#

it uses a custom enum class because the built in enum class was slower lol

verbal escarp
#

wha...?

#

can you post? ^^

#

i'm curious how that looks like

white nexus
#

the decorators and such I was talking about earlier are in the flags file

verbal escarp
#

need to test this ๐Ÿ™‚

#

i wonder if this was all worth the effort though

#

those timings are in the ns range

white nexus
#

given how this library serializes possibly hundreds of items to an enum per second, it is, it is really worth it

verbal escarp
#

i take your word for it

white nexus
rose schooner
white nexus
#

yeah

#

eg auto doesn't need to exist

rose schooner
#

but what if we made the enum.Enum object C-handled ๐Ÿค”

white nexus
#

although it would be so nice if IntFlag existed *in the custom impl

white nexus
rose schooner
#

wait

#

oh k

white nexus
#

in the custom impl, oops

#

most of the enums in use are intflags

rose schooner
#

probably will make the custom thing slower

white nexus
#

yeah :/

verbal escarp
#
class EInt(IntEnum):
    a = 2 ** 0
    b = 2 ** 1
    c = 2 ** 2
    d = 2 ** 3
bool(EInt.d & 7)
white nexus
#

lol I didn't even realize they were the same

#

I was thinking about what was 2 ** 1

#

and then realised that's the same as 1 << 1

#

although 1 << 1 would likely be faster

verbal escarp
#

faster? the only speed that matters is the lookup and &

#

you don't rebuild your enum every nanosecond (hopefully)

#

ahh

#

hehe

#

EInt.d and 7 is faster, nice

#
300
483.858
313.94142993274124
testEInt2
300
399.066
167.24355697028653
#

min, mean, stdev

#
def testEInt1():
    return bool(EInt.d & 7)

def testEInt2():
    return bool(EInt.d and 7)
#

using perf_counter

#

now let's see how your enum performs

white nexus
#

although given that a lot of these enums are used with try_enum which returns a proxy value if it doesn't exist... hm

verbal escarp
#

your enum is faster, indeed

#
testD1
100
201.619
266.19238798822596
testD2
200
248.104
239.16056774010974
testD3
100
217.641
289.94540141612526
#
def testD1():
    return D.a

def testD2():
    return D["a"]

def testD3():
    return D.a.value
#

about 3 times

white nexus
#

smh don't give me credit for it ๐Ÿ˜ญ

verbal escarp
#

not too shabby

white nexus
#

someone else wrote it who now has stepped away from maintaining the project

verbal escarp
#
testDict
100
193.089
215.1669143874366
#

that's a pure dict lookup

#

still faster ^^

#

but the dot syntax is nicer

spice pecan
verbal escarp
#

i didn't include the building of those in the timing tests

#

but i do wonder if numba could speed up these lookups..

spice pecan
#

I'd assume not really

#

slots?

verbal escarp
#

hmm

native flame
white nexus
#

hmm, if numba speeds it up I could probably add it as an optional dependency

spice pecan
white nexus
#

constant folding?

spice pecan
#

And also turning sets into frozensets in certain contexts (var in {1, 2, 3})

spice pecan
white nexus
#

wait what is frozenset difference?

#

oh no modifications nvm

#

tldr tuple + set

verbal escarp
#

oos. what happened there o.O

native flame
spice pecan
#

frozenset is an immutable variation of a set; if you have something like if var in {1, 2, 3}, instead of building the set every time, it caches a frozenset beforehand (I think? I haven't touched this one in a whiiile)

verbal escarp
#
@njit
def testEInt2_jit():
    return bool(EInt.d and 7)
#

numba doesn't like enum

spice pecan
#

Numba really doesn't like things other than ints and floats tbh

white nexus
#

what I'm curious about is the best way to make a custom flag thingyadoodle

spice pecan
#

It's in the name

verbal escarp
#

but it does work with &

#

woah

#

holy crap, that's.. wtf

#
@njit
def testEInt1_jit():
    return bool(EInt.d & 7)
#
testEInt1_jit
100
3606.791
1082232.7020728937
#

numba hard at work

white nexus
#

Where I need to be able to manipulate a bitmask and have multiple attributes, there's gotta be a good way to do this

spice pecan
#

1 << 0..howmanyyouwant

white nexus
#

non python ints from target library?

verbal escarp
#

but the min is down to the hand-optimized version of @white nexus

white nexus
#

smh stop giving me credit, I didn't write that

verbal escarp
#

you posted it

white nexus
spice pecan
verbal escarp
#

i don't care who actually wrote it :p

#

and you have "pls mention" in your name ๐Ÿ˜‰

spice pecan
#

Some libraries operate with native ints, and they sometimes provide ways to avoid converting from python to native and vice-versa in certain contexts

verbal escarp
#

aha, median seems to give a better idea what's going o

#

median of the jited version is at 200

white nexus
#

ah, this enum usecase is mostly converting bitmasks into flag instances using enums ><

verbal escarp
#

it hits 100 30527 times, so it's not accidental

#

the minimum timing

#

that's about 1/3

#

curious

#

your optimized enum only hits the minimum 24386 times, which is lower

#

the median is the same at 200

white nexus
verbal escarp
#

so i'd say give numba the prize

white nexus
#

!pypi numba

fallen slateBOT
white nexus
#

what changes are made to use this?

verbal escarp
#
@njit
def testEInt1_jit():
    return bool(EInt.d & 7)
#

just @njit

#

i don't know how to incorporate it in your code effectively, but it's something to consider

white nexus
#

and since decorators only run once... if numba doesn't exist then I could replace that decorator with a lambda to return the function unmodified with virtually no slowdown

verbal escarp
#

you could

white nexus
#

the only delay would be when first importing the module

verbal escarp
#

and the first execution of the code, yes

white nexus
#

ye

verbal escarp
#

the stdev is extremely high with numba, but only the first couple times

white nexus
#

so as it is used more and more it'd be faster

verbal escarp
#

?

verbal escarp
#

i don't think timeit does account for these cases

white nexus
#

yeah, I'll have to look more into it

#

if numbs does provide a speed benefit, I'll maybe add it to the optional installs and add internal support

verbal escarp
#

feel free to play with it

verbal escarp
# white nexus how does this sound?

dunno, you need to consider ease of use and performance.. i really like Enum, but flags bit me in the butt before, so IntEnum is my go-to these days

verbal escarp
#

i even used numpy for bitmasks before, but yeah..

white nexus
#

the current implementation is here, prepare to weep

verbal escarp
#

what docstring format is that?

white nexus
#

it's used with an instance, and each of those methods is actually a property

#

numpy w/sphinx iirc

verbal escarp
#

never seen .. describe before

white nexus
#

sphinx directive

verbal escarp
#

(at least not consciously)

white nexus
#

although it may be a custom extension, not sure

verbal escarp
#

ahh.. proper docstrings, what luxury ๐Ÿ˜‰

white nexus
#

documenting stuff is such a pain

#

I definitely didn't deprecate and replace several attributes on an enum only to be told after it was merged that I didn't update the docs :^)

verbal escarp
#

of course not. who would do that..

#

just delete the docs ๐Ÿ˜‰

#
    @flag_value
    def manage_events(self) -> int:
        """:class:`bool`: Returns ``True`` if a user can manage guild events.
        .. versionadded:: 2.0
        """
        return 1 << 33
#

that's a little verbose imo

white nexus
#

I'm under the idea that method shouldn't exist

verbal escarp
#

also, versionadded? isn't that what a commit history is for? lemon_raised_eyebrow

white nexus
#

no, it's used in the docs

#

sphinx adds that when it creates the documentation automatically

verbal escarp
#

ah..

white nexus
#

well, it doesn't add that, but it handles it specially since it's a directive

white nexus
verbal escarp
#

oh well. it seems like a good job for newbies to take care of ^^

white nexus
#

hi blue, tldr trying to optimize enums, flags, and permissions :^)

elder blade
white nexus
#

have you implemented those on wumpy yet

elder blade
#

Bitfields?

#

Yeah

verbal escarp
#

did you implement them performance-consciously?

white nexus
#

^

#

I'm looking to redo disnake's a bit because it's kind of a mess

elder blade
# verbal escarp did you implement them performance-consciously?

Yeah, because I am planning to change it to Cython as soon as I can use it for other reasons as well (there's a few deal-breaking things that I need fixed before I can use it really). I don't see how I could make it more efficient really ๐Ÿค”
https://github.com/wumpyproject/wumpy/blob/main/library/wumpy-models/wumpy/models/flags.py#L11-L83

GitHub

Discord API Wrapper - Easy enough for Wumpus, and fast enough for Clyde! - wumpy/flags.py at main ยท wumpyproject/wumpy

#

It's the same thing as disnake's fields though

#

Albeit easier to read. Permissions are also more efficient though

verbal escarp
#

only recently i've did a little test to compare numba against cython

#

numba beat cython in my test performance-wise

elder blade
white nexus
#

I rly want to rework permissions

#

and flags

elder blade
#

Which is the minimum theoretically possible

verbal escarp
#

i really wasn't expecting numba to be faster than cython, tbh, it's pretty crazy.. but it's also very limited and fiddly

#

in my time trial earlier it couldn't work with and but only with &

#

so if you tried to optimize your code using and instead of & before and then get the idea "oh, i could use numba to further speed it up" .. ๐Ÿ˜

#

and timeit doesn't account for things speeding up over time.. it really should include some plotting

#

best matplotlib with xkcd style ^^

elder blade
#

Haha true

white nexus
#

oh heck I needed to sleep hours ago

#

curse cpython internals and speedups

verbal escarp
#

๐Ÿ˜ฆ

spice pecan
verbal escarp
#

it tries to overload and it seems

spice pecan
#

Ooh, interesting

empty kite
#

Is there documentation somewhere on who maintains which standard library modules? Or at least a list of unmaintained ones? (Exceeding PEP 594)

magic nova
lusty scroll
#

I want to share this beautiful code I found in parser.c in block_rule

#
   asdl_stmt_seq* a;
   Token * dedent_var;
   Token * indent_var;
   Token * newline_var;
   if ((newline_var = _PyPegen_expect_token(p, NEWLINE))
   && (indent_var = _PyPegen_expect_token(p, INDENT))
   && (a = statements_rule(p))  // statements
   && (dedent_var = _PyPegen_expect_token(p, DEDENT)))
   {
     _res = a;
     goto done;
   }```
#

that's 4 variable assignments in one if condition

#

in the spirit of the walrus operator

#

my attempt to pythonize it

with cleanup():
  if (
      newline_var := p.expect_token(Token.NEWLINE)
   and indent_var := p.expect_token(Token.INDENT)
   and a := statements_rule(p)
   and dedent_var := p.expect_token(Token.DEDENT)
  ):
    return a
raven ridge
# verbal escarp put it behind a lock if you must :p

You would need to put any user code that opens files or executes subprocesses behind the same lock. You can get away with that if you're writing an application, but certainly not if you're writing a library

raven ridge
spice pecan
#

EInt.d and 7 is really just bool(EInt.d) (or EInt.d != 0)

white nexus
#

@verbal escarp ha someone redid the enums (this was in progress for a while) and they're even faster now

elder blade
#

How did they get "faster"?

next lion
#

I know you are supposed to used literals for matching on dicts, but isnt it weird that you can't match against dict on structural pattern matching?

#

!e

class A:
    def __init__(self, x): self.x = x

match A(x="foo"):
    case A(x=m):
        print(m)

match dict(x="bar"):
    case dict(x=m):
        print(m)
fallen slateBOT
#

@next lion :white_check_mark: Your eval job has completed with return code 0.

foo
grave jolt
#

!e

match dict(x="bar"):
    case dict(keys=hmm):
        print(hmm)
fallen slateBOT
#

@grave jolt :white_check_mark: Your eval job has completed with return code 0.

<built-in method keys of dict object at 0x7f54acbd2740>
next lion
#

Oh right, it is bultin so it behaves like the other class patterns. That does indeed look weird

rose schooner
#

so i don't know but that example is small compared to something like a function definition

lusty scroll
rose schooner
#

that's why there are spaces in stuff like this ```c
result = _PyAST_x( x , y , z , 5 );

lusty scroll
fossil blade
#

what do you call this?

#

this = "some text"
print(f"this: {this:r}")

raven ridge
#

the :r part?

fossil blade
raven ridge
#

I think you meant !r which would be a "conversion flag"

fossil blade
#

also could spaces affect python space in any way?

#
def f():
  smth()
__
  smth()
#

the _ represents the spaces

raven ridge
#

spaces on a blank line are ignored.

#

something after a : in a format string, like :x, is a "format specifier".

fossil blade
#

Thank you;

elder blade
#

Hol' up I didn't know that the object reference count was a signed integer?

#

The Immortal Objects PEP seems to imply that since worst-case apparently the reference count can become negative?

prime estuary
#

It's signed so you can decref to negative numbers for dead objects.

#

Probably to make it easier to check for dead objects, and so you can't overflow back to some absurdly high count.

fallen slateBOT
#

Include/object.h lines 505 to 509

#ifdef Py_REF_DEBUG
        if (op->ob_refcnt < 0) {
            _Py_NegativeRefcount(filename, lineno, op);
        }
#endif```
rose schooner
verbal escarp
#

i always measure with a -

#

and when the going gets rough i take out my j

static bluff
#

Hey internals people!

#

I have an internal-to-python-adjacent question. Not on python per say, but I think this channel is the best place to ask it

#

I'm doing a report for school about bad syntax, and why the various excuses for bad syntax in various languages aren't good enough

#

I'm wondering if anyone can point me to any research regarding the effect that expressive, pleasant syntax has on workflow, and or, the well being of the people who use it

#

Or even about the study of language design from a human-centric perspective

paper echo
#

i think programming language ergonomics is a hotly debated topic and generally an "unsolved problem"

#

and it will vary a lot by person and by the problem at hand

#

some people think haskell is the most comfortable language, other people think python is, other people think kotlin is, other people think scheme is

#

syntax is also kind of intertwined with data models, type systems, and standard library availability

#

as well as language features like macros, compiled vs interpreted, statically vs dynamically typed, etc.

#

as well as considering that there are many "lineages" of programming and that sometimes things just come down to preference & what people are comfortable with

static bluff
#

Un a word โ€” exclusionary. Does not communicate meaning implicitly and, therefore, limits the knowledge only to those with the training to understand it.

We use semantic programming to communicate implicitly and as a result, well written python is intelligible to pretty much anyone even if they aren't programmers let along aren't python programmers

paper echo
#

consider that the Dvorak alternative layout to Qwerty was developed to be faster than Qwerty, but that most users are more efficient with Qwerty just because it's so much more familiar to them

paper echo
static bluff
#

Relative, but measurable. Its the study of graphic design

paper echo
#

f() is "clearly a procedure/function call" only if you already are familiar with C-style programming languages

static bluff
#

Something we're quite capable of

paper echo
#

i'm not sure where you're going with that

#

even in graphic design, a lot of things that people take for granted as absolutes are actually cultural and relative

#

e.g. associations between colors and various emotions

#

also the idea that programming should be "self-documenting" (perhaps what you mean by "semantic programming") is itself up for debate and probably has no conclusive resolution

static bluff
#

Wow, I just can't seem to get a win

paper echo
#

short of actual long-term user studies, i don't think there's much else that you can say on the topic of programming language ergonomics beyond expressing one's own preferences

#

sorry, i don't mean to be shooting you down

#

but i hope that you can see that this is a broad topic with lots of subtle angles

#

there is actually a lot to discuss here, but you might do better to focus on some small subset of it, and add focus to the research question

#

for example you can evaluate the ergonomic tradeoffs of certain python syntax features

static bluff
#

I'm basically being told, by many people not just you, that the mere suggestion of applying better design principals to technical languages so they're easier to learn and use is short sighted and foolish of me

paper echo
#

no, i am not saying that

#

i am saying that it's naive to expect that there are such guiding principles

#

basically it's an open area of study

#

it's not a solved problem

#

and generally we have a severe lack of actual user data

static bluff
#

In absolute terms maybe not โ€” but there are some things we know

#

And there are objectively bad synatxes

paper echo
#

sure, that's an interesting angle

static bluff
#

Or at least, relatively bad

paper echo
#

for example you can look at Malbolge as an extreme example

#

or silly esolangs like Brainfuck or Whitespace

#

but then look at APL or J or K, which are just as impenetrable to an untrained reader but are touted as serious programming languages, and some people find them to be tremendously high-productivity tools

static bluff
#

My biggest issue โ€” what prompted me to do this presentation in the first place โ€” is boolean algebra notation

paper echo
#

i suggest starting with something small then

#

start there and use it as a jumping off point to talk about some specific subset of syntax and language design

#

also consider that pure math, programming, and theoretical computer science all tend to use slightly incompatible notation at times

#

there might be something to be said there too. it's been discussed before, but i think constructively

static bluff
#

In the early days of the web

#

Websites were just thrown together

#

But we got good. We developed the concept of UX design

#

Templates, standards

#

And now, web design is all about maximum communication in fractions of seconds

raven ridge
static bluff
#

My point is that we can, and do, do the same for technical languages. And programming languages (for all their faults) are actually the tip of the spear on this front

paper echo
#

you do realize that frontend web development is still a very very very active field in terms of language/framework/api design, right?

static bluff
#

Math notations should take point

paper echo
#

with many strong opinions and hotly debated tools

static bluff
#

Oh of course, as it should be!

#

My point is that if such a field can be so active, with so many new and excellent ideas being forwarded all the time

#

That no notation should be considered safe from that

paper echo
#

should? or is?

#

there are lots of sound arguments against so much churn

#

is all the churn really necessary for iterating towards a better dev experience? does it actually lead to better software? maybe/probably, but the tradeoff is tremendous complexity in some cases, and a large burden on devs to update their skills frequently

static bluff
flat gazelle
#

it would be a struggle to justify a breaking change just because "it makes the syntax prettier" outside of an early alpha, maybe a beta at latest

static bluff
#

In thirty short years since the personal computing became affordable for everyone we've developed a system of writing and sharing code, learning code, and improving on each others code that rivals any other human system

paper echo
#

not a system, many systems. with various degrees of mutual intelligibility

static bluff
#

We already do but a lot of energy into "self-documenting" code, and alongside ubiquitiously available resources, a person can mainline knowledge directly into their front cortex faster than, I think, with any other technical skill

#

Its truly inspiring just how good at communication we have become โ€” given that computer code started originally as a way of talking to computers

#

Now we have computer code that is basically human language

static bluff
raven ridge
# static bluff Math notations should take point

Perhaps, but then you're losing the expressiveness you were praising above. You can't use = to mean assignment in a programming language, for instance, if you want symbols to mean what they mean in math.

static bluff
raven ridge
#

Because you're used to it and learned it.

#

Math has = and โ‰  for what Python has as == and !=

static bluff
#

Because == is a perfectly logical extension of = โ€” one which capitalizes on the well defined meaning that the = symbol already has

flat gazelle
#

if you want some interesting syntaxes to look at,
COBOL - designed to be read by non-programmers, looks just like english, is nigh-incomprehensible to anyone but people who spent a lifetime writing cobol.
APL - symbol soup, yet an extremely expressive language
sequent calculus - great way to write down type axioms, fairly incomprehensible
lisp/prolog - different priorities than most syntaxes, but still have their own merits.
SML - designed to be easily definable by grammar.

static bluff
#

Well, to be honest

#

I've already got more than enough arguments against my position. And I'm not really looking to do a survey of language syntaxes. I more wanted to make my case that there is no excuse for bad syntax

#

(In a modern technical notation)

#

What I'd really like is for someone to agree with me

#

So, resisting the urge to get salty and storm off like a pouting toddler

#

I'm just going to continue searching for some research that does support my position

#

Invariably, when you talk to a group of experts about making improvements to their craft so its easier and more accessible you are met with the arguments "its not so hard", "just put in the work and then you'll be fine", "its too hard to change", "I don't want to have to update my skills", and so on. I remain unconvinced

flat gazelle
#

well, there are a number of aspects to a syntax, I don't think you can really say "bad syntax" "good syntax" as a binary choice in isolation. Ease of parsing, ease of specification, ease of reading, ease of writing, familiarity to probable users, expressivity, ... are often contradictory goals, and everyones preferences differ.

#

AFAIK, the closest thing anyone got to a universal syntax was XML, whose only real merit was "easy to extend"

frank dagger
paper echo
#

note that cobol and sql are often considered failures from the perspective of "non-programmers should be able to use them"

static bluff
#

But, "good" and "bad" doesn't mean "worst" and "perfect"

#

One example is that, as a community, we have pretty much adopted a set of standard for any modern language

paper echo
static bluff
#

Just about any modern language is going to have functions, lambdas, classes, try-catch blocks, we've more or less agreed to do away with goto

paper echo
#

not to mention the fundamental relativistic problems of what constitutes "bad", which again i have pointed out is broader than you are giving credit for

#

i'm not trying to argue against your thesis, i am trying to understand what you even mean by it

frank dagger
#

like, when you tout python as an example of "good syntax", because it is easier to understand by non-experts, I would actually argue that isn't true. Python is so easy to read b/c it hides a lot of detail from you through language features empowered by it's virtual machine. One cannot read python code and actually understand what the computer is doing without a Huge amount of background knowledge. Whereas with C or Rust code, it'll be much harder to read, but you'll have a much clearer picture of what the computer is actually doing when that code is executed. So in what sense is "Python syntax" better than "C syntax" better than "Rust syntax"? I'd argue they are simply different

static bluff
#

These are things we take for granted today, but this hasn't always been the case. For a long time programming languages were the wild west, a badland of good ideas and bad competing against each other

paper echo
#

it also seems like you are conflating syntax with semantics

#

and there are lots of bad ideas that have stuck around, and lots of good ideas that have gone dormant or fallen out of fashion

#

some people fucking love pascal still!

static bluff
#

Never. Fucking. Mind.

frank dagger
static bluff
#

The brains have spoken. Fuck me for thinking outside the box.

paper echo
#

@static bluff i think you are really badly misinterpreting the feedback you got here. i suggest stepping away and re-reading all this later

#

@spice pecan Free Pascal is alive and well with the Lazarus IDE

#

i've even used apps written in Lazarus

frank dagger
#

yoooo sorry if I'm coming off as harsh. I think it's an interesting idea to research! I'm asking questions so you can help me define for myself your idea

spice pecan
static bluff
paper echo
#

the point is that this stuff is entirely largely unsolved and there are no right answers, and might never be

#

so your question (which is stated in terms of "good" and "bad") might not be answerable

flat gazelle
#

my favourite language syntactically in recent memory is probably raku, but writing a raku parser is a ton of work compared to sth like scheme where you can get it done in under a day. My point is that in the same way there are merits to still having a gnu-style pure HTML webpages, there are merits to syntaxes which are perhaps not "good design" by whatever arbitrary measure a given judge chooses.

frank dagger
#

@static bluff quite literally the thing I'm missing is - when discussing software languages - what does the term "good design" mean? I think that's honestly an open question

paper echo
#

does raku even have a spec?

flat gazelle
#

nope

#

exploring the merits of various syntaxes for various goals is an open and interesting problem

#

determining whether a syntax is good in general is reductive

#

XML vs JSON, haskell/SML/Rust function type syntax vs. C function type syntax, symbols vs words in PLs, ... are all interesting discussions to have. "Is rust syntax better than XSLT" is utter nonsense.

boreal umbra
#

raku doesn't have a spec? mfw

raven ridge
paper echo
paper echo
#

also consider that lisp-derived languages do not have ==

flat gazelle
#

prolog unifies the two concepts, and F# uses the same symbol for two different things thanks to ML-like syntax. I do like keeping = as equality and using sth like := or <= <- for assignment.

raven ridge
feral cedar
#

not to mention functional langs

paper echo
#

it's not even unambiguous what a "class" is

#

it means different things to different people and in different languages

feral cedar
#

right, rust doesn't have "classes", but their structs have a lot of things python class does, except inheritance and a few other things

flat gazelle
#

I would disagree, a python class has a lot more than a rust struct, even disregarding inheritance. The descriptor protocol, a metaclass, methods

feral cedar
#

fair enough, it does have methods though

raven ridge
#

Without polymorphic access and inheritance, it's not what people generally think of as a class. Though it accomplishes some of the same goals (encapsulation, information hiding, etc)

feral cedar
#

what's polymorphic access?

raven ridge
#

The ability to override methods in a subclass, I suppose

feral cedar
#

oh, well that's out since there's no subclassing. rust does have trait objects though, which let you dispatch on the concrete type of something that implements a trait

raven ridge
#

Fair enough, that's polymorphic as well (code can be written to accept various concrete types)

grave jolt
#

tbh I could totally live without inheritance (implementation inheritance)

median palm
#

Isn't composition usually preferred over inheritance

boreal umbra
median palm
#

Fair enough

boreal umbra
#

polymorphic access
and here I was thinking I knew all the OOP esotericism. but the rabbit hole just keeps going.

raven ridge
#

That's not to say both aren't valuable tools to have in your toolbox, but often what inheritance saves you in lines of code/boilerplate, it costs you in coupling.

median palm
#

I see

white nexus
#

composition?

next lion
# white nexus composition?

inheritance

class Car(ABC): ...

class CarGas(Car): ...

class CarEletic(Car): ...

composition ish

class Engine(ABC): ...

class GasEngine(Engine):

class EletricEngine(Engine):

class Car:
    engine: Engine
#

You are just moving the responsibility up the chain, that way you can "compose" more complex objects without them being reliant on the specifics of implementation

spice pecan
#

The composition part is Car.engine, Engine and its subclasses are still inheritance (just a note)

#

A good way to think about composition vs inheritance is whether or not your entity is something or has something. An example I saw on SO used soccer teams to illustrate this - it has a list of players, among other things, but it isn't just a list of players

grave jolt
#

note of caution: if in the real world A is-a B, it doesn't mean that A and B should be related in a hierarchy somehow

next lion
boreal umbra
#

Ah yes. Another example of inheritance that does nothing to demonstrate if there's any practical application.

#

The one in my undergrad was literally FlightlessBird

#

You can't have a fly method in the Bird class

deft pagoda
#

how about rewrite some gui library with only composition

boreal umbra
#

Would that be bad?

deft pagoda
#

yes

boreal umbra
#

It seems that one of the best use cases of inheritance is for... I don't know what to call it. When the base class isn't really a "thing" but you write a few methods in the subclass and it does the rest.

#

I'm struggling to articulate how this is separate from inheritance in general.

peak spoke
#

an abc?

boreal umbra
#

That's part of it, but I'm talking about a larger design pattern. I think Django uses it?

#

I saw some submissions in an old Django code jam that barely involved any new logic. It was just a few modules with subclasses of Django types and boom, website. (Though not a very interesting one.)

deft pagoda
#

i imagine trying to recreate behaviors with composition is way more work than it's worth

paper echo
#

"abstract base class" is a specific kind thereof

#

although in practice a lot of "base classes" are not meant to be instantiated, so are conceptually abstract even if they aren't actual python ABCs

naive saddle
#

are ABCs effectively protocols? honestly I've never really learned what they are

#

Ah right ABCs do runtime checks