#esoteric-python
1 messages ยท Page 129 of 1
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
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
surely that can't parse, right?
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]
I'm adding a credits section to https://github.com/IFcoltransG/esoteric-python-guide and I've used your aphorism on the readme. How would you suggest I credit the quote?
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 [].-,
ya you can just use strs of code and exec them
Or you can store the functions in the dict.
Do you want any write ups from me for that guide?
It would be great to have a writeup about Cpython specific things, and possibly also bytecode. The goal is that someone can read a public resource, then understand most of what's going on in this channel.
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.
>>> 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_ubyte5).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'"))```
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
1
no i don't
only works on unix based OS, intel x86 cpu (unless the assembly happens to be the same on other platforms)
it actually should work if you rewrite mprotect to use the windows api
weirdly this doesn't seem to work unless the string was in the interned dict previously
strange
!e print(chr(ord(chr(ord(chr(ord("a")))))))
@thorny tapir :white_check_mark: Your eval job has completed with return code 0.
a
not even esoteric but wtv
!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"))
@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 :white_check_mark: Your eval job has completed with return code 0.
True
!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"))
@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 :white_check_mark: Your eval job has completed with return code 0.
True
hmm
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
!e ```py
def test(x: int, y) -> float:
...
print({**{arg: None for arg in test.code.co_varnames[:test.code.co_argcount]}, **test.annotations})
@tacit cobalt :white_check_mark: Your eval job has completed with return code 0.
{'x': <class 'int'>, 'y': None, 'return': <class 'float'>}
Oh that's nice, thanks. So it always has the arguments first?
Yeah
Great, thanks
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+
I haven't upgraded yet but that is very nice and I might as well upgrade now, so thanks, I'll use that.
.value expects a normal object, not an address
my bad
The one thing that the typing doesn't cover is the return dictionary element, but that will be fine to add
!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"))
@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
hm
I also think None as in unassigned is interchangeable with the None type that can be indicated, which may be an issue
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))
@tacit cobalt :white_check_mark: Your eval job has completed with return code 0.
False
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:
I guess Aster should just replace all None type hints with type(None)
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
__args__
Nice, thanks again
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)
@sick hound :white_check_mark: Your eval job has completed with return code 0.
True
!e print(exec(compile('1<>2','a','exec',4194304)))
@knotty delta :white_check_mark: Your eval job has completed with return code 0.
None
!d str.replace
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.
๐ค
!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!*
your appointment to FEMA will be finalized within the week
!e print(exec(compile('1<>2','a','eval',4194304)))
@earnest wing :white_check_mark: Your eval job has completed with return code 0.
None
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.
cursed code screenshot of the day
are you using kotlins C integration to make C python modules?
i can imagine
I mean it definitely could be worse
it's mainly the fact that staticCFunction needs to be top-level
also strings are wacky
Hello
o/
can anyone help me to get started with python
wrong channel buddy
sorry
crazy how people ask this channel of all places
its cause its active people ask in any channel that has activity
perhaps they want to learn esoteric python who knows
I don't think you'd word it as "get started with python" in that case
yo long time no see
yooo
what you been up to
working a lot lately
but i've been doing stupid stuff with python before that
doing some more work on my language vm now
oh god don't remind me
??
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())
trait system for python
oh god
i discovered many unsafe ways of monkeypatching object
Blanket impls 
what the actual fuck
```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
I mean have you seen my port of spongepowered/mixin to python 
i think so
unsurprisingly, c-implemented types mess up
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
sounds like #esoteric-python alright
and then something else breaks...
AttributeError: 'method' object has no attribute '__code__'
I wonder if I could use kotlin-reflect to make py types from kt classes
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)]
oh no
What method are you using to patch c types?
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)
whats the nasty for? (what does MethodSentinel do)
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
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
it should work
it toggles some type flags and lets python handle the inheritance (instead of how fishhook does it now)
oh is this the posix-only thing?
no
*it shouldnt be
https://paste.pythondiscord.com/uvutacehow.py use this one
(also tbh i never tested fishhook on windows fyi)
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
hahaha
https://github.com/chilaxan/pysnippets/blob/main/small_hook.py#L12-L29 small_hook does use an exploit to get memory rw instead of ctypes
is this a drop-in for fishhook?
it doesnt have hook_cls, hook_cls_from_cls, or unhook cause i havent added those yet
but hook(item, attr) should work the same?
ye
ah, well, it segfaults
shoot
python 3.9.5
haha
what hook segfaults it?
(also hook(cls, name, value) works with small_hook)
its not so much the hook, but the recursive hooking
is that github file the same as what you sent earlier?
oh you dont need to hook recursively anymore cause small_hook handles inheritance right
yea
wait lemme check something
hooking into type does BadThingsโข๏ธ
<unknown>RecursionError: maximum recursion depth exceeded while calling a Python object
@pure dew fixed the hook object bug (i needed to recursively allocate new structures)
hrm
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)
doesnt seem to work for me
still segfaulting?
what location
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...
and your only hook is __getattribute__?
only hook that overrides any possible existing entries, yes afaik
if I remove my object hook it works fine
ah yeah fishhook does work
but i probably shouldnt have a blank implementation anyway lol
if i had to guess i would assume that small_hook only sets the generic tp_getattr while fishhook sets all of them
wacky business here https://totally-not.a-sketchy.site/8BRwSV7.png
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
Internally fishhook and small hook should be doing the same things tho. Cause I wrote fishhook and small_hook from the same research
You created fishhook??
Woah
How did you achieve changing builtins?
fishhook uses ctypes to change function pointers at runtime
yea lol last year
c_void_p.address?
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
overwriting literal types? now that is esoteric python
That would overwrite the type of int, not 2 or 3
ah, how would you do the latter?
c_void_p.from_address(id(2)+8).value = new_cls
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
Ah, what if you wanted to change all integer types though?
That's trickier
Depends on what strategy you want to use
What would be an example of a strategy?
to override the literal type to allow say a new dunder
like if I want to add support for a certain dunder
then you should just hook int
wdym a new dunder tho
like adding __getitem__ to numbers?
it's a generic example, but say I wanted to add __iter__ and __next__ to int
and how would you implement it by itself
where you take new literals to implement those methods
oh well thats easy enough
just patch builtin int
but i mean doing where type(5) != int
how though
Without using a module like forbiddenfruit or fishhook
Yea so how would I try and do that
i don't know, your best bet is to look at what they do
lol
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..
^ thats what fishhook and small_hook do, they compute offsets at runtime
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
fishhook computes the actual offset for tp_repr, small_hook lets python do it
wondering how python could be off any help
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
oh so python already knows how to do it basically
it has to inorder for user defined classes to work
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?
sorta?
slot_wrappers have an offset attribute that can be used to find the C function they wrap
what is escoteric-python?
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.
.
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!
@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
yeah, that's what I'm doing right now
I'm assuming the jump target stands right after expr_b is fully loaded
It should
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
you need to use a decompiler and recompiler to make sure you dont break any jumps
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
that will work in the meantime but you could still run into issues
yeah, it's a wonky endeavor
sir this is a wendy's #esoteric-python
This sounds really interesting and weird. What kind of project makes you wanna do this?
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
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?
Lib/lib2to3/tests/test_fixers.py line 500
def test_trailing_comma_3(self):```
You might need to adjust some of the relative jumps, if they go over the replaced section.
true, gotta check if the jump target is inside the block and if it's not, adjust it accordingly
I've done that before
that scares me
[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''), {})()```
when python starts looking like in line assembly you know your from hell.
This is actually way simpler than it seems.
As you probably know, everything is an object - this extends to functions.
I know basic 32 assembly but shit tf is yall doing in here lmao
So if functions are a kind of object, then maaaybe there's a function constructor, right?
There is.
your making me cry.
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.
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.
im trying to ask a question but keep reading and getting more confused
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.
I only understand the part where it makes stack zero then crash
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
holy hell man this is hard to understand
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!
>>>```
!eval ```py
type(lambda:0)((lambda:0).code.replace(co_consts=()),{})()
@tacit cobalt :warning: Your eval job has completed with return code 139 (SIGSEGV).
[No output]
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.
!eval ```py
def a():yield
a().throw(type("E",(BaseException,),{"new": lambda*a:1}))
@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
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.
!eval ```py
import sys
print(sys.version_info)
@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)
I feel like a beginner when I see this channel
anyways, esteric side of python looks cool
@sick hound :warning: Your eval job has completed with return code 0.
[No output]
Still works with 1114113 constants
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 ๐
Still works with and
>>> 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
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
how do i get started with esoteric python this is my favourite channel in the whole server
you can also use any object that implements str for dynamic prompts
@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
I have line numbers and local time, what wacky stuff should I fill my prompt with?
I was thinking terminal colors
and syntax highlight 
hook into sys and override the keyboard input code
read the line as its typed and highlight it
like how zsh highlighting works
You could hook sys.stdin
Is there a way to do slice assignment without using slice notation?
!e
a = [1, 3, 6]
a[slice(2)] = [4, 6]
print(a)
@proper vault :white_check_mark: Your eval job has completed with return code 0.
[4, 6, 6]
@grave rover https://bytecode.readthedocs.io/en/latest/usage.html this may be useful for your decompiler, it has CFG
what is the opposite of golfing like making the most creative and long code to print hello world
I think that's called code bowling
Nevermind I figured it out
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)
is it lua
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
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.
What, you're just going to assume I want at least zero constants?
I want -1 constants. When my code is defined, it undefines a constant located somewhere else.
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())
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
<class 'tuple'>
that is because internally, a tuple looks like this [ob_refcount, ob_type, ob_size, item0, item1, item...]
ooh, neat lib
tbh wish i had found it sooner
I feel like I'm self-advertising a lot these days, but I made a guide at https://github.com/IFcoltransG/esoteric-python-guide
nice
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...
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
Guess I'll try writing a guide later
thanks
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)
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
Y & Z combinator ๐
I did it like this
`def true(a,b): return a
def Not(a): return a(true,false)
def And(a,b): return a(b,a)
`
hello, i have an hw to do but i am big noob, can someone help me ?
yup, that's the smart way
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.
@ruby briarhello, we generally don't help with graded homework, though you are free to ask about specific parts of the solution.
[print(''.join(_(O)for _ in map(lambda H,I:lambda O:H*(0==O/I%1),('Fizz','Buzz'),(3,5)))or O)for O in range(1,101)]
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)]
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
!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!*
!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='')
@grand tree :white_check_mark: Your eval job has completed with return code 0.
001 | H๏ฟฝe๏ฟฝllo๏ฟฝ,๏ฟฝ ๏ฟฝw๏ฟฝo๏ฟฝr๏ฟฝl๏ฟฝd๏ฟฝ!๏ฟฝ
002 | ๏ฟฝ
!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]]
@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]
Pog
!e
@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).
!unmute @maiden river
:incoming_envelope: :ok_hand: pardoned infraction mute for @maiden river.
!paste
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.
Please use our paste service for sending large code ^^
oh ok ๐
print(print(print(print(print(print(print("hello world")))))))
!e
print(print(print(print(print(print(print("hello world")))))))
@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
@maiden river :white_check_mark: Your eval job has completed with return code 0.
<function true at 0x7fe390028c10>
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๐๐
!e
def f(a, b, c):
return a**2 + b**2 == c**2
# or
f = lambda a, b, c: a**2 + b**2 == c**2
print(f(0,0,0))
print(f(3,4,5))
print(f(1,1,1))
@fleet bridge :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | True
003 | False
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()
just a normal method
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
i think the stubs for this might be wrong
self.__setitem__(i, BLACKLIST[i]) will not update the type object
but rather the namespace
the namespace should be the 3rd arg to type.new right?
Test () {'__module__': '__main__', '__qualname__': 'Test'}
This is what I found on it
actually, hold on
could it be the super() call in prepare
wouldn't just a return BlackListDict() work
doesnt look like it
I have just tried that now but it is still the same
oh, duh
your manual __setitem__ is triggering the filter
so __init__ is not getting set
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
The namespace is populated as the class body is executed
OK, thanks
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
Well at that point you could do all mro work at compile time
UNPACK_SEQUENCE trips it up?
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
hey, I'm back temporarily
how can I get the size of the call stack in one expression?
without importing inspect
like how many frames there are?
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
@rugged sparrow you there?
do you have sys?
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
I have sys
one sec
(f:=sys._getframe())and len([(f:=f.f_back)for _ in iter(lambda:f, None)])
How does that work?
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
@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
@grave rover I can help when I get home
Ping me tomorrow then we can work on it then
๐
I got bored and made this: https://gist.github.com/dzshn/6ec24800669595b7ce5ce680cd9f55b8
should probably fix the aspect ratio but also too lazy to lol
Cool, is that Mandelbrot?
yep it is
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?
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
Yeah, I wouldn't use eval in any serious code, this was just to check whether eval can be made safe.
Hence posted in esoteric python
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
Yeah, isalnum should make it fully safe from anyone trying to run malicious code
well, exit is a first problem
but it's being checked from a predefined list
^ And exit won't be there
"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
Yeah I'm currently looking at "fully safe", this program itself is useless but you need to find a way to crash it or run malicious code, if it's opened on IDLE and you can only input stuff on that IDLE screen
just dump 1 gb of text on it lol
You can only input stuff on that idle screen
You'd need to go to a different screen to copy the stuff lol
hmmm
Also, ctrl+c isn't allowed either
Uh, any stuff involving ctrl+something instead of inputting stuff and pressing enter is not allowed
you should use services like that to use eval in a safe way
we're trying to break it
Haven't needed to use eval so far
^
to break snekbox?
Nah, this simple code
right
Is snekbox breakable?
snekbox is actually useful though
it's hard to prove otherwise, so
this code example ^^ is pretty much useless, but can't be broken even though it uses exec
only way it could be safe is to make your own python implementation without access to system stuff
This'll reject anything other than letters and numbers. I can't think of any code that works without symbols to exploit eval
You need _ and .
brackets
mm I think just because of the checking against the list it's already probably impossible to exploit it with these conditions
If it used deny- rather than allow-filters, there would at least be a chance :>
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
can someone teach me the basics of esoteric python?
ie making python bend to your will
how would you maybe make that in java?
@rugged sparrow lmk when you're available :)
code snippet at https://hastebin.com/emubafogec.py, it's got a lot of stuff commented out since I wanted to completely redo it and it's kinda messy
@grave rover what was the reason you wanted to build the tree again? Was it to check stack state?
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
Do you actually code in Python byte code?
How do you run Python byte code on Windows?
Cant you just copy the stack when you add a branch? (And eventually when they re-merge you can assert that the stacks are equal)
You can't not run python bytecode when running a python program
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.
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
compiling expensive, caching good
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
Yeah ( is pretty tricky to get working 
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 
Violate segmentation.
that's the problem, figuring out where branches are
also the hecking loops and if-else expressions and that stuff
Branches should just be anywhere where the instruction pointer can be 2 different values after the opcode
Hey @bright hearth can you write a Hello World program in byte code and send it here?
well yeah but how should I go about "remembering" the stack across 7 different blocks between both branches
!e ```py
def f():
print("Hello, world!")
import dis
dis.dis(f)
@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
Alright but whither can I write this byte code and run it
You can with libraries like https://github.com/martmists-gh/pyasm (ignore the shameless self-plug :)
No problem. Friend helps friend.
(note: the pip install does not work yet)
You can maybe store a bytes object on every block with each byte representing the result of a opcode (like a LOAD_CONST adds the LOAD_CONST opcode onto the bytes obj, and a CALL_FUNCTION would remove a certain number of items from the bytecode string then add on the CALL_FUNCTION opcode to represent that the result of a function is there
like each block has a calculated bytes object thats something to represent the resulting stack (up until a branch)
hmm...
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)
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
current = (current + ( if (op >= 90) else stack_effect(op))) what happens here?
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
hello
hello
oh no I have to build classes now
listcomps are pain
what about type is variably sized so that it doesn't allow slots?
@sick hound link to your decompiler?
Wdym doesn't allow slots
like you cant subclass type with slots that arent empty, i get tuple, bytes and int not allowing it
I assume that python doesn't have the logic to calculate the space it needs to add the slots in front of the data for the internal type
!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",)), {})()
@tacit cobalt :white_check_mark: Your eval job has completed with return code 0.
Hello, World!
!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",)), {})()
@tacit cobalt :white_check_mark: Your eval job has completed with return code 0.
Hello, World!
I was looking around on github and I found this https://github.com/ssize-t/inlinec think you might find it interesting
@sick hound :white_check_mark: Your eval job has completed with return code 0.
Hello, World!
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)()
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...
is this the right place to talk about python code?
@sick hound :white_check_mark: Your eval job has completed with return code 0.
True
!e print(bool(1))
@acoustic gust :white_check_mark: Your eval job has completed with return code 0.
True
iot has gone mainstream.. it might have sold its esoteric card by now
"Alexa, write some esoteric Python"
iot isnt really esoteric at all
!e
type(lambda:0)((lambda:0).code.replace(co_code=b"d\x01F\x00d\x00S", co_consts=(None, type('',(),{'repr':lambda x:"Hello, World!"})())),{})()
@spring depot :white_check_mark: Your eval job has completed with return code 0.
Hello, World!
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
I mean with an esoteric way, using ctypes or something
!e ```py
def replace_const(oval, nval):
def wrapper(func):
consts = [*func.code.co_consts]
consts[consts.index(oval)] = nval
func.code = func.code.replace(
co_consts=tuple(consts)
)
return func
return wrapper
@replace_const(None, 1)
def test():
print('yeet')
print(test())
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
001 | yeet
002 | 1
Oh wow thank you
note: that replaces None everywhere in the function and may lead to strange results
a script that decodes base64 without importing base64?
!e ```py
import binascii
print(binascii.a2b_base64(b"aGk="))```
@tribal moon :white_check_mark: Your eval job has completed with return code 0.
b'hi'
!e
import binascii
print(getattr(binascii, dir(binascii)[7])(b"SGVsbG8gV29ybGQh="))
@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
this worked on my ide
!e
import binascii
print(getattr(binascii, dir(binascii)[8])(b"SGVsbG8gV29ybGQh="))
@astral rover :white_check_mark: Your eval job has completed with return code 0.
b'Hello World!'
im running 3.9.0
!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"))
@grave rover :white_check_mark: Your eval job has completed with return code 0.
hello world!
@steady lily
I could make it a lot more readable but you did ask in #esoteric-python :)
i think esoteric python is the coolest thing and shows a mastery in the language
@sick hound :white_check_mark: Your eval job has completed with return code 0.
001 | yeet
002 | 1
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
!e ```py
a=b=c=0
@sick hound :warning: Your eval job has completed with return code 0.
[No output]
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
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
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)
>>> {*[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
wait till you discover the promise of ctypes
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
!ban ConnnorS.
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
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
in is not is since is checks the id so since first fails it should/doesn't? check the 2nd
It desugars to True in [True] and [True] in [True]
I see
Because in is a comparison op like >=
are = lambda x:{take:= x in range(x * 2) and 42 }.union(range(2))
y = [x[-1], *x[:-1]]
```This is a little shorter, but less ugly.
https://pypi.org/project/pyasm/ it's here 
look at the C code mostly
If you want to learn bytecode, you'll eventually memorize ceval.c (https://github.com/python/cpython/blob/main/Python/ceval.c)
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
!e
print (([]==[])<<-~-~([]==[]))
@near gust :white_check_mark: Your eval job has completed with return code 0.
8
@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 :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]
that makes sense
Is it possible to make this work?
```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>```
It just exits the shell
!e print([0x_for x in bananas])
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
[15]
ohh right, i used ox instead of 0x
!e print([0x_for x in (()==()+()==())*print(e**3.12)*()==[]==()])
@wooden badge :white_check_mark: Your eval job has completed with return code 0.
[15]
!e print(()==()+()==()*()==()+(()==()+()==())+(()==()+()==()))
!e print(()==()+()==()*()==()+(()==()+()==())+(()==()+()==()))
@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'
!e print((()==())+(()==())+(()==()))
@wooden badge :white_check_mark: Your eval job has completed with return code 0.
3
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__)
@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'>
its different classes but if I print __class__ I get the same output
I guess the <locals> hides some of the details?
Not yet, I've been a tad preoccupied.
I appreciate what youve done already tho! As far as i can see, no other guide is that good
I hope I inspire people to make better guides.
!e
list(range(100000000000))
@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
pog
I guess I'll give it a shot
It doesn't no, In Python 2 it was. To help users in switching there's a special case message to suggest the fix.
if print can be either a function or not in python 2, does that mean it's a keyword?
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.
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
@sick hound :white_check_mark: Your eval job has completed with return code 0.
Code block escape attempt detected; will not output result
Full output: https://paste.pythondiscord.com/irelexewer.txt?noredirect
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?
it just checks at the end
Ahh ok
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?
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:`
cool to know, thanks
are you willing to do horrible acts
Anything to make it work
I assume there's some ctypes hackery
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
all ints
that's beyond by wheelhouse, then ๐
use forbiddenfruit to patch int.__iter__ instead
don't ask me how though
for x in 3? are ints even iterable in unmodified python?
!e iter(42)
@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
Can't do that, int is immutable
nothing is immutable for forbiddenfruit
!e setattr(int, "iter", None)
@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'
lol ๐คฃ
!e
from forbiddenfruit import curse
def hello(self):
return "blah"
curse(str, "hello", classmethod(hello))
assert str.hello() == "blah"
@thin trout :warning: Your eval job has completed with return code 0.
[No output]
see?
how does it defy forbiddenfruit..
oh nice
!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)
@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
oh, that's interesting
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)```
@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__'
interesting
Not even close
o.O
Meh
https://github.com/clarete/forbiddenfruit/pull/63 will add support for it
So basically I can't do it currently?
yup
The fact that forbidden fruit can even exist shows why Python needs to look up attributes every time they are accessed
yup
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
I used it in a Django project to generate generic routes
@last locust fishhook can hook all dunders
Fishhook can hook __iter__
I got frustrated with forbiddenfruits limitations so I wrote my own lib, fishhook is the result
So how would that work?
lmfao
!pypi fishhook
So ig```py
@hook(int)
def iter(self):
...
for x in 5:
print(x)```?
Yes
from fishhook import hook
@hook(int)
def __iter__(self):
yield from range(self+1)
for x in 5:
print(x)
```perfect, thanks @rugged sparrow ๐
No prob
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
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
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?
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
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?
I made this tool https://github.com/kootenpv/cliche
I think it's funny that it heavily uses dynamic features of python and it's really "ugly" but the idea is that at least to the user it is maximally convenient ๐
It might help to look into sys.settrace and try logging the inputs to a file.
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
send me what you end up writing im interested
if this is an amazing and dead-simple as it looks, I'll be your biggest fan
Let me know ๐
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
time to write esopython docs
your edits are quite clever tho
what part of esopython should I cover first
c_void_p.from_address(id(a) + 176).value
Nice
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']]))


