#internals-and-peps

1 messages · Page 49 of 1

raven ridge
#

you should only ever need to change the root logger's verbosity

magic python
#

i just wanted the same "thing" to be printing output to the console... I can probably just make one in each module tho

raven ridge
#

there's no need to touch any other module's logger in order to implement --debug

gloomy rain
#

Testing log output feels... A bit overkill. I dunno, I never do that personally.

void sonnet
#

transitioning away from that model made it easier to config. propagating and <something else i forget> was no longer required.

gloomy rain
#

@magic python Do that and the log output will be more useful, since the log entry will indicate where the log entry was created.

magic python
#

who tests the tests 😱

peak spoke
#

Usually not the output, but that something was actually logged

paper echo
#

@raven ridge i don't want debug output from third-party modules like gensim, so i need to restrict it at least to my own top level module

#

but yes that's fair

#

if it's all at one top level

magic python
#

@gloomy rain yeah - I just tried it and it seems so, idk why i didn't just do that straight away 🤦‍♂️

paper echo
#

e.g. main_logger = logging.getLogger('top_level_package')

gloomy rain
#

@paper echo Pretty sure you can just configure that.

magic python
#

is there an accepted workflow to this ? Seems something that a few do differently (going by this thread at least)

void sonnet
#

propagating and <something else i forget> was no longer required.
disable_existing_loggers was the something else.

gloomy rain
#

Without having to touch the code itself.

#

@magic python Haven't seen any good arguments against @raven ridge's approach so far.

#

They usually know what they're talking about anyway.

magic python
#

@raven ridge anything that i could google to get an outline of what you're saying?
or is

log = logging.getLogger(__name__)

about it

gloomy rain
cinder parrot
#

oh ok

raven ridge
#

that's pretty much all. inside of whatever module you're using as your main, that will create a logger called __main__. In every other module, it'll create a logger called foo.bar.baz or whatever. Each of them will propagate log records up to the root logger by default. In your if __name__ == '__main__': block you confiugre the root logger (get it using logging.getLogger()). If you need to get a handle to another module's logger for some reason (like to reduce verbosity for just one module), logging.getLogger('foo.bar.baz') lets you do it. Because of how propagation works, that also lets you cut down the verbosity for an entire package at once, isntead of just one module, by configuring logging.getLogger('foo.bar') instead.

magic python
#

@raven ridge hrm ok , thanks. So using a logger for each file wouldn't be ok?

raven ridge
#

@raven ridge hrm ok , thanks. So using a logger for each file wouldn't be ok?
@magic python I think you misunderstood me - using a distinct logger for each file, named by its module name, is the norm.

magic python
#

oh ok 😅 all good

gloomy rain
#

__name__ <- This will have a different value in every file.

magic python
#

sounds like i should watch that talk 🙃 thanks for the link

void sonnet
#

using getLogger(__name__) will insert the filename into the log entry.

#

unless your config changes the format...

gloomy rain
#

So if you do logger = logging.getLogger(__name__) in each file, you will get different loggers.

raven ridge
#

yeah, in every file except the initial one, __name__ resolves to the module's dotted import path. in the main it resolves to "__main__" instead. All of those will propagate log records to the root logger by default.

void sonnet
#

logging is an awesome lib. its modularity comes with the cost of complexity though. 😄

magic python
#

no one uses loguru then?

gloomy rain
#

@void sonnet Fortunately, most of the complexity is contained in the configuration. It's very easy to use "in the field".

void sonnet
#

fair point. i dove into it deeper needing to use SystemLogger. 😵

magic python
#

does singleton have anything to do with why one can't deepcopy a matplotlib axis object btw?

#

or is that completely unrelated

#

I've also just realised, if you have a separate logger in each file - it's pretty hard to change the level for logging isn't it?

raven ridge
#

no - you change it at one level of the hierarchy, and everything below it inherits that level by default.

void sonnet
#

you can change it in each file.

logger = logging.getLogger(__name__)
logger.setLevel(level)

you can set handlers, filters, etc per file.

gloomy rain
#

@magic python If you use loggers with dot-separated names (like module names), it creates an implicit "logger tree" that you can configure in a cascading manner.

#

So if you set log level DEBUG for "foo", then you also implicitly set it for "foo.bar" and "foo.baz"

#

But you could also explicitly override it for a specific subtree

raven ridge
#

the talk I linked to above would probably be very helpful for you, @magic python 🙂

paper echo
#

btw this is a great argument for using __main__.py

#

since if you -m your top level package

#

and naively use getLogger(__name__)

#

it won't be the parent of any of your sub-package loggers

#

i still like having the option/control to configure individual loggers, but you're probably right that getLogger vs importing isn't any worse, and enforces better habits

raven ridge
#

those individual loggers already have to be registered with logging by name in order for them to do any useful work, so there's no reason not to look them up in that registry, via logging.getLogger, rather than trying to import them. That way there's no ordering dependency; you can do that even before that module has been imported.

magic python
#

idk how this works with loguru... guess i'll go back to default ha

#

Is there a way to make logging print out the module it's called from? If i use:

logging.basicConfig(
    format=f"module : {__name__.split('.')[-1]} %(asctime)s %(message)s",
    datefmt="%m/%d/%Y %I:%M:%S %p",
    level=logging.INFO,
)

in the first call then __name__ will be the file of the 'main' module rather than the submodules

spark magnet
raven ridge
#

the module it's called from is __main__. The name of the first module in a Python program is always __main__.

spark magnet
#

@raven ridge rie means a later logging call from another module would still say __main__

tacit hawk
#

ctypes does not raises OSError when the function calls returns non zero codes?

raven ridge
#

why would it? What if the function is sin or strlen or printf or something like that?

heavy sphinx
#

yo can smone pls halp me i cannot figure out how I make my 3D mincecraft geme

tacit hawk
raven ridge
#

that's specific to oledll, not for everything you could call with ctypes.

rich wharf
#

Why doesn't python support bare tries?

#
try:
  CODE HERE
#no except following```
#

being equal to

#
try:
  CODE HERE
except:
  pass```
peak spoke
#

Explicit is better than implicit?

rich wharf
#

I think this would be a useful feature.

#

That's true.

peak spoke
#

Along with the fact that it'd be discouraged in 99% of its uses

rich wharf
#

Oh, that's true too.

raven ridge
#

because that's also equivalent to just not having the try: at all - so why allow it? There's already a clear and obvious way to run some code without catching exceptions or running finalizers, and it's not having a try at all.

charred wagon
#

In that case, why is a bare except allowed?

rich wharf
#

oh right, using a with suppress():

spark magnet
#

except: pass will swallow all exceptions, different than no try at all

raven ridge
#

ah, I misread.

#

yeah, suppress in that case being the obvious way to do that.

#

In that case, why is a bare except allowed?
that's actually a good question, though - that footgun probably should be removed from the language...

#

it's so nearly always the wrong thing to do that linters warn about it - forcing you to explicitly use BaseException when that's what you mean would be an improvement.

hollow crane
#

can you except like

spark magnet
#

in hindsight, it might have been better to disallow bare except, but it would be hard to remove now

hollow crane
#

i don't know

#

str

#

so it doesn't isinstance

rich wharf
#

hold on

hollow crane
#

rip

#

you can inherit from baseexception which except doesn't catch by default afaik

#

or something

#

there's some trickery with that

rich wharf
#

@peak spoke If explicit is better than implicit, why not use isinstance on an expression name?

#
try:
  ...
except e:
  if isinstance(e, TypeOne):
    ...
  elif isinstance(e, TypeTwo):
    ...
  raise
peak spoke
#

Not sure how that fits here

spark magnet
#

@rich wharf that's just more verbose than using except clauses

rich wharf
#

alright

raven ridge
#

too bad bare except didn't get removed from the language in 3. We're not likely to get another chance on that one for a while.

peak spoke
#

Any idea what the initial reason for it was? Not many cases where you need BaseException instead of Exception

raven ridge
#

I'm guessing "anything" just seemed like a sane default once upon a time, and no one caught it until it was firmly ingrained in the language.

night coral
#

Is list and array different?

#

And do we have arraylists in python?

visual shadow
#

Lists and arrays are different in python yes. Primarily difference being, lists are heterogeneous, they can contain items with different data types.

#

Arrays are understood to be homogeneous.

#

In python, usually when you say arrays, it's convention to be interpreted as numpy arrays

night coral
#

Oh, k

#

And then what are arraylists...

visual shadow
#

Sounds like a made up word.

night coral
#

I have that in c# and Java atleast

visual shadow
#

Sounds like not python. :)

#

Tell us what they are in c# and java, and we can probably find you the equivalent term in python if there is one.

night coral
#

Yep, thought there would be something similar in oython

visual shadow
#

They may or may not exist. Cause between arrays and lists I honestly don't see the need for another array like or list like container

night coral
#

So arraylists are just more functionality with arrays, you can add and pop anywhere you want, unlike arrays in Java, which are just declared and don't have much changability, tho you only have, 1D arraylists

#

My guess is arraylists are lists in python

visual shadow
#

Sounds like it, aye

#

Is the add and pop at the end an O(1) operation in arraylists?

#

If yes, they are similar to python lists in that sense. However, are they also heterogeneous or homogeneous

night coral
#

I didn't really understood what u said, but I know for a fact that they are homogeneous

visual shadow
#

Oh ok

night coral
#

Meaning only one type of value

visual shadow
#

Uh, that notation talks about time complexity of operations

#

It's basically like a measure of how much slower code gets as you increase the data points (or n) for any task

night coral
#

Uhh k

visual shadow
#

Time complexity is a pretty useful topic to pick up, I'd highly recommend looking into it in more detail when you have time

#

Pun intended 😉

night coral
#

K

raven ridge
#

The closest analogue to Java's arraylist is Python's list. Both are internally implemented as dynamic arrays.

grave jolt
#

And Javascript's arrays are actually ArrayLists, and that brings some confusion as arrays can be heterogenous.

#

But most of the time, I think, lists are used homogenously as well

flat gazelle
#

well, they are still homogenous. All JS objects share a common type, as do Python objects.

grave jolt
#

Well, technically yes.

#

But semantically, python objects can still have different types

#

as well as JS objects

flat gazelle
#

you can also do ArrayList<Object> in java, which is in essence what python/JS lists are

grave jolt
#

Well, yes

#

with boxing of non-object types

flat gazelle
#

but honestly, homogenous vs heterogenous is more of an implementation detail than a useful property, because same types as per the language can be entirely different types semantically. For example a string array where each even position is a name and each odd position is an email address. Both are strings, yet are disjoint types

unkempt rock
#

@hollow crane You wrote pront (''hallo''), you should fix that.

grave jolt
#

Well, it's supposed to raise an error

#

that's the point

unkempt rock
#

Oh, I am sorry I didn't see that.

tacit hawk
#

Does threading.Thread maps to a OS thread?

radiant fulcrum
#

no

#

wait sorry

#

miss read that

#

Yes, threading or any python threads (That i know of) are OS threads in implementation

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied mute to @subtle pike until 2020-06-18 12:38 (9 minutes and 59 seconds) (reason: chars rule: sent 3005 characters in 5s).

wide shuttle
#

!unmute 248887037447503872

fallen slateBOT
#

:incoming_envelope: :ok_hand: pardoned infraction mute for @subtle pike.

subtle pike
#

ty

#

i'll repost it

red solar
#

can you override the assignment operator in python?

subtle pike
#

@tacit hawk the threading library uses the more lower level _thread library under the hood (this module was optional up to 3.6.x). I do not believe the definition of a thread is specified, it appears to be left to the implementation - provided it implements the threading and _thread interface. In the implementation of threading.Thead.start (https://github.com/python/cpython/blob/3.8/Lib/threading.py#L852) an ivokation to _start_new_thread(self._bootstrap, ()) is made (this is aliased to _thread.start_new_thread. The implementation of _thread is more nuanced, the CPython source will use one of two implementations depending on if _POSIX_THREADS is defined upon compilation or not. If _POSIX_THREADS is not defined pthread.h will be included (https://github.com/python/cpython/blob/3.8/Python/thread.c#L11).

#ifndef _POSIX_THREADS
/* This means pthreads are not implemented in libc headers, hence the macro
   not present in unistd.h. But they still can be implemented as an external
   library (e.g. gnu pth in pthread emulation) */
# ifdef HAVE_PTHREAD_H
#  include <pthread.h> /* _POSIX_THREADS */
# endif
#endif

Additionally, the CPython implementation will opt to use the pthread implementation, otherwise it will assume the NT implementation (https://github.com/python/cpython/blob/3.8/Python/thread.c#L80).

#if defined(_POSIX_THREADS)
#   define PYTHREAD_NAME "pthread"
#   include "thread_pthread.h"
#elif defined(NT_THREADS)
#   define PYTHREAD_NAME "nt"
#   include "thread_nt.h"
#else
#   error "Require native threads. See https://bugs.python.org/issue31370"
#endif

Delving into thread_pthread.h, PyThread_start_new_thread (https://github.com/python/cpython/blob/3.8/Python/thread_pthread.h#L236) makes calls to pthread (https://github.com/python/cpython/blob/3.8/Python/thread_pthread.h#L280)

red solar
#

ooh

subtle pike
#
    status = pthread_create(&th,
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
                             &attrs,
#else
                             (pthread_attr_t*)NULL,
#endif
                             pythread_wrapper, callback);

(obviously). pthread makes userspace threads (not individually kernel backed). Looking into the NT implementation, we find the following invokation in PyThread_start_new_thread (https://github.com/python/cpython/blob/3.8/Python/thread_nt.h#L180), ```c
hThread = (HANDLE)_beginthreadex(0,
Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int),
bootstrap, obj,
0, &threadID);

The documentation for `_beginthreadex` is found here: <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/beginthread-beginthreadex?view=vs-2019>. These are also userland threads (not kernel backed). So, yes, CPython will use userland threads but the specification does not specifically require this. Alternative implementations are free to implement green threads or any m:n threading model they choose.
#

hope this is enough info to satisfy you 😄

peak spoke
#

@red solar not without changing the syntax itself or some encoding magic afaik, but for classey you can change setattr/setattribute etc.

red solar
#

but i can't override x = y, only attributes of the class?

#

hmm is there __get__ and __set__?

flat gazelle
#

yeah, cannot override that (except in class definitions to an extent afaik)

peak spoke
#

assignment is a simple statement, so you can't do that without being in some of the more magic classes

red solar
#

what would be one of the more magical classes?

peak spoke
#

and there isn't that much modifying it allows you to do

#

I haven't done it myself and can't look now but things like Enums modify it in some way to get subclasses on the values you assign it

#
In [6]: class A(Enum):
   ...:     a = 5
   ...:

In [7]: A.a
Out[7]: <A.a: 5>
wide shuttle
#

Ah, yeah, descriptors

red solar
#

hmm ok not quite what i needed :/

#

i think

wide shuttle
#

What do you need?

red solar
#

well i don't need it

peak spoke
#

get and set is used for the descriptor protocol, but you can't modify the assignment statement iself globally or at the module top level

red solar
#

lets say i have class A with attribute a, have and instance i, i = 3 sets a attribute to 3

#

rather than assigning a new object to that identifier

wide shuttle
#

In the case of Enum, I'm not sure what does the magic. It's probably done after the class is defined by a metaclass.

#

Let's test taht

#

!e

import enum

class Foo(enum.Enum):
    a = 1
    print(a)

print(Foo.a)
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

001 | 1
002 | Foo.a
wide shuttle
#

Right, so it happens after, maybe even at access time

#

hmm, I have not looked into this yet

#

lets say i have class A with attribute a, have and instance i, i = 3 sets a attribute to 3
@red solar

Is there any reason for not assign i.a = 3? That would make things much easier.

red solar
#

just nicer interface

flat gazelle
#

do you mean something like

class A:
    n = 0
    def __str__(self):
        return "A"
i = A()
i = 3
print(i, A.n) # A 3
red solar
#

wanna implement atomics, and would be nice if you could use them as normal numbers too

#

without needing to do .val the whole time

#

the other operators seem simple

#

but assignment not so much

#

oh wait that's a question for me - uhh

#

sure yeah

#

that

#

sry got distracted lol

flat gazelle
#

I think that entirely impossible. i = 3 does not ever actually look at value of i, so you would need to somehow recompile everything to do that, because you cannot determine at runtime whether this should happen or not

red solar
#

ah 😦

tawdry gulch
#

I wish static methods were indistinguishable from classmethods in python

#

so you could have this sorta stuff:

class Q:
  pass

t = Q()
t.a = "FOOBAR"

def func(self):
  print(self.a)

t.call = func

t.call() ## FOOBAR
#

I know you can do it with .bindstaticmethod

wide shuttle
#

The problem here is that you're assigning the function object to the instance instead of the class

#

the function objects we use for methods are assigned to class attributes

#

and that's when the descriptor protocol kicks in to insert the instance you access the class attributes on

#

If you were to assign func to Q.call, it would work

tawdry gulch
#

Oh, interesting

peak spoke
#

Also mind that a class method would be bound to the class object, not an instance of it

wide shuttle
#

methods are just regular function objects (unless you decorate them with something that returns something else)

#

!e

class Q:
  pass

t = Q()
t.a = "FOOBAR"

def func(self):
  print(self.a)

Q.call = func

t.call() ## FOOBAR
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

FOOBAR
tawdry gulch
#

But does calling a method in python still invoke __getattr__?

#

or is that only for fields

#

lemme check

#

it doesn't!

peak spoke
#

Python 2 had unbound methods, but 3 only has functions for functions/ static methods, and then bound methods to the class/instance depending on hwo you defined it

wide shuttle
#

@tawdry gulch Now try __getattribute__

tawdry gulch
#

Oh, sh*t I used the wrong dunder

wide shuttle
#

No, they both exist

peak spoke
#

It has to trigger one of the methods for getting attributes or it wouldn't be able to fetch the object

tawdry gulch
#

Oh

#

wat i thought there was just one

wide shuttle
#

But they play a different role in the attribute access logic

tawdry gulch
#

right

wide shuttle
#

__getattr__ only gets called if __getattribute__ raises an AttributeError (or calls __getattr__ directly)

red solar
#

why tho - why have both

wide shuttle
#

In this case, the attribute exists, so __getattribute__ will already return it

tawdry gulch
#

Wow!

#

Yeah

wide shuttle
#

It's to provide a safe way of dynamic attribute handling

tawdry gulch
#

Okay, I clearly need to be less cocky and look up what these other dunders do! : P

wide shuttle
#

The __getattribute__ takes care of explicitly defined attributes first

tawdry gulch
#

right

wide shuttle
#

Leaving you to safely implement __getattr__ to handle "dynamic"/"virtual" attributes

deft pagoda
#

i think i have some random spicy examples somewhere

wide shuttle
#

We all know you do

#

You're spice-die now

#

Unless you've got a salty example instead

flat gazelle
#

ah, so something like this, without screwing up things like __init__

class NS:
    def __init__(self, **kwargs):
        self._dict = some_dict
    def __getattr__(self, elem):
        try:
            return self._dict[elem]
        except KeyError:
            raise AttributeError
```or maybe just keep the keyerror
tawdry gulch
#

Thanks for the help btw Ves Zappa

#

👍

wide shuttle
#

I think people expect an AttributeError when accessing something as an attribute

deft pagoda
#
    def __getattr__(self, name):
        if name.startswith('bind_to_'):
            return self.__class__.__dict__[name[8:]].bind_deco(self)
        return super().__getattribute__(name)

i had this in a long class that allows you to bind functions to attributes

flat gazelle
#

why not use

vars(type(self))
``` and `getattr`
deft pagoda
#

cause i like chaining better

tawdry gulch
#

No offence but that looks quite fragile salt

flat gazelle
#

metaprogramming is fragile

deft pagoda
#

fragile?

flat gazelle
#

but convenient and people just have to not be stupid

tawdry gulch
#

Just the meddling with the strings, man I could literally trip myself up with that so easily haha

deft pagoda
#

it's just extra functionality

full jay
#

@flat gazelle Rules of programming in general, honestly

#

"Buyer beware" and all that

deft pagoda
#

we used it in a our peekable class too

tawdry gulch
#

its really interesting though

full jay
#

Please tell me you called it peek-a-boo

deft pagoda
#
    def __getattr__(self, attr):
        """Return the nth item in peeked with n  _'s, e.g., `.peek(2)` equivalent to `.__`"""
        n = attr.count('_')
        if n != len(attr):
            return super().__getattribute__(attr)
        return self.peek(n)[-1]
#
In [37]: p = peekable(range(100))

In [38]: p.__
Out[38]: 1

In [39]: p._____
Out[39]: 4

this was just silly though

tawdry gulch
#

Lol

cloud crypt
#

are we doing spicy things

#

not funny, not relevant lemon_unamused

wide shuttle
#

@deft pagoda That's... I don't know yet how that makes me feel

#

I mean, it's unusable in actual code, unless you've got magic eyesight for reading the number of _ when the number gets big

#

but it's quite funny as well

#

Hey, get me p.______________________________________________

deft pagoda
#

well it was mostly for like 1 to like 3

cloud crypt
#

p._{n}

deft pagoda
#

which i suppose you could just add manually as properties

cloud crypt
#

p._10

deft pagoda
#

but i thought it was hilarious at the time

#

and i standby that

wide shuttle
#

it is hilarious

cloud crypt
#

I found my code from a year ago and it just doesn’t have blank lines lol

wide shuttle
#

use this cool salt feature to get some vertical rulers as separators

cloud crypt
#

lol

full jay
#

Is there a font that separates underscores from each other to help count them?

cloud crypt
#

there is likely

#

@wide shuttle I once wrote the code that rotates all contents of the file 90° clockwise lemon_thinking

rare crane
#

hey guys. Im trying to capture the stack trace for the given line, which doesn't throw any error. Ive been looking at inspect, pbd and traceback, but didn't manage to wrap my head around it. Could anyone give me a hand pls?

deft pagoda
#

that's for a different channel

rare crane
#

okay, sorry for the off

flat gazelle
#

that would be an interesting code golf. A program which given a filepath would print that file rotated 90°

cloud crypt
#

yeah my code was a mess during the time I wrote it so time for a rewrite

rare crane
#

@deft pagoda which one would be the correct channel?

cloud crypt
#

@flat gazelle oh I probably know a way to do that

deft pagoda
cloud crypt
#

question is you can print spaces

#

like a instead of just a

flat gazelle
#

I would say yes

cloud crypt
#

alright that makes it much simpler

#
from itertools import zip_longest


def rotate_text(text: str) -> str:
    return "\n".join("".join(chars)[::-1] for chars in zip_longest(*text.splitlines(), fillvalue=" "))


def rotate_file(path: str) -> None:
    with open(path, "r") as file:
        data = rotate_text(file.read())

    with open(path, "w") as file:
        file.write(data)


def rotate_print(path: str) -> None:
    with open(path, "r") as file:
        print(rotate_text(file.read()))

path = input("Enter path: ")
rotate_print(path)``` @flat gazelle alright my brain came up with this
#

not a golf but it works

flat gazelle
#
with open(input())as f:a=[x.rstrip() for x in f];[print(''.join(a[r][c:c+1]or' 'for r in range(len(a))))for c in range(max(map(len,a)))]
``` attempt one
timid orbit
#
src/py_nitro_emulator.cpp:9:5: error: ‘nitro_emulator’ does not name a type
    9 |     nitro_emulator* emulator;
      |     ^~~~~~~~~~~~~~
src/py_nitro_emulator.cpp: In function ‘int NitroEmulator_Init(PyObject_NitroEmulator*, PyObject*, PyObject*)’:
src/py_nitro_emulator.cpp:13:11: error: ‘struct PyObject_NitroEmulator’ has no member named ‘emulator’
   13 |     self->emulator = new nitro_emulator();
      |           ^~~~~~~~
src/py_nitro_emulator.cpp:13:26: error: expected type-specifier before ‘nitro_emulator’
   13 |     self->emulator = new nitro_emulator();
      |                          ^~~~~~~~~~~~~~
error: command 'gcc' failed with exit status 1

This code works fine if I use it directly in src/py_module.cpp, but when compiling it on the side and including it with a header it fails suddenly. How would I fix this?

cloud crypt
#
print((lambda p:"\n".join("".join(c)[::-1]for c in __import__("itertools").zip_longest(*map(str.rstrip,open(p)),fillvalue=" ")))(input()))``` and golfed
timid orbit
#

you dont save any chars by defining n as \n, still takes the same amount of chars

#

actually

#

you waste one char because of the comma

cloud crypt
#

yeah you are right haha

#

updated

timid orbit
#

also, open(p).readlines() exists

flat gazelle
#

that would keep newlines, which mess it up

cloud crypt
#

doesn’t it yield a generator

flat gazelle
#

readlines is a list

cloud crypt
#

ah okay

flat gazelle
#

the file itself is a generator

cloud crypt
#

and yeah

flat gazelle
#

I should probably also use .read().split('\n')

cloud crypt
#

yeah

#

I mean it’s really memory-ineffective

#

but who cares when golfing :p

flat gazelle
#

though [*map(str.rstrip,f)] is just as long

cloud crypt
#

seems so

timid orbit
#

I remember when a year ago I golfed something that would be incredibly short but needed ~40TB of RAM to handle the created data

cloud crypt
#

you don’t need brackets though?

flat gazelle
#

for what I use, I do. I use indicies rather than zip transposition

cloud crypt
#

ah

#

okay

timid orbit
#

but yeah uh, did anyone see the question I posted

flat gazelle
#

I did, but I have no idea

timid orbit
#

hm

cloud crypt
#

As my Rustacean friend says, CPP being CPP Pog

flat gazelle
#

got it to 118 chars.

timid orbit
#

you could probably get it down even further using VTE codes Kappa

unkempt rock
#

How do i analyse images. For example do like:
Check the image resolution
Check how many red pixels exist
Check the position of blue pixels

Does anyone know how to help

gloomy rain
#

@unkempt rock You were misled.

#

This is not the correct channel to ask.

unkempt rock
#

oof

#

Ok what channel

gloomy rain
unkempt rock
#

Ok

#

Thanks

fossil jetty
#

What is the point of enums? Is strictly to catch typos? Why wouldn't you use a set instead of enums?

flat gazelle
#

Enums are useful when there is a finite number of variants to something. For example an enum of male, female, other

#

not sure how you would use a set here?

fossil jetty
#

so in your example, I can make an enum:

class Sex(Enum):
    male: 1
    female: 2
    other: 3

or I can make a set

sex = {'male', 'female', 'other'}
#

isn't one way shorter and more concise?

flat gazelle
#

you can decide to arbitrarily use some specific strings as variants.

#

but that is not what male is. male is not the 4 characters m a l e. male is one of the 3 variants

wide shuttle
#

The use of enum is typically not just to store a collection of values

#

Rather, it to have easily recognizable values that increase readabality

chilly silo
#

Server.py (Running on my aws ec2 instance)

import socket

s = socket.socket()
host = socket.gethostbyaddr('aws.ec2.public.ip')[0]
port = 12345
s.bind((host, port))

s.listen(5)
while True:
   c, addr = s.accept()
   print('Got connection from', addr)
   c.send('Thank you for connecting'.encode())
   c.close()

Client.py (Running on my local pc)

import socket

s = socket.socket()
host = socket.gethostbyaddr('aws.ec2.public.ip')[0]
port = 12345

s.connect((host, port))
print(s.recv(1024).decode())
s.close()

All inbound & outbound TCP traffic granted

The Server code shows no error.
But the Client code says

Traceback (most recent call last):
  File "/Users/sohamjain/Desktop/client.py", line 7, in <module>
    s.connect((host, port))
TimeoutError: [Errno 60] Operation timed out
>>> 

Connecting to the EC2 instance via rdp client works perfectly

When I run both these scripts on local host they seem to work fine.
But in case of AWS EC2 Instance, it does not.
Where did I go wrong?

fossil jetty
#

So it's there for code clarity and preventing typos?

flat gazelle
#

yes, and because it makes it clear that it is a variant rather than a string. Because when I see a string, I expect it to get printed or manipulated in some other way

fossil jetty
#

in what workflow would you not prefer it as a string?

#

being of type sex == 'male' vs. 'male'... is there a practical difference?

flat gazelle
#

not sure what do you mean?

fossil jetty
#

I'm struggling to see why you would prefer the enum Sex.Male vs. 'male'

#

And then when you evaluate Sex.Male, you will get 1, which is not very intuitive?

flat gazelle
#

well, you can do Male = 'male' instead of Male = 1

#

if I see 'male' I do not know what the other options are

#

and I do not know where to look

gloomy rain
#

@fossil jetty An enum type can only take on the defined values, whereas a string can be anything.

flat gazelle
#

as well as str not being the logical type of the value.

gloomy rain
#

Using enums to restrict the possible values decreases the risk of making a mistake.

flat gazelle
#

the logical type has 3 variants (a cardinality of 3). A string has many more options and context often does not tell me what the variants are, and whether there is even a finite number of them

#

and also you can do things like

class Direction(Enum):
    Up = Vector(0, 1)
    Down = Vector(0, -1)
    Left = Vector(-1, 0)
    Right = Vector(1, 0)
``` which would be a pain with strings
fossil jetty
#

Is the enum basically a frozendict?

flat gazelle
#

it is a mappingproxy internally, and also has a list of member names, and a backward map as long as values are hashable

sacred tinsel
#

imagine a function that takes a sex parameter as a string - how can you communicate what the allowed values would be? you may need extra documentation

def func(sex: str):
    """
    Allowed sex values: "male", "female", "other"
    """
    ...

maybe you should also mention whether they are case sensitive, and if you eventually decide to add another option, you risk having the docs go out-of-sync with the implementation, and it quickly becomes a mess

#

now consider this:

#
class Sex(Enum):
    MALE = 0
    FEMALE = 1
    OTHER = 2

def func(sex: Sex):
#

all of those problems are suddenly avoided, and you cannot pass an invalid value

#

~ you can, but then you're passing an invalid type

#

the value here is arbitrary (an int flag), we do not actually care what the value is, as long as it's unique

#

values don't have to be arbitrary, but in this example they are

flat gazelle
#
def func(sex: Union[Literal['male'], Literal['female'], Literal['other']]): ...
``` is an option, but ew
sacred tinsel
#

yeah, there's ways around it, but enums are very pleasant to work with in my experience

#

your editor will most likely offer you the members if you do Sex.

#

that alone is a massive benefit for me

flat gazelle
#

yeah, enum is definitely better

unkempt rock
#

hey

#
if "Access denied" in hey or "Error 502" in hey or "Deceptive site ahead" in now or "404 Error" in now:
            #Links.pop(link)
            array.append(link)```
#

what is the alternate way of writing this

flat gazelle
#

probably more suited to #python-discussion, but you can do {"Error 502", "Access denied"}.intersection(hey) or {"Deceptive site ahead", "404 Error"}.intersection(now)

#

well, as long hey and now are not strings

unkempt rock
#

can i do if ("Access denied" or "Error 502") in hey or ("Deceptive site ahead or "404 Error" ) in now:

cloud crypt
#

no

#

!or-gotcha

fallen slateBOT
#

When checking if something is equal to one thing or another, you might think that this is possible:

if favorite_fruit == 'grapefruit' or 'lemon':
    print("That's a weird favorite fruit to have.")

After all, that's how you would normally phrase it in plain English. In Python, however, you have to have complete instructions on both sides of the logical operator.

So, if you want to check if something is equal to one thing or another, there are two common ways:

# Like this...
if favorite_fruit == 'grapefruit' or favorite_fruit == 'lemon':
    print("That's a weird favorite fruit to have.")

# ...or like this.
if favorite_fruit in ('grapefruit', 'lemon'):
    print("That's a weird favorite fruit to have.")
cloud crypt
#

wait that’s not suitable here :p

deft pagoda
#
In [45]: from itertools import count
    ...: 
    ...: class IncrDict(dict):
    ...:     def __init__(self, start=0, step=1):
    ...:         self.counter = count(start, step)
    ...: 
    ...:     def __missing__(self, key):
    ...:         if key.startswith('__'):
    ...:             raise KeyError(key)
    ...: 
    ...:         self[key] = next(self.counter)
    ...:         return self[key]
    ...: 
    ...: class EnumMetaclass(type):
    ...:     def __prepare__(*args, **kwargs):
    ...:         start = kwargs.get('start', 0)
    ...:         step = kwargs.get('step', 1)
    ...:         return IncrDict(start, step)
    ...: 
    ...: class Enum(metaclass=EnumMetaclass):
    ...:     def __init_subclass__(cls, **kwargs):
    ...:         """Pull kwargs from class def"""
    ...:         
    ...: class Sex(Enum):
    ...:     MALE
    ...:     FEMALE
    ...:     OTHER

In [46]: Sex.MALE, Sex.FEMALE, Sex.OTHER
Out[46]: (0, 1, 2)
cloud crypt
#

damn it :p

#

again

#

I wonder about that it is [46] already lol

unkempt rock
#

...:

#

what is this

flat gazelle
#

ipython sessions go on for a while

deft pagoda
#

i've gotten into quad digits

flat gazelle
#

...: is how ipython shows continuing the same multiline input

deft pagoda
#

no

#

but probably this isn't the channel you're looking for?

half elbow
#

Hi, I'm a bit confused about the following:

from abc import ABC, abstractmethod
from typing import Type


class Base(ABC):

    @abstractmethod
    def foo(self) -> None:
        pass

    def bar(self) -> None:
        print("Base bar")


class Derived(Base):

    def foo(self) -> None:
        print("Derived foo")


def func(arg: Type[Base]):
    arg.foo()
    arg.bar()


func(Derived())

In principle this code works as expected, it prints Base bar and Derived foo, however, mypy complains about it:

test.py:22: error: Too few arguments for "foo" of "Base"
test.py:23: error: Too few arguments for "bar" of "Base"
test.py:26: error: Argument 1 to "func" has incompatible type "Derived"; expected "Type[Base]"
Found 3 errors in 1 file (checked 1 source file)

Even though I think I'm using Type as intended (see: https://docs.python.org/3/library/typing.html#typing.Type)

cloud crypt
#

mypy being mypy again

#

And no, you are using it wrong

#

Type[Class] means Class, not instance

#

should be just arg: Base

fossil jetty
#

I guess for my use case, I typically have a config file stored in config.yml.

When you parse it, you get a nested dict (and I convert to dot dict for convenience)

Then if I ever need to access something, I will do: config.sex.male

I guess I could convert the values of config.sex to enums? Not really sure

half elbow
#

@nekit you're completely right

#

thanks!

fossil jetty
#

as a practical example, an enum might be:

class Colors(Enum):
    BG_COLOR: 'red'
    FG_COLOR: 'blue'

bg_color = Colors.BG_COLOR

Or it could be a dict?

bg_color = config.colors.bg_color
flat gazelle
#
class Colors(Enum):
    BG_COLOR: 'red'
    FG_COLOR: 'blue'
``` this is not really an enum usecase
fossil jetty
#

though I guess you can't store your Vector example above

flat gazelle
#

that would be better as a dict

deft pagoda
#

or a dataclass

flat gazelle
#

dataclasses have instances, no?

#

SimpleNamespace if anything

deft pagoda
#

just define your own __call__ for the metaclass

flat gazelle
#

Enums are not about taking a string and giving it a value. An enum enumerates (lists all posible values) of some type. a Direction has 4 options, gender has 3, a boolean has 2, an ordering has 3, fingers on a hand have 5, teeth have ~40 IIRC,...

fossil jetty
#

Maybe this is a better example:

class AvailableColors(Enum):
    Red: 'red'
    Blue: 'blue'

vs.

config.availablecolors = ['red', 'blue']

flat gazelle
#

yeah, there an enum does make sense

fossil jetty
#

so you can write something like

def func(color):
    if color in config.availablecolors:
        ...

def func2(color):
    if color in AvailableColors:
        ...
#

and they are functionally equivalent?

#

Except the Enum in this case can give you a typehint

def func(color: AvailableColors):
    ...
flat gazelle
#

ye, and once again, makes it clear what options there are (though if you have it in config, I would say strings are fine if the config format does not support enums)

tacit hawk
#

@subtle pike I am dinamically linking libpthread to create mutexes. I configured a robust mutex but I does not works with python threads. When creating threads directly with pthread_create, the robust mutex works.

deft pagoda
#
class ColorDict(dict):
    def __init__(self):
        super().__init__()
        self['colors'] = []

    def __missing__(self, key):
        if key.startswith('__'):
            raise KeyError(key)
        self['colors'].append(key)


class ColorMeta(type):
    def __prepare__(*args):
        return ColorDict()

    def __call__(cls):
        return cls.colors

class Colors(metaclass=ColorMeta):
    ...

class MyColors(Colors):
    blue
    red
    orange

In [63]: MyColors()
Out[63]: ['blue', 'red', 'orange']
tacit hawk
#

@subtle pike The robust mutex only works when the python main thread exists with errors

subtle pike
#

what do you want me to do with this information?

timid orbit
#

@deft pagoda Thanks, I hate it

tacit hawk
#

I think it is not possible to detect a thread exited at low level

deft pagoda
#

thredo library offers ways to handle errors in threads

timid orbit
#

python threads are not "real" threads and this will always be a thing as long as the GIL exists, so detecting it at low level is impossible

deft pagoda
#

they are too, they are real posix threads

#

they are locked though

timid orbit
#

huh

tacit hawk
#

Is there any problem in creating threads without using threading?

deft pagoda
#

no idea, my knowledge about threads is not deep

timid orbit
#

I always thought they were just pooled interpreters on the same environment

#

@tacit hawk afaik, as long as the non-threading non-_thread threads are not using python, it's fine (otherwise this could cause issues with the GIL)

deft pagoda
#

they're actual factual threads, but they still obey the gil

#

you can use lower-level libraries that are threaded, i think

#

say, written in c++ or something

timid orbit
#

As long as threads not spawned through _thread don't use any PyXX C methods, you're fine

deft pagoda
#

i think so too

tacit hawk
#

I think I need a C extension, at python level it will not be possible to use mutexes

timid orbit
#

Does anyone here have experience with C++/Python Extensions btw?

#

I'm including a class from a library, and when I use it in py_module.cpp (the main file for my code) it works perfectly fine.
When I move the code using it to another file, and use a header to let py_module use py_nitro_emulator, I get an error, saying the class is not a valid name:
(nitro_emulator is a class from a library)

src/py_nitro_emulator.cpp:9:5: error: ‘nitro_emulator’ does not name a type
    9 |     nitro_emulator* emulator;
      |     ^~~~~~~~~~~~~~
src/py_nitro_emulator.cpp: In function ‘int NitroEmulator_Init(PyObject_NitroEmulator*, PyObject*, PyObject*)’:
src/py_nitro_emulator.cpp:13:11: error: ‘struct PyObject_NitroEmulator’ has no member named ‘emulator’
   13 |     self->emulator = new nitro_emulator();
      |           ^~~~~~~~
src/py_nitro_emulator.cpp:13:26: error: expected type-specifier before ‘nitro_emulator’
   13 |     self->emulator = new nitro_emulator();
      |                          ^~~~~~~~~~~~~~
error: command 'gcc' failed with exit status 1
tacit hawk
#
    thread_entry = c.CFUNCTYPE(c.c_void_p, c.py_object)(run)
    thread_id = c.c_ulong(0)
    my_mutex = mutex.DemoMutex('my_shared_mutex')
    if (e := mutex._pt.pthread_create(c.byref(thread_id), None, thread_entry, c.py_object(my_mutex))) != 0:
        my_mutex.close()
        raise OSError(e, os.strerror(e))
    thread_result = c.POINTER(c.c_int)()
    if (e := mutex._pt.pthread_join(thread_id, c.byref(thread_result))) != 0:
        my_mutex.close()
        raise OSError(e, os.strerror(e))
    print("Success")
    my_mutex.close()

run is a python func, _pt is the libpthread library. The posix robust mutex can detect when threads exits without releasing a mutex, it then notifies the next thread that attemps to lock the mutex by returning the error EOWNERDEAD. This error is returned with posix threads but not with python threads

#

This is the run func

def run(my_mutex):
    print("pthread thread started")
    time.sleep(5)
    my_mutex.lock()
    print("Mutex locked")
    # exit the thread without releasing the lock
    mutex._pt.pthread_exit(None)
tacit hawk
#

oops nevermind, my test had a bug lol

#

It works with python threads

radiant fulcrum
#

So with the subprocess module

#

we have Popen yeah

#

Now the system ive built with it has some context manager stuff so we close any open processes if the main area gets killed

#

but now, how does subprocess handle started processes if they don't get killed on exit

#

e.g just telling pycharm to restart the file without a context manager

#

🤔

peak spoke
#

subprocesses should get killed when the main process exits

radiant fulcrum
#

hmm cool

red solar
#
def store(self, value: int): pass
def store_explicit(self, value: int, memory_order: int): pass

or

def store(self, value: int, memory_order: Optional[int] = None): pass
#

?

sacred tinsel
#

you cannot have two functions with the same name exist in the same namespace

#

python doesnt support overloading

peak spoke
#
def store(self, value: int): pass
def store(self, value: int, memory_order: int): pass

is

def store(self, value: int, memory_order: int): pass
radiant fulcrum
#

one will just override the other

#

in order of decent if theyre all top level

sacred tinsel
#

yeah, its regular assignment like

a = 1
a = 2
red solar
#

sorry meant store_explicit for the second store

#

just realised

#

lemme edit rq

#
def store(self, value: int): pass
def store_explicit(self, value: int, memory_order: int): pass

or

def store(self, value: int, memory_order: Optional[int] = None): pass

ok this

peak spoke
#

Depending on how it's handled inside, but making it optional doesn't look like a bad idea

paper echo
#

@sacred tinsel type annotations do support overloading

red solar
#
def store(self, value: int, memory_order: int = atomic.memory_order_seq_cst)
paper echo
#

i think there's a decorator you need for it

red solar
#

ok probably this

#

but ok i'll try implement the optional one

paper echo
#

!d g typing.overload

fallen slateBOT
#
@typing.overload```
The `@overload` decorator allows describing functions and methods that support multiple different combinations of argument types. A series of `@overload`-decorated definitions must be followed by exactly one non-`@overload`-decorated definition (for the same function/method). The `@overload`-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-`@overload`-decorated definition, while the latter is used at runtime but should be ignored by a type checker. At runtime, calling a `@overload`-decorated function directly will raise [`NotImplementedError`](exceptions.html#NotImplementedError "NotImplementedError"). An example of overload that gives a more precise type than can be expressed using a union or a type variable:... [read more](https://docs.python.org/3/library/typing.html#typing.overload)
paper echo
#

@sacred tinsel ^

red solar
#

memory_order is still a position argument in def store(self, value: int, memory_order: int = atomic.memory_order_seq_cst) right?

peak spoke
#

Well annotations for stubs and actual working overloading are a bit different

#

Yes, unless you tell it to be a keyword only arg with a * it'll also be positional

red solar
#

can i tell it to be only arg?

peak spoke
#

Positional only?

red solar
#

yeah

peak spoke
#

Yes, with a / in the signature

red solar
#

def a(p1, p2, /) like that?

peak spoke
#

mind that it's 3.8+

red solar
#

ah :/

#

ok might stick with kwargs then

#

now to figure out how to implement it 🙂

peak spoke
#

They're still passable as positional args, just can't force it on older python versions

red solar
#

i'm doing this in c, and i don't want to have to figure out how to handle both cases 😂

#

ugh actually might have to cuz i can't force it as a kwarg either :/

#

maybe python will be kind enough to enforce it for me 🙂

peak spoke
#

any reason why it'd do type(0) and delete 2 references at the end of the module in the source?

pliant tusk
#

I'd guess that the auto-gen doesn't know about __all__ so it deletes those 2 names so they aren't visible to make the name space cleaner

#

It also might not know int exists as something it can access. Although it does know about list so who knows

snow kindle
#

I have a pain question to ask you, do you have some documentation to learn C implements Python ?

boreal umbra
#

I wish regex matches used __getitem__ to get the groups instead of group

grave jolt
#

They do, don't they?

boreal umbra
#

Do they?

#

I always use the group method.

grave jolt
#

!e

import re
m = re.match("(abc)(\\d+)", "abc42")
print(m[0])
print(m[1])
print(m[2])
fallen slateBOT
#

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

001 | abc42
002 | abc
003 | 42
boreal umbra
#

Wtf

grave jolt
#

Named groups work with stringly indices

boreal umbra
#

Now I have to refactor all my code.

grave jolt
#

If that's what you meant ^

spark magnet
#

@boreal umbra new in 3.6

snow kindle
#

@grave jolt yes I want another documentation

grave jolt
#

What do you mean by "another documentation"?

snow kindle
#

I see this one but I want other sources to see the difference @grave jolt

grave jolt
#

You can also just look at the implementation on GitHub

boreal umbra
#

There's a bool that came out recently about the internals. No idea if it's good.

#

Book*

#

Apparently I don't say book so my keyboard went with bool.

#

@spark magnet are you a core developer?

#

Sorry if I've asked you before.

spark magnet
#

no, i'm not, but i have poked around in the internals a bit

boreal umbra
#

Aha

spark magnet
#

(i always forget to use match[1] for groups also, thanks for the reminder)

boreal umbra
#

On a semi related note, I'm using regex for a project

#

That project includes reading a lot of files

#

So I'm using cached attributes to make sure that the disk read doesn't happen until and unless you need the data from the file, rather than just its metadata

#

But I'd need five cached attributes per file, so it would be choosing either zero to five reads per instance, or always one.

#

Unless I cache the content of the file as well

#

But now it seems like silliness.

red solar
#

@snow kindle which part do you want help with?

#

I have a pain question to ask you, do you have some documentation to learn C implements Python ?

#

@worldly venture ^^ 🙂

worldly venture
#

lol

red solar
#

cypt since you've already looked at the basic documentation, is this a question because you need help with something specific? or you just generally want more documentation to look at?

paper echo
#

@boreal umbra why would it be five reads to get five attributes from one file

#

Presumably you would have one method to invalidate all 5 cached attributes, and reload them all at once from one read

snow kindle
#

@red solar integration of C class in python

You write a C program with enter value and I want to be able to get them in python

red solar
#

C doesn't have classes 🤔

#

has this function/class already been written in C, and you want to access it from python? or you're trying to write your own from scratch?

polar carbon
#

How do I convert a pil.image to a format image (jpeg)?

red solar
#

Image.save(name, format="jpg") (or something similar)

#

@snow kindle

has this function/class already been written in C, and you want to access it from python? or you're trying to write your own from scratch?

#

oh you're on, pinged you cuz thouhgt you might be on a while later lol

snow kindle
#

@red solar I write a function in C for get time right and I want to be able to import it in python

polar carbon
#

@red solar plt.savefig(buffer, format="jpg")?

red solar
#

i don't think you can import a single function from C - you can either compile your C function as part of a shared library, and access it through ctypes (in which case it will be a single function), or if you want to access it as normal python, you need to turn it into a module @snow kindle

#

uhhh

snow kindle
#

@red solar ok thanks

polar carbon
#

@red solar I couldn't make it work
here is my code (it's a mess so far)

        plt.show() 

        buffer=BytesIO()
        plt.savefig(buffer, format="jpg")

        buffer.seek(0)
        #buffer.save("hello.jpg")
        im=PIL.Image.fromarray(buffer)
        print(im)
        im.save(buffer, "png")
        print(im)
        #image=PIL.Image.open(buffer) 
        #print(type(image))
        print(type(buffer))
        
        await ctx.send(file=discord.File(fp=plt, filename="hello.jpg")) ##works```
#

plt is a plot object

red solar
#

but buffer is empty?

#

ah ok i see

polar carbon
#

do you see where the problem is?

red solar
#

so wait, does plt hold the image?

#

like it's a full image, not some empty data?

polar carbon
#

yes it does

red solar
#
bufferedio = BytesIO()
avatar.save(bufferedio, format="PNG")
bufferedio.seek(0)
#

then yeah, this but JPG

#

(or JPEG i forget)

#

(also instead of avatar, plt)

polar carbon
#

Module 'matplotlib.pyplot' has no 'save' member

#

@red solar

red solar
#

you said this was pil.image?

red solar
#

ahh

#

my bad

polar carbon
#

@red solar np, how can I solve it?

red solar
#
plt.show()  # pyplot obj

buffer = BytesIO()
plt.savefig(buffer, format="JPEG")
buffer.seek(0)

file = discord.File(buffer, filename="hello.jpg")
await ctx.send(file=file, filename="hello.jpg"))
polar carbon
#

buffer.seek(0)

#

isn't this necessary?

red solar
#

yeah was just about to edit it in lol

#

just remembered

polar carbon
#

@red solar THE BOT sends an empty image

#

and the type of plt is module

#

which doesn't actually does what I want

red solar
#
        async with ctx.typing():

            # Get avatar bytes
            image_bytes = await ctx.author.avatar_url.read()
            avatar = Image.open(BytesIO(image_bytes))
            avatar = avatar.convert("RGBA").resize((1024, 1024))

            avatar = self.crop_avatar(avatar)

            ring = Image.open(Path(f"bot/resources/pride/flags/{flag}.png")).resize((1024, 1024))
            ring = ring.convert("RGBA")
            ring = self.crop_ring(ring, pixels)

            avatar.alpha_composite(ring, (0, 0))
            bufferedio = BytesIO()
            avatar.save(bufferedio, format="PNG")
            bufferedio.seek(0)

            file = discord.File(bufferedio, filename="pride_avatar.png")  # Creates file to be used in embed
            embed = discord.Embed(
                name="Your Lovely Pride Avatar",
                description=f"Here is your lovely avatar, surrounded by\n a beautiful {option} flag. Enjoy :D"
            )
            embed.set_image(url="attachment://pride_avatar.png")
            embed.set_footer(text=f"Made by {ctx.author.display_name}", icon_url=ctx.author.avatar_url)

        await ctx.send(file=file, embed=embed)
#

this is what i'm going off of 🤷

#

oh yeah wait

#
plt.show()  # pyplot obj

buffer = BytesIO()
plt.savefig(buffer, format="JPEG")
buffer.seek(0)

file = discord.File(buffer, filename="hello.jpg")
await ctx.send(file=file))
#

i think specifying filename made it send an empty file if the filename didn't exist

#

@polar carbon

signal eagle
#

Anybody here familiar with DP utilization within python?

red solar
#

DP being decimal point? or something else?

signal eagle
#

dynamic programming

red solar
#

ok... you're going to have to elaborate on what you mean by that

raven ridge
#

it's not really on topic for this channel.

red solar
#

like everything in python is dynamic

raven ridge
#

Discussion on the use cases, implementation and future of the Python programming language including PEPs, advanced language concepts, new releases, the standard library, and the overall design of the language.

signal eagle
#

ah ok my bad

raven ridge
signal eagle
#

though i dont think saying this falls within "implementation... of the Python programming language" is so farfetched

red solar
#

@grizzled vigil if you're on, ik you work mainly on async, but do you know if there's any good reason why python doesn't have any atomics support rn? only things i can think of are back in the day compiler support for stdatomic.h was lacking, and lack of interest

#

oh huh

#

it's an actual thing

polar carbon
#

the datatype of file is BytesIO this is the problem

#

@red solar

raven ridge
#

though i dont think saying this falls within "implementation... of the Python programming language" is so farfetched
@signal eagle If you were asking whether CPython uses dynamic programming in its implementation, that's on-topic. If you're asking how to use dynamic programming in Python, that's not.

#

"implementation of the language", not "implementation in the language".

signal eagle
#

ah gotcha

red solar
#

@polar carbon probably time to ask in #discord-bots cuz that's as much as i know 😂

polar carbon
#

@red solar lol thank you tho!

#

How do I convert BytesIO file into PNG? @raven ridge

red solar
polar carbon
#

this is more related to general python I guess

#

or PIL

red solar
#

what exception are you getting?

polar carbon
#

none

red solar
#
plt.show()

buffer = BytesIO()
plt.savefig(buffer, format="JPEG")
buffer.seek(0)

test_im = Image.open(buffer)
test_im.show()
#

try this

#

if it doesn't show the image again, then your issue is here

polar carbon
#

plt.show()

#

this works fine

raven ridge
#

How do I convert BytesIO file into PNG? @raven ridge
@polar carbon That's off-topic for this channel.

red solar
#

ok... what about test_im.show()?

polar carbon
#

ohh test oki!! let's me try

#

@raven ridge ohh oki

tidal karma
#

i am new here, what is all of this about?

red solar
#

the channel specifically?

#

or the server?

tidal karma
#

the server

#

and what qualifies as advanced python

red solar
#

anything python related pretty much

#

advanced python is

Discussion on the use cases, implementation and future of the Python programming language including PEPs, advanced language concepts, new releases, the standard library, and the overall design of the language.

tidal karma
#

okay

#

thank you

red solar
#

np 🙂

tidal karma
#

im on the most boring project rn, i wrote this whole long ass vectorization function for a chat agent and now they are making me use dialog flow

#

and just throw away my work

raven ridge
#

Not "anything Python related" at all.

red solar
#

did you at least get paid for it tho? (also yeah that)

raven ridge
#

the topic is about the language itself.

red solar
#

no i meant the server there :/

tidal karma
#

yeah im paid hourly and get bonuses

red solar
#

eh you'll manage then lol

#

but i get it, it sucks :/

tidal karma
#

yeah it was j annoying, i wanted to finish it so i could throw it on my application

#

for college that is, i am 18

hazy anchor
#

how precisely does a vectorisation function relate to a chat agent.

tidal karma
#

it was for classifying intents and finding spelling errors

red solar
#

throw it on your application anyway 🤷

hazy anchor
#

and you hand implemented something for that?

tidal karma
#

yeah

hazy anchor
#

theres a lesson involved

tidal karma
#

what’s that

hazy anchor
#

dont do that :p

tidal karma
#

it was pretty fun doing it tho

hazy anchor
#

noone wants to inherit homerolled nlp

#

you dont work for fun.

tidal karma
#

i know

polar carbon
#

ok... what about test_im.show()?
@red solar that works
but my bot doesn't send it because it's a PIL.PNGIMAGEPLUGIN.PNGIMAGEFILE

red solar
polar carbon
#

thanks!

tidal karma
#

what are you doing kranthos

red solar
magic python
#

I don't know what sort of formatting logger is using for it's format = ... , presumably it's logger specific?

I was wondering how to zero pad some fields so it printed nicer, like f" {blah:<20}" or something, that sort of formatting, I'm not sure how to do this with %(levelname)s though

#

oh i can just do %(module)10s instead of %(module)s , i guess I'm not familiar with this version of string formatting

spark magnet
#

@magic python it's %-formatting

magic python
#

@spark magnet thanks, is it more limited than the typical formatting?

#

for example, can it left/right align?

spark magnet
#

what are you counting as "typical"?

magic python
#

sorry, typical for me is f-strings I suppose

spark magnet
magic python
#

thanks ned... is it odd that logging still uses this "old" style? I thought that everything would move as one, but i might just be wrong there

#

curious whether it's something that would be in line for updating at some point, or if it's just fine as is

spark magnet
#

you'd have to think about backward compatibility

raven ridge
#

You can actually get logging to use .format() style format strings, instead - but, don't. Every library out there that does any logging is doing it with printf-style format strings, and so if you set up logging to use .format() style format strings it will break whenever you try to use any library that anyone else wrote.

hazy anchor
#

i believe the old style is lazyily evaluated in the sense that the formatting isnt done if the log level is unsufficient

raven ridge
#

that's true, but independent of style. It will be lazily evaluated if you use $ or { as your formatting style, too.

hazy anchor
#

ah that seems quite a nice version. unfortunately ive seen log.info("blabla".format()) quite a lot. ill have to bookmark that as the right way to do it.

paper echo
#

9 times out of 10 the str conversion isn't the expensive part of logging

#

so the lazy evaluation aspect never really helped me much in practice

#

since you're still computing all the arguments to the logger

hazy anchor
#

i've definitely had it be the expensive part in other systems, but never in python. probably instincts sending me astray there.

#

the truth of the matter is i simply like printf style better and this is ammo :p

raven ridge
#

the lazy evaluation is beneficial for other reasons, not just performance. If the substitution fails, for instance, the logger logs that the string formatting failed and then swallows the exception. If you're doing the string formatting yourself, you'll get an exception that will break out of the current block and bubble up

hazy anchor
#

the reason for my crusade is the common pattern ive seen is

#

i want to use format, the line gets too long and complex to use an inline "aaa".format inside the call to logger, so ill move that to a temporary variable called 'msg' or something.

#

it shits me up the wall.

raven ridge
#

lazy evaluation's behavior of printing out the exception and then swallowing it is usually better for you, because logging in error blocks can have a bug that goes unnoticed for a long time, and you don't want to compound an error if you can avoid it.

hazy anchor
#

thats a good point, definitely have observed the cascading failure of a seldom used log in an exception handler.

paper echo
#

@raven ridge maybe its just me but i often end up having to do non-trivial calculations just to log the output that i want

#

and things like type conversion is the least of my concerns (+ those errors should be caught in testing anyway)

#
timestamp = response.timestamp
logger.debug('Request timestamp: %s', timestamp.strftime(...))

unless there's a better way to do this

#

i cant think of an actual example from my code right now

raven ridge
#

hm. I'm thinking more like someone does:

def get_ip_address(host):
    try:
        return socket.gethostbyname(host)
    except socket.gaierror:
        logger.error("Failed to resolve host {host}".format(host=host))
        return None
``` and then someone comes along and makes a change like:
```python
def get_ip_address(hostname):
    try:
        return socket.gethostbyname(hostname)
    except socket.gaierror:
        logger.error("Failed to resolve host {host}".format(hostname=hostname))
        return None

and misses updating the format string even though they renamed the variable everywhere else. I've seen mistakes like that happen all too often, and they're pretty easy to make.

#

sure, that should get caught in testing, but error paths tend to be less well tested than success paths, and in this case the original author may have tested it, and it was valid when it was written, but it became incorrect after the fact.

#

@paper echo the strftime thing isn't a great example, since the default __str__ of a datetime.datetime is pretty reasonable, but yeah, I do see your point. The exception swallowing can't prevent every possible error, only some.

paper echo
#

yeah i agree its not a great example

tacit hawk
#

Is there any way to hook into object deallocation from python?

raven ridge
#

@tacit hawk you mean like take some action when an object is garbage collected? Or something else?

tacit hawk
#

yes, like a class destructor

raven ridge
#

if you mean for your own class, __del__ (though do note that it's not guaranteed to be called in all cases, and has some restrictions on what it can do).

tacit hawk
#

I knew about __del__, I though there was another way. Thanks

raven ridge
#

well - why do you want another way?

red solar
#
        if (!PyArg_ParseTupleAndKeywords(args, kwds, fmt, kwl, &PyLong_Type, &value_py, &mem_order)) { \
            return NULL; \
        } \
        Py_INCREF(value_py); \
        unsigned long long value = PyLong_AsUnsignedLongLong(value_py); \
        Py_DECREF(value_py); \
#

any thoughts as to whether I actually need Py_INCREF and Py_DECREF here?

tacit hawk
#

That finalizer seems to be more reliable than __del__

raven ridge
#

it has the exact same set of caveats, AFAIK

#

@red solar you don't, no. PyArg_ParseTupleAndKeywords gives you back a borrowed reference to value_py, and that borrowed reference is all you need.

red solar
#

ok awesome 🙂 i don't need to change all my functions 🙂 (there's like 10 that look just like this)

raven ridge
#

you may want to look into Cython, though. 🙂

red solar
#

does cython let me use C directly?

#

like compile it in?

raven ridge
#

yes.

red solar
#

hmm

tacit hawk
#

Compile CPython extensions?

red solar
#

does Cython have macros or templates?

red solar
#

Fused types are not currently supported as attributes of extension types.

#

:/

#

also tbh i don't want a fused type :/

#
#define PY_ATOMIC_DEFINE_METHOD_SIGNED_OP(TYPE, TYPE_NAME, OP, OP_NAME) \
    static PyObject* \
    PyAtomic_##TYPE_NAME##_##OP_NAME(PyAtomic_##TYPE_NAME##_Object *self, PyObject *args, PyObject *kwds) \
    { \
        long long value; \
        int mem_order = memory_order_seq_cst; \
        const char *fmt = "L|i"; \
        static char *kwl[] = {"value", "memory_order", NULL}; \
        if (!PyArg_ParseTupleAndKeywords(args, kwds, fmt, kwl, &value, &mem_order)) { \
            return NULL; \
        } \
        if (value > SMAX_FAST_OF(TYPE) || value < SMIN_FAST_OF(TYPE)) { \
            PyErr_SetString(PyExc_OverflowError, "Python int 'value' too large to convert to C " # TYPE); \
        } \
        else if (!is_valid_memory_order(mem_order)) { \
            PyErr_SetString(PyExc_ValueError, "invalid 'memory_order' value"); \
        } \
        if (PyErr_Occurred() != NULL) { return NULL; } \
        long long old_val = atomic_##OP##_explicit((volatile TYPE *) &self->value, (TYPE) value, mem_order); \
        return PyLong_FromLongLong(old_val); \
    }

like i have this

#

and i can use it here 🙂

#

and expand them all

#

not sure i can do that with fused types

raven ridge
#

hm - how many types do you need this for?

red solar
#

potentially all of these? realistically probably not

#

(although if any of them are wider than long long i'm kinda screwed)

#

tbh i'll probably do all of them just cuz i'm adding a from_addr() class method, and someone could provide an address to any of those types 🤷

raven ridge
#

is this code somewhere on github that I can play with it?

red solar
#

what i shared? or the list of types?

raven ridge
#

what you shared.

red solar
#

i literally started it today - i can send you a gist link when i finish if you want

raven ridge
#

I'd settle for a gist of what you have so far 🙂

red solar
#

although i usually write c++ - this is my first time intentionally writing C, and my first time with macros, so might be a little rough

#

ok one sec

raven ridge
#

you can write extensions in C++ instead if you prefer, FWIW

red solar
#

oh also my <limits.h> file for some reason doesn't actually provide min/max for any types

swift imp
#

why are on earth are you making a macro like that

red solar
#

i realise, but i don't want to deal with linkers, and also c in an environment where destructors aren't important is fun 🙂

#

i'll send the link here, you can see for yourself lol

raven ridge
#

the macro doesn't look unreasonable to me at first glance.

red solar
#

ah see that's cuz you're used to C then 😂

swift imp
#

That macro seems unwiedly lol

red solar
swift imp
#

How are you supposed to debug that?

red solar
#

uhhh

#

ask whoever debugs it 😂

#

i've managed to get it down to 2 warnings

#

and both of them are unavoidable

swift imp
#

Its just so much. Lke you drop the baby all over the place and preprocessor aint gonna check crap

red solar
#

well i'm not writing this out normally

#

that's not my fault right?

#
({
    __auto_type; //stuff
})

is the expansion of atomic_exchange_explicit macro provided by stdatomic.h

raven ridge
#

you realize that the GIL makes every int an atomic int, right?

red solar
#

not if you put it in shared memory

raven ridge
#

true enough.

red solar
#

any thoughts on the warning?

raven ridge
#

Looking at it...

#

I think you shouldn't have the cast to volatile, if I'm reading this right:

The argument is pointer to a volatile atomic type to accept addresses of both non-volatile and volatile (e.g. memory-mapped I/O) atomic objects, and volatile semantic is preserved when applying this operation to volatile atomic objects.

red solar
#

fetch_add/sub/or/xor/and also say that tho

#

ohhh i see what you mean :/ it should be volatile _Atomic(TYPE) *?

#

hmm nvm

#

(i mean that's not exactly what you said, but i what i followed on as)

#

i swear i got an error earlier for not casting it

#

ig i'll try again

raven ridge
#

I don't think there should be a cast to volatile at all

red solar
#

you think it should be a plain &self->value?

raven ridge
#

I don't think there should even be a cast - I think it should just be:

long long old_val = atomic_##OP##_explicit(&self->value, (TYPE) value, mem_order);
red solar
raven ridge
#

self->value is already of type _Atomic(TYPE), so the cast shouldn't be necessary - and it's not volatile, so casting it to volatile seems wrong...

#

what compiler are you testing with?

red solar
#

gcc 7.5.0

#

technically this is CLion (and not the compiler directly) but i trust it

#

exchange seems to want (TYPE *)

#

everything else wants (volatile TYPE *) (apart from store or load that uses exchange under the hood so it wants (TYPE *)

raven ridge
#

Hm, I'm using gcc 7.5.0 and don't even get that far...

py_atomics.c: In function ‘PyAtomic_Bool_FetchAdd’:
py_atomics.c:392:1: error: operand type ‘volatile _Bool *’ is incompatible with argument 1 of ‘__atomic_fetch_add’
PY_ATOMIC_DEFINE_ALL_UNSIGNED_METHODS_AND_STRUCT(_Bool, Bool)
red solar
#

you tried to compile it?

raven ridge
#

yeah - was the version you gisted not in a compilable state?

red solar
#

not even close 😂

#

hence why i've been going off CLion warnings

raven ridge
#

Fair enough, then. "Only one warning" made me think "and no errors" 😄

red solar
#

if you want i'll ping you when it's done and compiles with minimal errors for me

#

*warnings not errors

raven ridge
#

yeah, you have my curiosity. I've never seen something where Cython isn't the easiest path, and I'm intrigued by the challenge here.

#

I'm also not intimately familiar with the C atomics API.

red solar
#

me neither - and i'm still not happy with volatile on every operation

#

in c++ atomics get optimised out if they can

#

can't optimise out volatile :/

raven ridge
#

so the goal is to define a new Python type for each of the C atomic types, each having every operation in fetch_add/fetch_sub/fetch_or/fetch_xor/fetch_and/exchange/load/store/compare_exchange_weak/compare_exchange_strong/is_lock_free

red solar
#

at a minimum, yes

#

also getattr/setattr for value

#

and dunder methods

#

__(i/r)add/sub/or/xor/and__, __int__, probably some others

raven ridge
#

plays with Cython

red solar
#

i'm at 500 lines, and it's just macros - in cython it would be that much per type

#

no chance it happens in cython 😂

raven ridge
#

well, worst case scenario it wouldn't be the craziest thing in the world to use the preprocessor to generate a Cython file. Best of both worlds.

#

(Or, you know, generate it at build time in setup.py with Python code, if you're not a lunatic)

red solar
#

hmm, that's actually a decent idea

#

but i think i'm too far gone at this point

red solar
#

we not using __int__ anymore? or is this just __index__ calling it internally?

#

what is it with python and not caring about signed integers

#

it's like AsLongLong we'll convert it from non integer types, we'll do our best, overflow will throw an exception

#

AsUnsignedLongLong yeah you may get an overflow error at most

fallow yew
#

Hi

red solar
#

hi 🙂

raven ridge
#

@red solar I think I'm still not quite picturing how you plan to use this. the GIL gives atomicity for every integer operation, at least in CPython. You contended that it doesn't if the integer is in shared memory, which is true - the GIL only protects it within one process (and perhaps one day within one interpreter). But - you're defining the integer as a member variable of a Python object, which means it can't be in shared memory, anyway - it's on the interpreter's heap. What am I missing?

red solar
#

crap one sec

#

ok that shouldn't be much of an issue - just changes how i initialize my atomic class

raven ridge
#

to - what, allocate a page of shared memory via mmap in your __init__? And is the idea that you share it with child processes, or what?

red solar
#

yeah

boreal umbra
#

A while ago I mentioned the idea of having a __key__ method for sorting so that you don't have to know anything about how the other operand in a comparison function

red solar
#

how does sorting currently work?

boreal umbra
#

but do you have to know anything about the other operand for __lt__?

red solar
#

presumably you need to know its type

boreal umbra
#

@red solar It uses a special sorting algorithm called timsort, and it uses how __lt__ is defined for a given class to decide when to swap things

red solar
#

oh - seems standard

#

you would always need to know the type though

boreal umbra
#

I think it's similar to bubble sort but with certain optimizations in place to capitalize on common cases.

#

I'm trying to do a weird thing where the type isn't necessarily the same.

red solar
#

i don't see how using __key__ would be better than __lt__

#

@raven ridge you raise a good point tho, if i don't own the memory myself, then there's no need for the classes to be defined in terms of types - they can be defined in terms of signed/unsigned and width

#

(maybe they could originally)

#

hadn't thought of that

boreal umbra
#

Consider the entities, which are just labels in the text

#

and relations, which state that two entities are related in some way

raven ridge
#

@boreal umbra the type isn't required to be the same for < - when you do a < b Python will call a.__lt__(b) and if that returns NotImplemented it will call b.__gt__(a), so if either of the types knows how to deal with the other it's fine

boreal umbra
#

I want relations to sort themselves based on however the two entities that comprise it are sorted, even if someone wants to redefine how they're sorted in their own implementation.

red solar
#

what was wrong with sort(list, key=func)?

boreal umbra
#

I think it would be more concise if the key for a given class was part of the class

#

I suppose __lt__ is basically that

raven ridge
#

the problem with __key__ is, what would you do if the list contained some elements that had __key__ defined and some that didn't?

boreal umbra
#

if __lt__ is basically comparing tuples of different instance variables, it sort of violates DRY

raven ridge
#

nothing stops you from defining a def sort_key() as a @classmethod or @staticmethod and then doing sort(lst, key=MyClass.sort_key)

red solar
#

all __lt__ is doing is x < y - how that's doing is up to the implementation

boreal umbra
#

well that would be the same as __key__, just not using dunder naming.

raven ridge
#

no, it wouldn't be, because you have to tell it which class's sort key to use.

boreal umbra
#

oh, I was already doing that in my code. I guess I could have said that.

raven ridge
#

the point of the magic methods is that the interpreter looks them up automatically. The point I'm making is that it wouldn't make sense for the interpreter to automatically look up a __key__, because it's not clear what it could do if some elements in the list don't have an __key__

boreal umbra
#

well, isn't it the same with __lt__?

raven ridge
#

well, in that case it falls back to __gt__ with the arguments reversed.

boreal umbra
#

ah

#

not __ge__?

raven ridge
#

no - a < b implies that b > a

boreal umbra
#

ah yes

raven ridge
#

but, anyway - if some members of a list defined __lt__ but not __key__, and others defined __key__ but not __lt__, what's a sort() to do?

boreal umbra
#

it could try __key__ first, then __lt__, etc.

#

I guess you'd end up with attribute errors that you'd have to handle

#

so that would be annoying

raven ridge
#

If class A has only __key__ and class B has only __lt__, then each of them thinks they've done the right thing, but there's still no sane ordering for sorted([A(), B()])

boreal umbra
#

I think this really stems from the fact that I don't like how you have to have multiple copies of the same tuple for identity-related functions

red solar
#

which tuple?

boreal umbra
#

__eq__, __hash__, etc will all probably use the same tuple, so you'd have to have several copies of it, and I'm not aware of IDEs handling that

#

a tuple of whichever attributes define that instance.

raven ridge
#

usually that's made up on the fly in each method - creating a tuple is one of the cheapest things you can do in Python

red solar
#

^

#

also won't they generally just copy the pointer? rather than make a whole new object?

#

(unless it's immutable or something)

boreal umbra
#

I'm talking about the writing of the code rather than ease of execution.

raven ridge
#

ah. well, dataclasses can help a bit with that.

red solar
#

i don't see how writing the code for __hash__ is at all similar to something like __eq__

#

but also pycharm writes a few of them for you if you ask it to

boreal umbra
#
class Person:

    def __init__(self, name, age):
        ...

    def __hash__(self):
        return hash((self.name, self.age))

    def __eq__(self, other):
        return (self.name, self.age) == (other.name, other.age)
#

etc

red solar
#

ah i see

boreal umbra
#

I think there's a way to pick and choose which fields in a dataclass you want to get included in all that

raven ridge
#

yeah, there is.

boreal umbra
#

but you might not want them to be in the same order for sorting.

raven ridge
#

The order of the fields in all of the generated methods is the order in which they appear in the class definition.
So you have control over that, too.

boreal umbra
#

for equality and hash the order obviously doesn't matter

#

but I might want the order for sorting and the order in the class definition to be different.

red solar
#

different to what?

boreal umbra
#

different to each other.

red solar
#

why?

#

the order in the class definition has no effect apart from for sorting

raven ridge
#

it affects the repr as well... and the order of arguments for __init__

boreal umbra
#

yeah

red solar
#

ok but do those matter?

boreal umbra
#

yes

vernal quartz
boreal umbra
#

the most intuitive order for the human-readable content isn't necessarily the best order for sorting it.

red solar
#

i disagree, in general the most intuitive order is the most important first, which is generally the best order for sorting too

raven ridge
#

If __sort_key__ had existed from the start, I think I'd agree with you that it would be better. I just can't imagine a way for the interpreter to switch to that without causing a backwards compatibility nightmare.

boreal umbra
#

yeah, the backwards compatibility would be a big issue.

red solar
#

if they make a call for breaking changes because they decide to release python4, there's your chance 🙂

boreal umbra
#

@red solar the content I'm trying to represent is defined on that website I mentioned earlier, and it reads lines of documents where the order is string, int, int, string

#

but the two ints are what you'd want to use for sorting, followed by the first string

#

and the last string doesn't matter at all.

#

Sorting it would be completely pointless if it sorted it in the same order that the data is presented.

red solar
#

ahh ok

raven ridge
#

Python version numbers are sorted first by epoch, but you don't want to make epoch your first argument to __init__, because for almost every package in existence it's 0, and it's an extreme special case that anything ever uses anything else, so you'd want your constructor to do epoch=0 to set the sane default.

red solar
#
// module: atomic
class Uint:
    def __init__(self, ptr_or_memview, size: int, offset: int = 0):
      pass
#

@raven ridge as a constructor?

#

can you think of anything else you'd want to construct it from?

raven ridge
#

signedness?

red solar
#

UInt and Int are separate classes

raven ridge
#

ah - should they be?

red solar
#

(and there's also Buffer and Flag)

#

yes

#

they have different characteristics (well kinda, signed integer overflow is defined for atomics)

#

but anyway, it has to be a separate class due to implementation issues

raven ridge
#

what implementation issue is that?

#

I believe you, I just haven't spotted it yet 🙂

red solar
#

hmm... ok none ig, you could just check a flag - lets go with "i don't like that implementation" 😂

#

you need to keep track of it somehow tho

#

and i prefer as part of the type, than as an optional parameter that gets stored, and has to be checked on every function call

raven ridge
#

I'm not even clear on why you need to check it on every function call, though - the atomic_* functions are all overloaded for both signed and unsigned, so - beyond a cast to the appropriate type - what does signed vs unsigned change?

red solar
#

because we need to know what the appropriate type to cast to is

#

and we also need to cast the arguments to that type (e.g. if we're calling .store(value))

#

and converting python integers to int is completely different to converting them to unsigned

#

which is a right pain :/

#

signed is nice, it does conversions for us

#

unsigned does not 😒

#

but even without that it's still 2 different functions

raven ridge
#

and what's the point of offset - why not just make the user slice the memview themselves? Wouldn't that let you eliminate both the size and the offset arguments?

red solar
#

idk, maybe they're lazy, what can i say 🤷

#

maybe they're storing some random thing and using ctypes to access the internals

raven ridge
#

wouldn't you still be able to do that with just memoryview slicing? e.g.:

>>> m = memoryview(bytearray([0, 1, 2, 3, 4, 5, 6, 7]))
>>> list(m[:4])
[0, 1, 2, 3]
>>> list(m[4:])
[4, 5, 6, 7]
>>> list(m[0:2])
[0, 1]
>>> list(m[6:])
[6, 7]
red solar
#

yeah you would

raven ridge
#

so if that memory was supposed to be 4 int16_t they'd give you the last one with m[6:8], and you'd know the size is 2 and not need an offset. Likewise for 2 int32_t and m[4:8]

red solar
#

if it's a memoryview, the size and offset can be ignored - but i still want a way to create it from a pointer (just in case)

#

unless you can create a memoryview from pointer + size?

raven ridge
#

What type would you use for the pointer?

#

ctypes?

red solar
#

hmm ok maybe no offset

#

but yeah ctypes - if the pointer has no type (void), then size is used, otherwise it's ignored

raven ridge
#

why not just make them cast in that case?

red solar
#

cast in what case?

raven ridge
#

if they have a ctypes void pointer, why wouldn't you demand they cast it to a ctypes int pointer instead? Why allow them to pass pointer and size?

red solar
#

hmm... my reasoning was for 128 byte integers, lemme go check double's accuracy

raven ridge
#

a double can't even represent all 64-bit integers, let alone 128 bit ones.

cloud crypt
#

^

red solar
#

yeah :/ could technically have it as 3 doubles? but probably not worth the conversion effort

cloud crypt
#

isn't long long 64 bits?

red solar
#

minimum, yes

#

also for pointer types, ctypes only offers char *, wchar_t *, and void * :/

#

sorry if your question was is 64 bits enough, x64 offers atomic operations for 128bit ints

#

(well buffers, not really ints)

cloud crypt
#

you can define your own types with it huh

red solar
#

yeah 🙂

#

well kinda

cloud crypt
#

I just hoped in the convo, what is the end-goal though?

red solar
#

making c atomics in python 🙂

#

deciding on an interface

raven ridge
#

ya know - stdatomic isn't guaranteed to be lock free, and if it needs a lock that isn't going to work across processes...

red solar
#

yeah ik, that's why we have is_lock_free 🙂 but i'm glad you saw that

#

which means we also need AlignmentError, and WidthError

red solar
#

ok so the downside is that if i want 128bit buffers to be atomic, i need to use intrinsics :/

#

on the plus side, i only need to support like 2 compilers and 1 architecture (x86_64)

raven ridge
#

It has a setup.py that generates a Cython file with one class for each of the signed and unsigned integer types of size 1, 2, 4, and 8, along with 2 classes called Int and Uint that wrap them, and calls the C stdatomic library in the implementation for each.

red solar
#

Reading it on mobile sucks, but on the plus side I finally understand mixins 🙂

raven ridge
#

You should be able to clone and build it with something like:

pip3 install --user cython
python3 setup.py build_ext --inplace
#

--user to install Cython into your home dir, drop that flag if you're installing in a virtualenv (probably obvious, but just in case)

red solar
#

I’ll do that in the morning, i’m in bed rn 😂

raven ridge
#

I tested it only about this much:

py_atomics>python3 -c 'from py_atomics import Uint; x = Uint(bytearray(b"\x80\x80")); print(int(x)); x.store(256*256); print(int(x)); x+=1; print(int(x))'
32896
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "py_atomics.pyx", line 642, in py_atomics._DelegateToImplMixin.store
    return self._impl.store(value, memory_order)
  File "py_atomics.pyx", line 128, in py_atomics._uint16_t.store
    uint16_t_store_explicit(self.ptr, value, memory_order)
OverflowError: value too large to convert to uint16_t

py_atomics>python3 -c 'from py_atomics import Uint; x = Uint(bytearray(b"\x80\x80")); print(int(x)); x.store(256*256-1); print(int(x)); x+=1; print(int(x))'
32896
65535
0
#

there's almost certainly bugs, but it seems to basically work.

cloud crypt
#

updating dict be like:
not funky iterative python for other_dict in dicts: some_dict.update(other_dict) vs
funky and cool functional python any(map(some_dict.update, dicts))

hollow crane
#

what does the any do there

wide shuttle
#

Making sure that the entire map object gets exhausted

hollow crane
#

ahh

wide shuttle
#

The dict.update method returns None, so all return values are falsy

#

any will keep looking until it find a truthy one, which it never does

hollow crane
#

so it will use all of them

#

yep

wide shuttle
#

and so it runs to the end

hollow crane
#

why not list()

wide shuttle
#

because they're only using it for the side effects. list would create an actual list will elements pointing to None before discarding it.

hollow crane
#

ah

wide shuttle
#

I'm not saying I would write it like this, because this confusion is exactly why I think it's less readable

hollow crane
#

and the same with an iterator

#

list comprehension i mean

#

i keep pressing enter before i finish typing recently 🤔

cloud crypt
#

@wide shuttle but it's funky!

flat gazelle
#

how is it functional? It uses a function with a side effect, one of the least FP things out there

hazy anchor
#

it has all the key criteria of being functional

grizzled vigil
#

"funky and cool" tends to be rather entertaining for the purposes of esoteric amusement and can sometimes be helpful for learning, but it's something you wouldn't even want to touch with a 10-foot pole in a remotely serious environment (open source contributions, work, etc.). I'm sure most already know this, but I just wanted to mention that for anyone who may not be. When I was first getting into intermediate programming, I was periodically guilty of trying to fit as much onto a single line as I could, using some needlessly convoluted lambdas, etc. without fully realizing how bad of a practice it would be in the real world.

hazy anchor
#

its worse and harder to understand.

grizzled vigil
#

I think functional programming has it's place. I personally like to use it sometimes for quick real-time transformations where readability isn't particularly important (e.g. REPL or a script that only I'll use). It's also not bad when used for simple cases, it's just easy to get carried away with it

gloomy rain
#

Functional solutions can be more readable and less bug-prone in certain contexts.

#

Where the functional abstraction neatly expresses the idea and the syntax doesn't allow you to do things wrong.

visual shadow
#

It's another tool in your tool belt

#

Use it where it makes sense

grizzled vigil
#

Definitely, every paradigm has a place somewhere

#

That being said, it's certainly not for everyone. There are some incredibly talented developers I've encountered that dislike it in pretty much any context, and that's perfectly fine. I think everyone has to figure it out for themselves to some degree rather than relying on broad generalizations about the paradigms. Not everyone is inclined to rationalize code in the same patterns.

hazy anchor
#

it feels like a solution in search of a problem 9/10 times.

#

but i work on code and with teams of low to medium experience.

gloomy rain
#

I worked with Java for 5 years, and the introduction of the Streams API (which is basically adding functional features, similar to LINQ in C#) were useful in lots of contexts.

#

Python comprehensions are a type of functional abstraction (albeit with a user-friendly interface) that's widely useful.

flat gazelle
#

functional programming solves quite a few problems by creating constraints (pure functions, immutability, ...) and then solves the problems arising from that with other things. Which is why it can often seem like it solves made up problems.

hazy anchor
#

yeah i wouldnt put list/gen comprehensions under this. they're gucci

grizzled vigil
#

Yeah, I've found myself using C#'s LINQ in production environments periodically, particularly for simple sorting and filtering purposes.

gloomy rain
#

Chaining streams calls (and I know you can do similar things with LINQ) feels like it replaces 9/10 foreach loops.

#

in an objectively better way

grizzled vigil
#

My only dislike is that it can become difficult to debug when too many operations are chained (as can sometimes be common with "fluent interfaces"). But that's more on the user to make use of it responsibly, and separate it into multiple steps when needed.

flat gazelle
#

kotlin takes that even further, to a sometimes ridiculous extent

gloomy rain
#

If you have a particularly complex lambda in the middle of a chain, you can always just break it into a real function and give it a descriptive name

#

Then it's usually pretty easy to follow what happens in the chain

#

You'd end up with the same thing with a foreach loop, just spread over more lines, it feels like

#

If the logic is complex, it's gonna be complex in both cases

grizzled vigil
#

Yeah, I can agree w/ that sentiment. I suppose that I've just seen it abused more frequently, but that's more on the individual developers rather than the pattern itself.

gloomy rain
#

You can absolutely abuse any language feature