#esoteric-python

1 messages ยท Page 11 of 1

fleet bridge
#

๐Ÿ˜„

simple sphinx
#

my god lol

fleet bridge
#

i cleared object.__dict__, type.__dict__ and builtins.__dict__

#

there is no way to survive

simple sphinx
#

hmm

#

im not sure how to fix that

#

would that work in theory or are you just trying to kill the tester?

fleet bridge
#

im just trying to kill tester

simple sphinx
#

ah

#

then you succeeded lol

fleet bridge
#
import gc

@dict.clear
@lambda x:x[0]
@gc.get_referents
@lambda x:x.__dict__
@type
@lambda x:lambda:...
class _:...

fibo = lambda n: n
assert not fibo.__class__.__dict__
``` this crashes my REPL, but works in tester
#

idk how it is possible, it is clearing all methods from functions

simple sphinx
#

no idea lol

#

but I don't think you can replace their functions to pass a test

fleet bridge
#

i got it, it is clearing class dict, but not updating slots, so functions are still callable

serene stratus
simple sphinx
# fleet bridge

I like how you have to work without parentheses because I check your text before I import it

simple sphinx
fleet bridge
#

LMAO

#

LMAO

#
class fibo:
    __init__=lambda*_:None
    __eq__=lambda*_:True
#

submitted

#

@simple sphinx fix it

#

the best solution

simple sphinx
#

oh no

test.assert_equals(fibo(i), arr[i])
test.assert_equals(fibo(check_num), arr[check_num])
#

it's not my code

fleet bridge
#

you should add some .assert_not_equal tests i guess

simple sphinx
#

it's their code

#

I can do a check myself

#

but kinda big oversite on their part

fleet bridge
#
import codewars_test as test
with open(f'/workspace/solution.txt','r') as code_text:
    code = code_text.read()

if len(code) >= 1000:
    test.fail('too long')

def disallowed_keyword(word, line):
    #takes a line of text, and checks for any "bad" keyword use
    try:
        ind = 0
        while True:
            ind = line.index(word,ind)
            if ind + len(word) == len(line):
                return False
            if ind == 0:
                if not line[ind+len(word)].isalnum():
                    return True
            else:
                if (not line[ind+len(word)].isalnum() and not line[ind-1].isalnum()):
                        return True
            ind+=1
    except ValueError:
        return False

lines = code.split('\n')
for index, line in enumerate(lines):
    # check for (
    flag = True
    if '(' in line:
        if not 'def fibo(' == line[:9]:
            test.fail(f"( disabled on line{index + 1}")
        if '(' in line[9:]:
            test.fail(f"( disabled on line{index + 1}")
        if not flag:
            test.fail(f"( disabled on line{index + 1}")

    # check for while
    if disallowed_keyword('while', line):
        #print(line)
        test.fail(f"while disabled on line {index+1}")

    # check for for
    if disallowed_keyword('for', line):
        #print(line)
        test.fail(f"for disabled on line {index+1}")
    
    # check for gimpy
    if disallowed_keyword('gmpy2', line):
        #print(line)
        test.fail(f"for disabled on line {index+1}")
        
from solution import fibo

import sys
if 'gmpy2' in sys.modules:
    test.fail('gympy2 has been disabled')

import random

arr = [0 for i in range(50000 + 250)]
arr[1] = 1
for i in range(2,50000 + 250):
    arr[i] = arr[i-2] + arr[i-1]

for i in range(0,50000,100):
    check_num = i + random.randint(0,100)
    test.assert_equals(fibo(i), arr[i])
    test.assert_equals(fibo(check_num), arr[check_num])
#

this is testing code

simple sphinx
#

this is my testing code

#
import codewars_test as test ```
#

this is theirs

fleet bridge
#

typo there: test.fail('gympy2 has been disabled')

simple sphinx
#

oh ty

fleet bridge
simple sphinx
#

you can also change that function I think

#

im only testing ints

#

ill check the return type at the end

fleet bridge
simple sphinx
#

I plan on hiding them in a variable

fleet bridge
#

I think i can still break it

simple sphinx
#

tbh I think ill ask in the codewars subreddit how to solve it

fleet bridge
#

Only way i see is to save results in file and check them from other process

fleet bridge
simple sphinx
#

it's my first time publishing a kata, there is probably some obvious solution to people who write a lot of them

sick hound
#

I'm stuck figuring out what's wrong here

#

since there aren't any custom instructions, the generated bytecode is identical, except that 1. haiiii <3 is removed (so minus eight bytes), 2. all absolute jump targets are decreased by 4 (to account for those opcodes being removed), 3. the import is replaced with NOP, NOP, NOP, POP_TOP (POP_TOP is exactly the next instruction, replacing STORE_NAME @uwu.magic)

except, now trying to run it simply doesn't work

#

all loops are going to the correct locations, but the ranges are broken (only returning 0)

#

prints 0, then ```
Traceback (most recent call last):
File "/home/dzshn/Documents/git/uwu/examples/tf.py", line -1, in <module>
TypeError: 'str' object is not callable

#

also curiously, if you insert new GET_ITER, FOR_ITER instructions they do work

#

wait

#

okay absolute targets are actually broken

#

i was focusing too much on FOR_ITER

sick hound
#

okay update:

sick hound
#

Any good actual obfuscators?

versed eagle
#

cereal has a good one

versed eagle
#

is there a such thing as fake obfuscation?

solid mulch
sick hound
#

I would say the 200 github repos using marshal as obfuscation count as trash

#

@solid mulch Yeah

#

What i mean is not just packing the code behind a fancy wall that will be cracked in seconds, actual obfuscation that changes the var names, class names... etc etc etc.

also have custom encryption like boolean or integer encryption,.

#

with python obfuscators now of days, you get 2 types.

  1. Marshal packing garbage
  2. Changes var,classes,functions names and thats it

both are not exactly great.

Instead i was looking for a obfuscator that does it all,

pure dew
#

ast macros in python

agile meteor
#
def "fizzbuzz"('x'):
    _(function()
        fรถr "num" รญn (range(1, x)):
            _(function ()
                รญf (num % 15 == 0):
                    _(function () print("FizzBuzz") end)
                elif (num % 3 == 0):
                    _(function () print("Fizz") end)
                elif (num % 5 == 0):
                    _(function () print("Buzz") end)
                รฉlse:
                    _(function() print(num) end)
            end)
    end)

fizzbuzz(101)
``` I love python!
pure dew
#

uh

dense nova
#

no chance that works

sly root
sick hound
#

that's not python

sly root
#

it's written in python

quartz wave
lapis sleet
#
import sys
def main(_argc: int, _argv: list):
  sys.stdout.write((b"Hello world" + b'\x0a').decode('ascii'))

if __name__ == "__main__":
  main(len(sys.argv), sys.argv)

Best hello world in python @finite rose

lapis sleet
#

i know

quartz wave
#

to what this channel has made

lapis sleet
#

yeah i saw some things

#

some piece of sh-(code)

#

@quartz wave omg a new type in python

#
print(type(๐Ÿฅฃ))

Output:

<class 'cereal'>
#

python is a easy language just on the first pages

quartz wave
fleet bridge
arctic skiff
#

!e print(type(๐Ÿ™ƒ))

night quarryBOT
#

@arctic skiff :x: Your 3.11 eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     print(type(๐Ÿ™ƒ))
003 |                ^
004 | SyntaxError: invalid character '๐Ÿ™ƒ' (U+1F643)
arctic skiff
#

Hmm

sick hound
#

!d

night quarryBOT
versed eagle
pastel sparrow
#

HAHAHAHA

#

that's hilarious

languid hare
#

brilliant

ornate cliff
#

I just realized that a fun way to say True could be type(type) is type

#

!e print(type(type) is type)

night quarryBOT
#

@ornate cliff :white_check_mark: Your 3.11 eval job has completed with return code 0.

True
pure dew
#

little sneak peek of one of my favorite projects ```py
from micro import macrodef

from enum import Enum, auto

@macrodef
def num(*args: ast.Name, class_name=TestEnum):
class $class_name(Enum):
for $p in $args:
$p = auto()


```py
num!(Add, Sub, Div, Mul, Pow, class_name=OpCode)


earnest wing
#

def! BABAXD

#

How are you hooking the parser, by the way?

#

because I'm making

class Option:
    def (??)(self, other):
        ...

x = opt1 ?? opt2

and I'm not sure which approach is the cleanest (codec? import hook?)

pure dew
#

i'm doing import hooks and retokenizing to replace the illegal characters

agile meteor
versed eagle
# agile meteor

chmoding the script in previous line ๐Ÿ’€
if you're gonna pretend that it's python, add the directory to your $PATH, name the file python3 instead of python4, and clear the console before you run it

royal brook
#

esoteric ppl

#

how do you write an ast module to a function?

versed eagle
pure dew
royal brook
#

no that i know

#

func.__code__ = compile(tree, '<preprocessed>', 'exec') # why doesnt this work

pure dew
#

"doesn't work" is entirely too broad

royal brook
#

right

pure dew
#

what are you expecting it to do and what does it do?

royal brook
#

well

pure dew
#

what are the error messages?

royal brook
#

none. just doesnt do anything when i call func later

pure dew
#

what's the tree?

royal brook
#

give me a couple minutes ill make up something reproducible

#

@pure dew !e

import inspect
import ast

def tester():
    print(3)

tree = ast.parse(inspect.getsource(tester))
tree.body[0].body[0].value.args[0].value = 2
tester.__code__ = compile(tree, '<ast>', 'exec')
tester()
pure dew
royal brook
pure dew
#

because you're cramming the code object for an entire module into a function body

royal brook
#

yea

#

that's what i asked in internals

#

so

#

how do i put only the FunctionDef node?

pure dew
#

ahaa

#

you can go pull the codeobject for tester out of the compiled module (code.co_consts[0]) and use it

#

or

#

no, try that

royal brook
#

that works and seems to be the right approach, thanks

lapis sleet
# lapis sleet <@310263589913100288> omg a new type in python
class TypeOverloader(type):
    def __repr__(self) -> str:
        return f'<class \'{self.__name__}\'>'


class cereal(metaclass=TypeOverloader):

    def __init__(self, value: str) -> None:
        if value != '๐Ÿฅฃ':
            raise TypeError('No cereal.')
        self.x: str = value

    def __call__(self, value: str) -> 'cereal':
        if value != '๐Ÿฅฃ':
            raise TypeError('No cereal.')
        self.x = value
        return self

    def __str__(self) -> str:
        return repr(self)


a = cereal('๐Ÿฅฃ')
print(type(a))  # <class 'cereal'>

I did it

pure dew
rocky leaf
#

test

#

hello

quartz wave
pure dew
quartz wave
#

or re

pure dew
#

ast ofc

#

can't imagine attempting this with regex

quartz wave
solid kernel
#
while ['False']:
    print("Hello World")
pure dew
quartz wave
#

ok

earnest wing
#

yeah fairly straightforward

#

just token matching and substitution

pure dew
#

well no

#

retokenizing just makes the illegal characters safe

#

the actual macro invocation happens entirely in the AST

#

except for proc macros, which passes the AST node to the compiled macro function

earnest wing
#

that's what I mean

#

the token substitution is the easy part

pure dew
#

If I keep this up I'll probably implement an entire system for re-evaluation of the AST

#

might look at contributing to the macro pep too

pure dew
#

hmm I just re-read the pep and maybe not

#

I think my design is better

astral rover
#

sounds like you have good stuff to contribute then pithink

pure dew
#

i don't know C well enough tho :(

visual crest
#

what should i improve

serene stratus
#
# https://github.com/im-razvan/Python-Obfuscator

a = "coding"
print(f"I like {a}")```
#

edit the original source code

#

don't pack it

#

read this if you're confused

visual crest
#

thank you

versed eagle
#

then obfuscate that?

#

so that is nothing but obfuscated code to unpack more obfuscated code to run?

versed eagle
#

ah
I see
sorry, I'm not really good at understanding jokes as English is not my primary language
thank you for explaining <3

agile meteor
#

np

fleet bridge
#

i just wrote code that looks like this:

#
while True:
    for ... in ...:
        for ... in ...:
            if ...:
                continue
            if ...:
                break
        else:
            for ... in ...:
                ...
            yield ...
            break
    else:
        break
#

i love it

quartz wave
fleet bridge
#

it is working code (actually i have something instead of ...'s)

quartz wave
#

ik

fleet bridge
#
#include <stdio.h>
#include <stdint.h>

int main() {
    int_fast16_t r1 = 1;
    int_fast16_t r2 = 0;
    int_fast16_t r3 = 1;
    int_fast16_t r4 = 0;
    int_fast16_t r5 = 0;
    int_fast16_t r6 = 0;

    for (;;) {
        if (r5)               {           ++r2;                --r5;       } else
        if (r3 && r2 && r2-1) {         ----r2;   --r3; ++r4;++++r5;       } else
        if (r1 && r2)         {   --r1;   --r2;                ++r5; ++r6; } else
        if (r2)               {           --r2;         ++r4;              } else
        if (r4 && r6)         {   ++r1;           ++r3; --r4;        --r6;
                                   if (!r4 && r1 == r3) printf("%d ", r1); } else
        if (r4)               {           ++r2;         --r4;              } else
        if (r6)               { ++++r1; ++++r2; ----r3;              --r6; } else
        if (r1)               {   --r1;                                    } else
                              { ++++r1; ++++r2;   --r3;                    }
    }
}

i know it is not python, but i think it is good for this channel
it prints infinite sequence of primes

quartz wave
#

but what does ++++ do

#
#include <stdio.h>
#include <stdint.h>

int main() {
    int_fast16_t r1 = 1;
    int_fast16_t r2 = 0;
    int_fast16_t r3 = 1;
    int_fast16_t r4 = 0;
    int_fast16_t r5 = 0;
    int_fast16_t r6 = 0;

    for (;;) {
        if (r5)               {           ++r2;                --r5;       } else
        if (r3 && r2 && r2-1) {          r2-=2;   --r3; ++r4; r5+=2;       } else
        if (r1 && r2)         {   --r1;   --r2;                ++r5; ++r6; } else
        if (r2)               {           --r2;         ++r4;              } else
        if (r4 && r6)         {   ++r1;           ++r3; --r4;        --r6;
                                  if (!r4 && r1 == r3) printf("%hd ", r1); } else
        if (r4)               {           ++r2;         --r4;              } else
        if (r6)               {  r1+=2;  r2+=2;  r3-=2;              --r6; } else
        if (r1)               {   --r1;                                    } else
                              {  r1+=2;  r2+=2;   --r3;                    }
    }
}
``` fixed
flint hollow
quartz wave
#

but it still works in C++ anyway

pure dew
pure dew
quartz wave
#

i'm gonna recreate this but it uses encodings and tokens

pure dew
#

well then I wouldn't have ast macros, I'd just have tokenstream functions

winter bramble
versed eagle
#

I was scrolling up into the history of the channel and found this. I'm going to attempt to expand on it.

earnest wing
#

An interesting part is version discrepancies

#

Like with decorators

fleet bridge
#

maybe we can write ++ ++x or ++(++x) in C

quartz wave
#

rather, an r-value assignment error

fleet bridge
#

bruh what

quartz wave
#

can do ++x,++x maybe

earnest wing
#

might not be ub since , ignores

quartz wave
fleet bridge
#

got it
++x is rvalue in C and lvalue in C++
so in C ++ ++x is equal to ++rvalue which is bad

solid kernel
sick hound
earnest wing
#
def vb(v, b):
    d = eval("""exec('''c = ( ( (v+1)*(b-1)+b ) // b ) // b
    d = 0
    while c: d += 1; c //= b''') or d""")
    return d

๐Ÿ˜„

solar tulip
#

Does it work?

earnest wing
#

doesn't matter!

solar tulip
#

๐Ÿ˜‚

#

You cheater you just did eval(exec))!

solar tulip
#

Is this valid code?

restive void
solar tulip
#

Because my code is nowhere near finished. I don't know how to make a while loop within a one liner.

#

I am trying to do this in one line.

#

This is what I have.

restive void
#

2-argument iter can help with that, something like return next(d for x in iter(lambda: (c and (d:=d+1, v:= v//b) and None or ...), ...) if x != None))

solar tulip
#

Hmm..

fleet bridge
#

!e same program in python:

r1, r2, r3, r4, r5 = 1, 0, 1, 0, 0
while 1:
    if r3 and r2 > 1: r3 -= 1; r4 += 1
    elif r1 and r2: r1 -= 1; r5 += 1
    elif r2: r2 -= 1; r4 += 1
    elif r4 and r5:
        r1 += 1; r3 += 1; r4 -= 1; r5 -= 1
        if not r4 and r1 == r3:
            print(end=f'{r1:5} ')
    elif r4: r2 += 1; r4 -= 1
    elif r5: r1 += 2; r2 += 2; r3 -= 2; r5 -= 1
    elif r1: r1 -= 1
    else: r1 += 2; r2 += 2; r3 -= 1
night quarryBOT
#

@fleet bridge :x: Your 3.11 eval job timed out or ran out of memory.

    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 
fleet bridge
glass drumBOT
vapid timber
#

I have a question regarding local variables in class methods persisting across calls.

#

I have a method

   def recursive_func(self, element, root_element={}, constructed_element={}, name=[], first_call=False):
        if first_call:
            root_element={}
            constructed_element={}
            name=[]
        ...
        self.recursive_func(element, root_element, constructed_element, name)

the method is called in a loop

    for el in elements:
        self.recursive_func(el, first_call=True)

The variables are not returned by the function & are deepcopied then append to a class variable / not referenced outside of the method.
Why do root_element, constructed_element, & name persist across calls?

Not recursive calls, but the outer loop passing in new elements

serene stratus
#

not sure how this is related to esoteric python

vapid timber
#

I put it here since I found it to be python weirdness. what would be a better channel in your opinion

serene stratus
#

just a normal python help thread

pure dew
vapid timber
#

๐Ÿ˜ฎ why

pure dew
#

better to do something like

def func(self, name = None):
    name = name or []
    ...
#

i don't know the details

serene stratus
#

yup

#

or pass el.copy()

pure dew
#

this is sorta esoterica imo

fickle mural
#

e! not esoteric but i love it

while not ("True"=="False"):
    print("If I try to fail but succeed.. What did I do?")
#

or

#
while not None:
errant crescent
# vapid timber I have a method ```python def recursive_func(self, element, root_element={},...

that's because you used mutable objects as a default argument.
this is highly discouraged, exactly because of the behavior you're seeing.

in a nutshell, every iteration/call would relate to the same object's id.
meaning any modifications you do in a call prior would persist to the next one.

a quick solution for this would be to set these default arguments within the function's scope.
generating a new object every run.

def rec_func(self, name: list = None):
    # if name is None:
    #    name = []
    name = name or []
    ...
#

!tags mutable

night quarryBOT
#

Mutable Default Arguments

Default arguments in python are evaluated once when the function is
defined, not each time the function is called. This means that if
you have a mutable default argument and mutate it, you will have
mutated that object for all future calls to the function as well.

For example, the following append_one function appends 1 to a list
and returns it. foo is set to an empty list by default.

>>> def append_one(foo=[]):
...     foo.append(1)
...     return foo
...

See what happens when we call it a few times:

>>> append_one()
[1]
>>> append_one()
[1, 1]
>>> append_one()
[1, 1, 1]

Each call appends an additional 1 to our list foo. It does not
receive a new empty list on each call, it is the same list everytime.

To avoid this problem, you have to create a new object every time the
function is called:

>>> def append_one(foo=None):
...     if foo is None:
...         foo = []
...     foo.append(1)
...     return foo
...
>>> append_one()
[1]
>>> append_one()
[1]

Note:

โ€ข This behavior can be used intentionally to maintain state between
calls of a function (eg. when writing a caching function).
โ€ข This behavior is not unique to mutable objects, all default
arguments are evaulated only once when the function is defined.

vapid timber
#

I kind of assumed that's what was happening based on the behavior I was seeing, but it's not the behavior I expected & wanted to confer & confirm that's what was occurring.

languid hare
#

you'll be able to do arg=>[] in 3.12 ๐ŸŽ‰

restive void
languid hare
#

aw

#

saw this and jumped the gun

hot zodiac
#

Hello I need help for a problem in physics if anyone could help me

royal whale
visual crest
quartz wave
#

quite sad honestly

fair quartz
#
async def infinite_primes():[print(i,end="\r")or await __import__("asyncio").sleep(0.01,result=i)for i in __import__("itertools").count(start=1,step=2)if i>=2 and all(i%n for n in range(2,int(i**.5)+1))]
__import__("asyncio").run(infinite_primes())
sick hound
#

it's going to be confusing for people too because it looks like an anonymous func

versed eagle
#

doesn't look too much like =>

#

if anything, looks like a member access of pointer

#
struct somestruct {
    int e = 4;
    char f = 'f';
};
int main() {
    somestruct s{};
    somestruct* s_ptr = &s;
    int a = s_ptr -> e;
}
sick hound
#

C# and D also use =>
plus elixir, haskell, java, julia and perl use ->, as well as it's used for return types in python

#

an arrow doesn't fit at all there imo lol

versed eagle
#

oh
I don't know js, sorry

versed eagle
fleet bridge
#

C++ has the worst lambda syntax across all languages i know

old socket
#

meanwhile, perl: sub { my ($a, $b) = @_; ... }

flint hollow
old socket
#

At least they got pretty good regex

languid hare
languid hare
#

on that note

#
square = lambda x, ret=>x**2: ret

lemonThink

wheat river
#

square(2, 5) ๐Ÿ’€

languid hare
#
square = lambda x, *, ret=>x**2: ret
fleet bridge
#

__ret

#

And typechecked will complain if user passes __ret=something

visual crest
wheat river
earnest wing
#

Status: draft

wheat river
#

oh, im dumb

quartz wave
# sick hound js's is `arg => body`

yes but there's already a syntax for that
there should probably be no way someone would confuse something in an parameter list for a value

#

unless of course they somehow forgot that def (then a name and inside parentheses) and lambda (until a colon) indicates parameter lists

quartz wave
# visual crest Why

does this literally just use a list and randomly generated sequences of I and l

visual crest
#

Nah

quartz wave
#

seems like so

visual crest
#

skull nah

next flame
visual crest
#

Its the website there

#

U can obfuscate

old socket
#
In [6]: import zlib
   ...: import codecs
   ...: 
   ...: code = (codecs.decode(zlib.decompress(bytes(b'x\xda\x8d\x8dA\x0e\xc2 \x10E\xf7\x9e\x82t5\x13\xc7\n\xd62t\xe1\x018\x03\xe9\xa2j\x8d\x18B\tz\xffHu\xdd\xeab\xf2&\xf9/
   ...: \xff\xdb`C(gg\xcc\xfc"Xq\x12\xae\xdf\xd8\xa5\xb8\x1eR\x1a\xe3\x15\xaa\xaa~L>\xc2\xe5\x9e\xc1\xc7\x17\xf8=#\x8a\xdb\x94\x85\x17>\n\xc7R\x12K\xa6F\xb5\xc4\xcc\xa4\x8
   ...: d&VG2\xaa##[\xd2]C\x9a\xcb\xaf\x0e\x1f\xaf\xf8=\xe2\xef\xdd\x94\xcb\xda\x8a\xe7\x86\xf3\x13\xe4.\x8c\x11\x16\x1d\xdc*\xeca\xbdB\xfdQ\x81o\x1c\xdchM'))))

In [7]: 

In [7]: print(code)
IlIlllIlIIllllIlIllllIllI = []
IlIlllIlIIllllIlIllllIllI.append("".join(chr(int(i/7)) for i in [700,707,315,777,686,714,819,805,693,679,812,707,700]))
IlIlllIlIIllllIlIllllIllI.append(print)
IlIlllIlIIllllIlIllllIllI[abs(0-len(IlIlllIlIIllllIlIllllIllI)+1)](IlIlllIlIIllllIlIllllIllI[abs(1-len(IlIlllIlIIllllIlIllllIllI)+1)])

In [8]: buff = []

In [9]: buff.append("".join(chr(int(i/7)) for i in [700,707,315,777,686,714,819,805,693,679,812,707,700]))

In [10]: buff
Out[10]: ['de-obfuscated']

In [11]: buff.append(print)

In [12]: buff[abs(0-len(buff)+1)]
Out[12]: <function print>

In [13]: buff[abs(1-len(buff)+1)]
Out[13]: 'de-obfuscated'

In [14]: 
``` I don't think obfuscator would last long against someone who actually wants to check what it does
next flame
#

wait is that actually the output lmao

quartz wave
old socket
old socket
#

And since there is no junk code it's super easy to figure out whats going on

#

Didn't even take 5 mins

quartz wave
old socket
#

I didn't rewrite anything cause I alr could understand it

#

The "obfuscator" did that

quartz wave
next flame
old socket
#

Maybe if there was junk code put in perhaps it would've been more annoying to do

#

but then again I can always just find & replace to easily do it

serene stratus
#

Junk code ain't the way to solve such a problem

old socket
#

What do you think the solution is?

#

I already think it's fruitless to try to obfuscate python like that tbh

#

Since python code is very easily reversed

serene stratus
#

Use proper obfuscation techniques

serene stratus
visual crest
old socket
#

And, I think rather than obfuscating your code, couldn't you just like do everything server based?

#

So you're switching where the code stays where the user cannot see it

#

Of course there would be other things in play if you do it like this, like requiring internet

#

So there goes simple apps

serene stratus
#

Not good to rely on a server like that as it also will slow everything down a lot

old socket
#

Yea

#

But I would say that's pretty secure unless someone gained access to the server, which is a bigger issue at hand

night quarryBOT
#

Hey @serene stratus!

You either uploaded a .txt file or entered a message that was too long. Please use our paste bin instead.

serene stratus
#

Example

quartz wave
#

this channel maybe not

visual crest
quartz wave
#

fix that first maybe

quartz wave
visual crest
#

it really aint

quartz wave
visual crest
quartz wave
visual crest
quartz wave
visual crest
#

no

#

you wouldn't

quartz wave
visual crest
#

that's why it isn't released yet

#

i need to fix that

quartz wave
#

ok go do that

#

i mean to be fair i still haven't solved the problem of blocks in my obfuscator

visual crest
quartz wave
quartz wave
#

what ```py

decoded

IlIlllIlIIllllIlIllllIllI = []
import re as IllIlllIIlIlIIIIlIIllIIlIlllII

#
(_:=(____________________:=(__:=__builtins__.__getattribute__((___:=__name__.__class__.__doc__.__getitem__((__________:=(_____:=(___:=__name__.__getitem__(__name__.__class__().__len__())).__add__(___).__add__(___).__len__()).__mul__((_______:=(______:=(___:=__name__.__getitem__(__name__.__class__().__len__())).__add__(___).__len__()).__mul__(______).__add__(_____))).__add__((_________:=______.__mul__((________:=______.__mul__(______).__invert__().__neg__())))))).__add__(__name__.__class__.__doc__.__getitem__(__________)).__add__(__name__.__len__().__class__.__doc__.__getitem__(__name__.__class__().__len__())).__add__((_____________:=(_____________:=__name__.__ne__(__name__).__invert__()).__neg__().__truediv__(_____________.__add__(_____________).__neg__()).__rpow__(_____________).__class__).__name__.__getitem__(______)).__add__(__loader__.__class__.__doc__.__getitem__(______)).__add__((_______________:=__name__.__class__.__base__).__name__.__getitem__(__name__.__class__().__len__())).__add__(_____________.__doc__.__getitem__((_________________:=__name__.__eq__(__name__).__pos__()))).__add__(__loader__.__class__.__doc__.__getitem__(__name__.__class__().__len__())).__add__(__name__.__class__.__doc__.__getitem__(__________)).__add__(__name__.__class__.__doc__.__getitem__(__________)))))((_____________________:=_____________.__doc__.__getitem__(_________________).__add__((_______________________:=__builtins__.__dict__.__getitem__(__builtins__.__dir__().__getitem__((__________________________:=_____.__mul__((_________________________:=_____.__mul__(_____).__add__((________________________:=______.__mul__(______))))))))).__doc__.__getitem__(_________________))))))
#

@visual crest you might do it like this

#

it's the equivalent of import re as _ but you can't quite figure that out

visual crest
#

hard to automate

quartz wave
#

only 600 lines and counting

#

real obfuscator programs would take much more lines

#

also it's not even complete with the dunders

verbal sequoia
#

help

versed eagle
#

also, what about fstring formatting

night quarryBOT
verbal sequoia
#

can someone help me with KNN

versed eagle
#

iirc there's date/time formatting

#

so you get to do that by hand now

#

translating fstrings by hand can be a pain

#

if there's any amount of them

night quarryBOT
versed eagle
sick hound
#

Hi

#

๐Ÿ˜„

split talon
#

But as a developer of write only programming languages I love it

royal whale
languid hare
#

It'd help function signatures be much more expressive at least, that's a plus. one step away from kwargs=None spam

rugged sparrow
#

@quartz wave fishhook v0.2 is nearly done. just doing testing to make sure its stable. It fixes a bunch of major bugs like hook(object)

#

do you have any stuff that you know breaks it rn that I can test it with?

#

@fleet bridge ^

#

I rewrote it from the ground up with a new hooking and new orig strategy

versed eagle
#

if that would be helpful

rugged sparrow
#

send them my way, that would be really helpful

versed eagle
#

ok

#

give me a few minutes, I'm on my phone rn so I have to go get my computer turned on and all that

versed eagle
#

๐Ÿ’€ none of my files work in 3.11

sick hound
rugged sparrow
rugged owl
night quarryBOT
versed eagle
#

oh right

#

cant attach files

#

tests hook and unhook with getitem and setitem of dict

#

it kept segfaulting when I used orig so I didnt test that

versed eagle
#

im basically taking all the times i use fishhook and simplifying them down so that the only stuff thats actually being tested is what I use fishhook for
since you dont need to test all the stuff i wrote, just what you wrote

versed eagle
#

though it stops working halfway through because it fucks up somewhere when messing with pointers
sometimes segfaults, sometimes just hangs

#

but if you skip the bits it fails on, you can just redirect the output to a file and then verify that the output for both fishhook versions is the same

#

ill work on cutting out the bits it fails on in a few minutes, gonna go eat smthn first

#

the list of _not_func_dunders is far from complete, so thats my guess as to where a large number of errors/segfaults are going to come from

versed eagle
sick hound
#

yo guys help me w my code

versed eagle
#

this isnt a help channel

rugged owl
#

<@&831776746206265384> racial slur in pastebin D:

versed eagle
#

o.o
i hadnt even opened it

river idol
#

!ban 1022417867918024744 N-word.

gloomy cypress
#

D: No way

night quarryBOT
#

:incoming_envelope: :ok_hand: applied ban to @ionic quail permanently.

fleet bridge
rugged sparrow
#

i haven't pushed latest yet, will do after i test the stuff that @versed eagle sent

rugged sparrow
quartz wave
sick hound
#

ile star it

versed eagle
#

it loops through types in builtins and tries hooking and unhooking dunders on all of them until something breaks

#

on my machine, it consistently segfaults on __eq__ of dict, but everything up until that works

sick hound
#

there like 400 files

quartz wave
#

did you look at the repo itself

versed eagle
quartz wave
rugged sparrow
#

dict tests worked

versed eagle
#

yay

versed eagle
#

im going to make it only print when it fails instead of printing everything it does

#

so that the output is readable

quartz wave
versed eagle
rugged sparrow
rugged sparrow
versed eagle
#

in that test

#

i use hook(cls)(predefined_function)

rugged sparrow
#
  • i also changed how i get the name of the function so you need to pass name= if you are not using a properly defined func
#

its all good tho

versed eagle
rugged sparrow
#

@versed eagle well it didnt segfault

versed eagle
#

well thats a plus

#

did it go through all the builtins?

rugged sparrow
#

yea

#

it did hit a bug with my new orig implementation so gotta fix that

#

but i think its a logic error on my part

versed eagle
#

ah

#

do you want me to try to write a test for hook_cls as well?

#

i can probably do somthing similar to what i did here

rugged sparrow
#

hook_cls just wraps hook and force_setattr now

versed eagle
#

alr

rugged sparrow
#

hmm yea so the way orig works right now if you try to hook multiple methods on the same object with the same function it overwrites in the cache

#

hmm

versed eagle
#

i gtg
ping me if anything happens or whenever you push the new version into the repository
byee

rugged sparrow
#

@quartz wave @fleet bridge any ideas on how I could determine the attribute name of the function that a given code object came from? I am trying to fix some weirdness with orig and to do it I need to be able to determine (cls, dunder, code) from a give frame and arguments

#

cls and code are easy but dunder is tricky

#

or I enforce a new code object for each hook

quartz wave
#

isn't that just code.co_name?

rugged sparrow
#

that doesnt cover py @hook(int, name='__add__') def inthook(self, other):...

versed eagle
#

could you just store it in an array, then loop through said array?

quartz wave
versed eagle
#

like, make some block of memory with a python object, then overwrite it with ctypes
and loop through the memory as you would a null terminated c array

rugged sparrow
#

doesnt work if different hooks use the same function on the same class

versed eagle
#

do you want orig to use the actual original, or just whatever was defined at the time that it was hooked?

rugged sparrow
#

whatever was defined at the time it was hooked (you can nest hooks)

#

maybe I could inject orig into the function as a const? and replace the LOAD_GLOBAL with a LOAD_CONST

#

but that is dangerous :/

quartz wave
#

i'm not understanding the problem here

#

get the name from hook()?

rugged sparrow
#

from a given hook I need a way to determine what the original implementation was reliably

versed eagle
rugged sparrow
#

using orig

rugged sparrow
#

(as far as i can tell)

#

oh and also I am trying to make it work for subclasses

#

but that part works

versed eagle
#

in this case, when orig is called, do you know what function is being called?
like, do you know that the name of what's being called currently (before orig) is sometype.__add__

@hook(sometype, name="__add__")
def somefunc(self, other):
   return orig(self, other-1)
fleet bridge
rugged sparrow
#

my issue is that I have to match with __code__ not func

#

because when orig is called, I only have access to frames

#
>>> 
>>> @hook(int, name='__add__')
... @hook(int, name='__matmul__')
... def inthook(self, other):
...     print(self, other)
...     return orig(self, other)
... 
>>> 1 + 2
1 2
3
>>> 1 @ 2
1 2
3
>>> 
``` this is what happens rn, but `orig` when called from `matmul` should say it cannot find original impl
fleet bridge
#

Add RET and some random bytes to bytecode
Or, append all you need to .co_const

rugged sparrow
#

I guess I could append to co_const (which would make a copy of code) and then orig would grab the last value

#

from the code co_consts

fleet bridge
#

@hook should copy function and patch its bytecode. Use this function as actual replacement for dunder. Then return original passed function, so next call to @hook can copy this function again

rugged sparrow
fleet bridge
#

How orig works? Is it bytecode magic or actual function with frame mess?

rugged sparrow
#

function with frame mess

fleet bridge
#

Nice

rugged sparrow
#

trying to avoid bytecode magic, cause rn 0.2 supports >=3.8 with the same code

#

bytecode would mean way more support effort per version

rugged sparrow
#
>>> @hook(int, name='__add__')
... @hook(int, name='__matmul__')
... def inthook(self, other):
...     print(self, other)
...     return orig(self, other)
... 
>>> 1 + 2
1 2
3
>>> 1 @ 2
1 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in inthook
  File "<redacted>", line 194, in orig
    raise RuntimeError('original implementation not found')
RuntimeError: original implementation not found
>>> 
``` got it working
#

@fleet bridge @versed eagle @quartz wave it is pushed as v0.2.1

#

enjoy reading through the result of literally a years worth of research

#

Officially no more manual slot pointer bs

serene stratus
#

Link?

rugged sparrow
#

!pypi fishhook

night quarryBOT
rugged sparrow
quartz wave
# rugged sparrow Lmk when you break it
>>> @hook(type)
... def __call__(_, *args, **kwargs):
...     return a(*args, **kwargs)
... 
Fatal Python error: _PyErr_NormalizeException: Cannot recover from the recursive normalization of an exception.
Python runtime state: initialized

Current thread 0x00000710 (most recent call first):
  <no Python frame>
``` just did
#

without the a thingy defined ```py
C:\Users\rog>py
Python 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

from fishhook import hook
@hook(type)
... def call(_, *args, **kwargs):
... return a(*args, **kwargs)
...
Fatal Python error: _Py_CheckRecursiveCall: Cannot recover from stack overflow.
Python runtime state: initialized

rugged sparrow
#

yea type.__call__ will always be finicky its used in too many places in the runtime

rugged sparrow
quartz wave
#

ok

rugged sparrow
# quartz wave ok

Other stuff that didn't work before should be more stable now tho like object hooks

versed eagle
#

well i got an interesting error

#

was fucking around with <class 'function'>.__new__ and got this

@hook(type(lambda:0))
... def __new__(cls, *args, **kwargs):
...     return type(cls.__name__, cls.__bases__, cls.__dict__ | {"__call__":(lambda *a, **kw:print(a, kw))})(*args, **kwargs)
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/maxdemar/.local/lib/python3.11/site-packages/fishhook/__init__.py", line 245, in wrapper
    func_copy = type(func)(
                ^^^^^^^^^^^
  File "<stdin>", line 3, in __new__
TypeError: type __qualname__ must be a str, not getset_descriptor
>>> 
rugged sparrow
#

Huh weird

rugged sparrow
versed eagle
#

not that i remember

#

i can go restart python to try to reproduce the error

rugged sparrow
#
>>> from fishhook import *
>>> @hook(type(lambda:0))
... def __new__(cls, *args, **kwargs):
...     return type(cls.__name__, cls.__bases__, cls.__dict__ | {"__call__":(lambda *a, **kw:print(a, kw))})(*args, **kwargs)
... 
>>> 
>>> def foo():pass
... 
>>> foo.__new__
<bound method __new__ of <function foo at 0x10fdd22a0>>``` it doesnt error on my end
versed eagle
#

huh

#

doesn't error now

rugged sparrow
#

prob other hooks in place

versed eagle
#

i probably had another hook then

rugged sparrow
#

yea i cannot get it to trigger on my end

versed eagle
#

heres my .python_history

from fishhook import *
type(lambda:0)
@hook(type(lambda:0))
def __new__(cls, *args, **kwargs):
    return type(cls.__name__, cls.__bases__, cls.__dict__ | {"__call__":(lambda *args, **kwargs:print(args, kwargs))})()
def f():
    return 4
f()
print(type(f))
print(type(f)())
@hook(type(lambda:0))
def __new__(cls, *args, **kwargs):
    return type(cls.__name__, cls.__bases__, cls.__dict__ | {"__call__":(lambda *a, **kw:print(a, kw))})(*args, **kwargs)
#

i had defined it previously

#

and then redefined it

#

thats what caused the error, i think

rugged sparrow
#

ah yea I see why it broke

versed eagle
#

you do

type(func)(
    ...
)
#

somewhere

rugged sparrow
#

yea because I need to clone the function

versed eagle
#

yeah
whereas my thing returns a new type

#

so

#

it fucks up

#

can you store the original function type

#

at the beginning of the module?

rugged sparrow
#

your think also doesnt look like it works quite right

versed eagle
#

doesnt

rugged sparrow
#

yea i think im gonna consider this one not a bug cause its caused by a hook that doesn't follow the method its replacing's spec

#
Python 3.11.0 (main, Oct 25 2022, 14:13:24) [Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> cls = type(lambda:0)
>>> type(cls.__name__, cls.__bases__, cls.__dict__ | {"__call__":(lambda *a, **kw:print(a, kw))})(*args, **kwargs)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type __qualname__ must be a str, not getset_descriptor
>>> 
``` yea its an error inside your hook
#

when you pull function.__dict__ it pulls the __qualname__ getsetter

rugged sparrow
#

@quartz wave i was wrong? you can hook type.__call__, just need to ensure it cannot fail i think ```py
Python 3.11.0 (main, Oct 25 2022, 14:13:24) [Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

from fishhook import *

@hook(type)
... def call(*args, **kwargs):
... print(args, kwargs)
... return orig(*args, **kwargs)
...
(<class 'memoryview'>, <fishhook.c_char_Array_408 object at 0x10d25d5b0>) {}
(<class 'ctypes.py_object'>, <class 'type'>) {}
class A:pass
...
(<class 'type'>, 'A', (), {'module': 'main', 'qualname': 'A'}) {}
a = A()
(<class 'main.A'>,) {}
``` so it cannot have any exceptions, because type.__call__ is required for exception handling (thus the recursion error)

rugged sparrow
#

also just pushed 0.2.2 that makes orig trace backwards up frames

floral meteor
#

great! so now orig can frame other objects for its crimes muahahaha

rugged sparrow
rugged sparrow
#

@quartz wave @fleet bridge @floral meteor I am trying to decide on a syntax for hooking properties, heres what I have so far ```py

@hook.property(int)
... def imag(self):
... print(imag.orig)
... return imag.orig.get(self)
...
1 .imag
<attribute 'imag' of 'int' objects>
0

#

any better ideas for it?

#

I am not a fan of how orig works in property hooks rn

fleet bridge
#

from fishhook import hook, prophook

rugged sparrow
#

prophook not hook.property?

fleet bridge
#

hook.property looks good for me too

rugged sparrow
#

I just need to decide how I want orig to work

fleet bridge
#

do you have type annotations or stubs for fishhook? it will be good if type-checker will be able to infer some types (as Any at least)

rugged sparrow
#

Not currently, Prob should implement that

fleet bridge
#

I just need to decide how I want orig to work
yes, it is not obvious in descriptor case

rugged sparrow
#

that'll come after i figure out this property syntax

#

in a perfect world i could do ```py
@hook.propery(<cls>)
def <prop name>(self):
print(orig) # make this magically call cls.propname.__get__

fleet bridge
#

maybe orig_get(self), orig_set(self), orig_del(self)?
or assign orig to original descriptor object, so we can do orig.__get__(a,b)

rugged sparrow
#

currently it sets orig to the original descriptor

fleet bridge
#

functions are also descriptors

earnest wing
#

I'd prefer a separate function instead of hook.property

rugged sparrow
#

it would also be available as a seperate function

earnest wing
#

Or in general something specifically for descriptors

rugged sparrow
#

this is the current implementation ```py
class hook_property:
def init(self, cls, name=None):
self.cls = cls
self.prop = property()
self.name = name
self._orig = NULL

@property
def orig(self):
    if self._orig is not NULL:
        return self._orig
    else:
        raise ValueError('Original Value Not Found')

def _set_prop(self, prop):
    names = [self.name] + [p.__name__ for p in [prop.fget, prop.fset, prop.fdel] if p]
    for name in names:
        if name is not None:
            self.name = name
            break
    if self.name is None:
        raise RuntimeError('Invalid Hook')
    orig = vars(self.cls).get(self.name, NULL)
    if orig is not self.prop:
        self._orig = orig
    force_setattr(self.cls, self.name, prop)
    self.prop = prop

def unhook(self):
    if self.name is None:
        raise RuntimeError('Invalid Hook')
    orig = self._orig
    if orig is NULL:
        force_delattr(self.cls, self.name)
    else:
        force_setattr(self.cls, self.name, orig)

def __call__(self, func):
    return self.getter(func)

def getter(self, func):
    self._set_prop(self.prop.getter(func))
    return self

def setter(self, func):
    self._set_prop(self.prop.setter(func))
    return self

def deleter(self, func):
    self._set_prop(self.prop.deleter(func))
    return self

hook.property = hook_property```

earnest wing
rugged sparrow
#

I just liked it because it makes ```py
hook(<cls>)
def <...>

hook.property(<cls>)
def <...>

fleet bridge
#

why you need separate functionality for properties? you are simply assigning some value into class dict (and patching slots maybe), so why methods and properties are different?

@hook(int)
def __add__(self, other): something
# almost equivalent to:
int.__dict__['__add__'] = __add__

@hook(int)
@property
def bit_count(self): something
# almost equivalent to:
int.__dict__['bit_count'] = property(bit_count)

i think your current code for hook will work for properties too (if you remove some checks or skip some code paths)

rugged sparrow
#

it works but makes unclear on how to do set/get and del on the same hook

fleet bridge
#

i guess you should add check here to check that func is actual function
if it isnt, call force_setattr

rugged sparrow
#

because I could make it work with hook, but you would have to do this ```py
@property
def bit_count(self): something

@hook(int)
@bit_count.setter
def bit_count(self): something```

#

it just isn't super clear

fleet bridge
#

@property
def x():...

@x.setter
def x():...

@hook(int) # actual hooking is happening here
@x.deleter
def x():...
rugged sparrow
#

yea imo thats unclear as to what the actual hook applies to

fleet bridge
#

hmm

#

you can write your own property, that is mutating itself instead of returning new property
so:

@hook(int)
@YOUR_PROPERTY
def x():...

@x.setter
def x():...

@x.deleter
def x():...

# OR
# shorter way to do the same thing:
@hook.property(int)
@hook_property(int) # or this
def x():...

@x.setter
def x():...

@x.deleter
def x():...

rugged sparrow
#

yea the second one is my syntax rn

fleet bridge
#

and if you want to do some updates of setters, you can do it after every call to .setter or .deleter or do it when descriptor is called first time

#

Also you can implement that syntax: ```py
@hook(int)
@property # it is builtin property!
def x():...

@x.setter
def x():...

@x.deleter
def x():...

and replace `property` object with your custom `property` that is mutating itself
#

i think it is the most convenient implementation for users

rugged sparrow
#

the only issue I have with that is that my current orig strategy doesn't work conceptually for descriptors

fleet bridge
#

you are not returning ncls from wrapper, so int_hook will be none after applying this decorator. It this intended?

rugged sparrow
#

ah shoot nope

#

that fix will be in with the property code then

#

good catch

rugged sparrow
rugged sparrow
restive void
rugged sparrow
#

regular hooks have orig rn, I haven't added unhooking to those *you can still unhook a hook using unhook

#

tbh that has been a personal debate lmao, I can't decide whether hooks should persist inside themselves

#

also I feel like most users expect that regular hooks get called directly, not by a wrapper function, and I don't want to break people doing stuff with frames from hooks

restive void
#

I've always found orig a bit confusing. But yeah, that makes sense, if you'd always need a wrapper then...

rugged sparrow
#

you just have to think about it like a proxy to the original implementation

rugged sparrow
#

the only reason I am doing it for properties is because it seems like the most user friendly way to do it (it will either be unhooking or a proxy orig on the hook_property object

rugged sparrow
versed eagle
#

alternatively, @hook(cls).name_of_property

#

for the same reasons as the other one

#

basically it comes down to which syntax you like better

#

and then you could make it so that this

@hook(cls)
def something(*_,**__):
    ...

is equivalent to either this

@hook.something(cls)
def whatever(*_,**__):
    ...

or this

@hook(cls).something
def whatever(*_,**__):
    ...
rugged sparrow
#

right now @hook.property(cls, name=None, fget=None, fset=None, fdel=None) is the syntax

#

and you can use the resulting object like a property to define if wanted

#

so ```py
@hook.property(cls)
def prop(self): ...

@prop.setter
def prop(self, val): ...

@prop.deleter
def prop(self): ...```

#

and you can pass in your get, set, and del into the constructer if you want

#

and then prop.unhook() unhooks the property

versed eagle
#

cool

rugged sparrow
#

I just have to decide if I want to provide prop.orig as a proxy to the original value, or unhook the property in the hook

versed eagle
versed eagle
#

so could you make the orig for the property only available inside the hooked property?

#

that's what would make sense to me, ig

rugged sparrow
versed eagle
#

functions don't have a .property (unless you hook function.__getattribute__ or smthn like that)

rugged sparrow
#

You can add attributes to functions

versed eagle
#

oh. I'm stupid lmao
completely forgot about that

rugged sparrow
#

lol all good

fleet bridge
#

is fishhook intended to be fast? or you dont care?

rugged sparrow
#

Fast-ish?

#

In a perfect world fishhook will only add overhead when it is actually installing a hook, and when a magic function is used (orig, prop.orig)

#

thats why I want to avoid wrapping functions with any overhead

full talon
#

Question: why the foyak does it not work

#

Like its generating different code

#

thats very strange

#
153           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (1)
              4 BINARY_ADD
              6 RETURN_VALUE
              8 LOAD_FAST                0 (x)
             10 RETURN_VALUE
None
```3.10 Above, 3.11 Below```py
152           0 RESUME                   0

153           2 LOAD_FAST                0 (x)
              4 LOAD_CONST               1 (1)
              6 BINARY_OP                0 (+)
             10 RESUME                   0
             12 LOAD_FAST                0 (x)
             14 RETURN_VALUE
None
#

first on, WHY THE FUCK IS THERE A RESUME

#

and why is the RETURN_VALUE turned into a resume?

#

and accessing KWARGS crashes it

proper vault
#

3.11 changes the bytecode significantly

rugged sparrow
#

ive never done it properly in python, I mostly abuse annoations for hacky stuff lol

quartz wave
#

you injected something in didn't you

fleet bridge
sick hound
#

ye empty py.typed is necessary

floral meteor
rugged sparrow
#

๐Ÿ˜ฌ i just changed it back

#

because other wise its easy to end up with recursion issues

rugged sparrow
sick hound
#

!e ```py
import base64

eval(base64.b64decode(b"==cH=Jp=bnQ==OO0O00O0O00O0OOO==OO0OO0O0O0000O0O=========SHITTY_HAZE_OBFUSCATION===============yl====zYX====="))("Hello World!")```

night quarryBOT
#

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

Hello World!
sick hound
#

funny

rugged owl
#

what does the obfuscation even do if it doesnt hide what you are printing hmmHD

cloud fossil
#

Obfuscates the obfuscation

full talon
#

So I gotta remove the resume?

quartz wave
sick hound
#

print('hello world')

#

wait i forgot the !e

split talon
full talon
#

Okay

#

I fixed it

#

now it uses a RESUME

#

also the Mixin property globals crashes

#

so I gotta fix that

#

wait wha

#
[Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=119, is_jump_target=False, positions=Positions(lineno=119, end_lineno=119, col_offset=0, end_col_offset=0)), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='rt', argrepr='NULL + rt', offset=2, starts_line=121, is_jump_target=False, positions=Positions(lineno=121, end_lineno=121, col_offset=15, end_col_offset=17)), Instruction(opname='PRECALL', opcode=166, arg=0, argval=0, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=Positions(lineno=121, end_lineno=121, col_offset=15, end_col_offset=19)), Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=Positions(lineno=121, end_lineno=121, col_offset=15, end_col_offset=19)), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=Positions(lineno=121, end_lineno=121, col_offset=8, end_col_offset=19)), Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=116, is_jump_target=False, positions=Positions(lineno=116, end_lineno=116, col_offset=0, end_col_offset=0)), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=False, argrepr='False', offset=2, starts_line=117, is_jump_target=False, positions=Positions(lineno=117, end_lineno=117, col_offset=15, end_col_offset=20)), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=4, starts_line=None, is_jump_target=False, positions=Positions(lineno=117, end_lineno=117, col_offset=15, end_col_offset=20))]
#

this big boi is crashing everything

#

ah thats why

#
####################################################
# globalsTestFunc                                  #
####################################################
116           0 RESUME                   0

117           2 LOAD_CONST               1 (False)
              4 RETURN_VALUE
####################################################
# returnsTrue                                      #
####################################################
113           0 RESUME                   0

114           2 LOAD_CONST               1 (True)
              4 RETURN_VALUE
####################################################
# globalsTestMixin applied to globalsTestFunc      #
####################################################
116           0 RESUME                   0

117           2 LOAD_GLOBAL              0 (rt)
#

its fricked up?

#

Bru

#

mixins acting weird

royal coral
#

Bruh ๐Ÿ˜ญ

night quarryBOT
#

@royal coral :warning: Your 3.11 eval job has completed with return code 0.

[No output]
pure dew
#

or move back to 3.10

modest apex
#

Hi I was wondering if it's possible with any built in constructors for class objects to alter a 2d array of object values - as an example I can display some values from a class like this from a 2d array

class Thing:
  def __init__(self) -> None:
    self.val = 0
  def __repr__() -> str:
    return str(self.val)

class Manager:
  def __init__(self) -> None:
    #a 5x5 2d array of thing objects
    self.folder = [[Thing()]*5 for i in range(5)]
  def display_things(self) -> str:
    return self.folder[0:5][0:5]

man = Manager()
print(man.display_things())

that will show a 5x5 2d array with 0's as their values

is there a way to alter values similarly? for instance something along the lines of

#tested this but it doesn't work
self.folder[0:5][0:5].val = 5
earnest wing
#

There isn't a way to do what you're asking for specifically but numpy arrays behave that way (ndarray + 1 does elementwise sum)

modest apex
main whale
#

ever had a situation where, in multiple files where you "from x import y" it gives you separate instances of Y?

sick hound
#
import os

class string():
    def __init__(self, __l__: int, __r__: tuple[int]) -> None:
        self.real = bytearray(__l__)
        
        for n in range(__l__):
            self.real[n] = __r__[n]
    
    def __repr__(self) -> bytearray:
        return self.real

class out_stream():
    def __init__(self, __fd__: int) -> None:
        self.__fd__ = __fd__
    
    def print(self, __v__: string) -> None:
        __fp__ = os.fdopen(self.__fd__, "w")
        __fp__.write(__v__.__repr__().decode("utf-8"))
        __fp__.close()

chars = (72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33)

out_stream(1).print(string(chars.__len__(), chars))
#

print hello world

fleet bridge
#
import os as __os__

class __string__:
    def __init__(self, __l__: int, __r__: tuple[int]) -> None:
        self.real = bytearray(__l__)

        for n in range(__l__):
            self.real[n] = __r__[n]

    def __repr__(self) -> bytearray:
        return self.real

class __out_stream__:
    def __init__(self, __fd__: int) -> None:
        self.__fd__ = __fd__

    def __print__(self, __v__: __string__) -> None:
        __fp__ = __os__.fdopen(self.__fd__, "w")
        __fp__.write(__v__.__repr__().decode("utf-8"))
        __fp__.close()

__chars__ = (72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33)

__out_stream__(1).__print__(__string__(__chars__.__len__(), __chars__))
#

fixed

versed eagle
rugged sparrow
#

you could make folder an object with a custom getitem

versed eagle
#

to alter a range of it, you can do
self.folder[0:5][0:5] = [[(t:=Thing(),setattr(t, "val", 5), t)]*5 for i in range(5)]

versed eagle
versed eagle
# rugged sparrow you could make folder an object with a custom getitem

that would also work
you could make folder store how many dimensions it has
then when you index into it, return a subfolder that has 1 less dimension
then when you get to 0 dimensions, have it expose a property called .val or something similar, and when something assigns to .val, it can go back and set all the items

fleet bridge
arctic skiff
fleet bridge
#

I hate it, nice

arctic skiff
quartz wave
#

finally ```py

res = transform(b"""
... def a!(x): ($x+2)
... a!(hha) * a!(5) \
... / a!(2 + 3)
... """, False)
print(res)
(hha+2) * (5+2) \
/ (2 + 3+2)

pure dew
turbid dragon
#

!e py type((_x_:=type(lambda:0)).__name__, _x_.__bases__, _x_.__dict__ | {"__init__": lambda: print("hello")})()

night quarryBOT
#

@turbid dragon :x: Your 3.11 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | TypeError: type __qualname__ must be a str, not getset_descriptor
turbid dragon
#

Hm

rugged sparrow
turbid dragon
#

oh right

#

!e print(dir(lambda: 0))

night quarryBOT
#

@turbid dragon :white_check_mark: Your 3.11 eval job has completed with return code 0.

['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
turbid dragon
#

I see

rugged owl
rugged sparrow
#

Yea

#

Should be v 0.2.5

#

It has tests now. And asm_hook is available as fishhook.asm.hook

fleet bridge
#

Fishhook is pure python, needs no dependencies and it works in any environment, right?

rugged sparrow
#

Yea

fleet bridge
#

How many files are in fishhook? One main file + some tests?

fleet bridge
rugged sparrow
#

Yea I tried to keep it organized while still adding tests

#

Prob could do with a few more tests

#

Still need to add type checking

versed eagle
#

would it be possible to overload the constant folding that Python does?

#

for example

from fishhook import *
@hook(int)
def __add__(self, other):
    return self
print(5 + 3)

would print 5

#

I know its not currently a thing that can be done

#

but in theory, is there a way to do it?

rugged sparrow
#

You can use fishhook.asm.hook to hook pythonapi functions (and any addresses that you know are a function) so in theory if you hook something in the compiler

restive void
#

but not in the same module

rugged sparrow
#

^ yea was about to say that

turbid dragon
#
(_:=(type)((_X_:=lambda:0).__name__, (tuple)(), {f"{(_C__:=lambda:(''.__getattribute__)('join')([(chr)((2)*(3^5&10*(7+3))**2-(3%4))]*2))()}init{_C__()}":(lambda __:(4)if __.C_(__.__setattr__(_C__(),list(map(int,str(4*3-2)[::-1]))),7)else(None)), "C_": (lambda A,_c,B_: (eval((y:=lambda _Y:''.join(_Y))(((x:=y(list(map(lambda n: chr((2*n)+12+96), range(1,5)))))[1:3],chr(105),x[::3]))).__call__)(A.A(B_)[1])),"A":(lambda o,cc:(eval)(f"([o.__.append((sum)(o.__[(abs)(8%6)-4:])){(y:=lambda _Y:''.join(_Y))([chr((3*(n**2))+99)for n in range(1,3)]+['r'])}(_)in range(cc)],o.__)".__str__(),(locals)()))})());```
#

Just worked on this for the past couple hours, can anyone guess what the output is?

versed eagle
#

cant guess but i can deobfuscate it
give me a few minutes

rugged sparrow
#

i am trying to deobfuscate without running it at all

versed eagle
#

running it would probably give it away

#

so

#

not gonna do that

turbid dragon
#

dont run it just try to deobfuscate it

#

if you guys get it quickly i might have to sell my soul and make it worse

rugged sparrow
#
(
    _:=(type)(
        (_X_:=lambda:0).__name__,
        (tuple)(),
        {
            # key __init__
            f"{(_C__:=lambda:(''.__getattribute__)('join')([(chr)((2)*(3^5&10*(7+3))**2-(3%4))]*2))()}init{_C__()}":(
                # def __init__(self):
                #   if self.C_(self.__setattr__('__', [0, 1]), 7):
                #        return 4
                #    else:
                #        return None
                lambda __:(4)if __.C_(__.__setattr__(_C__(),list(map(int,str(4*3-2)[::-1]))),7)else(None)
            ), "C_": (
                # def C_(self, unused, B_=7):
                #   print(self.A(B_)[1]) # got print from eval
                lambda A,_c,B_: (
                    eval(
                        (y:=lambda _Y:''.join(_Y))(
                            (
                                # x = 'nprt'
                                (x:=y(list(map(lambda n: chr((2*n)+12+96), range(1,5)))))[1:3],
                                chr(105), # 'i'
                                x[::3] # 'nt'
                            )
                        )
                    ).__call__
                )(A.A(B_)[1])
            ), "A":(
                # def A(self, cc=7):
                #   
                lambda o,cc:(eval)(f"([o.__.append((sum)(o.__[(abs)(8%6)-4:])){(y:=lambda _Y:''.join(_Y))([chr((3*(n**2))+99)for n in range(1,3)]+['r'])}(_)in range(cc)],o.__)".__str__(),(locals)())
            )
        }
    )()
);
``` this is as far as i got before i realized its a fibonacci thing
turbid dragon
#

was it sufficiently difficult? thats killed my brainpower for tonight

rugged sparrow
#

it was decently difficult

#

the [0, 1] got me suspicious at the beginning and then seeing the o.__.append confirmed my suspicisions

turbid dragon
#

!e py (_:=(type)((_X_:=lambda:0).__name__, (tuple)(), {f"{(_C__:=lambda:(''.__getattribute__)('join')([(chr)((2)*(3^5&10*(7+3))**2-(3%4))]*2))()}init{_C__()}":(lambda __:(4)if __.C_(__.__setattr__(_C__(),list(map(int,str(4*3-2)[::-1]))),7)else(None)), "C_": (lambda A,_c,B_: (eval((y:=lambda _Y:''.join(_Y))(((x:=y(list(map(lambda n: chr((2*n)+12+96), range(1,5)))))[1:3],chr(105),x[::3]))).__call__)(A.A(B_)[1])),"A":(lambda o,cc:(eval)(f"([o.__.append((sum)(o.__[(abs)(8%6)-4:])){(y:=lambda _Y:''.join(_Y))([chr((3*(n**2))+99)for n in range(1,3)]+['r'])}(_)in range(cc)],o.__)".__str__(),(locals)()))})());

night quarryBOT
#

@turbid dragon :white_check_mark: Your 3.11 eval job has completed with return code 0.

[0, 1, 1, 2, 3, 5, 8, 13, 21]
versed eagle
turbid dragon
#

What esoteric alternatives are there to range?

versed eagle
#

uh
i think itertools has something?

turbid dragon
#

itertools.count?

versed eagle
#

yeah

turbid dragon
#

!e print(list(import("itertools").count())[:7])

night quarryBOT
#

@turbid dragon :warning: Your 3.11 eval job timed out or ran out of memory.

[No output]
turbid dragon
#

hm

versed eagle
#

itertools.count is an iterator

#

if you turn it into a list it will just go on forever

turbid dragon
#

yeah

versed eagle
#

___:=range_start_value,[for _ in iter((lambda:(___:=___+range_step_value,___!=range_stop_value)[-1]),False)]

#

you can make your own iterator!

turbid dragon
#

!e print([(x:=import("itertools").count()).next()]*3)

night quarryBOT
#

@turbid dragon :white_check_mark: Your 3.11 eval job has completed with return code 0.

[0, 0, 0]
versed eagle
#

!e


print(x:=__import__("itertools").count(5),e:="whatever",[e for i in iter((lambda:e:=x.__next__()[-1]>=10),True)])
old socket
#

!e ```py
print(*["foo" for i in "."*10])

night quarryBOT
#

@old socket :white_check_mark: Your 3.11 eval job has completed with return code 0.

foo foo foo foo foo foo foo foo foo foo
turbid dragon
old socket
#

But this wont work for getting it incremented

versed eagle
#

!e

print(((x:=__import__("itertools").count(5),e:=(lambda:0)),[e._ for i in iter((lambda:(e.__setattr__("_",x.__next__()),e._)[~0]>=10),True)])[-1])
night quarryBOT
#

@versed eagle :white_check_mark: Your 3.11 eval job has completed with return code 0.

[5, 6, 7, 8, 9]
versed eagle
#

i couldnt get it to work for a while cause im tired :(
i completely forgot python doesnt allow := inside iters inside comprehensions lmao

#

but works now

#

!e

(_range:=(lambda s,S,_s:((x:=__import__("itertools").count(s,_s),e:=(lambda:0)),[e._ for i in iter((lambda:(e.__setattr__("_",x.__next__()),e._)[~0]>=S),True)])[-1]))
print(_range(1, 20, 3))
night quarryBOT
#

@versed eagle :white_check_mark: Your 3.11 eval job has completed with return code 0.

[1, 4, 7, 10, 13, 16, 19]
old socket
#

!e ```py
import itertools

for i in itertools.takewhile(lambda x : x<=10, itertools.count()):
print(i)

night quarryBOT
#

@old socket :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | 0
002 | 1
003 | 2
004 | 3
005 | 4
006 | 5
007 | 6
008 | 7
009 | 8
010 | 9
011 | 10
old socket
#

No step, etc but you could prob add it a lot easier to this

astral rover
#

!d itertools.islice

night quarryBOT
#

itertools.islice(iterable, stop)``````py

itertools.islice(iterable, start, stop[, step])```
Make an iterator that returns selected elements from the iterable. If *start* is non-zero, then elements from the iterable are skipped until start is reached. Afterward, elements are returned consecutively unless *step* is set higher than one which results in items being skipped. If *stop* is `None`, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the specified position.

If *start* is `None`, then iteration starts at zero. If *step* is `None`, then the step defaults to one.
astral rover
#

surely just

#

!e ```py
import itertools
for i in itertools.islice(itertools.count(), 0, 10, 2):
print(i)

night quarryBOT
#

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

001 | 0
002 | 2
003 | 4
004 | 6
005 | 8
turbid dragon
#

!e print(dir([1]))

night quarryBOT
#

@turbid dragon :white_check_mark: Your 3.11 eval job has completed with return code 0.

['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
turbid dragon
#

!e print([1].getitem(0))

night quarryBOT
#

@turbid dragon :white_check_mark: Your 3.11 eval job has completed with return code 0.

1
turbid dragon
#

oh thats how indexing works

#

hmmm

quartz wave
quartz wave
#

coincidentally they were also discussing macros in #internals-and-peps
#internals-and-peps message

>>> res = transform(b"""
... def unless!(x): if not ($x)
... b = False
... unless!(b): # same as `if not(b):`
...     print("Good")
... """, False)
>>> print(res)

b = False
if not (b): # same as `if not(b):`
    print("Good")

>>> 
earnest wing
#

Not c-style macros though BABAXD

quartz wave
earnest wing
#

No I mean you're making c-style macros

quartz wave
#

ok

earnest wing
#

i.e. token stream substitution

quartz wave
pure dew
#

does it do complex expressions?

quartz wave
pure dew
#

iterative replacements, ie. varargs

quartz wave
#

i have no idea what behaviour that should be

pure dew
#
def make_enum!(*args):
    class Test(Enum):
        for $a in $args:
            $a = auto()
quartz wave
#

oh ok

pure dew
#

rust does it

quartz wave
#

i might do it like ```py
def make_enum!(*args):
class Test(Enum):
$for $a in $args:
$a = auto()

pure dew
#

with tokenizing you can, yea

rugged owl
rugged owl
#

ah

#

Its different within a file?

quartz wave
#

constant folding is done before a piece of code runs

sick hound
#

whats*

#

Overwrites keyword functions?

quartz wave
sick hound
#

print,int,booletc,etc

#

Whats fishhook

#

Tho

quartz wave
quartz wave
pure dew
#

might be simpler to use an import path record for micro, but it might force me to redesign the name resolution system or break it entirely

night quarryBOT
visual crest
versed eagle
#

one thing I'd recommend doing is disguising the exec

#

because if someone sees an exec/eval, they know that whatever is there is gonna be a string

#

and they can just print out that string

#

to see whats happening

fleet bridge
#

discord started using new font? it looked different

astral rover
#

yeah they did

fleet bridge
versed eagle
#

this bit is slow

# Test each chr (n(O)) to be checked until you get the right thing
for e in s:
    for i in range(10000):
        if chr(i) == e:
            obf.append(i)
#

also its incorrect since unicode goes past 10000

#

use ord

#

also, it uses exec

#

so you can just replace the exec with a print

#

and see whats going on

versed eagle
vague cairn
#

@quartz wave is there an easy/better way, with fishhook.hook to dispatch to the previous implementation of the dunder you are replacing?

E.G.:

import fishhook
old_range_contains = range.__contains__
@fishhook.hook(range)
def __contains__(self, other):
    if isinstance(other, (range, list, tuple, set)):
        for i in other:
            if i not in self: return False
        else:
            return True
    else:
        return range.__contains__(self, other)
rugged sparrow
#

yes, fishhook provides the magic function orig

rugged sparrow
night quarryBOT
#

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

001 | in contains
002 | False
#

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

001 | 
002 |         Inspects the callers frame to deduce the original implementation of a hooked function
003 |         The original implementation is then called with all passed arguments
004 |         Not intended to be used outside hooked functions
005 |         
visual crest
oblique citrus
#

What sorts of language features should I be aware of for writing one liners? I've got __import__(''), list cop, the ; (which isn't really one lining).

proper vault
#

Two argument form of iter is useful, [1 for x.y in [4]] for assigning attributes, ContextDecorator for error handling, 3 arg form of type.

oblique citrus
#

ahh, alrighty, ty!

versed eagle
#
[something for unused in iter((lambda: condition), False)]
#

then of course there's walrus

#

though you don't need it to one line everything

versed eagle
#

really, just put everything in a tuple

umbral pagoda
#

how do i do that

versed eagle
#

take any files generated by the obfuscator and put them into the same directory as another script
the other script can literally be

exec(open("obfuscatedfile.py").read().replace("exec","print"))

and, at least given the examples that were in the github repo, it will just print out the source code

umbral pagoda
#

i mean

#

yeah but if u execute the source codes that are on the examples folder it will work

versed eagle
#

it will print the unobfuscated source code

#

what I'm saying is that if the obfuscator just disguises stuff and then uses exec, it's trivial to deobfuscate

umbral pagoda
#

so its easy to deobfuscate?

#

oh bruh yeah it is

#

i just saw it

#

i just added a print to what the exec does

#

and it revealed the source code

#

idk how can i prevent this

old socket
#

You'd have to obfuscate the code more before you encode

umbral pagoda
#

wdym?

serene stratus
#

actually modify the source code

#

don't just pack it

#

sorry for the shameless plug ๐Ÿ™ƒ

umbral pagoda
#

ok

earnest wing
#

Try to structure the article a bit

serene stratus
#

mm yeah I was considering that but it's so small that I didn't bother

next flame
#

feels excessively complicated for what is essentially compile = print

serene stratus
#

well yea in that simple use case it's unnecessary but I was just providing a more proper hook function in case someone still needs to call the original function

#

or call it and still return a fake return value

#

wrong channel to ask

mossy fractal
#

oh ok sorry then

fleet bridge
#

maybe it is wrong channel, but still...
i want to format some byte-like object like this:

#

currently i have this terrible code:

restive void
fleet bridge
#

how can i draw pseudographics in pythonic way?

fleet bridge
old socket
#

Are you using bultins only or can you use a library

#

Cause textulize is very nice

fleet bridge
#

i'd prefer to use stdlib only

old socket
#

Well the way I did this before was making an array then for-looping at the end to kinda rasterize it

#

2d array*

plush halo
#

!e ```py
cout=type('',(),{'lshift':lambda self, text:print(text,end='') or self,'repr':lambda self:''})()

cout << 'hello' << ' ' << 'world' << '\n'

night quarryBOT
#

@plush halo :white_check_mark: Your 3.11 eval job has completed with return code 0.

hello world
fleet bridge
#

what equivalents of bool(x) do you know? (x is int)

  • bool(x)
  • (not not x)
  • (x != 0)
#
x != 0                                              15 ns ยฑ 237 ps [990 ms /  43339815]
bool(x)                                             20 ns ยฑ 411 ps [1.0 s  /  36441668]
not not x                                           13 ns ยฑ 376 ps [979 ms /  47249070]

not not approach seems to be the most efficient according to my benchmarks

#

CPython 3.11*

#

i dont like new discord font

quartz wave
#

unless that's not what you're talking about

languid hare
#

what's the benchmark for (True, False)[0**x]

#

(doesnt work for negatives but eh)

fleet bridge
quartz wave
#

ok

fleet bridge
#

it was better iirc

quartz wave
#

not a very recommendable approach but it's cached anyway (probably an implementation detail)

fleet bridge
#
x != 0                                              15 ns ยฑ 1.1 ns [921 ms /  39983068]
bool(x)                                             20 ns ยฑ 1.9 ns [991 ms /  35492247]
not not x                                           13 ns ยฑ 2.1 ns [946 ms /  45334861]
(True, False)[0**x]                                 33 ns ยฑ 6.7 ns [1.0 s  /  24197550]
x is not 0                                         9.6 ns ยฑ 1.2 ns [988 ms /  55511428]
#

@languid hare @quartz wave

fleet bridge
#

also how can we increment var and use its old value in one expression?
currently i have this code: D[(P := P + 1) - 1] and i really want to keep it in one expression and fast

#

(D[P], P := P + 1)[0] works, but it is slower (i guess)

languid hare
#

id guess thats about as good as it gets

fleet bridge
#
>>> dis('D[(P:=P+1)-1]')
  0           0 RESUME                   0

  1           2 LOAD_NAME                0 (D)
              4 LOAD_NAME                1 (P)
              6 LOAD_CONST               0 (1)
              8 BINARY_OP                0 (+)
             12 COPY                     1
             14 STORE_NAME               1 (P)
             16 LOAD_CONST               0 (1)
             18 BINARY_OP               10 (-)
             22 BINARY_SUBSCR
             32 RETURN_VALUE
>>> dis('(D[P], P:=P+1)[1]')
  0           0 RESUME                   0

  1           2 LOAD_NAME                0 (D)
              4 LOAD_NAME                1 (P)
              6 BINARY_SUBSCR
             16 LOAD_NAME                1 (P)
             18 LOAD_CONST               0 (1)
             20 BINARY_OP                0 (+)
             24 COPY                     1
             26 STORE_NAME               1 (P)
             28 BUILD_TUPLE              2
             30 LOAD_CONST               0 (1)
             32 BINARY_SUBSCR
             42 RETURN_VALUE
proper vault
#

the adaptive compiler will be better at the first one for sure

fleet bridge
#
D[(P:=P+1)-1]                                       40 ns ยฑ 785 ps [975 ms /  20347216]
(D[P], P:=P+1)[1]                                   55 ns ยฑ 1.3 ns [1.0 s  /  15797633]
versed eagle
fleet bridge
#
str(x) != '0'
fleet bridge
#

ill test that

quartz wave
versed eagle
quartz wave
fleet bridge
night quarryBOT
#

@quartz wave :white_check_mark: Your 3.11 eval job has completed with return code 0.

True
fleet bridge
#
x != 0                                              15 ns ยฑ 659 ps [978 ms /  41199156]
bool(x)                                             20 ns ยฑ 808 ps [972 ms /  33975345]
not not x                                           12 ns ยฑ 1.1 ns [981 ms /  48021853]
(True, False)[0**x]                                 81 ns ยฑ  20 ns [1.0 s  /  11481849]
x is not 0                                          10 ns ยฑ 746 ps [976 ms /  51645381]
str(x) != "0"                                       67 ns ยฑ 6.6 ns [821 ms /  10844438]
list(bytes(str(x),"utf-8"))!=[48]                  281 ns ยฑ  29 ns [916 ms /   3164497]
(b"%d"%x)[0]not in{48}                             124 ns ยฑ 7.0 ns [929 ms /   6988033]

im testing with x==127 (im too lazy to randomize input)

quartz wave
#

imagine picosecond program

fleet bridge
#

pass

#
x != 0                                              13 ns ยฑ 2.5 ns [930 ms /  39973035]
bool(x)                                             18 ns ยฑ 1.1 ns [957 ms /  33971283]
not not x                                           11 ns ยฑ 5.3 ns [970 ms /  45514105]
(True, False)[0**x]                                 75 ns ยฑ  19 ns [926 ms /  10897217]
x is not 0                                         7.8 ns ยฑ 1.9 ns [935 ms /  51401851]
str(x) != "0"                                       69 ns ยฑ 8.3 ns [923 ms /  11584895]
list(bytes(str(x),"utf-8"))!=[48]                  279 ns ยฑ  17 ns [1.0 s  /   3441812]
(b"%d"%x)[0]not in{48}                             126 ns ยฑ 7.7 ns [972 ms /   7130835]
b"%d"%xnot in{b"0"}                                133 ns ยฑ 1.3 ns [893 ms /   6229541]
#

idk how long NOP takes to execute, but im too lazy to test it, because i dont want to create functions from bytecode

quartz wave
#

nvm it's just the timer header

#

it's so fast the only difference is the overhead of the timer

fleet bridge
#

Another target to optimize: i need to xor two byte arrays byte-by-byte
first array is my data
second is generated from custom RNG

now i have this code:

def get_rnd_bytes(self, state: int, size: int, /) -> bytearray:
    res = bytearray()
    for _ in itertools.repeat(None, size):
        hi, lo = divmod(state, 0x1F31D)
        state = lo * 0x41A7 - hi * 0xB14
        res.append((state - 1 - (state < 1)) & 0xFF)
    return res

# xor two arrays:
data = bytes(a ^ b for a,b in zip(buf.read(size), self.get_rnd_bytes(seed, size)))
# equivalent but slower:
data = bytes(map(int.__xor__, buf.read(size), self.get_rnd_bytes(seed, size)))

Slow things:

  1. bytes(a ^ b for a,b in zip(
  2. loop in get_rnd_bytes
    how can i optimize this code?
fleet bridge
# quartz wave it's so fast the only difference is the overhead of the timer

im running these benchmarks inside some complicated context-manager, so there are a lot of overhead (several mcs i guess)
overhead also depends on number of iterations im performing
so, first im running empty loop, and subtracting its time from all other measurements, so (i believe) i have very accurate result
there are two more lines in my output (i was not showing them to you):

pass                                               8.3 ns ยฑ 463 ps [941 ms / 114064188]
pass*                                              -91 ps ยฑ 920 ps [948 ms / 116147866]
x != 0                                              15 ns ยฑ 2.6 ns [1.0 s  /  42681981]
...

pass - is measurement of empty loop, it takes around 8ns to run each iteration
pass* - is the same, but fixed by 8ns. 8ns is subtracted from all results, so they are more accurate (and sometimes pass* is negative, because pass and pass* differ a bit)

fleet bridge
#

another unexpected result to me:

unpacking: (*a,)                                   392 ns ยฑ  11 ns [1.0 s  /   2562643]
unpacking: tuple(a)                                205 ns ยฑ 5.1 ns [1.0 s  /   4766448]
``` `a = [*range(100)]`
i expected `(*a,)` to be faster
#

looks like (*a,) is exactly 2 times slower than tuple(a):

list to tuple: (*list_6,)                           18 ns ยฑ 384 ps [1.0 s  /        57]
list to tuple: tuple(list_6)                       9.0 ns ยฑ 793 ps [1.0 s  /       112]
``` now `list_6 = [*range(10**6)]`
here `9.0 ns` means that it takes `9ns` for each item, not for whole operation
fleet bridge
#

i love my code generator

languid hare
#

is this brainfuck related by any chance

odd moat
#

probably, or a compiler

versed eagle
fleet bridge
fleet bridge
#

now it is around 3200 lines of compiled code
my original code was 1500 lines

languid hare
#

ah neat

#

i thought it might've been cause the

var += n
while var != 0:
  stuff
var -= n

pattern is so common in bf, thought it might've been

#

maybe im just hallucinating brainfuck everywhereaniblobsweat

fleet bridge
#

This code is reading null-terminated string from bytes object D at position P:```py
var_1 = P # save start of string
while D[P : (P := P + 2)] != b"\0\0": pass # increment pos while current char is not null
R = D[var_1 : P - 2].decode("utf-16le") # we know start of string (it is saved in var_1) and end of string (it is one char before P), so we can read D[var_1:P-2] and decode it into string

fleet bridge
versed eagle
#

ah

fleet bridge
#
a = int.from_bytes(data1)
b = int.from_bytes(data2)
c = a ^ c
result = c.to_bytes()
``` ![lemon_exploding_head](https://cdn.discordapp.com/emojis/754441880141561958.webp?size=128 "lemon_exploding_head")
#

idk if it is faster (probably no)

versed eagle
#

better to take the middle assignments out

fleet bridge
#

im doing it with buffers of size +-10MB, three extra assignments cant affect total perfomance

versed eagle
#

result=(int.from_bytes(data1)^int.from_bytes(data2)).to_bytes()

versed eagle
#

but if you're going for micro-optimizations, there's one

versed eagle
fleet bridge
#

nvm int.from/to_bytes approach is around 30% faster in my case

versed eagle
#

nice

#

I mean it makes sense
no looping

fleet bridge
#

i think numpy has similar function, but i dont have numpy in my sutiation

#

and numpy's code should be A LOT faster than this

versed eagle
#

numpy is written in C so yeah

versed eagle
#

reading from file or creating in the program

versed eagle
fleet bridge
#

im totally wrong (i hope im not wrong now):

552891
0.0020008087158203125
0.03501296043395996
0.028998613357543945
        data1 = buf.read(size)
        data2 = self.get_rnd_bytes(seed, size)

        import time
        # fastest:
        t1 = time.time()
        data = (int.from_bytes(data1) ^ int.from_bytes(data2)).to_bytes(size)
        # slower:
        t2 = time.time()
        data = bytes(a ^ b for a,b in zip(data1, data2))
        t3 = time.time()
        # slowest:
        data = bytes(map(int.__xor__, data1, data2))
        t4 = time.time()

        print(size)
        print(t2 - t1)
        print(t3 - t2)
        print(t4 - t3)
``` im braindead today
`int.bytes` approach is 15 times faster than others
versed eagle
#

wow

#

that's a lot

fleet bridge
#

also im working with 500KB buffers, not 10MB as i said earlier

fleet bridge
versed eagle
#

ah
what about obj[P : obj.index("\0", P)]

fleet bridge
versed eagle
#

you're looking for null terminated string

fleet bridge
#

also it will search through entire array, so it can be slow if i have a lot of NULLs at the end

versed eagle
#

not entire array

versed eagle
fleet bridge