#esoteric-python

1 messages · Page 128 of 1

urban cradle
#

@rich hound

rich hound
#

o.o

grave rover
#
", ".join((lambda n:(lambda cb:setattr(cb,"__code__",cb.__code__.replace(co_code='d\x01}}\x00|\x00d\x02k\x05r\x0e|\x00d\x02\x18\x00\x04\x00}}\x00d\x03\x13\x00q\x02g{0}S\x00'.format(chr(n)).encode("latin1"),co_consts=(None,n,1,2),co_varnames=("x",),co_nlocals=1))or map(str,cb()[::-1]))(lambda:None))(10))
rich hound
#

oh.

#

oh my god

#

does this work

grave rover
#

tias

rich hound
#

show

grave rover
#

!e ```py
", ".join((lambda n:(lambda cb:setattr(cb,"code",cb.code.replace(co_code='d\x01}}\x00|\x00d\x02k\x05r\x0e|\x00d\x02\x18\x00\x04\x00}}\x00d\x03\x13\x00q\x02g{0}S\x00'.format(chr(n)).encode("latin1"),co_consts=(None,n,1,2),co_varnames=("x",),co_nlocals=1))or map(str,cb()[::-1]))(lambda:None))(10))

night quarryBOT
#

@grave rover :warning: Your eval job timed out or ran out of memory.

[No output]
rich hound
#

o.o

grave rover
#

wait what

#

it works for me

rich hound
#

kek

grave rover
#

!e import("sys").version_info

night quarryBOT
#

@grave rover :warning: Your eval job has completed with return code 0.

[No output]
rich hound
#

hm

grave rover
#

!e print(import("sys").version_info)

night quarryBOT
#

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

sys.version_info(major=3, minor=9, micro=6, releaselevel='final', serial=0)
grave rover
#

hmm

rich hound
#

hmmm

grave rover
#
Python 3.10.0rc2+ (heads/3.10:c523022, Sep 26 2021, 15:34:18) [GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> ", ".join((lambda n:(lambda cb:setattr(cb,"__code__",cb.__code__.replace(co_code='d\x01}}\x00|\x00d\x02k\x05r\x0e|\x00d\x02\x18\x00\x04\x00}}\x00d\x03\x13\x00q\x02g{0}S\x00'.format(chr(n)).encode("latin1"),co_consts=(None,n,1,2),co_varnames=("x",),co_nlocals=1))or map(str,cb()[::-1]))(lambda:None))(10))
'0, 1, 4, 9, 16, 25, 36, 49, 64, 81'
#

works on py10

rich hound
#

hmmmm

grave rover
#

as for the implementation: py startlbl = Label() endlbl = Label() ops = [ # x = n LOAD_CONST(n), STORE_FAST("x"), startlbl, # while x >= 0: LOAD_FAST("x"), LOAD_CONST(1), COMPARE_OP(">="), POP_JUMP_IF_FALSE(endlbl), # x = x - 1 LOAD_FAST("x"), LOAD_CONST(1), BINARY_SUBTRACT(), DUP_TOP(), STORE_FAST("x"), # push x**2 LOAD_CONST(2), BINARY_POWER(), JUMP_ABSOLUTE(startlbl), endlbl, # [...] BUILD_LIST(n), RETURN_VALUE() ]

rich hound
#

]e

", ".join((lambda n:(lambda cb:setattr(cb,"__code__",cb.__code__.replace(co_code='d\x01}}\x00|\x00d\x02k\x05r\x0e|\x00d\x02\x18\x00\x04\x00}}\x00d\x03\x13\x00q\x02g{0}S\x00'.format(chr(n)).encode("latin1"),co_consts=(None,n,1,2),co_varnames=("x",),co_nlocals=1))or map(str,cb()[::-1]))(lambda:None))(10)) 
turbid dewBOT
rich hound
#

o yeah

signal violet
#

Sorry if I typed on the wrong channel. How do I detect that a function or method returns a value or just runs a code?

grave rover
signal violet
#

i have a function object

grave rover
#
# pip install git+https://github.com/martmists-gh/pyasm
from asm import Deserializer, RETURN_VALUE, LOAD_CONST

def returns_value(func):
    d = Deserializer(func.__code__)
    ops = d.deserialize()
    returns = [op for op in ops if isinstance(op, RETURN_VALUE)]
    for i, op in enumerate(ops):
        if op in returns and (not isinstance(ops[i-1], LOAD_CONST) or ops[i-1].arg != None):
            # None is returned by default, but that's not the case here -> returning something else!
            return True
    return False
``` I think this *should* work, but it's untested code
#

it treats no return, return and return None as not returning a value

signal violet
#

thanks you!

signal violet
# grave rover ```py # pip install git+https://github.com/martmists-gh/pyasm from asm import De...

hello, this code gets an error

Traceback (most recent call last):
  File "/home/thekralgame/PycharmProjects/test/node_editor_test.py", line 2, in <module>
    from asm import Deserializer, RETURN_VALUE, LOAD_CONST
  File "/home/thekralgame/PycharmProjects/test/venv/lib/python3.8/site-packages/asm/__init__.py", line 2, in <module>
    from asm.serializer import Serializer, Deserializer, Label
  File "/home/thekralgame/PycharmProjects/test/venv/lib/python3.8/site-packages/asm/serializer.py", line 7, in <module>
    from asm.stack_check import StackChecker
  File "/home/thekralgame/PycharmProjects/test/venv/lib/python3.8/site-packages/asm/stack_check.py", line 9, in <module>
    opmap["JUMP_IF_NOT_EXC_MATCH"],
KeyError: 'JUMP_IF_NOT_EXC_MATCH'
#

Code:

from asm import Deserializer, RETURN_VALUE, LOAD_CONST

def returns_value(func):
    d = Deserializer(func.__code__)
    ops = d.deserialize()
    returns = [op for op in ops if isinstance(op, RETURN_VALUE)]
    for i, op in enumerate(ops):
        if op in returns and (not isinstance(ops[i-1], LOAD_CONST) or ops[i-1].arg != None):
            # None is returned by default, but that's not the case here -> returning something else!
            return True
    return False

def foo():
    print("Foo")

print(returns_value(foo))
golden finch
#

Hey, I reckon ast can be used to (ab)use stuff for this channel.

signal violet
#

okay

#

i tried in python 3.9

#
Traceback (most recent call last):
  File "/home/thekralgame/PycharmProjects/test/test.py", line 1, in <module>
    from asm import Deserializer, RETURN_VALUE, LOAD_CONST
  File "/home/thekralgame/PycharmProjects/test/venv/lib/python3.9/site-packages/asm/__init__.py", line 4, in <module>
    __all__ = tuple(dis.opmap.keys()) + (
NameError: name 'dis' is not defined
#

okay i fixed

#

you need to write "import dis" to asm/__init__.py

night quarryBOT
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

Hello, World!
onyx jacinth
grave rover
#

@signal violet reinstall with pip and it should work

next flame
#
a=[]
for _ in[1]*int(input()):_=input().split();getattr(a,_[0],lambda:print(a))(*map(int,_[1:]))

96 bytes @onyx jacinth

grave rover
#

Best I could do was```py
l=[]
for _ in[0]*int(input()):(lambda x,*y:getattr(l,x,lambda:print(l))(*map(int,y))))(*input.split())

grave rover
#

oh wait but there are none ignore me

next flame
#
a=[]
for _ in[1]*int(input()):x,*y=input().split();getattr(a,x,lambda:print(a))(*map(int,y))

91 bytes, thanks for the destructuring trick

grave rover
#

np

next flame
grave rover
#

ah

rugged sparrow
#
for a in[[]]*int(input()):f,*r=input().split();getattr(a,f,lambda:print(a))(*map(int,r))
``` 88 bytes
knotty delta
#

whats the challenge

rugged sparrow
onyx jacinth
#

ohh these are some great solution much better than mine LOL

rugged sparrow
#
for(a)in[[]]*int(input()):f,*r=input().split();vars(list).get(f,print)(a,*map(int,r))
``` 85 bytes
onyx jacinth
rugged sparrow
#

I just get the length of the string

#

sys.getsizeof is for getting internal object sizes

rugged sparrow
#

Typical golfing rules measure the textual representation of the code in bytes not the compiled code

grave rover
golden finch
#

Hey

#

How do I use ast?

#

(to (ab)use stuff)?

next flame
rugged sparrow
#

Where did you have to add the code?

rugged sparrow
#

Imma try and write a runtime patch to enable that

rugged sparrow
#

@sick hound where is that token number found?

golden finch
#

sith magic

rapid sparrow
#

time for a pull request

#

it'd be fun to see what the reason for rejecting it is, at least

#

is ! like not or ~ ?

earnest wing
rapid sparrow
#

could be that

void terrace
#

how do i code esoteric python? is there a guide on how to write it?

old hawk
#

By practicing python for a while

rugged sparrow
#
>>> from decimal import Decimal
>>> from asm_hook import *
>>> 
>>> class d(c_double):pass # hack to delay converters
... 
>>> @hook(pythonapi.PyFloat_FromDouble, restype=py_object, argtypes=[d])
... def pyfloat_fromdouble(doub):
...     return Decimal(doub.value)
... 
>>> @hook(pythonapi.PyFloat_FromString, restype=py_object, argtypes=[py_object])
... def pyfloat_fromstring(string):
...     return Decimal(string)
... 
>>> 1.0
Decimal('1')
>>> 1.5
Decimal('1.5')
>>> 2.5
Decimal('2.5')
>>> ``` was able to get float literals to be `Decimal`s automatically in the interpreter
rapid sparrow
#

is there any package that doesn't include workarounds for numpy (this is in the dill Pickler class)

golden finch
sick hound
#

should I dm him for the guide?

rugged sparrow
#

its on their github

sick hound
#

DAMN this is good

#

thanks

radiant anchor
#

random thought experiment, does anyone know how to create a NaN float value in python without a) importing anything (including cheaty ways to import things), or b) without just doing float("nan")

#

like, are there any builtin arithmetic operations that can result in nan?

#

(also doing float("inf") to do math with is not allowed)

rugged sparrow
#

!e print(1e999/1e999)

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

nan
radiant anchor
#

noice

#

that was quick heh

#

TIL 1e999 is a quick way to get inf

#

1e999*0 also works

royal sun
snow beacon
golden finch
#

I am currently working out how to use the tokenize module to change python's syntax

#

Has anyone done this before?

snow beacon
#

From memory people tried to fit Haskell syntax into Python function bodies at some point.

golden finch
#

Do you have source?

rapid sparrow
#

is it linking to a different repo? i can't tell on here

#

oh its linking to wiki

rapid sparrow
snow beacon
golden finch
#

That's impressive, no source though

terse mortar
#

This is really not that hard

#

Can't do it rn as I'm about to be in class but I might do it later

earnest wing
#

x=object()
print(((x==x)<<((x==x)<<(x==x)+(x==x)))-(x==x))

leaden vault
next flame
#

!e ```py
print(ord(""))
import sys;print(sys.version_info.minor+sys.version_info.micro)

night quarryBOT
#

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

001 | 15
002 | 15
sick hound
#
decrypt__it = 'but you are total trashes'
____ = decrypt__it.split(' ')

getattr(__import__(True.__class__.__name__[1] + [].__class__.__name__[2]), 'write')(1, eval(eval('____[0][0] + ____[1][0] + ____[3][0] + ____[4][5:]'))(''.join(chr(i) for i in [int((4-4+2**4+4-2//5-4/4%2-4/4//2%5-1**4+4/2-4%4*2+5+4//4*2%4//4-2%5+1+3) - -45.0), int((1+1*5-1*1//5-3-1**1-5-1*1/5//3%2+1-1/5%1+1*5//3**1**1*5%1+1+5*3//2+4) - -91.2), int((3%3/1-3/3%1-2+3//3/1%3//3//1-2-5**3%3+1-3/3/1%2+3+3%1+3+3%1%2//5-4) - -112.0), int((3%3/1-3/3%1-2+3//3/1%3//3//1-2-5**3%3+1-3/3/1%2+3+3%1+3+3%1%2//5-4) - -112.0), int((4//4**2%4%4+2**5-4%4**2+4*4//2-5/3**4-4-2-4-4**2/5%4+4/2**4*4-2/5+3//1) - -84.66172839506173), int((5%5%3**5**5//3%1%5-5%3+5-5-3-1/2//5//5%3%5-5+3//1%5%5+3**5/5//3%1-2//4) - -39.0), int((2-2+4+2+2/4//3*2//2%4+2//2**4%3**1-2%2%4-2+2//4//3+2-2**4/2*2**4+3//1+5) - -201.0), int((4//4**2%4%4+2**5-4%4**2+4*4//2-5/3**4-4-2-4-4**2/5%4+4/2**4*4-2/5+3//1) - -84.66172839506173), int((3%3%2*3+3%2-5%3-3/2//3%3/2/5**4*3*3%2//3*3-2+5%3-3/2**3+3-2/5/4%1) - -112.475), int((3%3/1-3/3%1-2+3//3/1%3//3//1-2-5**3%3+1-3/3/1%2+3+3%1+3+3%1%2//5-4) - -112.0), int((1-1%5**1//1%5*3/1*1-5%1/1**5+3+2**1-1//5%1-1+5//3*1/1**5-1**1%5*3**2+4) - -102.0), int((1**1/3%1/1//3-4/1-1+3*1**1%3//4/5+1+1*3**1//1**3/4*1**1*3//1**1*3%4*5**2) - 13.0)]), 'ascii'))```
#

P.S. the string was only putted there to roast my school teacher. Nothing to do with you guys Kelly_shrug_FB

wild monolith
#

yo

rapid sparrow
#

yo

snow beacon
golden finch
#

!e

print(len('               '))
night quarryBOT
#

@golden finch :white_check_mark: Your eval job has completed with return code 0.

15
next flame
#

unicode characters
so no strings at all?

#

@sick hound

#

or did you mean

#

only printable ascii (32 to 126) allowed

next flame
next flame
#

just replace the spaces with literally any other character

#

!e print(["","","","","","","","","","","","","","",""].count(""))

night quarryBOT
#

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

15
golden finch
#

this is the loophole channel lmao

snow beacon
#

@sick hound This doesn't actually do what you asked, but it's related.

#

(It has len in it a lot.)

golden finch
#

that's... art

snow beacon
#

It took a lot of work from the people in this channel.

#

!e Anyway...

print(((lambda z: lambda *x, **y: z)(None)).__code__.co_flags & (lambda *x, **y: x).__code__.co_flags)
night quarryBOT
#

@snow beacon :white_check_mark: Your eval job has completed with return code 0.

15
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

001 | 15
002 | 53
snow beacon
#

That looks awfully complicated. I think I prefer my method.

#

Isn't the second one equivalent to is?

#

is does not do ==, that's what == is for.

#

I'm not sure I follow.

next flame
#

is literally does pointer comparision

#

every object in python is a pyobject*

#

and id just returns the pointer as an int

#

thus is and ids are exactly the same (at least in cpython)

#

@sick hound

#
class A:
  def __hash__(self):
    return random.randint(1,6)
snow beacon
#

Implementing a hashtable, perhaps.

next flame
#

but thats just comparing is to == on ints

#

not is to ids

snow beacon
#

My hesitance was that ids could be id(x) is id(y), in which case it would not be equivalent to is.

#

That looks like is then.

#

It's good. After all, doesn't the Zen say something about how many ways to do something there should be?

next flame
#

!e class A: def init(self, x): self.thing = x

night quarryBOT
#

@next flame :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     class A: def __init__(self, x): self.thing = x
003 |              ^
004 | SyntaxError: invalid syntax
next flame
#

hm

knotty delta
#

man not obsessed with original python's esotericness, so he started editing the source

crimson panther
#

can i get hepl ?

#

anyone ?

#

help ?

terse mortar
crimson panther
crimson panther
terse mortar
#

And you got to this channel?

golden finch
terse mortar
golden finch
#

we'd need one who is already sensitive to the darkness

next flame
#

grab an asm programmer and throw them straight into esoteric

sick hound
#

!e

>>> print({(1<<5)+(1<<4)+(1<<1):'Hello, World!'}[((-1[=-2)*[50])[0]])
Hello, World!
night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     >>> print({(1<<5)+(1<<4)+(1<<1):'Hello, World!'}[((-1[=-2)*[50])[0]])
003 |     ^
004 | SyntaxError: invalid syntax
sick hound
#

Oh ur code didn’t work

golden finch
#

so, so many things are wrong with that

prisma coral
rapid sparrow
cerulean rivet
#

why i get syntaxerror in slice using star expressions like that?

>>> tuple[*[str]*12]
  File "<stdin>", line 1
    tuple[*[str]*12]
                   ^
SyntaxError: invalid syntax```and in functions this work????
```py
>>> def a(x, b, c):
...     ...
...
>>> a(*[1]*3)```
next flame
astral rover
#

this is probably fixed on 3.11 with pep 646(??)

proper vault
#

@cerulean rivetin the meantime, tuple[(*[str]*12,)] does the same thing. On that note, what hellish thing are you working that a 12 tuple of strings is the correct data structure

cerulean rivet
proper vault
#

essentially, a[1, 2, 3] just passes the tuple (1, 2, 3) to __getitem__, which is the same as what happens when you pass a tuple directly

#
In [2]: dis.dis('a[b, c]')
  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 LOAD_NAME                2 (c)
              6 BUILD_TUPLE              2
              8 BINARY_SUBSCR
             10 RETURN_VALUE

In [3]: dis.dis('a[(b, c)]')
  1           0 LOAD_NAME                0 (a)
              2 LOAD_NAME                1 (b)
              4 LOAD_NAME                2 (c)
              6 BUILD_TUPLE              2
              8 BINARY_SUBSCR
             10 RETURN_VALUE
```as you can see in the bytecode
prisma coral
#

Is it possible to redefine operators / define new operators without rebuilding the interpreter?

#

Like with ctypes or an interpreter hook or something

golden finch
#

redefine, yes. define new - for some very limited subsets

#

@prisma coral
redefinition is just dunder modification
new operators are a much nastier kettle of fish, and usually need either direct bytecode modification or messing with the AST/tokenizer/lexer

golden finch
#

I'd be interested to see a comparison of the baseline rate of mental disorders in this channel compared to the rest of the server

prisma coral
golden finch
#

example of the dunder redefinition:

std,cout=type('',(),{'__getitem__':lambda self,name:type('',(),{'__lshift__':lambda self,data:(__import__('sys').stdout.write(str(data)),self)[1],'__repr__':lambda self:''})()})(),0

#include <iostream>

a=2
b=502
std[::cout] << a << b;
#

all objects?

#

!pypi fishhook

night quarryBOT
golden finch
#

my approach would be to use a variation on sys.settrace to repeatedly perform that on all objects using fishhook

prisma coral
#

Ok thanks

#

I’ll look into it

golden finch
#

cool

snow beacon
#

type(None).__bool__.__doc__ is "self != 0" for some reason.

#

It's not often that you find an instance of NoneType that's equal to zero, I guess.

golden finch
#
>>> type(None).__bool__.__doc_
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    type(None).__bool__.__doc_
AttributeError: 'wrapper_descriptor' object has no attribute '__doc_'
#

not for me

snow beacon
#

Is it an IPython thing then?

golden finch
#

!e

print(type(None).__bool__.__doc_)
night quarryBOT
#

@golden finch :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | AttributeError: 'wrapper_descriptor' object has no attribute '__doc_'
golden finch
#
>>> type(None).__bool__(None)
False
snow beacon
#

It works on my machine.

#

Python 3.7 and Python 3.9, the latter with and without IPython. I wonder why that is.

rugged sparrow
#

!e print(type(None).bool.doc)

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

self != 0
rugged sparrow
#

@golden finch you had a typo

golden finch
#

right

#

can confirm it's that

#
>>> type(None).__bool__.__doc__
'self != 0'
#

that's unusual

#

maybe type(None).__bool__=lambda self:self!=0

#

it appears to be the same for all types

night quarryBOT
#

Objects/typeobject.c lines 8020 to 8021

UNSLOT("__bool__", nb_bool, slot_nb_bool, wrap_inquirypred,
       "self != 0"),```
golden finch
#

thanks

#

interesting

#

I wonder why that is

#
equalzero=lambda self:eval(type(None).__bool__.__doc__)
potent comet
#

Originally, the bool method in Py2 was __nonzero__, and in both versions if you don't define the magic method Python will try checking len() == 0. So it might be a remmnant of that.

golden finch
#

That's interesting.

golden finch
gilded orchid
#

I'm trying to golf a raytracer I wrote, I've got a 3d vector represented as [x,y,z], what's the shortest way to normalise it? the current best I've got is this (where r is the vector)

map(lambda x:x/sum(map(lambda n:n*n,r))**.5,r)
earnest wing
#

Honestly with three elements it might be faster to unroll

#

or rather shorter

gilded orchid
#

oh yeah sum(n*n for n in a) is shorter than sum(map(lambda n:n*n,r))

earnest wing
#
s=sum(x**2for x in r)**-.5
map(s.__mul__,r)

the last bit is longer than ideal but I like it

#

I'm personally a big fan of map(dunder, ...)

gilded orchid
#
[m/sum(n*n for n in r)**.5for m in r]

I think this is the shortest possible

#

I might use that map dunder thing somewhere else though

rugged sparrow
#

@grave rover im gonna use your pyasm to implement tail call recursion optimization

grave rover
#

Oh no

#

Good luck :)

#

Feel free to report any issues you find

#

(note: not on pypi yet)

rugged sparrow
#

ah ill need to clone the github then

grave rover
#

Pypi package seems to be a squat but made an ownership request already

opaque fossil
#
    out = Value.replace('€', '')
    if 'M' in out:
        out = float(out.replace('M', ''))*1000000
    elif 'K' in Value:
        out = float(out.replace('K', ''))*1000
    return float(out)``` How can I do its reversion?
golden finch
#

we need a special copypasta for this channel about why you don't get help here

golden finch
thorny tapir
#
print("hello world")
#

make ugly

rapid sparrow
# thorny tapir make ugly

!e

with open(1, "w") as f:
    import operator
    operator.methodcaller("write", "Hello world").__call__(f)
night quarryBOT
#

@rapid sparrow :white_check_mark: Your eval job has completed with return code 0.

Hello world
rapid sparrow
thorny tapir
#

hehe

#

esoteric is a scary word

#

so that is a good point

rapid sparrow
#

edit -- as a bonus, if you run it interactively, it makes the interpreter useless

#

i had to use kill -9 to close it .

golden finch
thorny tapir
#

im crying rrn

rapid sparrow
#

oh the jaws of defeat

rapid sparrow
golden finch
#

it's so much black magic and I have no idea what any of it does

tepid otter
#

@thorny tapir i can make it uglier i think

thorny tapir
#

gl

#

what is bytecode

tepid otter
#

!e

exec(bytes('牰湩⡴栢汥潬眠牯摬⤢', 'u16')[2:])

@thorny tapir

night quarryBOT
#

@tepid otter :white_check_mark: Your eval job has completed with return code 0.

hello world
tepid otter
#

my superior hello world code

tepid otter
thorny tapir
#

!bytes

#

o ok

tepid otter
#

its what computers interpret into binary basically

#

well a few levels above that

#

you can see the translated bytecode of a function through some roundabout methods

#

!e

print((lambda: 0).__code__.co_code.decode('u8'))
night quarryBOT
#

@tepid otter :white_check_mark: Your eval job has completed with return code 0.

dS�
tepid otter
#

@thorny tapir this is bytecode

#

d i believe is return

#

thats all i really remember

#

that roughly translated to "return 0" afaik

thorny tapir
#

o ok

snow beacon
#

!e ```py
import('dis').dis(lambda: 0)

night quarryBOT
#

@snow beacon :white_check_mark: Your eval job has completed with return code 0.

001 |   1           0 LOAD_CONST               1 (0)
002 |               2 RETURN_VALUE
snow beacon
#

It looks like the d is the LOAD_CONST, and the S is the RETURN_VALUE.

tepid otter
#

!e

import dis

def f(): ...

dis.dis(f)
night quarryBOT
#

@tepid otter :white_check_mark: Your eval job has completed with return code 0.

001 |   3           0 LOAD_CONST               0 (None)
002 |               2 RETURN_VALUE
snow beacon
#

Same bytecode, different constant.

tepid otter
#

!e

import dis

def f(): ...
print(f.__code__.co_code.decode('u8'))
night quarryBOT
#

@tepid otter :white_check_mark: Your eval job has completed with return code 0.

d�S�
tepid otter
#

yeah your right

#

that makes  0 then

#

oh my god i just had the worst idea

snow beacon
#

I don't think it usually encodes the constant itself in the bytecode. The number is usually an index in a tuple of constants that gets packaged into the function.

#

co_consts I believe.

golden finch
#

the python compiler does many strange things in making bytecode

rapid sparrow
snow beacon
#

Not to my knowledge.

#

There's possibly some op that can construct values. You'd have to ask Chilaxan.

rapid sparrow
# snow beacon There's possibly some op that can construct values. You'd have to ask Chilaxan.

!e

from types import CodeType, FunctionType
from dis import dis
func =  FunctionType(CodeType(*dict(co_argcount=1, co_posonlyargcount=0, co_kwonlyargcount=0, co_nlocals=1, co_stacksize=2, co_flags=67, co_code=b't\x00|\x00\x83\x01S\x00', co_consts=(None,), co_names=('eval',), co_varnames=('stmts',), co_filename='<stdin>', co_name='get_constant', co_firstlineno=1, co_lnotab=b'').values()), {'eval': eval})
print(func)
print(func.__code__)
print(dis(func))
arg = "('abc', 'def', 1, 2)"
print("construct value from %s" % repr(arg))
val = func(arg)
print("func(%s) -> %s" % (repr(arg), repr(val)))
print(val)
night quarryBOT
#

@rapid sparrow :white_check_mark: Your eval job has completed with return code 0.

001 | <function get_constant at 0x7f1b801e8a60>
002 | <code object get_constant at 0x7f1b8018f030, file "<stdin>", line 1>
003 |   1           0 LOAD_GLOBAL              0 (eval)
004 |               2 LOAD_FAST                0 (stmts)
005 |               4 CALL_FUNCTION            1
006 |               6 RETURN_VALUE
007 | None
008 | construct value from "('abc', 'def', 1, 2)"
009 | func("('abc', 'def', 1, 2)") -> ('abc', 'def', 1, 2)
010 | ('abc', 'def', 1, 2)
rapid sparrow
#

@rugged sparrow 😅 👍

#

"magic constant-less constant generator"

snow beacon
#

That's nice, although I was meaning something that doesn't need to read from args or constants.

golden finch
#

can't you just fiddle with the stack a bit?

#

loading onto stack is tough but possible

golden finch
#

load a value onto the stack and edit it from there

#

the question is how to get it

snow beacon
#

Making a new version of the programming language isn't really in the spirit of solving a problem within the language under a constraint.

rapid sparrow
#

but thinking outside the box might be

#

ctypes

#

jk

#
frame->localsplus + frame->stacktop
rapid sparrow
#

hahaha, nice

cerulean rivet
proper vault
#

oh yeah, that is nicer

tender steeple
#

wdym by esoteric python?

prisma coral
tender steeple
#

been working on my code since you helped me

#

wanna see?

tacit cobalt
#

!e ```py
(
lambda _, , , ____, , , ______, ________: getattr(
import(True.class.name[
] + [].class.name[
]),
().class.eq.class.name[:
]
+ ().iter().class.name[
:][
:
__],
)(
_,
(lambda _, __, ___: (, __, ___))(
lambda _, __, : bytes([ % __]) + (, __, ___ // __)
if ___
else (lambda: _).code.co_lnotab,
_ << ___,
(((
<< __) + ) << (( << ____) - ))
+ (((((
<< ) - ) << ) + ) << (( << ) + ( << )))
+ (((
<< _) - ) << ((((( << ) + )) << ) + ( << )))
+ (((
<< ) + ) << (( << ) + ))
+ (((
<< ) - ) << ((
<< )))
+ (((
<< ) - ) << (((( << ) + ) << ) - ))
- (
<< ((((
<< ) - ) << ) + ))
+ (
<< (((((
<< ___) + _)) << _)))
- ((((((
<< ) + )) << ) + ) << (((( << ) + ) << )))
+ (((
<< ) - ) << ((((( << ) + )) << )))
+ (((
<< ) + ) << ((
<< )))
+ (
<< _____)
+ (
<< ___),
),
)
)(
*(lambda _, __, ___: (, __, ___))(
(
lambda _, , : [([(lambda: _).code.co_nlocals])]
+ (, __, ___[(lambda _: _).code.co_nlocals :])
if ___
else []
),
lambda _: _.code.co_argcount,
(
lambda _: _,
lambda _, __: _,
lambda _, __, ___: _,
lambda _, __, ___, ____: _,
lambda _, __, ___, ____, _____: _,
lambda _, __, ___, ____, _____, ______: _,
lambda _, __, ___, ____, _____, ______, _______: _,
lambda _, __, ___, ____, _____, ______, _______, ________: _,
),
)
)

night quarryBOT
#

@tacit cobalt :white_check_mark: Your eval job has completed with return code 0.

Hello world!
tacit cobalt
#

Python 3 version

prisma coral
tender steeple
#

i came up with 2 versions of the spanish code

#

okkk

#

np

#

uhhh

#

which channel lol

#

python general

prisma coral
#

Yeah sure

rapid sparrow
#

I got a fun one too:
`XXX readobject called with exception set
Fatal Python error: pycore_interp_init: failed to initialize importlib
Python runtime state: preinitialized
IndexError: list index out of range

Current thread 0x0000007ff7a7dde0 (most recent call first):
<no Python frame>
`

#

looks like sys is imported before builtins, funnily enough

thorny tapir
rapid sparrow
#
def <lambda>(1, 2, 3, 4, 5, 6, 7, 8):
  return getattr(__import__((True).__class__.__name__[1] + [].__class__.__name__[2]), ().__class__.__eq__.__class__.__name__[:2] + ().__iter__().__class__.__name__[1:][5:8])(1, (lambda 1, 2, 3: 1(1, 2, 3))(lambda 1, 2, 3: bytes([3 % 2]) + 1(1, 2, 3//2) if 3 else (lambda : 1).__code__.co_lnotab, 1 << 8, ((5 << 4) + 1 << (3 << 5) - 3) + (((3 << 2) - 1 << 3) + 1 << (5 << 4) + (1 << 1)) + ((7 << 2) - 1 << ((1 << 3) + 1 << 3) + (1 << 1)) + ((7 << 3) + 1 << (1 << 6) + 1) + ((7 << 4) - 1 << (7 << 3)) + ((1 << 4) - 1 << ((3 << 2) + 1 << 2) - 1) - (7 << ((3 << 2) - 1 << 2) + 1) + (7 << ((1 << 3) + 1 << 2)) - (((1 << 3) + 1 << 2) + 1 << ((3 << 2) + 1 << 1)) + ((7 << 2) - 1 << ((1 << 3) + 1 << 1)) + ((3 << 3) + 1 << (5 << 1)) + (5 << 6) + (1 << 3)))
thorny tapir
#

:blinking:

#

ok

#

what is <<

rapid sparrow
#

some math required .. I guess that's bit shifting

thorny tapir
#

oh okay

rapid sparrow
#

this part is os.write:

__import__((True).__class__.__name__[1] + [].__class__.__name__[2]), ().__class__.__eq__.__class__.__name__[:2] + ().__iter__().__class__.__name__[1:][5:8]
thorny tapir
#

k

rapid sparrow
#

reminds me of obfuscated javascript

earnest wing
#

it constructs a byte string using arithmetic & code objects shenanigans, and writes it to stdout

rapid sparrow
#

here's what some of the subexpressions evaluate to

rapid sparrow
#

not sure exactly what they're doing with the huge numbers, unless it's making a number that represents "Hello world" when viewed as bytes

thorny tapir
#

whoa thats ugly

rapid sparrow
#

but does it work on pypy

#

....no 😅
Traceback (most recent call last): File "prog.py", line 54, in <module> File "prog.py", line 29, in <lambda> + ().__iter__().__class__.__name__[_:][_____:________], AttributeError: 'module' object has no attribute 'incei'

golden finch
#

that's neat

rapid sparrow
#

-DRANDALL_WAS_HERE

#

haha

nova urchin
#

As a novice, This thread terrifies me.

rugged sparrow
#

@grave rover py def foo(a, b, c): print('ah') if a: return foo(1, 2, 3) else: return foo({}, sum([]), foo) breaks the serializer

#
>>> Serializer(Deserializer(foo.__code__).deserialize(), foo.__code__).serialize()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/chilaxan/Desktop/Coding/python/pysnippets/tail_call_optimizer/asm/serializer.py", line 105, in serialize
    data += x.serialize(self)
  File "/Users/chilaxan/Desktop/Coding/python/pysnippets/tail_call_optimizer/asm/ops/abc.py", line 82, in serialize
    return self.int_arg(self.arg)
  File "/Users/chilaxan/Desktop/Coding/python/pysnippets/tail_call_optimizer/asm/ops/abc.py", line 18, in int_arg
    return pack("Bb" if x < 0 else "BB", self.id, x)
TypeError: '<' not supported between instances of 'Label' and 'int'```
sick hound
#

how would I bypass "SyntaxError: cannot assign to None"

#

or anything involving messing with None

shut trail
#

I got the same error when adding the almost equal operator

#

I don’t remember how I fixed it

#

A case statement I’m guessing?

#

For the new node

#

Got it

#

I need to pick up on some basics of C tbh

#

so I can understand CPython source code

#

@sick hound here’s a hard challenge - add a null coalescing operator for python

#

!pep 505

night quarryBOT
#
**PEP 505 - None-aware operators**
Status

Deferred

Python-Version

3.8

Created

18-Sep-2015

Type

Standards Track

golden finch
#

I'm sure that's going to make it so readable

rapid sparrow
rapid sparrow
#

"Are you really, REALLY sure you want to get the attribute??"

golden finch
#

yep

rapid sparrow
#

maybe_none!!!.values()

#

what's the difference between this and
cond ? if-true : if-false

#

is that the same ?? operator?

#

oh ok, i see

#

i might want to use your cpython myself, if you implement any of that

#

i think the idea is it short-circuits the .c if a.b is None ?

#

that's a separate issue I guess

grave rover
#

I hate these things

fickle pond
#

Well, I don't know if it's the right channel, but Esoteric python seems like it could answer questions about magic commands!
So I have many Jupyter notebooks with different widgets programs in it. Now, I wanna make a "Master notebook" and use the %run magic command to run the other scripts in the cells of my master notebook. The problem is that i have to pass a dataframe to the children widget programs and it seems like I can't.

I am running

 %run widgets_program1.py {df}

in a cell, and it doesn't seem to be passing the variable. It seems he can only pass strings, but even if I do

df_string=dft.to_csv() #in the master notebook
%run widgets_program1.py {df_string}

and then

df=pd.read_csv(StringIO(sys.argv[1]))  #in the children

it doesn't seem to work, infact if I print the lenght of sys.argv[1] in the children notebook it's completly wrong. Does anybody have a guess of why?

grave rover
#

which python version are you on?

rapid sparrow
#

don't know the answer

grave rover
#

depends on the bytecode

#

in that example (d = a?.b?.c ?? "") this would be the bytecode: py LOAD_FAST("a") DUP_TOP() LOAD_CONST(None) COMPARE_OP("is not") POP_JUMP_IF_FALSE(stringLabel) LOAD_ATTR("b") DUP_TOP() LOAD_CONST(None) COMPARE_OP("is not") POP_JUMP_IF_FALSE(stringLabel) LOAD_ATTR("c") DUP_TOP() LOAD_CONST(None) COMPARE_OP("is not") POP_JUMP_IF_FALSE(stringLabel) JUMP_ABSOLUTE(endLabel) stringLabel POP_TOP() LOAD_CONST("") endLabel STORE_FAST("d")

#

wait no

#

there we go

#

not sure how cpython does it but it can't be that different

#

but here's my suggestion; why not just make an import hook that modifies the source code and expands those

#

like a?.b is expanded to (a if a is None else a.b)

#

and <expr> ?? "abc" becomes (x if (x := <expr>) is not None else "abc") (where you'd need to change x to an unused name)

#

uhh

#

opcode or operator

#

I don't think you need a custom opcode for that

grave rover
#

also what in the world is LOAD_ATTR_ADAPTIVE and all that

#

huh

#

also not documented on the website

#

it's mentioned in PEP 659 but that one is still a draft

#

what

#

3.10 isn't even released yet afaik

#

oh no

#

time to figure out what opcodes were changed in 3.11

rapid sparrow
#

here's a few

grave rover
#

oh no

#

oh no

rapid sparrow
#

the official release notes only mention CALL_METHOD_KW

grave rover
#

this is bad

#

there's ops with argument before 90

golden finch
#

check the dis.opmap

#

!e

print(*__import__('dis').opmap)
night quarryBOT
#

@golden finch :white_check_mark: Your eval job has completed with return code 0.

POP_TOP ROT_TWO ROT_THREE DUP_TOP DUP_TOP_TWO ROT_FOUR NOP UNARY_POSITIVE UNARY_NEGATIVE UNARY_NOT UNARY_INVERT BINARY_MATRIX_MULTIPLY INPLACE_MATRIX_MULTIPLY BINARY_POWER BINARY_MULTIPLY BINARY_MODULO BINARY_ADD BINARY_SUBTRACT BINARY_SUBSCR BINARY_FLOOR_DIVIDE BINARY_TRUE_DIVIDE INPLACE_FLOOR_DIVIDE INPLACE_TRUE_DIVIDE RERAISE WITH_EXCEPT_START GET_AITER GET_ANEXT BEFORE_ASYNC_WITH END_ASYNC_FOR INPLACE_ADD INPLACE_SUBTRACT INPLACE_MULTIPLY INPLACE_MODULO STORE_SUBSCR DELETE_SUBSCR BINARY_LSHIFT BINARY_RSHIFT BINARY_AND BINARY_XOR BINARY_OR INPLACE_POWER GET_ITER GET_YIELD_FROM_ITER PRINT_EXPR LOAD_BUILD_CLASS YIELD_FROM GET_AWAITABLE LOAD_ASSERTION_ERROR INPLACE_LSHIFT INPLACE_RSHIFT INPLACE_AND INPLACE_XOR INPLACE_OR LIST_TO_TUPLE RETURN_VALUE IMPORT_STAR SETUP_ANNOTATIONS YIELD_VALUE POP_BLOCK POP_EXCEPT STORE_NAME DELETE_NAME UNPACK_SEQUENCE FOR_ITER UNPACK_EX STORE_ATTR DELETE_ATTR STORE_GLOBAL DELETE_GLOBAL LOAD_CONST LOAD_NAME BUILD_TUPLE BUILD_LIST BUILD_SET BUILD_MAP LOAD_AT
... (truncated - too long)

Full output: https://paste.pythondiscord.com/videbizipu.txt?noredirect

grave rover
#

oh I use opcode.opmap

rapid sparrow
grave rover
#

!e py print(__import__("opcode").opmap)

night quarryBOT
#

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

001 |   File "<string>", line 1
002 |     py print(__import__("opcode").opmap)
003 |        ^
004 | SyntaxError: invalid syntax
grave rover
#

whoops

#

!e print(import("opcode").opmap)

night quarryBOT
#

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

{'POP_TOP': 1, 'ROT_TWO': 2, 'ROT_THREE': 3, 'DUP_TOP': 4, 'DUP_TOP_TWO': 5, 'ROT_FOUR': 6, 'NOP': 9, 'UNARY_POSITIVE': 10, 'UNARY_NEGATIVE': 11, 'UNARY_NOT': 12, 'UNARY_INVERT': 15, 'BINARY_MATRIX_MULTIPLY': 16, 'INPLACE_MATRIX_MULTIPLY': 17, 'BINARY_POWER': 19, 'BINARY_MULTIPLY': 20, 'BINARY_MODULO': 22, 'BINARY_ADD': 23, 'BINARY_SUBTRACT': 24, 'BINARY_SUBSCR': 25, 'BINARY_FLOOR_DIVIDE': 26, 'BINARY_TRUE_DIVIDE': 27, 'INPLACE_FLOOR_DIVIDE': 28, 'INPLACE_TRUE_DIVIDE': 29, 'RERAISE': 48, 'WITH_EXCEPT_START': 49, 'GET_AITER': 50, 'GET_ANEXT': 51, 'BEFORE_ASYNC_WITH': 52, 'END_ASYNC_FOR': 54, 'INPLACE_ADD': 55, 'INPLACE_SUBTRACT': 56, 'INPLACE_MULTIPLY': 57, 'INPLACE_MODULO': 59, 'STORE_SUBSCR': 60, 'DELETE_SUBSCR': 61, 'BINARY_LSHIFT': 62, 'BINARY_RSHIFT': 63, 'BINARY_AND': 64, 'BINARY_XOR': 65, 'BINARY_OR': 66, 'INPLACE_POWER': 67, 'GET_ITER': 68, 'GET_YIELD_FROM_ITER': 69, 'PRINT_EXPR': 70, 'LOAD_BUILD_CLASS': 71, 'YIELD_FROM': 72, 'GET_AWAITABLE': 73, 'LOAD_ASSERTION_ERROR': 74, 'INP
... (truncated - too long)

Full output: https://paste.pythondiscord.com/ofotidaquj.txt?noredirect

rapid sparrow
#

well that was spooky

golden finch
#

__import__('opcode').opmap==__import__('dis').opmap
make this false

golden finch
golden finch
rapid sparrow
#

seems to be a lot

+  PUSH_EXC_INFO = 35
+  POP_EXCEPT_AND_RERAISE = 37
+  BEFORE_WITH = 53
-  POP_BLOCK  = 87
-  SETUP_FINALLY = 122
-  LOAD_CLOSURE = 135
-  LOAD_DEREF = 136
-  STORE_DEREF = 137
-  DELETE_DEREF = 138
+  MAKE_CELL  = 135
+  LOAD_CLOSURE = 136
+  LOAD_DEREF = 137
+  STORE_DEREF = 138
+  DELETE_DEREF = 139
-  SETUP_WITH = 143
-  SETUP_ASYNC_WITH = 154
+  CALL_METHOD_KW = 166```
#

they changed opcodes ?

#

disregarding the opcode number, the changes I see:

Removed:

SETUP_WITH SETUP_FINALLY SETUP_ASYNC_WITH POP_BLOCK # Added:
PUSH_EXC_INFO POP_EXCEPT_AND_RERAISE MAKE_CELL CALL_METHOD_KW BEFORE_WITH

#

pretty horrendous 😵

#

thats using this snippet
__import__('opcode').opmap

#

makes me sad.. to think all the work I put into making unpyc work up to 3.9

grave rover
#

alright I think I have the opcodes now

#

but here comes the painful part

#

how do jumps work now that we have 3-byte ops

golden finch
#

we have what?

grave rover
#

oh they're 4 bytes but with a dummy byte in between

#

I see

#

_unpack_opargs won't work with the new ops either PainPeko

#

oh well, pushing partial 3.11 support I guess

grave rover
#

which is kind of odd since you'd expect them to just use EXTENDED_ARG instead

#

oh wait no that's for size

#

JUMP_ABSOLUTE_QUICK=40 breaks the convention of HAVE_ARGUMENT=90

shut trail
#

They’re adaptive instructions:
There’s gonna be a counter and if inputs are expected it’s incremented otherwise it’s decremented, and once the counter hits the minimum value, the adaptive instruction is just replaced(?)

#

And so adaptive instructions are specialized at what their corresponding instruction is

grave rover
#

yeah as you can see I looked into the 3.11 updates earlier

rapid sparrow
#

I didn't think they were merging that

rapid sparrow
#

the walrus operator doesn't work in comprehensions 😭

#

ice been forced to use map and filter as a result

#
/* Map from opcode to adaptive opcode.
  Values of zero are ignored. */
static uint8_t adaptive_opcodes[256] = {
    [LOAD_ATTR] = LOAD_ATTR_ADAPTIVE,
    [LOAD_GLOBAL] = LOAD_GLOBAL_ADAPTIVE,
    [LOAD_METHOD] = LOAD_METHOD_ADAPTIVE,
    [BINARY_ADD] = BINARY_ADD_ADAPTIVE,
    [BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE,
    [STORE_ATTR] = STORE_ATTR_ADAPTIVE,
};
#

that's all in specialize.c, I guess they are merging it

grave rover
rapid sparrow
#

!e

[(t := x) for x in range(5)]
night quarryBOT
#

@rapid sparrow :warning: Your eval job has completed with return code 0.

[No output]
rapid sparrow
#

oh it did work? o.O

grave rover
#

!e py nums = [(x if (x:=y**2) > 10 else y) for y in range(100)] print(nums)

night quarryBOT
#

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

[0, 1, 2, 3, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]
rapid sparrow
#

wtf?

#

well this is annoying

#

!e

list([*list([t := x]) for x in range(5)])
night quarryBOT
#

@rapid sparrow :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     list([*list([t := x]) for x in range(5)])
003 |           ^
004 | SyntaxError: iterable unpacking cannot be used in comprehension
rapid sparrow
#

maybe I dreamed it

#

that's good then

earnest wing
#

you can't unpack, but you can nest comps

grave rover
#

you can also somewhat unpack if you know how

#

!e ```py
print([x
for y in [[1, 2],
[3, 4]]
for x in y])

night quarryBOT
#

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

[1, 2, 3, 4]
earnest wing
#

yeah that's what I meant

grave rover
#

ah

#

who's ready to do some testing on how to break code objects Yay

rugged sparrow
#
>>> import sys
>>> sys.setrecursionlimit(10)
>>> def fact(n, acc=1):
...     if (n < 2):
...         return acc
...     return fact(n - 1, n * acc)
... 
>>> fact(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in fact
  File "<stdin>", line 4, in fact
  File "<stdin>", line 4, in fact
  [Previous line repeated 5 more times]
  File "<stdin>", line 2, in fact
RecursionError: maximum recursion depth exceeded in comparison
>>> dis.dis(fact)
  2           0 LOAD_FAST                0 (n)
              2 LOAD_CONST               1 (2)
              4 COMPARE_OP               0 (<)
              6 POP_JUMP_IF_FALSE       12

  3           8 LOAD_FAST                1 (acc)
             10 RETURN_VALUE

  4     >>   12 LOAD_GLOBAL              0 (fact)
             14 LOAD_FAST                0 (n)
             16 LOAD_CONST               2 (1)
             18 BINARY_SUBTRACT
             20 LOAD_FAST                0 (n)
             22 LOAD_FAST                1 (acc)
             24 BINARY_MULTIPLY
             26 CALL_FUNCTION            2
             28 RETURN_VALUE
>>> fact = tco(fact)
>>> dis.dis(fact)
  2     >>    0 LOAD_FAST                0 (n)
              2 LOAD_CONST               1 (2)
              4 COMPARE_OP               0 (<)
              6 POP_JUMP_IF_FALSE       12

  3           8 LOAD_FAST                1 (acc)
             10 RETURN_VALUE

  4     >>   12 NOP
             14 LOAD_FAST                0 (n)
             16 LOAD_CONST               2 (1)
             18 BINARY_SUBTRACT
             20 LOAD_FAST                0 (n)
             22 LOAD_FAST                1 (acc)
             24 BINARY_MULTIPLY
             26 STORE_FAST               1 (acc)
             28 STORE_FAST               0 (n)
             30 JUMP_ABSOLUTE            0
>>> fact(10)
3628800
>>> ```
#

@grave rover had to handroll a smaller dissassembler but its working

grave rover
#

nice

#

I'm working on actually testing stuff on 3.7

#

but uh

#

ValueError: code: varnames is too small

rugged sparrow
grave rover
#

creating a code object

#

just deserializing and reserializing

rugged sparrow
#

that is weird

#

is that the version on git?

grave rover
#
    /* Ensure that the co_varnames has enough names to cover the arg counts.
     * Note that totalargs = nlocals - nplainlocals.  We check nplainlocals
     * here to avoid the possibility of overflow (however remote). */
    int nlocals;
    get_localsplus_counts(con->localsplusnames, con->localspluskinds,
                          &nlocals, NULL, NULL, NULL);
    int nplainlocals = nlocals -
                       con->argcount -
                       con->kwonlyargcount -
                       ((con->flags & CO_VARARGS) != 0) -
                       ((con->flags & CO_VARKEYWORDS) != 0);
    if (nplainlocals < 0) {
        PyErr_SetString(PyExc_ValueError, "code: co_varnames is too small");
        return -1;
    }
#

not quite

#

the weird thing is that my nlocals, argcount, kwonlyargcount and varnames are all the same

rugged sparrow
#

nlocals - argcount - kwonlyargcount should be >=0

rugged sparrow
#

and len(varnames) == nlocals

rapid sparrow
#

i hacked up a package to use the docstring to figure out what to pass to the CodeType ctor 😅

rugged sparrow
#

oh yea i wrote one of those too lol

rapid sparrow
#

otherwise i don't see how it can work on more than a couple versions

rapid sparrow
grave rover
rapid sparrow
#

why doesn't it have a __text_signature__ ...

rugged sparrow
#
def replace(codeobj, **kwargs):
    code_args = []
    argnames = type(codeobj).__doc__.split("(")[1].split("[")[0].split(",")
    for argname in argnames:
        argname = argname.strip()        
        if argname == "codestring":
            argname = "code"
        if argname == "constants":
            argname = "consts"
        code_args.append(kwargs.get("co_"+argname, getattr(codeobj, "co_"+argname)))

    return type(codeobj)(*code_args)``` this is I think a working version
rapid sparrow
rugged sparrow
#

@grave rover maybe flags issue?

grave rover
#

I ended up doing it like this ```py

def code_replace(code_obj: CodeType, **kwargs) -> CodeType:
if sys.version_info >= (3, 8):
return code_obj.replace(**kwargs)

def _(n: str):
    return kwargs.get(n, getattr(code_obj, n))

print(_("co_nlocals"), _("co_argcount"), _("co_kwonlyargcount"), _("co_flags"))

return CodeType(
    _("co_argcount"),
    _("co_kwonlyargcount"),
    _("co_nlocals"),
    _("co_stacksize"),
    _("co_stacksize"),
    _("co_code"),
    _("co_consts"),
    _("co_names"),
    _("co_varnames"),
    _("co_filename"),
    _("co_name"),
    _("co_firstlineno"),
    _("co_lnotab"),
    _("co_freevars"),
    _("co_cellvars")
)
#

flags are the same on both too (67)

rapid sparrow
#

lmao

#

could a signature be hacked onto a built-in function

grave rover
#

wait

#

I ^D'd

#

and stacksize is in there twice

#

is that really my issue

rugged sparrow
#

ye

grave rover
#

there we go

rapid sparrow
#

now there's like kwposonlyonlyonlyargcount

grave rover
#

it was passing stack as flags

rapid sparrow
#

anyone knoq what CO_NEW_LOCALS does

#

or is it CO_NEWLOCALS

grave rover
#

@rugged sparrow <3.8 support should be up now

rugged sparrow
#

i ran into that label bug earlier on 3.9

grave rover
#

yup fixed that too

rapid sparrow
#

i bet there's hundreds of these

grave rover
#
            elif op in hasjabs:
                idx = arg * 2 if sys.version_info >= (3, 10) else arg
#

looks like they changed in 3.10

#

makes sense since it'd always be a multiple of 2

rugged sparrow
#

wait jumps are now index/2?

grave rover
#

wait that means I shouldn't divide by 2 when writing again

#

for absjumps yes

#

reljumps not sure

rapid sparrow
#

there's no stability guarantees for cpython bytecode i guess

#

python 3.12 - "make bytecode it big-endian"

grave rover
#

if you find any issues with the version I just pushed due to jumps let me know @rugged sparrow

rugged sparrow
#

will do

#
import dis

def decompile(byc):
    jmp_tbl = {}
    decomp = []
    idx = 0
    while idx < len(byc):
        op, arg = byc[idx: idx + 2]
        idx += 2
        while dis.opname[op] == 'EXTENDED_ARG':
            oarg = arg
            op, arg = byc[idx: idx + 2]
            arg |= oarg << 8
            idx += 2
        decomp.append([dis.opname[op], arg])
    for idx, ((op, arg), lst) in enumerate(zip(decomp, decomp)):
        if op == 'JUMP_FORWARD':
            jmp_tbl[id(lst)] = decomp[idx + (arg // 2) + 1]
        elif 'JUMP' in op:
            jmp_tbl[id(lst)] = decomp[arg // 2]
    return decomp, jmp_tbl

def insert_extensions(decomp):
    while any(filter(lambda t:t[1] > 255, decomp)):
        for idx, (op, arg) in enumerate(decomp[:]):
            nshift = (arg.bit_length() / 8).__ceil__()
            if op != 'JUMP_FORWARD' and 'JUMP' in op and nshift:
                arg += (nshift - 1) * 2
            if arg > 255:
                decomp[idx][1] = arg & 255
                decomp.insert(idx, ['EXTENDED_ARG', arg >> 8])
                break

def find(decomp, dest):
    for idx, lst in enumerate(decomp):
        if lst is dest:
            return idx

def recompile(decomp, jmp_tbl):
    insert_extensions(decomp) # insert EXTENDED_ARG for non JUMPs
    for idx, ((op, arg), lst) in enumerate(zip(decomp, decomp)):
        if 'JUMP' in op:
            offset = (idx + 1) if op == 'JUMP_FORWARD' else 0
            dest_op = jmp_tbl.get(id(lst))
            if (dest := find(decomp, dest_op)) is not None:
                arg = lst[1] = (dest - offset) * 2
    insert_extensions(decomp) # insert EXTENDED_ARG for JUMPs
    return b''.join(bytes([dis.opmap[op], arg]) for op, arg in decomp)``` this is my small decompiler im using rn
#

it prob has some issues but it works for 3.9

grave rover
#

that seems incredibly painful lol

rapid sparrow
#

what kind of output do you get with it

rugged sparrow
#

a list of [opname, oparg] and a jump table

rapid sparrow
#

oh that's cool, that should be in the dis module

rugged sparrow
#

it collapses EXTENDED_ARGS and then re-expands them during recompilation

rapid sparrow
#

there's a pyasm i was trying to get to work a little better to parse the typical listing, but haven't had much success

rugged sparrow
rapid sparrow
#

/me steals it

rugged sparrow
#

go ahead just credit me

rapid sparrow
#

i shall, thanks

#

what decompiler are people having good results with?

grave rover
#

define decompiler

#

if it's turning bytecode into ops then I'm pretty happy with mine

#

but into actual code there's decompyle6

rapid sparrow
#

preferably generate python source

grave rover
#

I think decompyle6 is about the only tool there is for that atm

rapid sparrow
#

if it's readable that's not a hard requirement

#

it's unmaintained now though, right?

grave rover
#

sounds like a fun task to do though, might take that up later

rapid sparrow
rugged sparrow
grave rover
#

lol

#

I mean this will assume unmodified unoptimized bytecode

rapid sparrow
#

sometimes it works great, sometimes it fails with "popped an empty stack!"

grave rover
#

ah

rapid sparrow
#

tried to fix the cases i could track down

grave rover
#

using stack_effect?

rapid sparrow
#

i'm trying to remember.. it's hard to find where things went off the rails mostly

#

i don't think i've used stack_effect

grave rover
#

strange, I always remember at what point I gave up :P

rapid sparrow
#

haha

#

i do like uncompyle6 too

#

the main github has a note that the guy was gonna rewrite it

#

that's been like that for years

#

so how would you use stack_effect

#

don't you need to know exactly what to do with each pop/push?

grave rover
#

not 100%

#

sure if I see LOAD_GLOBAL("input") CALL_FUNCTION(0) I need to understand it calls input()

#

but I don't actively track the stack effect for that

rapid sparrow
#

the generics thing looks cool. you added type arguments for List, Tuple, etc that actually work?

#

til there's two libraries named pyasm

#

that aren't at all similar

#

very nice

#

i'm thinking if the python
parser can be generated, it should be possible to generate a de-parser. is this right, or just crazy talk

grave rover
#

if compilers were injective functions then yes

rugged sparrow
worn jay
#

What combinations of compiling / obfuscation tools do you guys use to create code that is virtually impossible to get human-readable stuff out of reverse engineering?

#

I already use Cython for compiling but I'd like to be able to generate a single executable that isn't easy to decompile, or at least not easy to read when decompiled

grave rover
#

hard to do honestly, since a lot of cpython internals are well-defined

snow beacon
worn jay
#

The obfuscation is less about security and more about making it difficult to read

rapid sparrow
rapid sparrow
worn jay
#

Thing with Cython is that it's still possible to reverse engineer

next flame
#

c/c++ is also possible to reverse engineer

#

no obfuscation will work against a sufficiently determined actor

rapid sparrow
#

So perhaps you don't need to bother

#

why would that be though, are there secret keys in it ?

rapid sparrow
worn jay
#

I just want to make it as difficult as possible for someone who wants to reverse engineer my code
I'm doing something stupid like storing any secret/private keys or passwords, I just want to make it not worth the effort for a bad actor to try to look at the source code

rapid sparrow
#

that's what I'd like to understand more. it's not to hide the logic, you just want to make things difficult for would-be reverse-engineering?

#

what if they're not a bad actor, they like your software, and wanted to see how you did it

#

the way I see it, it's like spraypainting over a museum painting

worn jay
#

I suppose it is like that

next flame
#

also those not-bad actors can also help improve your program

worn jay
#

The thing with one of my apps is that I have some stuff that I want to be open source, and other stuff that I want to be closed - that closed stuff is what I'd want to obfuscate

prisma coral
#

!e Hmm...

print(bool(type(None)))
print(type(None).__bool__(None))
night quarryBOT
#

@prisma coral :white_check_mark: Your eval job has completed with return code 0.

001 | True
002 | False
prisma coral
#

Welp I guess instead of True and False I'll just use these from now on

grave rover
#

I mean those are effectively bool(NoneType) and bool(None) respectively

spring depot
#

Python truthy values like if [0]: pass

prisma coral
rapid sparrow
#

!e

print(
    f"{not ()=} \n"
    f"{not ().__class__=}"
)
```   coincidence?
night quarryBOT
#

@rapid sparrow :white_check_mark: Your eval job has completed with return code 0.

001 | not ()=True 
002 | not ().__class__=False
rapid sparrow
#

bonus points if someone knows how to make a metaclass that evaluates False

rugged sparrow
#

like class a(metaclass=...); a is False?

rapid sparrow
#

thinking like

class a(metaclass=...)
bool(a.__class__)    # False
#

i don't even know where the truth value of a type object comes from. Is it just because bool(not None) -> True ?

grave rover
#

oh no I know of several ctype hacks to do this

rapid sparrow
#

** the metaclass part is optional

#

AttributeError: type object 'type' has no attribute '__bool__'

rugged sparrow
#

!e ```py
class M(type):
bool = lambda s:False

class A(type, metaclass=M):pass
class a(metaclass=A):pass
print(bool(a.class))```

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

False
grave rover
#

metaclass of a metaclass

#

I hate it but I love it

rapid sparrow
#

w a t

#

!e

class M(type):
  __bool__ = lambda s:False
class A(type, metaclass=M):pass
class a(metaclass=A):pass
an_a = a()
print(bool(an_a.__class__)) 
night quarryBOT
#

@rapid sparrow :white_check_mark: Your eval job has completed with return code 0.

True
rapid sparrow
#

asdfghjkl

#

bonus awarded

#

but I'm gonna try to do a less nice version

#

hello id(type)

grave rover
#

ctypes time

rapid sparrow
#

oops

#

curious abort instead of segfault

rugged sparrow
rapid sparrow
rugged sparrow
#

so you tried to read the reference counter of type as a pointer to 16 characters?

rapid sparrow
#

yes, and instead it tried to read from address 0x3d >_>

rugged sparrow
#

thats the current ref count of type most likely

rapid sparrow
#

oh? O.o

#

what should I have done

rugged sparrow
#

whats your goal?

rapid sparrow
#

i just wanted it as character data

rugged sparrow
#

read the first 16 bytes of type?

rapid sparrow
#

yea

rugged sparrow
#

then (c_char * 16).from_address(id(type))

rapid sparrow
#

omg it worked, thank you so much ❤️

#

does from_addtess mean I was creating a pointer to the thing I wanted?

#
>>> arr.raw
b'=\x00\x00\x00\x00\x00\x00\x00P\xb1\xf9\xf7\x7f\x00\x00\x00'
``` is what I was looking for
#

0x3b is the = iirc

#

that must be refcount, cause the rest are all zeroes, like you said..

grave rover
#
typedef struct _object {
    Py_ssize_t ob_refcnt;
    PyTypeObject *ob_type;
} PyObject;
#

for a PyTypeObject it's ```c
typedef struct _PyTypeObject PyTypeObject;

struct _PyTypeObject {
Py_ssize_t ob_refcnt;
PyTypeObject ob_type;
Py_ssize_t ob_size;
const char
tp_name;
Py_ssize_t tp_basicsize;
Py_ssize_t tp_itemsize;
void* tp_dealloc;
// ...
}```

rapid sparrow
#

so it's definitely ob_refcnt then

#

how'd you get that? did you macro expand it?

#

normally it will say e.g. PY_OBJECT_HEAD or somesuch

#

was just curious if there was a technique i don't know of

#

oh it's defined to empty is why

#

cool

grave rover
#

important to note PyVarObject is NOT PyObject

grave rover
#

what's the generated bytecode?

#

I'm guessing OPTIONALOP works like DUP_TOP() LOAD_CONST(None) COMPARE_OP(is not) POP_JUMP_IF_FALSE(+2)?

#

idk what you mean by that lol

#

that seems

#

wrong

#

because then a?.b.c.d is handled as if it were a?.b?.c?.d

#

wouldn't you instead just want ```c
TARGET(OPTIONALOP): {
if (TOP() == Py_None) {
next_instr++;
}
DISPATCH();
}

#

also ```
10 LOAD_CONST 0 ('')
12 COALESCE 0

#

e.g. a?.b ?? new_b() will always call new_b

#

huh

#

I assumed it would since LOAD_CONST('') was before the COALESCE so it'd be evaluated first

#

well yeah but LOAD_FAST(a) would still happen before BINARY_POWER

rapid sparrow
#

oh sweet

rapid sparrow
#

I have a weird reloading-related (I already am in "don't do that" territory thus asking this chanmrl) issue with supposedly incompatible types in a super() that's rejecting some arguments (I think..)
What would explain why I get:

Traceback
  File <stdin>, line 1, in <module>
    pythonrc.exec_in_module(readstring('/data/media/0/,scripts/edited--gdb_extras.py.1630903616.bak'), gdb_extras):
  File /data/media/0/pythonrc.py, line 3615, in exec_in_module
    result = builtin_exec(codeobj, dicts[0], _out_locals):
  File /tm/tmp_py_src_7tppmsbs.py, line 757, in <module>
    if IS_GDB: ListExCommand():
  File /tm/tmp_py_src_7tppmsbs.py, line 470, in __init__
    super(ListExCommand, self).__init__("li", gdb.COMMAND_USER):
TypeError: super(type, obj): obj must be an instance or subtype of type

BUT I went to check the two names there (ListExCommand and self) from the traceback frame, to see if they were incompatible evil twins:

>>> pp([(id(x),x) for x in (self.__class__, ListExCommand,)])
[(387405958144, <class 'gdb_extras.ListExCommand'>),
 (387405958144, <class 'gdb_extras.ListExCommand'>)]
``` bit confused..
#

oh and the usecase is a source lister that expands macros that you can still step through, if anyone was curious

grave rover
knotty delta
#

!e

from ctypes import c_void_p
class Rick:
    def __str__(self):
        return "Never gonna make you cry"
c_void_p.from_address(id(object)+8).value = id(Rick)
Never_gonna_run_around = desert_you = object



print(Never_gonna_run_around and desert_you)
night quarryBOT
#

@knotty delta :white_check_mark: Your eval job has completed with return code 0.

Never gonna make you cry
floral meteor
#

wooooow i got rickrolled

#

this is my favourite rickroll so far

rapid sparrow
#

lmao

#

what does it actually do to PyObject_Type ?

rapid sparrow
floral meteor
rapid sparrow
#

set it's ob_type to Rick? haha

#

pretty amazing the interpreter manages to even exit successfully

#

@sick hound is your None-coalescing operator fork on github?

sleek sphinx
#

can someone explain the inner workings of "import this"?

potent cliff
#

you mean the cipher?

#

it's just ROT13

#

the "Ceasar Cipher"

#

for every letter, it "advances" 13 letters ahead, wrapping around at the end of the alphabet.

rapid sparrow
#

from what I recall

#

ok, it's simpler than that. It just prints. But yeah, I guess you were asking about the ciphered text so nevermind ...

sleek sphinx
#

yea the cipher is confusing

golden finch
#

the this module is curious

#

I like it

#

looking at it:

>>> this.c
97
>>> this.d
{'A': 'N', 'B': 'O', 'C': 'P', 'D': 'Q', 'E': 'R', 'F': 'S', 'G': 'T', 'H': 'U', 'I': 'V', 'J': 'W', 'K': 'X', 'L': 'Y', 'M': 'Z', 'N': 'A', 'O': 'B', 'P': 'C', 'Q': 'D', 'R': 'E', 'S': 'F', 'T': 'G', 'U': 'H', 'V': 'I', 'W': 'J', 'X': 'K', 'Y': 'L', 'Z': 'M', 'a': 'n', 'b': 'o', 'c': 'p', 'd': 'q', 'e': 'r', 'f': 's', 'g': 't', 'h': 'u', 'i': 'v', 'j': 'w', 'k': 'x', 'l': 'y', 'm': 'z', 'n': 'a', 'o': 'b', 'p': 'c', 'q': 'd', 'r': 'e', 's': 'f', 't': 'g', 'u': 'h', 'v': 'i', 'w': 'j', 'x': 'k', 'y': 'l', 'z': 'm'}
>>> this.i
25
>>> this.s
"Gur Mra bs Clguba, ol Gvz Crgref\n\nOrnhgvshy vf orggre guna htyl.\nRkcyvpvg vf orggre guna vzcyvpvg.\nFvzcyr vf orggre guna pbzcyrk.\nPbzcyrk vf orggre guna pbzcyvpngrq.\nSyng vf orggre guna arfgrq.\nFcnefr vf orggre guna qrafr.\nErnqnovyvgl pbhagf.\nFcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.\nNygubhtu cenpgvpnyvgl orngf chevgl.\nReebef fubhyq arire cnff fvyragyl.\nHayrff rkcyvpvgyl fvyraprq.\nVa gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.\nGurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.\nNygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.\nAbj vf orggre guna arire.\nNygubhtu arire vf bsgra orggre guna *evtug* abj.\nVs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.\nVs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.\nAnzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"
#

!e

print(chr(97))
#this.d is a rot13 dict
i=25#length of the alphabet?
#this.s is just the string
night quarryBOT
#

@golden finch :white_check_mark: Your eval job has completed with return code 0.

a
golden finch
#

actually, I bet it's the difference between lower and upper case

#
s = """Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print("".join([d.get(c, c) for c in s]))

complete source

golden finch
#

looks like the two for loops generate d

grave rover
#

going pretty good so far

#

can't wait to have to actually parse branches

rugged sparrow
#

thats awesome

golden finch
#

are you actually turning __code__ into code? madlad

grave rover
#

made a small fix to make strings work

rapid sparrow
#

oh no worries 👍

#

just don't lose or FUBAR it by accident (for me the line is very thin between fixing and FUBAR'ing)

grave rover
#
n = 0
if (2 * offset + n < len(self.code)):
    op = self.code[2 * offset + n:None]
    arg, op = unpack('BB', op[None:2])
    n = n += 1
    if (op >= 90):
    else:
    current = stack_effect(op, arg) += stack_effect(op)
    self.max = max(self.max, current)
    if (op in hasbranch):
        new_jumped = jumped + [arg, current + n]
        if (arg not in jumped):
            self.check_offset(arg, current, new_jumped)
        if (current + n not in jumped):
            self.check_offset(current + n, current, new_jumped)
        return
    if (op in hasjabs):
        if (arg not in jumped):
            self.check_offset(arg, current, jumped + [arg])
            return
        if (op in hasjrel):
            if (offset + n + arg not in jumped):
                self.check_offset(offset + n + arg, current, jumped + [offset + n + arg])
                return
            if (op == opmap['RETURN_VALUE']):
            return
#

not the worst result

#

source that caused that is ```py
def check_offset(self, offset: int, current: int, jumped: list):
n = 0
while 2 * (offset + n) < len(self.code):
op = self.code[2 * (offset + n):]
op, arg = unpack("BB", op[:2])
n += 1
current += stack_effect(op, arg) if op >= 90 else stack_effect(op)
self.max = max(self.max, current)

        # TODO: Something still goes wrong here
        # if current < 0:
        #     raise ValueError("Negative stack index!")

        if op in hasbranch:
            new_jumped = jumped + [arg, current + n]

            # do both branches
            if arg not in jumped:
                self.check_offset(arg, current, new_jumped)
            if current + n not in jumped:
                self.check_offset(current + n, current, new_jumped)
            return

        elif op in hasjabs and arg not in jumped:
            # do jump
            self.check_offset(arg, current, jumped + [arg])
            return
        elif op in hasjrel and offset + n + arg not in jumped:
            # do jump
            self.check_offset(offset + n + arg, current, jumped + [offset + n + arg])
            return

        if op == opmap["RETURN_VALUE"]:
            break
#

that x if y else z really messes it up

#
LOAD_FAST(id=124, arg='current'), 
LOAD_FAST(id=124, arg='op'), 
LOAD_CONST(id=100, arg=90), 
COMPARE_OP(id=107, arg='>='), 
POP_JUMP_IF_FALSE(id=114, arg=100), 
LOAD_GLOBAL(id=116, arg='stack_effect'), 
LOAD_FAST(id=124, arg='op'), 
LOAD_FAST(id=124, arg='arg'), 
CALL_FUNCTION(id=131, arg=2), 
JUMP_FORWARD(id=110, arg=104), 
LOAD_GLOBAL(id=116, arg='stack_effect'), 
LOAD_FAST(id=124, arg='op'), 
CALL_FUNCTION(id=131, arg=1), 
INPLACE_ADD(id=55, arg=0), 
STORE_FAST(id=125, arg='current'), 
#

I wonder if there's an easy way to detect this structure

#

maybe check if the stack is empty?

#

but there's probably other situations

#

idk

grave rover
#
n = 0
if (2 * offset + n < len(self.code)):
    op = self.code[2 * offset + n:]
    arg, op = unpack('BB', op[:2])
    n += 1
    stack_effect(op, arg) if (op >= 90) else current += stack_effect(op)
    self.max = max(self.max, current)
    if (op in hasbranch):
        new_jumped = jumped + [arg, current + n]
        if (arg not in jumped):
            self.check_offset(arg, current, new_jumped)
        if (current + n not in jumped):
            self.check_offset(current + n, current, new_jumped)
        return
    if (op in hasjabs):
        if (arg not in jumped):
            self.check_offset(arg, current, jumped + [arg])
            return
    if (op in hasjrel):
        if (offset + n + arg not in jumped):
            self.check_offset(offset + n + arg, current, jumped + [offset + n + arg])
            return
    if (op == opmap['RETURN_VALUE']):
    break
    continue
return
``` if only that `break` lined up better...
rapid sparrow
grave rover
#

I hate the indents tho

#

It also kind of doesn't know elifs yet

golden finch
#

are you making a disassembler?

grave rover
#

Yes

#

Thought it'd be fun to try

rapid sparrow
#

This doesn't help you does it?

#

^ the traceback seems like it could match

#

sys is the first module loaded.. you could set a bteakpoint on PyException_SetTraceback and enable PYTHONVERBOSE maybe

#

oh, oh, maybe you need re-generate the frozen modules ??

#

you would need a debugger. did you build with MSVC?

#

ok, thst might workk

grave rover
#

Attach a debugger yeah

#

Not sure how easy vscode is compared to pycharm

rapid sparrow
#

get WinDbg

#

from MS store

#

the new one doesn't suck

#

then you will be able to source debug and set breakpoints

#

gdb won't work with MSVC -compiled binaries, iirc

#

other last resort action is nuke (just) the build dir and rebuild python

#

did you build in the source dir? or separate

#

also delete any and all __pycache__ dirs

#

thats only the win-specific parts, right?

#

you see .obj files under Python/ ?

#

can you locate sysmodule.o or sysmodule.obj

#

maybe try build.bat -r --regen

#

alternately if that fails, delete everything under PCbuild/obj

#

that's the "build dir" i suppose

#

and this:
%MSBUILD% "%dir%\pythoncore.vcxproj" /t:Regen %verbose%^ /p:Configuration=%conf% /p:Platform=%platf%^ /p:ForceRegen=true

#

"will regenerate all grammar, tokens, and opcodes."

#

🤷‍♂️

#

ah

#

one thing I would try

#

is to change where it says sys. to __import__("sys"). - and see if it can maybe get passed initializing builtins then

in Lib/importlib/_bootstrap.py:255

#

does running python with python.exe -S -s -x start?

knotty delta
#

.topic

glass drumBOT
#
**What's a common part of programming we can make harder?**

Suggest more topics here!

knotty delta
#

wow there are actually topics for esoteric python

rapid sparrow
#

wow, that shouldn't be happening. what's the code for _requires_builtin_wrapper now?

#

the bytecode is messed up

#

it should of course have LOAD_DEREF

#

might be worth setting PYTHONDONTWRITEBYTECODE=1 in the environment until you're out of the woods

grave rover
#

Splitting code into blocks is actually painful what the heck

#

For some reason it keeps trying to recurse even when I'm only allowing forward junps

rugged sparrow
#

Do you have handling for while loops?

grave rover
#

not yet

#

I need to clean it up lol

rapid sparrow
shut trail
#

What’s the best tutorial on ctypes out there?

grave rover
#

Find a good C tutorial

rapid sparrow
#

if you're looking to use it for a "sanctioned" purpose, or more "esoteric" purposes

rapid sparrow
# shut trail What’s the best tutorial on ctypes out there?
shut trail
#

oh wrong reply

#

and thanks :D

rapid sparrow
#

thought so

shut trail
#

How do you all know so much about the byte offset of objects? Like I'm wondering how you all know that id(True) + 8 defines is behavior

rapid sparrow
#

I'd() always gives you the memory address

potent comet
#

Well not quite, CPython does so, but PyPy doesn't and it's not guaranteed in general.

snow beacon
shut trail
rugged sparrow
#

When python does is it is equivalent to id(obj1) == id(obj2)

rugged sparrow
#

It is, it just compares the pointers

#

I was saying that's the equivalent python

rapid sparrow
#

does anyone know what PyInterpreterState_Clear is useful for?

delicate scroll
#

Good to now there is also an 'esoteric' version of Python. But why? 🤣

delicate scroll
#

But the esoteric languages are just for the fun of it right? not really useful

#

👍 thank you for your answer

#

🐸 obfuscated javascript equals unveiled C

potent comet
#

JS obfuscation isn't really that, but it's a side effect. The intent is to make the file size as small as possible, by removing all whitespace, comments, swapping to equivalent smaller code, renaming variables to one-letter versions, and also generally optimising by inlining constants etc.

rugged sparrow
#

3.10 has broken a lot of my bytecode level hacks

grave rover
#

Same

earnest wing
#

There's a lot of bytecode changes

rugged sparrow
#

are they all documented anywhere?

inland sparrow
#

Hello

harsh rampart
rugged sparrow
#

Various runtime shenanigans

harsh rampart
#

Why nowadays people are using python for microcontroller programming and flashing converted Cpython code into controller ?

earnest wing
#

because it's funny

barren trout
#

what is this channel for

#

wait nvm read the desc

shut trail
rugged sparrow
#

There are some improved optimizations (early returns being one of them) so my scanner functions that look for certain patterns don't account for them

shut trail
#

Ah

#

bytecode hacks will deffo break for 3.11

#

adaptive bytecodes

snow beacon
rugged sparrow
#

I need to make some portions more general. Tbh might just make a generic bytecode scanner that can look for defined patterns

potent comet
#

Well actually the adaptive bytecode will be deactivated if you enable tracing etc, so you shouldn’t have to deal with them.

rugged sparrow
#

I might be able to do some cool things with the adaptive bytecode tho

potent comet
#

It’s also not visible in the code object, it first copies the byte code to a private array before modifying.

thin trout
#

!e range(3, 4, s=5, g=7, *a, **b, **c)

night quarryBOT
#

@thin trout :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | NameError: name 'a' is not defined
thin trout
#

I thought that'd be invalid syntax

earnest wing
#

Why would it? It's just normal call syntax

tall glacier
#

Hello you crazy golfers ⛳

#

anyone have any written guides for golfing if statements?

#

wanted to golf this a bit and learn about golfing and stress out my university lecturer.

gritty mesa
#

Depends what you're doing, maybe send an example

tall glacier
#

ok

#
def windspeed(inputint):
    if inputint < 20:
        print("Breeze")
    elif 20 < inputint < 50:
        print("Gale")
    elif inputint > 50:
        print("Storm")
eager sphinx
#

!e

range(3, 4, s=5, g=7, *(1, 2))
night quarryBOT
#

@eager sphinx :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: range() takes no keyword arguments
eager sphinx
#
def f(*args, **kwargs):
  ...

f(3, 4, s=5, g=7, *(1, 2))
tall glacier
#

!e ```python
def windspeed(inputint):
if inputint < 20:
print("Breeze")
elif 20 < inputint < 50:
print("Gale")
elif inputint > 50:
print("Storm")

night quarryBOT
#

@tall glacier :warning: Your eval job has completed with return code 0.

[No output]
eager sphinx
#

!e

def f(*args, **kwargs):
  ...

f(3, 4, s=5, g=7, *(1, 2))
night quarryBOT
#

@eager sphinx :warning: Your eval job has completed with return code 0.

[No output]
tall glacier
#

thats pretty cool

eager sphinx
#

Very weird

earnest wing
#

*args seems to be fine with it

gritty mesa
#

!e

windspeed=lambda _:print("Breeze")if _<20 else print("Gale")if 20<_<50 else print("Storm")

windspeed(12)
windspeed(34)
windspeed(64)
night quarryBOT
#

@gritty mesa :white_check_mark: Your eval job has completed with return code 0.

001 | Breeze
002 | Gale
003 | Storm
tall glacier
gritty mesa
#

Just a variable name that's terrible to confuse things more

#

You'll see that a lot around here

tall glacier
#

I have noticed, however it like a race to get chars down?

#

Tight

#

I want to get into code golfing but I feel like I am not that good at programming yet lol

#

thank you kind internet people for humoring my questions 🙂 @gritty mesa && @sick hound 🙂

gritty mesa
#

!e I'm sure your lecturer would have fun with this

from __future__ import annotations

@lambda c:c()
class __annotations__:
    def __setitem__(self, k, v):
        if k == "For":
            self.condition = v.split(",")[1].strip()
            self.var = v.split(",")[0].strip("(")
            globals()[self.var] = 0

        elif k == "_":
            code = v.strip("{").strip("}").strip().split(", ")
            code_string = "\n".join(stuff.strip("'") for stuff in code)

            while eval(self.condition):
                exec(code_string)
                globals()[self.var] += 1


For:(x, x < 5, ++x);_:{
    print(x)
}
night quarryBOT
#

@gritty mesa :white_check_mark: Your eval job has completed with return code 0.

001 | 0
002 | 1
003 | 2
004 | 3
005 | 4
tall glacier
#

my eyes o.0

night quarryBOT
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

001 |  0
002 |  1
003 |  2
004 |  3
005 |  4
006 |  5
007 |  6
008 | __
009 | 21
gritty mesa
#

import __future__ as __past__ good lord

tall glacier
#

I will be back in 6 months lol

night quarryBOT
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

001 |  0
002 |  1
003 |  2
004 |  3
005 |  4
006 |  5
007 |  6
008 | __
009 | 21
gritty mesa
#

]e Will this work first try, here we go

exec('def windspeed(_):\n\tmatch _:\n\t\tcase _<20:print("Breeze")\n\t\tcase 20<_<50:print("Gale")\n\t\tcase _>50:print("Storm")\nwindspeed(5)')
turbid dewBOT
#

@gritty mesa :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 |   File "<string>", line 3
004 |     case _<20:print("Breeze")
005 |           ^
006 | SyntaxError: expected ':'
proper vault
gritty mesa
#

woops

#

wait

#

where did I

proper vault
#

you can't do this with case

gritty mesa
#
print('def windspeed(_):\n\tmatch _:\n\t\tcase _<20:print("Breeze")\n\t\tcase 20<_<50:print("Gale")\n\t\tcase _>50:print("Storm")\nwindspeed(5)')
#

!e

print('def windspeed(_):\n\tmatch _:\n\t\tcase _<20:print("Breeze")\n\t\tcase 20<_<50:print("Gale")\n\t\tcase _>50:print("Storm")\nwindspeed(5)')
night quarryBOT
#

@gritty mesa :white_check_mark: Your eval job has completed with return code 0.

001 | def windspeed(_):
002 | 	match _:
003 | 		case _<20:print("Breeze")
004 | 		case 20<_<50:print("Gale")
005 | 		case _>50:print("Storm")
006 | windspeed(5)
proper vault
#

it would be case _ if _ < 20 IIRC

gritty mesa
#

Oh right

#

_ is reserved

tall glacier
gritty mesa
#

!e Maybeeee

exec('def windspeed(i):\n\tmatch i:\n\t\tcase i<20:print("Breeze")\n\t\tcase 20<i<50:print("Gale")\n\t\tcase i>50:print("Storm")\nwindspeed(5)')
night quarryBOT
#

@gritty mesa :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 |   File "<string>", line 2
004 |     match i:
005 |           ^
006 | SyntaxError: invalid syntax
gritty mesa
#

damn

#

!e

print('def windspeed(i):\n\tmatch i:\n\t\tcase i<20:print("Breeze")\n\t\tcase 20<i<50:print("Gale")\n\t\tcase i>50:print("Storm")\nwindspeed(5)')
night quarryBOT
#

@gritty mesa :white_check_mark: Your eval job has completed with return code 0.

001 | def windspeed(i):
002 | 	match i:
003 | 		case i<20:print("Breeze")
004 | 		case 20<i<50:print("Gale")
005 | 		case i>50:print("Storm")
006 | windspeed(5)
gritty mesa
#

Why are you invalid, I need to read up on patma

#

oh

#

wait

#

]e

exec('def windspeed(i):\n\tmatch i:\n\t\tcase i<20:print("Breeze")\n\t\tcase 20<i<50:print("Gale")\n\t\tcase i>50:print("Storm")\nwindspeed(5)')
turbid dewBOT
#

@gritty mesa :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 |   File "<string>", line 3
004 |     case i<20:print("Breeze")
005 |           ^
006 | SyntaxError: expected ':'
gritty mesa
#

Ok yeah might have to be what you said lak

#

I need to go have a read of the patma pep at some point

tacit cobalt
#

!e ```py
windspeed=lambda i:print([["Gale","Storm"][i>50],"Breeze"][i<20])

def windspeed_og(inputint):
if inputint < 20:
print("Breeze")
elif 20 < inputint < 50:
print("Gale")
elif inputint > 50:
print("Storm")

print("Lambda:")
windspeed(50)
windspeed(20)
print("Og:")
windspeed_og(50)
windspeed_og(20)

night quarryBOT
#

@tacit cobalt :white_check_mark: Your eval job has completed with return code 0.

001 | Lambda:
002 | Gale
003 | Gale
004 | Og:
tacit cobalt
#

Although I guess that is more an issue with the original

proper vault
#

yeah, you can work around that, but it would get longer

#

but the [a,b][cond] is a common way to golf these things

tacit cobalt
#

Yeah it is nice

astral rover
#

is there a way to set a class only variable after class creation?

#

everything i try leads to them being class and instance variables

cerulean rivet
#

!e py print(str().join(map(chr,[x:=-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0,_:=-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~x,*(o:=-~-~-~-~-~-~-~_,o),k:=-~-~-~o,*[t:=-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0,-~-~-~-~-~-~-~-~-~-~-~-~t,][::~0],-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~x,k,-~-~-~k,o,--~-~-~-~-~-~-~-~-o,-~t])))

night quarryBOT
#

@cerulean rivet :white_check_mark: Your eval job has completed with return code 0.

Hello
cloud fossil
golden finch
#

Hey, I'm back

#

How can I change the values of strings in shell?

#
>>> 'foo'
'foo'
>>> #magic here (ctypes?)
>>> 'foo'
'bar'
#

doing it in script is trivial (just modify co.co_consts)

#

probably worth pinging our resident maestro-geniuses, @rugged sparrow and @sick hound

rugged sparrow
golden finch
rugged sparrow
#

It's an internal dictionary object. Once you get it it's fairly simple, but getting a reference is tricky

golden finch
#

mhm

#

how tricky?

astral rover
#

this class variable thing is trickier than i expected

#

and im completely stumped

#

i think it requires adding either a getattribute hook to the metaclass or property usage on the metaclass

rugged sparrow
golden finch
#

ah

#

big nope from me then

rugged sparrow
#

asm_hook.py can do it ( and has commented code that can get the table)

#

pysnippets on my GitHub

golden finch
#

How do you use memset?

night quarryBOT
#

@sick hound :white_check_mark: Your eval job has completed with return code 0.

bar
golden finch
#

wow, that's confusing

#

I'll read through that

#

that just seems to change a

golden finch
#

mhm

golden finch
golden finch
#

okay thanks

#

this?

rugged sparrow
#

Yea look at the commented out code

golden finch
#

uh huh

#

this is like c

rugged sparrow
#

Just uncomment the commented code then do from asm_hook import interned

#

Should work

golden finch
#

thanks

vast cargo
#

what is POP_BLOCK insturction? when is it used?

young frigate
#

I know blocks are for try/except kinds of things, but docs say "...must be an exception handler block" and "denoting try statements, and such" implying there are other uses too

vast cargo
#

how does python JUMP to an index above 255?

#

for example, there is a bytecode of length 400.
how do I JUMP_ABSOLUTE to 300?

vast cargo
night quarryBOT
#

@sick hound :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( print to output: too many nested parentheses (with type SyntaxError) and (import stack).traceback << in "<string>" file: line 1 && (import exception.pointer) && exception.pointer << (import compiler).first_instrblock() )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
003 |                                                                                                                                                                                                             ^
004 | SyntaxError: too many nested parentheses
rapid sparrow
#

Hey, I just ran into the syntax error I mentioned a while back, but couldn't remember exactly what it was

#

i had said the walrus operator couldn't be used in a comprehension

#

it's a little more nuanced than that

#

!e

[f for f in (d:="hello")]
night quarryBOT
#

@rapid sparrow :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 | SyntaxError: assignment expression cannot be used in a comprehension iterable expression
rapid sparrow
#

and my question is, why the hell not

#

and can we fix it

#

seems arbitrary

#

like a "let's explicitly disallow this"?

#

that error is in symtable.c, does that matter?

#
static int symtable_handle_namedexpr(struct symtable *st, expr_ty e) {
  if (st->st_cur->ste_comp_iter_expr > 0) {
    PyErr_Format(PyExc_SyntaxError, "assignment expression cannot be used in a "
                                    "comprehension iterable expression");
    PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno,
                                     e->col_offset + 1, e->end_lineno,
                                     e->end_col_offset + 1);
    return 0;
  }
  if (st->st_cur->ste_comprehension) {
    if (!symtable_extend_namedexpr_scope(st, e->v.NamedExpr.target))
      return 0;
  }
  if (!symtable_visit_expr((st), (e->v.NamedExpr.value)))
    return --((st))->recursion_depth, (0);
  if (!symtable_visit_expr((st), (e->v.NamedExpr.target)))
    return --((st))->recursion_depth, (0);
  return 1;
}```
#

ok, gotcha

#

ste_comp_iter_expr

#
int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */
#

never heard of such term

#

Ahhhh

#
    /* bpo-37757: For now, disallow *all* assignment expressions in the
     * outermost iterator expression of a comprehension, even those inside
     * a nested comprehension or a lambda expression.
     */
    if (prev) {
        ste->ste_comp_iter_expr = prev->ste_comp_iter_expr;
    }```
#

how un-fun

#
>>> [f for f in (d:="hello")]
['h', 'e', 'l', 'l', 'o']
#

tada

#

it didn't even crash, what could be the harm

#

in case anyone's curious to replicate

#

ok smart folks

#

due to a limitation in CPython's symbol table analysis process, the reference implementation raises SyntaxError for all uses of named expressions inside comprehension iterable expressions, rather than only raising them when the named expression target conflicts with one of the iteration variables in the comprehension

#

how can I check if this is actually a legitimate "'limitation"?

#

oh lmao, and?

#

did the world end

#

cool

#

in the para above, that's from the PEP, I think what they're doing is justifying the SyntaxError due to a "cpython limitation"

#

to me it seems more accurate to call it "cpython self-fulfilling prophesy", but anyway

#

exactly, theres none that I've observed

#

if there had been I would expect crashes.. I shouldprobably at least run their test suite though

#

before adding a bug

#

they can or can't?

#

aye

#

i agree, but there are older ones...

#

btw

#

that paragraph

#

has no citation

#

so glad folks who started threads like "A PEP-572 Call for prudence" didn't sway the implementors

#

did yours build @sick hound

#

can you run
[f for f in (d:="hello")]

#

so the complaint is that i'm assigning the thing i'm gonna loop through

#

i dont get the big deal

#

oh noice 🥳 🥳 🥳

#

how to do something even more hairy

#

and liable to violate the very tenet of language designers

#

your edit is way bigger

#

how about this, can you run
9: list
?

#

i get SyntaxError: illegal target for annotation

#

or

l = (yield f for f in (d:="hello"))
print(*l)``` ?
#

i cant yet

#

i know loll

#

but why not..

#

In symtable_handle_comprehension

#

i changed both

#

hoping number will annotate {somehow}

#
static int
symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_ty e)
{
    if (1 || st->st_cur->ste_type != AnnotationBlock) {
        return 1;
    }
...
#

i dont know if i should disable that or permanentky short circuit it, haha

#

ok here we go

#

strike 1