#esoteric-python

1 messages ยท Page 129 of 1

rapid sparrow
#

opening

#

is it near yield_expr

#

maybe whatever comes after that? or maybe the problem is that nothing is supposed to follow it?

#

that looks kind of relevant as well

#

ahh the number annotation won't work either

#

because annotated expr starts with NAME

#

nooo my other change stopped working

rapid sparrow
#

Programs/_freeze_module importlib._bootstrap /data/media/0/src/python3/src/Lib/importlib/_bootstrap.py /data/media/0/src/python3/src/Python/frozen_modules/importlib__bootstrap.h Makefile:765: *** [Python/frozen_modules/importlib__bootstrap.h] Aborted (core dumped)

#

sometimes gotta be slapped to be sure changes are still happening

#

oh damn reslly?

#

what happens to them

#

how do you edit it?

#

do you have a python-aware/powered editor?

#

dang, why would my change not show up anymore

#

pyc cache?

#

mine is similarly unresuscitationable

#

i'm probably doing domeyhing stupid

#

like running the wrong progran

#

omg yes

#

i forgot to set RPATH on it

#

its using my system-installed libpython

#

that fixed it OMG

#

patchelf --set-rpath '$ORIGIN/:$ORIGIN/../lib/' build/python.exe

#

Syntax error

#

>>> [f for f in (d:="hello")] File "<stdin>", line 1 SyntaxError: assignment expression cannot be used in a comprehension iterable expression

#

ya

#

syntab.c and the file you told me to look at

#

have no idea what do do with it so i just started doing random changes, natural selection-style

#

lost? ๐Ÿ˜•

#

whycoz.. you have the source files still?

#

its just some dumb build issue

#

or run issue

#

im sure

golden finch
#

surely that can't parse, right?

cerulean rivet
#
brainfuck = [(sys:=__import__(SystemError.__name__[:-~-~-~0].lower())).setrecursionlimit(pow(_:=-~-~-~-~-~-~-~-~0,_)),(type(str().__add__(bin.__name__[0].__add__(range.__name__[:-~-~0]).__add__(int.__name__[:~0]).__add__(type(lambda:0).__name__[:-~-~0]).__add__(chr.__name__[0].__add__(KeyError.__name__[0]))),(),{(0).__init__.__name__:lambda s,c:(None,_:=lambda f,v:setattr(s,f.__name__[0],v),_(id,0),_(pow,0),_(chr,c),_(all,[0]),_(repr,[]),)[0],exec.__name__:lambda s:[lambda:0,lambda:[s._(s.c[s.i]),setattr(s,id.__name__[0],s.i.__add__(-~0),),s.exec()][~0]][s.i.__lt__(len(s.c))](),__import__.__name__[0]:lambda s,c:__import__(str().__add__(compile.__name__[:-~-~0].__add__(len.__name__[0].__add__(len.__name__[:~0].__add__(chr.__name__[0].__add__(TimeoutError.__name__[:-~-~0].lower().__add__(oct.__name__[0].__add__(next.__name__[0].__add__(str.__name__[0]))))))))).defaultdict(lambda:lambda:0,{chr(_:=ord(str(0)).__sub__(-~-~-~0)):lambda:[lambda:0,lambda:s.a.__setitem__(s.p,s.a[s.p].__sub__(-~0),),][s.a[s.p].__ne__(0)](),chr(_.__sub__(-~-~-0)):lambda:s.a.__setitem__(s.p,s.a[s.p].__add__(-~0)),chr(-~_):lambda:print(end=chr(s.a[s.p])),chr(_:=-~-~-~ord(str(-~-~-~-~-~-~-~-~-~0))):lambda:setattr(s,pow.__name__[0],s.p.__sub__(-~0)),chr(-~-~_):lambda:[lambda:[s.a.append(0),setattr(s,pow.__name__[0],s.p.__add__(-~0))],lambda:0,][s.p.__eq__(len(s.a))](),chr(_:=-~ord(zip.__name__[0].upper())):lambda:s.r.append((s.i,s.p)),chr(-~-~_):lambda:[_:=s.r.pop(),[lambda:0,lambda:[s.r.append(_),setattr(s,id.__name__[0],_[0])]][s.a[_[~0]].__gt__(0)]()]})[c]()}))][~0]
golden finch
#

I'm gonna be honest what does that do?

#

I see a lot of incrementing via unary

snow beacon
golden finch
#

or decrementing

#

neat implementation

#

I think you can actually get rid of the need for the - via int.__neg__

#

wait, no

#

that won't work because it contains .

#

use getattr then, perhaps

#

though your implementation does in fact contain [].-,

simple crystal
#

ya you can just use strs of code and exec them

snow beacon
#

Or you can store the functions in the dict.

rugged sparrow
snow beacon
#

I don't currently understand a lot of Cpython or bytecode โ€” I haven't bothered to learn โ€” so I can't really make those guides.

#

I should really bother to write some more guides as well.

#

Do you mean a preexisting one?

#

I don't care about duplicating things that already exist. People have a lot of knowledge in their noggins that isn't already out in the world, which is most important to share.

rugged sparrow
#
>>> interned['abc'] = 'magic'
>>> 'abc'
'magic'
>>> 'abc' is 'magic'
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
True
>>> ```
#

they do in 3.10

#

if they werent in 3.10 then the above code wouldnt have worked

#

PyAST_Optimize does it i think?

#
>>> interned['abc'] = 1
>>> 'abc'
1
>>> ``` ๐Ÿ‘€
#

!e ```py
from ctypes import util
from ctypes import *
import atexit

base_size = sizeof(c_void_p)
libc = cdll.LoadLibrary(util.find_library('c'))

PAGE_SIZE = libc.getpagesize()
MEM_READ = 1
MEM_WRITE = 2
MEM_EXEC = 4
ENDIAN = 'little' if memoryview(b'\1\0').cast('h')[0]==1 else 'big'

libc.mprotect.argtypes = (c_void_p, c_size_t, c_int)
libc.mprotect.restype = c_int

def mprotect(addr, size, flags):
addr_align = addr & ~(PAGE_SIZE - 1)
mem_end = (addr + size) & ~(PAGE_SIZE - 1)
if (addr + size) > mem_end:
mem_end += PAGE_SIZE
memlen = mem_end - addr_align
libc.mprotect(addr_align, memlen, flags)

def addr(cfunc):
ptr = c_void_p.from_address(addressof(cfunc))
return ptr.value

def hook(cfunc, restype=c_int, argtypes=()):
cfunctype = PYFUNCTYPE(restype, argtypes)
cfunc.restype, cfunc.argtypes = restype, argtypes
o_ptr = addr(cfunc)
mprotect(o_ptr, 5, MEM_READ | MEM_WRITE | MEM_EXEC)
mem = (c_ubyte
5).from_address(o_ptr)
default = mem[:]
def wrapper(func):
@cfunctype
def injected(*args, **kwargs):
try:
mem[:] = default
return func(*args, **kwargs)
finally:
mem[:] = jmp
n_ptr = addr(injected)
offset = n_ptr - o_ptr - 5
jmp = b'\xe9' + (offset & ((1 << 32) - 1)).to_bytes(4, ENDIAN)
mem[:] = jmp
@atexit.register
def unhook():
mem[:] = default
injected.unhook = unhook
return injected
return wrapper

@hook(pythonapi.PyDict_SetDefault, restype=py_object, argtypes=[py_object]*3)
def setdefault(self, key, value):
if key == 'MAGICVAL':
return self
return pythonapi.PyDict_SetDefault(self, key, value)

pythonapi.PyUnicode_InternFromString.restype = py_object
interned = pythonapi.PyUnicode_InternFromString(b'MAGICVAL')
setdefault.unhook()
interned['abc'] = 1
print(eval("'abc'"))```

night quarryBOT
#

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

1
rugged sparrow
#

no i don't

#

only works on unix based OS, intel x86 cpu (unless the assembly happens to be the same on other platforms)

rugged sparrow
#

it actually should work if you rewrite mprotect to use the windows api

rugged sparrow
golden finch
#

strange

thorny tapir
#

!e print(chr(ord(chr(ord(chr(ord("a")))))))

night quarryBOT
#

@thorny tapir :white_check_mark: Your eval job has completed with return code 0.

a
thorny tapir
#

not even esoteric but wtv

knotty delta
#

!e

from ctypes import c_void_p
class int2(int):
    def __add__(self, other):
        return self - other
c_void_p.from_address(id(int)+8).value = id(int2)

print(1 + 1)
print(int("1") - int("1"))
night quarryBOT
#

@knotty delta :x: Your eval job has completed with return code 1.

001 | 2
002 | Traceback (most recent call last):
003 |   File "<string>", line 8, in <module>
004 | TypeError: 'int2' object is not callable
knotty delta
#

hm?

#

!e

class test:
    ...
print(callable(test))
night quarryBOT
#

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

True
knotty delta
#

!e

from ctypes import c_void_p
class int2(int):
    def __add__(self, other):
        return self - other
print(callable(int2))
c_void_p.from_address(id(int)+8).value = id(int2)

print(1 + 1)
print(int("1") - int("1"))
night quarryBOT
#

@knotty delta :x: Your eval job has completed with return code 1.

001 | True
002 | 2
003 | Traceback (most recent call last):
004 |   File "<string>", line 9, in <module>
005 | TypeError: 'int2' object is not callable
knotty delta
#

oh nvm i probably don't want to use c_void_p

#

!e

print(callable(object))
night quarryBOT
#

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

True
knotty delta
#

hmm

velvet lichen
#

Is there a way to get the annotations of a function, where it is also includes untyped? I'm sure there's a way that combines __annotations__ with __code__, but all I can find in __code__ is the co_argcount, just the number of arguments or co_varnames, the names of all variables in the function, not just arguments?

#

e.g calling the function to get the annotations on this method

def test(x: int, y) -> float:

would return {'x': int, 'y': "", 'return': float} if the thing to indicate untyped was empty string.
I may just go with the inpect module, but I was sort of hoping to do it module-less

tacit cobalt
#

!e ```py
def test(x: int, y) -> float:
...

print({**{arg: None for arg in test.code.co_varnames[:test.code.co_argcount]}, **test.annotations})

night quarryBOT
#

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

{'x': <class 'int'>, 'y': None, 'return': <class 'float'>}
velvet lichen
#

Oh that's nice, thanks. So it always has the arguments first?

tacit cobalt
#

Yeah

velvet lichen
#

Great, thanks

astral rover
#
def test(x: int, y) -> float:
    ...

print(dict.fromkeys(test.__code__.co_varnames[:test.__code__.co_argcount]) | test.__annotations__)```might be more succinct if youre on 3.9+
velvet lichen
#

I haven't upgraded yet but that is very nice and I might as well upgrade now, so thanks, I'll use that.

earnest wing
knotty delta
velvet lichen
#

The one thing that the typing doesn't cover is the return dictionary element, but that will be fine to add

knotty delta
#

!e

from ctypes import c_void_p
class int2(int):
    def add(self, other):
        return self - other
c_void_p.from_address(id(int)+8).value = int2
print(1 + 1)
print(int("1") - int("1"))
night quarryBOT
#

@knotty delta :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 5, in <module>
003 | TypeError: cannot be converted to pointer
knotty delta
#

hm

velvet lichen
tacit cobalt
#

Docs say that

Note that None as a type hint is a special case and is replaced by type(None).
But

#

!e ```py
def test() -> None:
...

print(test.annotations["return"] == type(None))

night quarryBOT
#

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

False
tacit cobalt
astral rover
#

thats when you use

#

!d typing.get_type_hints

night quarryBOT
#

typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)```
Return a dictionary containing type hints for a function, method, module or class object.

This is often the same as `obj.__annotations__`. In addition, forward references encoded as string literals are handled by evaluating them in `globals` and `locals` namespaces. If necessary, `Optional[t]` is added for function and method annotations if a default value equal to `None` is set. For a class `C`, return a dictionary constructed by merging all the `__annotations__` along `C.__mro__` in reverse order.

The function recursively replaces all `Annotated[T, ...]` with `T`, unless `include_extras` is set to `True` (see [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated "typing.Annotated") for more information). For example:
tacit cobalt
#

I guess Aster should just replace all None type hints with type(None)

velvet lichen
#

Thanks

#

Also, is there a way to get the types from a types.Union? I did a dir of it and found nothing obvious, and apparently you can't create an instance of it

astral rover
#

__args__

velvet lichen
#

Nice, thanks again

velvet lichen
#

How might I get a class' dunder method to be a method of the metaclass it is derived from? (preferably without the dynamic code gen)

night quarryBOT
#

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

True
knotty delta
#

!e print(exec(compile('1<>2','a','exec',4194304)))

night quarryBOT
#

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

None
knotty delta
#

!d str.replace

night quarryBOT
#

str.replace(old, new[, count])```
Return a copy of the string with all occurrences of substring *old* replaced by *new*. If the optional argument *count* is given, only the first *count* occurrences are replaced.
knotty delta
#

๐Ÿค”

night quarryBOT
#
Command Help

!eval [code]
Can also use: e

*Run Python code and get the results.

This command supports multiple lines of code, including code wrapped inside a formatted code
block. Code can be re-evaluated by editing the original message within 10 seconds and
clicking the reaction that subsequently appears.

We've done our best to make this sandboxed, but do let us know if you manage to find an
issue with it!*

vestal solstice
#

your appointment to FEMA will be finalized within the week

earnest wing
#

!e print(exec(compile('1<>2','a','eval',4194304)))

night quarryBOT
#

@earnest wing :white_check_mark: Your eval job has completed with return code 0.

None
shadow carbon
#

Hey guys. Does anyone know how to program an event of detecting a windows toast notification?
I want python to detect a type of toast notification with specific keywords, etc to perform an action.

grave rover
#

cursed code screenshot of the day

rugged sparrow
#

are you using kotlins C integration to make C python modules?

grave rover
#

yes

#

and it's painful as heck

rugged sparrow
#

i can imagine

grave rover
#

I mean it definitely could be worse

#

it's mainly the fact that staticCFunction needs to be top-level

#

also strings are wacky

sullen glen
#

Hello

grave rover
#

o/

sullen glen
#

can anyone help me to get started with python

grave rover
#

wrong channel buddy

sullen glen
#

sorry

grave rover
#

crazy how people ask this channel of all places

rugged sparrow
#

its cause its active people ask in any channel that has activity

knotty delta
grave rover
#

I don't think you'd word it as "get started with python" in that case

pure dew
grave rover
#

yooo

grave rover
pure dew
#

working a lot lately

#

but i've been doing stupid stuff with python before that

#

doing some more work on my language vm now

grave rover
#

oh god don't remind me

pure dew
#

??

#

oh you'll like thjis

#

@grave rover and this too

class A:
    ...


@derive(Debug, Colorize)
@dataclass
class CFrame(A):
    x: int
    y: int
    z: int

    rx: float
    ry: float
    rz: float

    @classmethod
    def origin(cls) -> "CFrame":
        ...

    def add(self, other: "CFrame") -> "CFrame":
        ...

    def translate(self, x: int, y: int, z: int):
        ...

    @staticmethod
    def zero() -> int:
        ...


cframe = CFrame(23, 4, 12, 98.2, 110.2, 0.002)

print("Debug:")

print(cframe.fmt())

print("\nColorize:")

print(cframe.bright_green().on_black())

https://totally-not.a-sketchy.site/yQPacJK.png

#

trait system for python

earnest wing
#

oh god

pure dew
#

i discovered many unsafe ways of monkeypatching object

earnest wing
#

Blanket impls ohyeahwooyeahdance

grave rover
#

what the actual fuck

pure dew
#

lemon_scared ```py
def derive_all():
def format_wrapper(self):
return repr(self)

# WARNING: very sensitive - arbitrary things cause this to break
for _type in object.__subclasses__():
    if _type not in IMPLEMENTED_TYPES:
        if _type.__module__.startswith("traitor"):
            continue

        # print(f"{_type.__name__}: {_type.__module__}")
        impl(Debug >> _type)(type(f"Debug{_type.__name__.title()}", (object,), {"fmt": format_wrapper}))
#

this breaks on nearly every non-pure-python module

grave rover
#

I mean have you seen my port of spongepowered/mixin to python kekw

pure dew
#

i think so

earnest wing
#

unsurprisingly, c-implemented types mess up

pure dew
#

but i can patch c-implemented types

#

but the blanket impl breaks it

#

so I just implemented it for object and let inheritance cover my ass

grave rover
pure dew
#

and then something else breaks...
AttributeError: 'method' object has no attribute '__code__'

grave rover
#

I wonder if I could use kotlin-reflect to make py types from kt classes

pure dew
#

this here is fun too

>>> range(10).map(lambda x: Nothing if x % 2 == 0 else Just(x)).collect()
[Nothing, Just(1), Nothing, Just(3), Nothing, Just(5), Nothing, Just(7), Nothing, Just(9)]

>>> _.map(lambda m: m.fmap(lambda n: n + 2)).collect()
[Nothing, Just(3), Nothing, Just(5), Nothing, Just(7), Nothing, Just(9), Nothing, Just(11)]

grave rover
#

oh no

rugged sparrow
pure dew
#

fishhook, under the hood

#

but there's a whole bunch of nasty above it

if "__sentinel" not in self.target.__dict__.keys():
            sentinel = MethodSentinel(self.target)

            @wraps(self.target.__getattribute__)
            def wrapper(s, name):
                return sentinel(s, name)

            hook(self.target, "__sentinel")(sentinel)

            hook(self.target, "__getattribute__")(wrapper)

        getattr(self.target, "__sentinel").add_impl(self.trait, self.impl)
rugged sparrow
#

whats the nasty for? (what does MethodSentinel do)

pure dew
#

it replaces __getattribute__ and manages multiple traits and possible overlaps

#

if you have two traits with the same method implemented for the same type, it'll catch it and make you disambiguate

#

like Rust

rugged sparrow
#

ahh clever

#

would you want my smaller hook implementation instead of fishhook?

pure dew
#

and also handles rebinding of methods to the new instance

#

if it works, sure

#

if you ever wanted a trial by fire this is it lol

rugged sparrow
#

it should work

#

it toggles some type flags and lets python handle the inheritance (instead of how fishhook does it now)

pure dew
#

oh is this the posix-only thing?

rugged sparrow
#

no

#

*it shouldnt be

#

(also tbh i never tested fishhook on windows fyi)

pure dew
#

i dont know if i ever did or not

#

but i run linux so it doesnt really matter

#

this shouldnt be near a production machine to begin with

rugged sparrow
#

hahaha

pure dew
#

is this a drop-in for fishhook?

rugged sparrow
#

it doesnt have hook_cls, hook_cls_from_cls, or unhook cause i havent added those yet

pure dew
#

but hook(item, attr) should work the same?

rugged sparrow
#

ye

pure dew
#

ah, well, it segfaults

rugged sparrow
#

shoot

pure dew
#

python 3.9.5

rugged sparrow
#

hmmm

#

lemme test

pure dew
#

owait

#

this may be an issue with my code

rugged sparrow
#

haha

#

what hook segfaults it?

#

(also hook(cls, name, value) works with small_hook)

pure dew
#

its not so much the hook, but the recursive hooking

#

is that github file the same as what you sent earlier?

rugged sparrow
#

oh you dont need to hook recursively anymore cause small_hook handles inheritance right

#

yea

#

wait lemme check something

pure dew
#

oh

#

hooking into object breaks it

rugged sparrow
#

yup found the bug

#

gimme 5

pure dew
#

hooking into type does BadThingsโ„ข๏ธ

#

<unknown>RecursionError: maximum recursion depth exceeded while calling a Python object

rugged sparrow
#

@pure dew fixed the hook object bug (i needed to recursively allocate new structures)

pure dew
#

hrm

rugged sparrow
#

originally i only allocated structs for the passed in class, so python was writing to invalid memory when it attempted to handle subclasses

#

fishhook only works with this cause i did the subclasses myself (so it passed my struct check and allocate code)

pure dew
#

doesnt seem to work for me

rugged sparrow
#

still segfaulting?

pure dew
#

yes

#

but i've narrowed down the location and it makes no sense

rugged sparrow
#

what location

pure dew
#
from traitor.traits.debug import Debug
print("done with imports")

class A:
    ...

print("set up A")
#

it seems to break on the A

#

oh yeah its whenever i declare a class

#

how...

rugged sparrow
#

and your only hook is __getattribute__?

pure dew
#

only hook that overrides any possible existing entries, yes afaik

#

if I remove my object hook it works fine

rugged sparrow
#

but fishhook works?

#

thats bizzare

#

guess i need to work on small_hook more

pure dew
#

ah yeah fishhook does work

#

but i probably shouldnt have a blank implementation anyway lol

rugged sparrow
#

if i had to guess i would assume that small_hook only sets the generic tp_getattr while fishhook sets all of them

pure dew
#

as soon as i declare a class it segfaults

#

and thats with object hooked

#

i wonder if yours is trying to make the inheritance work too hard and screwing with A as its being setup

rugged sparrow
#

Internally fishhook and small hook should be doing the same things tho. Cause I wrote fishhook and small_hook from the same research

shut trail
#

Woah

#

How did you achieve changing builtins?

rugged sparrow
#

fishhook uses ctypes to change function pointers at runtime

pure dew
#

oh you wrote fishhook?

#

nice lol

rugged sparrow
#

yea lol last year

shut trail
#

I tried doing that but it didnโ€™t change the actual things itself

For example, I tried to overwrite int with a new class for c_void_p.address(id(int) + 8) but if I used integers like 2 and 3 they would still be an int

pure dew
#

overwriting literal types? now that is esoteric python

rugged sparrow
shut trail
rugged sparrow
#

c_void_p.from_address(id(2)+8).value = new_cls

pure dew
#

is it possible to overwrite the type of a literal tho?

#

not to just overwrite the type of 3, but change the type of any literal integer

#

without hardcoding infinite numbers

shut trail
rugged sparrow
shut trail
rugged sparrow
#

you can abuse inheritance

#

also what would your goal be?

shut trail
#

like if I want to add support for a certain dunder

rugged sparrow
#

then you should just hook int

#

wdym a new dunder tho

#

like adding __getitem__ to numbers?

shut trail
#

and how would you implement it by itself

#

where you take new literals to implement those methods

pure dew
#

oh well thats easy enough

#

just patch builtin int

#

but i mean doing where type(5) != int

shut trail
#

Without using a module like forbiddenfruit or fishhook

pure dew
#

you can't

#

but all they're doing is messing with C pointers

#

and it is pure python

shut trail
pure dew
#

i don't know, your best bet is to look at what they do

rapid sparrow
#

classic

#

you have to use C I expect

#

to fill the various Type "slots"

#

maybe it could be done in python if you are good at computing offsets..

rugged sparrow
#

^ thats what fishhook and small_hook do, they compute offsets at runtime

rapid sparrow
#

oh that's clever, so you translate __repr__ to wherever the tp_repr is?

#

on this monster

#

and somehow give it the right type

#

too bad there's two different meanings for slots

#

does it work the same whether it's a static or heap allocated type

rugged sparrow
#

fishhook computes the actual offset for tp_repr, small_hook lets python do it

rapid sparrow
#

wondering how python could be off any help

rugged sparrow
#

well i toggle the flag that python checks to forbid modifying static classes (so python thinks its a heap type class)

#

then i just setattr

#

and then i flip the flag back

rapid sparrow
#

oh so python already knows how to do it basically

rugged sparrow
#

it has to inorder for user defined classes to work

rapid sparrow
#

huh, never thought of that

#

so when's the third hooking package coming

#

maybe large_hook?

#

so when you do __dict__ on a type, it had to be all generated from whatever's on these slots?

rugged sparrow
#

sorta?

#

slot_wrappers have an offset attribute that can be used to find the C function they wrap

gilded spoke
#

what is escoteric-python?

snow beacon
#

Intentionally weird code.

#

Things like trying to write your code with as few characters as possible, or making 2 + 2 = 5.

#

I bet that's valid Haskell code, including the >>>.

#

Actually those quotes might not work.

pure hearth
still lily
#

Quick question, has anyone tried replacing and and or in bytecode with function calls? I need that for a project of mine and I wouldn't want to reinvent the wheel

#

So that expr_a and expr_b becomes f(expr_a, expr_b)

#

I guess I could rotate the stack slightly to avoid the pain of inserting LOAD_CONST before the left expr

#

yeah

#

I could load f right after JUMP_IF_FALSE_OR_POP, then ROT_TWO and insert CALL_FUNCTION after expr_b is on the stack I guess?

#

Right, yeah

#

I'm thinking I could use JUMP's destination to find the point where expr_b is on the stack

#

I wonder how much code relies on the short-circuit aspect of it tbh

#

Thanks for the help!

rugged sparrow
#

@still lily depending on when your code is executed to mutate the bytecode, expr_b may not be on the stack yet

#

But you can use the jump to determine the segment of bytecode that corresponds to expr_b and move it as a block

still lily
#

yeah, that's what I'm doing right now

#

I'm assuming the jump target stands right after expr_b is fully loaded

rugged sparrow
#

It should

still lily
#

So I'm inserting CALL_FUNCTION immediately before the jump target

#

Though that's probably going to mess up further jumps, now that I think about it

rugged sparrow
#

you need to use a decompiler and recompiler to make sure you dont break any jumps

still lily
#

Could I perhaps fix further jumps by keeping track of the replacements count? Each replacement should insert two instructions, so I'm thinking about incrementing every non-relative jump's target accordingly

#

That seems to have mostly fixed the issue

rugged sparrow
#

that will work in the meantime but you could still run into issues

still lily
#

yeah, it's a wonky endeavor

severe bison
#

hey

#

how do i hide blocked messages

#

in discord

#

using python

earnest wing
severe bison
#

where do i ask then

#

@earnest wing

mortal thorn
still lily
#

I'm toying around with a proxy-ish kind of thing for LINQ-like syntax in python, though there's a LOT of hoops to jump through for more complicated cases

#

The goal is to allow for things like this:

with collection.item as i:
    squares = collection.select(i ** 2).where(i < 10)
#

i is an instance of said proxy class that first stores every operation performed on it, and then performs the same set of actions on any object you pass to its protected __eval method

#

Common operations (attribute access, method calls, calling the proxy itself, operators, so on and so forth) are trivial, but things become way harder when it comes to and, or, passing it as a function argument, and some other cases

#

I've made it around and and or with bytecode manipulation (If you want to support correct evaluation of and and or, you apply a proxify decorator to the function this takes place in), and I have some ideas on how to allow mixing proxies together (i.attr(i.other_attr)), but I'll probably have to put strict limitations on passing proxies as function arguments

#

Funnily enough, this whole project started from an entirely unrelated AttributeIndexer mapping that would allow you to query a sequence of items via any of its attributes

fleet loom
#

I noticed that when I use 2to3 on the simple script print "foo", it converts it to python3 with a different print behavior. Example below:

$: cat myscript.py
print "foo",
$: python2 myscript.py
foo
$: 2to3 -w -n --add-suffix=3 myscript.py 
RefactoringTool: Skipping optional fixer: buffer
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: set_literal
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored myscript.py
--- myscript.py    (original)
+++ myscript.py    (refactored)
@@ -1 +1 @@
-print "foo",
+print("foo", end=' ')
RefactoringTool: Writing converted myscript.py to myscript.py3.
RefactoringTool: Files that were modified:
RefactoringTool: myscript.py
$: cat myscript.py3 
print("foo", end=' ')
$: python3 myscript.py3
foo $:

That is, without a trailing newline. The print behavior is clearly different, but this exact case is covered by tests in the source code: https://github.com/python/cpython/blob/main/Lib/lib2to3/tests/test_fixers.py#L500

Why would it be this way? What am I missing?

night quarryBOT
#

Lib/lib2to3/tests/test_fixers.py line 500

def test_trailing_comma_3(self):```
snow beacon
still lily
#

true, gotta check if the jump target is inside the block and if it's not, adjust it accordingly

sick hound
#

the hell is dis?

#

mf seg faulted python how?

bright hearth
sick hound
#

that scares me

bright hearth
#
[a for a in ().__class__.__class__.__base__.__subclasses__() if a.__name__ == 'function'][0]([a for a in ().__class__.__class__.__base__.__subclasses__() if a.__name__ == 'code'][0](0, 0, 0, 0, 0, 0, b'please explode now :)', (), (), (), '', '', 0, b''), {})()```
sick hound
#

when python starts looking like in line assembly you know your from hell.

bright hearth
#

This is actually way simpler than it seems.

#

As you probably know, everything is an object - this extends to functions.

sick hound
#

I know basic 32 assembly but shit tf is yall doing in here lmao

bright hearth
#

So if functions are a kind of object, then maaaybe there's a function constructor, right?

#

There is.

sick hound
#

your making me cry.

bright hearth
#

A function constructor requires a name, and a piece of raw bytecode to execute when the function is called.

#

Raw bytecode is also a kind of object, of the code class It has its own constructor.

#

To construct a code object, you need byte code as bytes - and some smol metadata about how to do the setup for executing it.

#

All the zeros and empty tuples and shit you see in this snippet are just metadata I've ignored or provided junk values to. Importantly, this tries to set up the code with a stack size of zero.

#

So this constructs code which will try to run with a zero size stack - and builds a function which will execute that code

#

then it calls the function.

#

Since there's no stack, it crashes instantly.

sick hound
#

then it is outside the stack

#

ok gotcha

bright hearth
#

b'please explode now :)' is actually a red herring. this is the bytecode which will try to execute, and the instructions are junk.

#

It doesn't matter what instructions you put here because the code will always crash on entry without even running the instructions.

sick hound
#

im trying to ask a question but keep reading and getting more confused

bright hearth
#

Oh right there's a bit of other weird shit here huh

#

() is an object - it's an empty tuple literal.

#

So it has a class

#

and that class has parent classes.

#

().__class__.__class__.__base__ is the object base class.

sick hound
#

I only understand the part where it makes stack zero then crash

bright hearth
#

So ().__class__.__class__.__base__.__subclasses__() is every subclass of the object base class

#

which includes both the function class and the code class.

#

I just do a list comprehension to find them.

#

So [a for a in ().__class__.__class__.__base__.__subclasses__() if a.__name__ == 'function'][0] will get you the function class.

#

Because it filters out classes whose name is equal to 'function'

#

Only one class has that function, so the list comprehension builds a list with only one element - the function class.

#

[0] just pulls it out of the list ofc, that's just regular list use

#

().__class__.__class__.__base__.__subclasses__() if a.__name__ == 'code'][0] does the same thing, but for the code class instead.

#

Finding them lets me call their constructors - which I need to do since I need to make a code object, and a function object.

#

Try it in repl

sick hound
#

holy hell man this is hard to understand

bright hearth
#

This might be easier to look at

sick hound
#

yeah it breaks in mine too

#

also that helps a bit

bright hearth
#

This one is really cool but a lot harder to explain and only works in some python versions

#
import random
class E(BaseException):
    def __new__(cls, *args, **kwargs):
        return 1
def a(): yield
a().throw(E)```
#

it only works in some versions because unlike my crappy little joke code, this is actually due to a legitimate bug in the Python interpreter.

#

I think it works up until 3.9

#

In later versions, it raises a TypeError saying that an instance of Exception was expected, not int.

#

In older versions, it segfaults due to a null pointer dereference.

#
def a(): yield```
This little function just constructs and returns a generator
#

This generator has no items, so as soon as you try to call next() on it you'll raise StopIteration.

#

Generators have a little-known feature called throw, which allows you to set up a generator such that the next time someone tries to get a value from it, an exception of your choice is raised.

#

Actually it might just throw from the iterator right away, it's a weird feature...

#
>>> a().throw(ValueError("Boo!"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in a
ValueError: Boo!
>>>```
tacit cobalt
#

!eval ```py
type(lambda:0)((lambda:0).code.replace(co_consts=()),{})()

night quarryBOT
#

@tacit cobalt :warning: Your eval job has completed with return code 139 (SIGSEGV).

[No output]
bright hearth
#

Anyways, the important thing is that an exception is raised from the generator builtin type's code.

#

And that code is written in C.

#

But in Python you can control __new__, which lets you write the code for making new objects of a particular class.

#

__new__ has to return an object. This object is then used as self for the __init__ method.

#

Anyways, you'll notice that this E class - which inherits BaseException, returns an int from __new__.

#

So even though the E class inherits baseException, actually calling the constructor returns an int.

#

So here's how the crash works:
generator.throw (which is written in C) calls the constructor to build a new Python Object. It then uses an attribute of this object.

#

generator.throw fails to actually check the type of the object it built (in fixed versions it checks and raises TypeError)

#

So it gets a pointer to python int, not a pointer to python BaseException.

#

It then tries to use a member of BaseException. And since the pointed object is a python int which doesn't have that member, this is invalid. Junk memory is accessed and it fatally dies.

tacit cobalt
#

!eval ```py
def a():yield
a().throw(type("E",(BaseException,),{"new": lambda*a:1}))

night quarryBOT
#

@tacit cobalt :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 2, in <module>
003 |   File "<string>", line 1, in a
004 | TypeError: calling <class '__main__.E'> should have returned an instance of BaseException, not int
bright hearth
#

Yup, that's how it should work.

#

Can you make the bot run the code in a specific version?

#

Try 3.5, I know it works in that.

tacit cobalt
#

!eval ```py
import sys
print(sys.version_info)

night quarryBOT
#

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

sys.version_info(major=3, minor=10, micro=0, releaselevel='final', serial=0)
tacit cobalt
#

Oh they updated

#

Works in 3.9.4 anyways

tired umbra
#

I feel like a beginner when I see this channel

#

anyways, esteric side of python looks cool

night quarryBOT
#

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

[No output]
tacit cobalt
#

Still works with 1114113 constants

knotty delta
#

what are you guys trying haha

#

on which version?

#

ooo

#

lets try python 1.9

#

ok nvm cant find it, lets use 1.6.1

#

possibly won't work on windows ๐Ÿ˜ข

#

๐Ÿ˜ฆ

#

guess the only way is to wsl

#

but i don't know how

#

that is python 1.6.1 lol

#

ooo

#

lets see is it a lot of constants were on 0.9.1 already ๐Ÿ˜ˆ

tacit cobalt
#

Still works with and

knotty delta
#
>>> sys.ps5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'sys' has no attribute 'ps5'
``` ๐Ÿ˜ฆ
#

there is no ps5

#

not yet

#

i'm still on 3.9

#

i dont have any c compilers now

#

are there some compiled binaries i can install

tacit cobalt
#

It actually just optimizes everything away and returns 0 so you end up with

  2           0 LOAD_CONST               1 (0)
              2 RETURN_VALUE
#

I tried with addition but it just does nothing

#

Or exceeds the maximum recursion depth

sleek sphinx
#

how do i get started with esoteric python this is my favourite channel in the whole server

earnest wing
#

you can also use any object that implements str for dynamic prompts

rugged sparrow
#

@sick hound with EXTENDED_ARG python can handle up to max 32 bit signed integer constants

#

Because internally the variable for oparg is 4 bytes

earnest wing
#

I was thinking terminal colors

knotty delta
earnest wing
#

Do that yourself

#

The prompt gets no direct info about the code executed.

pure dew
#

hook into sys and override the keyboard input code

#

read the line as its typed and highlight it

#

like how zsh highlighting works

rugged sparrow
#

You could hook sys.stdin

near gust
#

Is there a way to do slice assignment without using slice notation?

proper vault
#

!e

a = [1, 3, 6]
a[slice(2)] = [4, 6]
print(a)
night quarryBOT
#

@proper vault :white_check_mark: Your eval job has completed with return code 0.

[4, 6, 6]
rugged sparrow
grave rover
#

oh hey that;s basically pyasm

#

and uh

#

I'm actually almost done with my CFG impl

sleek sphinx
#

what is the opposite of golfing like making the most creative and long code to print hello world

grave rover
#

I think that's called code bowling

near gust
#

I'm working on a compiler that compiles Python (from bytecode) to another language that can call Python functions. However, the language has the exact reverse of Python bytecode call function semantics, so I would have to reverse a slice of the stack (or I could create another stack and do a bunch of transferring back and forth)

grave rover
#

is it lua

near gust
#

No, it's an esoteric language that I made that will scar you for life

#

I made both a compiler (to python) and interpreter (in pure Python)

#

Quite literally the compiled version can import any installed python module and push any Python function to the stack and call it with positional arguments

#

I'm doing this as a joke to prove that the language is turing complete because there are too many languages that use simple languages to prove turing completeness, so I'm deciding to make the entirety (with some limitations) of Python.

#

Wait a minute... It is already turing complete because it is a pda with at least 2 stacks with the ability to push, pop, rot2, rot3 and transfer between stacks

bright hearth
#

I'm pretty sure MS Word Autocomplete is turing-complete

#

You just have to have a human to "power" the turing machine by clicking the prompt which accepts the suggested change.

rugged sparrow
#

Yea

#

You can also overflow oparg with EXTENDED_ARG

astral rover
#

Why is the number of constants signed?

#

That just seems like a waste

bright hearth
#

I want -1 constants. When my code is defined, it undefines a constant located somewhere else.

rugged sparrow
#

ironically you can construct code that loads the -1 const

#

this ends up loading the size of the consts as a pointer to a py_object

#

(if you load -2 you get tuple)

#

!e py import dis f = lambda:None f.__code__ = f.__code__.replace(co_code=bytes([ dis.opmap['EXTENDED_ARG'], 255, dis.opmap['EXTENDED_ARG'], 255, dis.opmap['EXTENDED_ARG'], 255, dis.opmap['LOAD_CONST'], 254, dis.opmap['RETURN_VALUE'], 0 ])) print(f())

night quarryBOT
#

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

<class 'tuple'>
rugged sparrow
#

that is because internally, a tuple looks like this [ob_refcount, ob_type, ob_size, item0, item1, item...]

rugged sparrow
#

weird

#

i dont think it should crash (but i have no idea lol)

rugged sparrow
#

tbh wish i had found it sooner

snow beacon
sleek sphinx
#

nice

shadow dome
#

are there no metaclasses in there?

#

I think there's not even dynamic class creation... And I don't think there's really a way to contribute to a gh wiki...

bright hearth
#

have a slightly esoteric fizz buzz

#
_ = any(map(lambda n: (False, print((lambda n: (n, "fizz", "buzz", "fizzbuzz")[int(0 == n % 3) + 2 * int(0 == n % 5)])(n)))[0], range(100)))```
#

that is better

sick hound
#

any good guide on bytecode?

#

Im asking cause I have only come across this one

grave rover
#

Guess I'll try writing a guide later

maiden river
#

while studying lambda calculus, got an interesting idea, how about implementing it just using functions in python
like defining 'true' 'false' just using functions

and surprisingly i was successful in making gates and half adder, then a full adder and finally a 4 bit adder : )
i used 'l' for 1 and 'o' for 0

the aim was to implement binary logic from ground up, so can't use 1,0 because they are already reserved
(for fun and learning of course)

proper vault
#

yeah, that is pretty fun

#

there is however one difference in that python is strict, but lambda calculus is lazy

#

so you need a Z combinator instead of a Y combinator

maiden river
ruby briar
#

hello, i have an hw to do but i am big noob, can someone help me ?

proper vault
#

yup, that's the smart way

ruby briar
#

Write a program that asks to enter three integers defining a supposedly valid time (under
the form h, m, s) and that displays the time that it will be a second later.
Example: Donโ€™t you have the time? 15
What about the minutes? 59 And the seconds? 59
In a second, it will be 4:00 p.m. 0s.

proper vault
#

@ruby briarhello, we generally don't help with graded homework, though you are free to ask about specific parts of the solution.

strange basin
near gust
#

Python but you can only use list comprehensions

#

And all of the builtin types and functions except __import__, exec, and eval

#
  • All function calls must happen inside a list comp
  • lambdas (or iterables containing a lambda) cannot be assigned to a variable
#
  • Walrus is specifically allowed
#

Examples
Fib (in a single list comp)

[(a := [print(0), 0, 1]) if not i else (a := [print(a[2]), a[-1], a[-2] + a[-1]]) for i in range(10)]
grand tree
#
weights = [ 
    -73.0,  88.0, -11.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 
      0.0,   0.0,   0.0,  1.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 
      0.0,   0.0,   0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 
      0.0,   0.0,   0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 
      0.0,   0.0,   0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 
      0.0,   0.0,   0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 
      0.0,   0.0,   0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  2.0, 
     77.2,   0.0,   0.0, 70.0,  0.0,  0.0, 69.0, 80.0,  0.0, 83.0, 
     13.0,  83.1,   0.0, 76.9,  0.0,  0.0,  0.0,  0.0, 79.9,  0.0, 
      1.0, -88.0,  80.0, 83.0, 77.0, 69.0,  2.0 
] 
  
pos, transition = 0, [ -1, 1 ] 
epsilon, delta = (.001, 0.2) 
feedback = [] 
  
while weights[pos]: 
    weight = abs(weights[pos]) 
    transition[0] = int(weight) + ( 
            2 ** 5 - 1 if weights[pos] >= 0 else -1) + ( 
            weight - int(weight) + delta > 1.0) 
    transition[1] = transition[0] if abs( 
    weight - int(weight) - delta) < epsilon else 0 
    feedback.extend(transition) 
    pos = int(weight) 
  
print(''.join(chr(val) for val in feedback), end='') 
#

!e

night quarryBOT
#
Command Help

!eval [code]
Can also use: e

*Run Python code and get the results.

This command supports multiple lines of code, including code wrapped inside a formatted code
block. Code can be re-evaluated by editing the original message within 10 seconds and
clicking the reaction that subsequently appears.

We've done our best to make this sandboxed, but do let us know if you manage to find an
issue with it!*

grand tree
#

!e ```py
weights = [
-73.0, 88.0, -11.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0,
77.2, 0.0, 0.0, 70.0, 0.0, 0.0, 69.0, 80.0, 0.0, 83.0,
13.0, 83.1, 0.0, 76.9, 0.0, 0.0, 0.0, 0.0, 79.9, 0.0,
1.0, -88.0, 80.0, 83.0, 77.0, 69.0, 2.0
]

pos, transition = 0, [ -1, 1 ]
epsilon, delta = (.001, 0.2)
feedback = []

while weights[pos]:
weight = abs(weights[pos])
transition[0] = int(weight) + (
2 ** 5 - 1 if weights[pos] >= 0 else -1) + (
weight - int(weight) + delta > 1.0)
transition[1] = transition[0] if abs(
weight - int(weight) - delta) < epsilon else 0
feedback.extend(transition)
pos = int(weight)

print(''.join(chr(val) for val in feedback), end='')

night quarryBOT
#

@grand tree :white_check_mark: Your eval job has completed with return code 0.

001 | H๏ฟฝe๏ฟฝllo๏ฟฝ,๏ฟฝ ๏ฟฝw๏ฟฝo๏ฟฝr๏ฟฝl๏ฟฝd๏ฟฝ!๏ฟฝ
002 | ๏ฟฝ
near gust
#

!e

[bool(b := [1]) + bool(print([i for i in b if
    i < 1000 and (not b.append(i + 1)) and not
    [j for j in range(2, i) if not i % j]])) for _ in [1]]
night quarryBOT
#

@near gust :white_check_mark: Your eval job has completed with return code 0.

[1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
near gust
#

Pog

open grail
#

!e

night quarryBOT
#

@maiden river :white_check_mark: Your eval job has completed with return code 0.

001 | 0 XNOR 0 = 1
002 | 
003 | 
004 | Half Adder : 1+1 = 10
#

:incoming_envelope: :ok_hand: applied mute to @maiden river until <t:1634212383:f> (9 minutes and 59 seconds) (reason: newlines rule: sent 106 newlines in 10s).

last locust
#

!unmute @maiden river

night quarryBOT
#

:incoming_envelope: :ok_hand: pardoned infraction mute for @maiden river.

last locust
#

!paste

night quarryBOT
#

Pasting large amounts of code

If your code is too long to fit in a codeblock in discord, you can paste your code here:
https://paste.pythondiscord.com/

After pasting your code, save it by clicking the floppy disk icon in the top right, or by typing ctrl + S. After doing that, the URL should change. Copy the URL and post it here so others can see it.

last locust
#

Please use our paste service for sending large code ^^

maiden river
#

oh ok ๐Ÿ˜…

frank dome
#

print(print(print(print(print(print(print("hello world")))))))

royal sun
#

!e
print(print(print(print(print(print(print("hello world")))))))

night quarryBOT
#

@royal sun :white_check_mark: Your eval job has completed with return code 0.

001 | hello world
002 | None
003 | None
004 | None
005 | None
006 | None
007 | None
night quarryBOT
#

@maiden river :white_check_mark: Your eval job has completed with return code 0.

<function true at 0x7fe390028c10>
wintry island
#

Is there someone who would help me with this? (
For the given natural numbers a, b and c. Decide whether a2 + b2 = c2) Iam new to python, dont be mean thank you๐Ÿ‘‰๐Ÿ‘ˆ

fleet bridge
night quarryBOT
#

@fleet bridge :white_check_mark: Your eval job has completed with return code 0.

001 | True
002 | True
003 | False
velvet lichen
#

I was just messing with metaclasses and tried to make this. The issue is, despite it overriding the constructor and not throwing any errors, it does not print No "__init__"s!. I then tried exec-ing the string for the code in, but it did exactly the same thing. Does anyone know what is going wrong here?

def __init__(self):
    print("No \"__init__\"s!")

BLACKLIST = {"__init__": __init__}

class BlackListDict(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for i in BLACKLIST.keys():
            self.__setitem__(i, BLACKLIST[i])

    def __setitem__(self, k, v):
        if k in BLACKLIST:
            return
        super().__setitem__(k, v)

class Uninitializable(type):
    @classmethod
    def __prepare__(metacls, __name, __bases, **kwds):
        return BlackListDict(super().__prepare__(__name, __bases, **kwds))


class Test(metaclass=Uninitializable):
    def __init__(self, x) -> None:
        self.x = x

a = Test()
astral rover
#

its cause prepare shouldnt be a classmethod

#

its not ever called

velvet lichen
#

Oh, I thought it had to be?

#

What should it be instead?

astral rover
#

just a normal method

velvet lichen
#

Okay, I am now getting TypeError: Uninitializable.__prepare__() missing 1 required positional argument: 'bases' and I don't really understand what this error is trying to say. Do you think you could help?

#

I do think it is a classmethod, as everything worked when I did that except that it didn't print anything. It did overwrite the existing init like it was supposed to though, and I also looked it up and the first example was a classmethod

astral rover
#

i think the stubs for this might be wrong

earnest wing
#

self.__setitem__(i, BLACKLIST[i]) will not update the type object

#

but rather the namespace

astral rover
#

the namespace should be the 3rd arg to type.new right?

#
Test () {'__module__': '__main__', '__qualname__': 'Test'}
velvet lichen
earnest wing
#

actually, hold on

#

could it be the super() call in prepare

#

wouldn't just a return BlackListDict() work

astral rover
#

doesnt look like it

velvet lichen
#

I have just tried that now but it is still the same

earnest wing
#

oh, duh

#

your manual __setitem__ is triggering the filter

#

so __init__ is not getting set

velvet lichen
#

You are so right, thanks

#

It is good now

#

Presumably exec into a namespace also calls __setitem__? I had tried that, expecting that to catch any of the issues but it still had the same when I tried it

earnest wing
#

The namespace is populated as the class body is executed

velvet lichen
#

OK, thanks

near gust
#

I wonder how different it would be if new classes and new methods for classes couldn't be created it deleted at runtime

#

I bet there would be a lot more room for Python to be optimized

earnest wing
#

Well at that point you could do all mro work at compile time

grave rover
#

My disasm project is going perfectly fine

#

then boom
UNPACK_SEQUENCE

rugged sparrow
#

UNPACK_SEQUENCE trips it up?

grave rover
#

well uh

#

it pushes variables on the stack

#

and there will be multiple STORE_FASTs after it

#

which I need to somehow join together as x, y, z = TOS_before_UNPACK_SEQUENCE

golden finch
#

hey, I'm back temporarily

#

how can I get the size of the call stack in one expression?

#

without importing inspect

rugged sparrow
#

like how many frames there are?

golden finch
#

yeah

#

equivalent to ```py
len(import('inspect').stack())

grave rover
#

I mean op, arg = unpack("BB", op[:2]) is UNPACK_SEQUENCE(2) STORE_FAST(arg) STORE_FAST(op)

#

but right now I'm stuck on figuring out how to convert my CFG to a tree view without breaking everything

#

no I mean like

#

right after

#

BUILD_TUPLE UNPACK_SEQUENCE isn't the issue since my decompiler handles it just fine

#

it's the multiple STORE_FASTs I had trouble with

golden finch
#

@rugged sparrow you there?

rugged sparrow
#

you can just traverse the stack frames

#

and count

golden finch
#

I'm not sure how to do that

#

it has to be an expression

rugged sparrow
#

do you have sys?

grave rover
#

more or less
but it's annoying to work with when you only know a variable "x" is on the stack and UNPACK_SEQUENCE has oparg 3

golden finch
rugged sparrow
#

one sec

#
(f:=sys._getframe())and len([(f:=f.f_back)for _ in iter(lambda:f, None)])
golden finch
#

How does that work?

rugged sparrow
#

first it stores the current frame into f

#

then it uses iter(func, flag) to call lambda:f until it returns None

#

and on each iteration, it sets f to f.f_back

golden finch
#

I see

#

and then the and len gets you it as an integer

grave rover
#

@rugged sparrow wanna help me out real quick? I've got the blocks from the CFG, but now I need to turn it into a tree view (or something) to know what the stack is for each block, without having to potentially process blocks twice somehow

#

but child nodes also need to know both branches that point to them I think

rugged sparrow
#

@grave rover I can help when I get home

grave rover
#

sure thing

#

it's 2 AM for me rn so I'll be heading off to bed then :)

rugged sparrow
#

Ping me tomorrow then we can work on it then

grave rover
#

๐Ÿ‘

sick hound
#

should probably fix the aspect ratio but also too lazy to lol

sick hound
#

yep it is

keen sierra
#

The following code is run in IDLE:

while True:
  action = input(" > ")
  if not action.isalnum():
    print("Unsafe input.")
  elif action not in functions:
    print("Not found.")
  else:
    exec(action + "()")
    break

Is it possible to run malicious code on this program through the exec?

sick hound
#

I don't see a way it would be, but you're probably better off with:

functions = {
  "somefunction": somefunction
  # ...
}
while True:
  action = input(' > ')
  if action not in functions:
    print('Not found.')
  else:
    functions[action]()
    break
keen sierra
sick hound
#

if you only allow alphanumeric characters then I guess it does work as so

if you didn't check it against functions, I think the worst that could happen is a SyntaxError

keen sierra
#

Yeah, isalnum should make it fully safe from anyone trying to run malicious code

thin trout
#

well, exit is a first problem

sick hound
#

but it's being checked from a predefined list

keen sierra
#

^ And exit won't be there

sick hound
#

"fully safe" is maybe an overstatement
I can't think of anything though that doesn't depend on breaking the runtime itself, and those would probably apply to normal programs

keen sierra
sick hound
#

just dump 1 gb of text on it lol

keen sierra
#

You can only input stuff on that idle screen

#

You'd need to go to a different screen to copy the stuff lol

sick hound
#

hmmm

keen sierra
#

Also, ctrl+c isn't allowed either

sick hound
#

but is ctrl+d

#

that would raise an EOFError probably

keen sierra
#

Uh, any stuff involving ctrl+something instead of inputting stuff and pressing enter is not allowed

thin trout
#

you should use services like that to use eval in a safe way

sick hound
#

we're trying to break it

keen sierra
#

Haven't needed to use eval so far

keen sierra
thin trout
#

to break snekbox?

thin trout
#

right

keen sierra
#

Is snekbox breakable?

thin trout
#

maybe

#

two people broke it in the past

keen sierra
#

snekbox is actually useful though

sick hound
#

it's hard to prove otherwise, so

keen sierra
#

this code example ^^ is pretty much useless, but can't be broken even though it uses exec

sick hound
#

only way it could be safe is to make your own python implementation without access to system stuff

keen sierra
#

You need _ and .

#

brackets

sick hound
#

mm I think just because of the checking against the list it's already probably impossible to exploit it with these conditions

earnest wing
#

If it used deny- rather than allow-filters, there would at least be a chance :>

near gust
#

But if you try to do anything, it usually segfaults

#

Source: I've tried messing with that stuff before

#

The object at the id of an object + 8 is the __class__ of the object

#

You can turn an empty tuple into a list this way

wooden badge
#

can someone teach me the basics of esoteric python?

#

ie making python bend to your will

wooden badge
grave rover
#

@rugged sparrow lmk when you're available :)

rugged sparrow
#

@grave rover what was the reason you wanted to build the tree again? Was it to check stack state?

grave rover
#

it was to pass the current stack to both branches

#

if you have e.g. LOAD_CONST(1) LOAD_FAST(some_bool) POP_JUMP_IF_FALSE() then both branches need to know the 1 is there

#

and if you just parse it sequentially it won't know it exists

cloud fossil
#

Do you actually code in Python byte code?

grave rover
#

occasionally

#

but right now I'm trying to make a decompiler

cloud fossil
#

How do you run Python byte code on Windows?

rugged sparrow
bright hearth
#

Python source just gets compiled into bytecode

#

So you just use the interpreter. You can bind bytecode to a function and call the function, exec it in place with exec(), whatever

#

exec() can take a code object, not just python source as a str

#

To construct a code object, you just call the code class's constructor. It takes the raw bytes of instructions as a bytes object, and some metadata.

near gust
#

When the code for a module gets compiled, the .pyc file contains a header and then a marshalled code object which contains the code for the module

bright hearth
#

compiling expensive, caching good

near gust
#

In that code object are the bytecode, constants (that can contain more code objects), flags, stacksize, etc.

#

And you need all 16 parameters of the constructor for the code object to be able to effectively code in bytecode

#

After working with some esoteric languages, programming in bytecode feels like a breeze

bright hearth
#

Yeah ( is pretty tricky to get working nice

near gust
#

I wonder how many ways there are to segfault the interpreter

#

There are a lot

bright hearth
#

Since bytecode can be executed directly, I imagine as many ways as there are to segfault at all

#

So in a way there's exactly one way to segfault the interpreter nice

#

Violate segmentation.

grave rover
rugged sparrow
#

Branches should just be anywhere where the instruction pointer can be 2 different values after the opcode

cloud fossil
#

Hey @bright hearth can you write a Hello World program in byte code and send it here?

grave rover
earnest wing
night quarryBOT
#

@earnest wing :white_check_mark: Your eval job has completed with return code 0.

001 |   2           0 LOAD_GLOBAL              0 (print)
002 |               2 LOAD_CONST               1 ('Hello, world!')
003 |               4 CALL_FUNCTION            1
004 |               6 POP_TOP
005 |               8 LOAD_CONST               0 (None)
006 |              10 RETURN_VALUE
cloud fossil
#

Alright but whither can I write this byte code and run it

grave rover
cloud fossil
#

No problem. Friend helps friend.

grave rover
#

(note: the pip install does not work yet)

rugged sparrow
grave rover
#

wha?

rugged sparrow
#

like each block has a calculated bytes object thats something to represent the resulting stack (up until a branch)

grave rover
#

hmm...

rugged sparrow
#

or you could represent the stack as its own tree

#

(which wouldnt be efficient cause it should have the same structure as the block tree)

grave rover
#
n = 0

if ((2 * (offset + n)) < len(self.code)):

op = self.code[(2 * (offset + n)):]
op, arg = unpack(BB, op[:2])
n = (n + 1)



    current = (current + ( if (op >= 90) else 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]):

                continue_or_break
                continue_or_break

    return
#

not a terrible start so far

#

original function: ```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
#

I wonder what's making the indents so wacky

rugged sparrow
#

current = (current + ( if (op >= 90) else stack_effect(op))) what happens here?

grave rover
#

wait why is that first part missing

#

the heck

#

oh wait I see

#

right

#

uhhh

#

crap

#

the problem is that that if-else expression is modified in two different branches

#

attempt 2: py n = 0 if ((2 * (offset + n)) < len(self.code)): op = self.code[(2 * (offset + n)):] op, arg = unpack(BB, op[:2]) n = (n + 1) current = (current + (stack_effect(op, arg) if (op >= 90) else 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]): continue_or_break continue_or_break return

#

I think this is actually correct

#

only the continue_or_break is left to figure out

#

aand done

sick hound
#

hello

grave rover
#

hello

grave rover
#

oh no I have to build classes now

grave rover
#

yeah I made it a lot simpler now

#

what is that disassembler func

grave rover
#

listcomps are pain

astral rover
#

what about type is variably sized so that it doesn't allow slots?

rugged sparrow
#

@sick hound link to your decompiler?

rugged sparrow
astral rover
rugged sparrow
tacit cobalt
#

!e ```py
type(lambda:0)((lambda:0).code.replace(co_code=b"t\x00d\x01\x83\x01\x01\x00d\x00S", co_consts=(None, "Hello, World!"), co_names=("print",)), {})()

night quarryBOT
#

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

Hello, World!
tacit cobalt
#

!e ```py
type(lambda:0)((lambda:0).code.replace(co_code=b"t\x00d\x01\x83\x01S", co_consts=(None, "Hello, World!"), co_names=("print",)), {})()

night quarryBOT
#

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

Hello, World!
tribal moon
night quarryBOT
#

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

Hello, World!
bleak ermine
#

If you have a class attribute assigned to a function like so:

class someObject:
  def __init__(self):
    self.func = self.someFunction

  def someFunction(self):
    pass

And you get the value of self.func and call it like so:

self.func()

Does it run the someFunction() or does it try to look for a method named func()?
Is there any reasoning behind this, like how does Python decide what it should do?

#

Oh, possible to have it call someFunction() by using the variable?

#

oh wait

#

can you do

#

(self.func)()

sick hound
#

You know wha I find esoteric ? Lighting up a lamp through watering plants by IoT using PYTHON !
https://youtu.be/XW17p62AQa4

๐Ÿ”— Useful Links
โœ…Tuya IoT platform: https://auth.tuya.com/?_source=d721577c86dbfae18cfcf69f43aa09bb
โœ…Cloud project quick demo: https://iot.tuya.com/cloud/?code=1234&_source=0ddb6af98c5593b28623464e580df9b7

๐Ÿ“šAbout
This video shows you a DIY IoT Plant watering reminder system through Tuya IoT gadgets and Tuya Cloud platform using Python. We use th...

โ–ถ Play video
honest locust
#

is this the right place to talk about python code?

night quarryBOT
#

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

True
acoustic gust
#

!e print(bool(1))

night quarryBOT
#

@acoustic gust :white_check_mark: Your eval job has completed with return code 0.

True
grave rover
#

I'm in pain that you can say that so easily PainPeko

#

What the heck

rapid sparrow
#

iot has gone mainstream.. it might have sold its esoteric card by now

#

"Alexa, write some esoteric Python"

pure dew
#

iot isnt really esoteric at all

spring depot
#

!e
type(lambda:0)((lambda:0).code.replace(co_code=b"d\x01F\x00d\x00S", co_consts=(None, type('',(),{'repr':lambda x:"Hello, World!"})())),{})()

night quarryBOT
#

@spring depot :white_check_mark: Your eval job has completed with return code 0.

Hello, World!
normal vortex
#

hi

#

pff

gusty hill
#

is it possible to replace None with 1, for example when a function doesn't have a return type it returns 1 instead of None

cloud fossil
#

You can do that with a decorator

#

Or put return 1 as the last line in the function

gusty hill
#

I mean with an esoteric way, using ctypes or something

rugged sparrow
night quarryBOT
#

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

001 | yeet
002 | 1
gusty hill
#

Oh wow thank you

grave rover
#

note: that replaces None everywhere in the function and may lead to strange results

steady lily
#

a script that decodes base64 without importing base64?

tribal moon
#

!e ```py
import binascii

print(binascii.a2b_base64(b"aGk="))```

night quarryBOT
#

@tribal moon :white_check_mark: Your eval job has completed with return code 0.

b'hi'
steady lily
night quarryBOT
#

@steady lily :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 2, in <module>
003 | TypeError: 'ModuleSpec' object is not callable
steady lily
#

this worked on my ide

astral rover
#

!e

import binascii
print(getattr(binascii, dir(binascii)[8])(b"SGVsbG8gV29ybGQh="))
night quarryBOT
#

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

b'Hello World!'
steady lily
#

im running 3.9.0

astral rover
#

im on 3.10 and that worked for me

#

and so is the python bot now apparently

grave rover
#

!e py b64decode = lambda t:(lambda l:''.join(chr(int(l[i:i+8],2))for i in range(0,len(l),8)))(''.join(format('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.index(c),'06b')for c in t.strip("="))) print(b64decode("aGVsbG8gd29ybGQh"))

night quarryBOT
#

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

hello world!
grave rover
#

@steady lily

steady lily
#

woah

#

wth this channel is on another level

grave rover
steady lily
#

i think esoteric python is the coolest thing and shows a mastery in the language

night quarryBOT
#

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

001 | yeet
002 | 1
sick hound
#

Someone should write a c compiler in pure python

#

What?

#

i feel like doing unspeakable things in python, where can i get started?

#

Start by learning dirty tricks

#

Like defining multiple variables in one line and using lambda

#

Or idk some weird math to make code go brrr

sick hound
night quarryBOT
#

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

[No output]
sick hound
#

I don't do esoteric programming for just making code look weird, I just like less lines and chars

#

Unlike these guys who are crazy segfaulting python

#

This is new

#

Perfect

shut trail
#

I would start on messing with the call stack muhaha

#

acutally that's a bad place to start

#

i would start on learning bytecode / messing with inspect

iron hedge
#

ImportError: cannot import name 'handle_database_command' from partially initialized module 'src.utils.handle_database_command' (most likely due to a circular import) why am i getting this error (this sounds really generic, but i've no idea of what code should i send to help you to answer me)

iron hedge
#

oh okay

#

im sorry

floral meteor
#
>>> {*[2+(int)(Math.random()*6)+(int)(Math.random()*6)for fart in range(100000)]}
{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
>>> 
#

rolling two dice in Java, just gotta make sure in python tho

#

me: writing in Java
Java: sucks
me: rewrites Java in python in order to test Java code
Java: successfully debugged

rapid sparrow
tepid otter
#
x = [1, 2, 3] # (this being an example list-- any works)
y = [x[-1], *([0]*(len(x)-1))]
exec('i = 1;' + 'y[i] = x[i-1]; i += 1;'*(len(x)-1))
print(y)

not terribly esoteric compared to what ive done before, but i was just asked to help someone rotate a given list to the right without any loops, list methods or what have you (obviously * is technically iteration, but its notfor or while, and indexing is technically __getitem__ but its not explicit) and i just thought the resulting code was ugly in a funny way

smoky palm
#

!ban ConnnorS.

pliant current
#

hi

#

i been messing around:
rukidding = 1 and True is not False in [bool, str, True]

#

yes = True if None is not True else False

#

silly i know

#

butwait = 1 in list(range(2)) if 'more' in 'lessismore'.split() else None or True

earnest wing
#

True in [True] in [True]

#

(False)

pliant current
#

i've seen that ^, very confusing - in any rate it shouldn't be code

#

great = 1 or 4 if len('idontneedthis'.split()) == 10 else lambda y: y + 1 if y + 2 < 4 else 5

pliant current
earnest wing
#

It desugars to True in [True] and [True] in [True]

pliant current
#

I see

earnest wing
#

Because in is a comparison op like >=

pliant current
#

are = lambda x:{take:= x in range(x * 2) and 42 }.union(range(2))

snow beacon
grave rover
#

look at the C code mostly

#

where next_instr is a _Py_CODEUNIT*

#

After everything is turned to bytecode it calculates the offsets and puts it in the bytecode

#

fun fact, if your bytecode jumps more than 8.6GB worth of bytecode the compiler won't be able to handle it because EXTENDED_ARG can only be used 3 times, making the max jump 2^32 instructions or 2^33 bytes

near gust
#

!e

print (([]==[])<<-~-~([]==[]))
night quarryBOT
#

@near gust :white_check_mark: Your eval job has completed with return code 0.

8
wooden badge
#

this is awesome! is there more?

#

!e print([ox_for x in bananas])

night quarryBOT
#

@wooden badge :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     print([ox_for x in bananas])
003 |            ^^^^^^^^^^^^^^^^^^^
004 | SyntaxError: invalid syntax. Perhaps you forgot a comma?
wooden badge
#

hmm

#

!e import sys print(sys.version)

night quarryBOT
#

@wooden badge :white_check_mark: Your eval job has completed with return code 0.

3.10.0 (default, Oct  6 2021, 00:08:37) [GCC 8.3.0]
wooden badge
#

that makes sense

worldly musk
#

Is it possible to make this work? lemon_thinking ```py

from ctypes import py_object
py_object.from_address(id(True)+8).value = False
True
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
PS C:\Users\me>```

rugged sparrow
#

!e print([0x_for x in bananas])

night quarryBOT
#

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

[15]
wooden badge
#

ohh right, i used ox instead of 0x

#

!e print([0x_for x in (()==()+()==())*print(e**3.12)*()==[]==()])

night quarryBOT
#

@wooden badge :white_check_mark: Your eval job has completed with return code 0.

[15]
wooden badge
#

!e print(()==()+()==()*()==()+(()==()+()==())+(()==()+()==()))

#

!e print(()==()+()==()*()==()+(()==()+()==())+(()==()+()==()))

night quarryBOT
#

@wooden badge :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: can't multiply sequence by non-int of type 'tuple'
wooden badge
#

!e print((()==())+(()==())+(()==()))

night quarryBOT
#

@wooden badge :white_check_mark: Your eval job has completed with return code 0.

3
forest plaza
#

not sure if this count but I find it funny:

#

!e

class A():
  def __init__(self,a):
    self.a=a
    
    class B():
      c=a
      def __init__(self,a):
        self.a = a
  
    self.b=B(self.a)
    self.c=B(self.a)
    
x=A('a')
y=A('b')
x.b.__class__.c = 'aa'
print(x.c.c)
print(x.c.__class__)
print(y.c.c)
print(y.c.__class__)
night quarryBOT
#

@forest plaza :white_check_mark: Your eval job has completed with return code 0.

001 | aa
002 | <class '__main__.A.__init__.<locals>.B'>
003 | b
004 | <class '__main__.A.__init__.<locals>.B'>
forest plaza
#

its different classes but if I print __class__ I get the same output

#

I guess the <locals> hides some of the details?

snow beacon
wooden badge
snow beacon
#

I hope I inspire people to make better guides.

near gust
#

!e

list(range(100000000000))
night quarryBOT
#

@near gust :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | MemoryError
near gust
#

pog

grave rover
potent comet
#

It doesn't no, In Python 2 it was. To help users in switching there's a special case message to suggest the fix.

rapid sparrow
#

if print can be either a function or not in python 2, does that mean it's a keyword?

potent comet
#

It's a keyword normally, but the function always exists (you can see it in the builtins module), using globals() etc.

#

The __future__ flag changes behaviour inside the parser and compiler so it is or is not a keyword.

sick hound
#

You guys have a bot that runs code right?

#

I wonder if it's possible to escape the this with some weird tricks

#

Get it to @ someone or trigger a command as admin lmao

night quarryBOT
sick hound
#

Damn that sounded fun tho

#

Does it read for specific cases?

#

Like if I putbit in hex or a weird thing

#

Does it just have that check at the end to see if it contains that character?

rugged sparrow
#

it just checks at the end

sick hound
#

Ahh ok

vast cargo
#

any reference how to calculate EXTENDED_ARG?

#

also is this the right channel to ask this question?

#

oparg is byte?

#

or an 32 bit integer?

last locust
#
class MyInt(int):
    """Custom `int` representiation with a `__iter__` method."""
    ...
```is there a way I can make python default to using `MyInt` instead of `int` for integers? I currently have to do like `for x in MyInt(3)` etc. but I'd like to be able to do just `for x in 3:`
rapid sparrow
last locust
#

I assume there's some ctypes hackery

rapid sparrow
#

yes

#

actually it could be trickier than I thought. are you wanting all ints to be MyInt or just new ones created after your program starts

rapid sparrow
#

that's beyond by wheelhouse, then ๐Ÿ˜…

thin trout
#

don't ask me how though

rapid sparrow
#

for x in 3? are ints even iterable in unmodified python?

thin trout
#

!e iter(42)

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 | TypeError: 'int' object is not iterable
twin dock
thin trout
#

nothing is immutable for forbiddenfruit

twin dock
#

!e setattr(int, "iter", None)

night quarryBOT
#

@twin dock :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: cannot set '__iter__' attribute of immutable type 'int'
rapid sparrow
#

lol ๐Ÿคฃ

thin trout
#

!e

from forbiddenfruit import curse


def hello(self):
    return "blah"


curse(str, "hello", classmethod(hello))

assert str.hello() == "blah"
night quarryBOT
#

@thin trout :warning: Your eval job has completed with return code 0.

[No output]
thin trout
#

see?

rapid sparrow
#

how does it defy forbiddenfruit..

twin dock
#

oh nice

thin trout
#

!e

from forbiddenfruit import curse

def hello(self):
    for i in range(4): yield i


curse(int, "__iter__", classmethod(hello))

for i in 36:
    print(i)
night quarryBOT
#

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

001 | Traceback (most recent call last):
002 |   File "<string>", line 7, in <module>
003 |   File "/snekbox/user_base/lib/python3.10/site-packages/forbiddenfruit/__init__.py", line 425, in curse
004 |     _curse_special(klass, attr, value)
005 |   File "/snekbox/user_base/lib/python3.10/site-packages/forbiddenfruit/__init__.py", line 319, in _curse_special
006 |     assert callable(func)
007 | AssertionError
thin trout
#

oh, that's interesting

twin dock
#

seems pretty immutable to me

thin trout
#

oh, I am stupid that's it

#

!e ```py
from forbiddenfruit import curse

def iter(self):
return iter(range(self))

curse(int, "iter", iter)

for i in 5: print(i)```

night quarryBOT
#

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

001 | Traceback (most recent call last):
002 |   File "<string>", line 6, in <module>
003 |   File "/snekbox/user_base/lib/python3.10/site-packages/forbiddenfruit/__init__.py", line 425, in curse
004 |     _curse_special(klass, attr, value)
005 |   File "/snekbox/user_base/lib/python3.10/site-packages/forbiddenfruit/__init__.py", line 332, in _curse_special
006 |     tp_as_name, impl_method = override_dict[attr]
007 | KeyError: '__iter__'
thin trout
#

interesting

twin dock
#

Not even close

thin trout
rapid sparrow
#

o.O

twin dock
#

Meh

thin trout
last locust
thin trout
#

yup

near gust
#

The fact that forbidden fruit can even exist shows why Python needs to look up attributes every time they are accessed

thin trout
#

yup

near gust
#

If python did not need to do so much lookup, it would be a lot faster, but that's the price you have to pay to be able to create new classes and attributes at runtime

#

I believe I've only used the creation of new classes at runtime for non-esoteric reasons only a handful of times, and all of them were named tuples

#

And for adding methods at runtime, I only used once in a discord bot because I had many (like 75) slash commands that took the same form. So I stored the command info in named tuples and added a method to the cog for each instance of the special named tuple class. And it somehow worked

thin trout
rugged sparrow
#

@last locust fishhook can hook all dunders

rugged sparrow
thin trout
#

oh nice

#

didn't know about that one

rugged sparrow
#

I got frustrated with forbiddenfruits limitations so I wrote my own lib, fishhook is the result

last locust
thin trout
#

lmfao

rugged sparrow
night quarryBOT
last locust
#

So ig```py
@hook(int)
def iter(self):
...

for x in 5:
print(x)```?

rugged sparrow
#

Yes

last locust
#
from fishhook import hook

@hook(int)
def __iter__(self):
    yield from range(self+1)


for x in 5:
    print(x)
```perfect, thanks @rugged sparrow ๐Ÿ‘
rugged sparrow
#

No prob

restive void
#

Finally, loose typing in Python! :D

@hook(str)
def __add__(self, other):
    if isinstance(other, str):
        return orig(other)
    return self + str(other)
#

And the inverse of str.__mul__ is possible, too, amazing <3

rugged sparrow
#

type(obj).__sizeof__(obj) works on all objects. obj.__sizeof__() fails if obj is a class

#

wdym?

#

what other dunders would there be?

#

which tp_* slots can fishhook not hook?

#

__mro__ isnt a function tho?

#
>>> from fishhook import *
>>> @hook(int)
... def __dir__(self):
...     print('hooked')
...     return orig(self)
... 
>>> v = dir(1)
hooked
>>> ```
#

fishhook can still hook it

#

generate_slotmap() is only needed for dunders that exist as tp_* function pointers. __dir__ (and others) are just a dictionary lookup

#

yea thats what .__subclasses__() uses to get the currently active subclasses

rugged sparrow
#

it doesnt need to, they are implemented by the same tp_* slot

#

yea

#

yea

steady lily
#

I found this online and it gives the square root of 17. How do all those symbols give you a number?

__=((()==[])+(()==[]));___=(__**__);____=((___<<___));_____=((____<<(__**__)));______=((_____<<(__**__)));
_________=((___<<_____));__________=((((___<<_____))<<(__**__)));_=((__**__)+(______<<(__**__)));_______=(__**__)
for ________ in range((_____+(_________<<(__**__))+(__________<<(__**__)))):
    _______=_______-((_______**((___<<___))-_)/(((___<<___))*_______))
print(_______)
#

Is there an online guide of some sort or a video?

last locust
#

Well at the begging there'spy __=((()==[])+(()==[]))this evaluates topy __ = (False + False)which ispy __ = 0 + 0or justpy __ = 0

#

Then there's a load of stuff which is basically just that repeated but with different symbols (e.g. ** which is exponent)

#

That gives a bit of an insight @steady lily

scarlet osprey
#

hey everyone. a friend of mine has been sent a token stealer and i've been looking into it and it's a pyarmor encrypted pyinstaller packed exe. i've retrieved the code from the pyc and the pyarmor decrypter dll. running this, it complains about missing deps so i created dummy files for it to import and i've put my own code into it so i now believe i have my own code running after the decryption.
what i need now is to dump this running code so i can take a look at the decrypted original source however i'm not to great with the dis, inspect modules and all that. anyone got any ideas?

nocturne patrol
snow beacon
grave rover
#

working on a simple website to host my esopython guides n stuff on

#

wondering if I should add running code snippets in a snekbox instance

rugged sparrow
#

send me what you end up writing im interested

pure dew
nocturne patrol
rugged sparrow
#

You could collapse the attr_cache and method_cache into one dict

#

Also those additions kinda defeat the point of fishhook (its dynamic so it works automatically on most versions without hard coded offsets)

#

I did have an idea for how to do those hooks dynamically tho,

#

I'm working on an implementation of that rn

grave rover
#

time to write esopython docs

rugged sparrow
#

your edits are quite clever tho

grave rover
#

what part of esopython should I cover first

rugged sparrow
#

c_void_p.from_address(id(a) + 176).value

rugged sparrow
#

Nice

steady lily
#

Here's my first attempt at obfuscation

import binascii, __main__

O0OO0OOOo0000oO = b'WXMyazlwZG9NbUJHT0cw'

o0ooo0OOoOOoO0O = b'd2hpbGUgVHJ1ZToKICAg'

o00o00oOoOOoO0O0 = b'IHByaW50KCJ5b3VyZSBh'

o00O0oo0OoOo00Oo = b'IGR1bWJhc3MiKQoKI2RK'

getattr(getattr(__main__, [x for x in dir(__main__) if x.startswith('__b')][0]), (lambda: "ArithmeticError" and "AssertionError" and "AttributeError" and "BaseException" and "BlockingIOError" and "BrokenPipeError" and "BufferError" and "BytesWarning" and "exec")())(''.join([getattr(binascii, [x for x in dir(binascii) if x.startswith(chr(97)+str((()==())+([]==[]))+chr(98))][0])(globals().get(var_name)).decode() for var_name in ['o0ooo0OOoOOoO0O', 'o00o00oOoOOoO0O0', 'o00O0oo0OoOo00Oo']]))