#internals-and-peps
1 messages · Page 146 of 1
I'm pretty stoked. Getting CPU parallelism from threads would be really convenient.
multiprocessing isn't bad but there's a whole bunch of minor headaches
lol wonder how many people this will screw over who relied on the GIL for ordering between threads
speaking of...
from atomics import AtomicIntViewContext
if __name__ == "__main__":
buf = bytearray(4)
with AtomicIntViewContext(buffer=buf) as a:
# type(a) -> AtomicIntView
print(a.exchange(5))
print(a.fetch_neg())
print(a.load())
# print(a.load()) -> exception
better? @grave jolt (and ig @halcyon trail )
the GIL never really did that anyway, so it probably wouldn't be many people
It didn’t do it, or it wasn’t meant to do it? Because one thread releasing a mutex and another acquiring it provides ordering
sure, but the GIL could change between any two bytecodes, so it didn't provide much guarantee
just incrementing the same int from two threads would lose updates.
oh yeah so most things aren't atomic in the first place, forgot lol
i.__iadd__(1)
and here was me thinking this would be a single bytecode :/
that method call is one bytecode, but that's not how you increment an int.
"i += 1" is four bytecodes
Hmm, godbolt turned it into load and store for the method call
https://stackoverflow.com/a/18568017 i can definitely see people doing this as a hack though, and then getting their code broken if the GIL disappears (which isn’t a bad thing imo, but still)
Seems fine to me doodspav
I probably wouldn't bother with context in the name personally, though that's taste
What would you call it then tho? I can’t call it AtomicIntView since that’s what it produces on enter
Wrong channel my bad*
I have a private python package, hidden. In that package, I'd like to use another private package of mine, zempy.
In hidden's requirements, there is a line [-e ]git+https://gitlab.com/group/zempy.git@0.4.7#egg=zempy
And I'm installing hidden with python3 -m pip install [-e ]. (in hidden's main directory)
But I got an error:
error in hiddenco setup command: 'install_requires' must be a string or list of strings containing valid project/version requirement specifiers; Parse error at "'-e git+h'": Expected W:(abcd...)
This seemed like working before. Suddenly it stopped working. Anyone has an idea? I have tried nearly everything in that requirements line. It's installing without that line. But I need zempy in hidden.
I have double checked install_requires parameter in setup. It is a list of string.
Well, the user doesn't see the name of that class so it's not important though
or not as important, at the very least
tbh, I would've probably made this API like
with buf as view:
# stuff
```but I can see why you wouldn't like that
ah, shame.
the whole point of this API is that it provides an atomic view of memory that could come from wherever
Not really, if you don't do it that way then you are tied to a particular way of getting the memory
if you separate the responsibility for acquiring the buffer and for performing operations on it atomically then you can do atomic operations on a buffer that comes from anywhere without writing any more code
want it for type hinting tho
although type hinting is a separate issue that i should probably solve, because rn i don't have any sort of base class that i expose :/
well, this thing only lives purely inside the context manager, so it's a bit unusual to pass it into other stuff, though not non-existent I suppose. But yeah, fair enough, i don't think context would be my first choice but I dont' know immediately what is better
Manager feels wrong, and Factory i didn't like because it's single use
Is the outer thing even a class? it can just be a function, can't it?
the way that e.g. open is a function
it's a class that implements __enter__ and __exit__
i forget the chain of reasoning for why two classes are needed in the first place, tbh
one implements __enter__ and __exit__, and the other implements all the operations
(kinda)
oh, because you only want the useful API on the inner thing
yeah
and enter and exit on the outer thing
(AtomicCore isn't exposed, so creating an AtomicBaseView object isn't easy for the user)
okay, but the enter/exit class is never used by the user, should never be type hinted, or anything
So instead of the user calling the init function for this class that they never really use otherwise, they could just call a function instead
with view_atomically(buffer) as :
...
hmm
and now the name of the "outer" class is an implementation detail, there's just the view_atomically function and the inner type
which you can call AtomicView
ok i like it 🙂
but i need to figure out where in that interface the user specifies if it's Int, Uint, or Bytes
brb shopping
view_atomically(buffer, as=AtomicIntView)?
hmm
or maybe make a new enum just for that
err why not just pass the type
seems more logical
i guess with an enum you constrain it
so maybe that's okay to, if you want it to work in terms of type annotations though it's simpler to just pass the type
as doesn't work as a kwarg unfortunately...
I wonder if as could be controlled with a dunder method
sounds cursed but cool nevertheless
I think we need less dunders, operators and other syntax (like walrus, f-strings etc.)
not sure about patma yet
i wouldn't say less fstrings
not specifically python related, but is it possible to hit redis with so much traffic at once that you essentially DOS the eviction process? hit OOM and saw 0 evictions from a hard spike in traffic--anybody seen that before?
what operators do you have in mind? I agree there's probably too many magic dunders, and probably agree about walrus, but I think those are simply solving problems created or not addressed by other aspects of python
for example, the function composition proposal
f-strings however are amazing and are really the right way to do strings, not sure why you don't like them (and I think they're the future for more languages as well)
Ah, so you are talking about operators that are not yet standardized
as in, I think adding new syntax for what's already possible isn't a good idea
most of the time
sorry that wasn't clear since you said "less", thought you were talking about stuff that's already in
that's kinda funny, but also i have no idea :/ you'd be better off asking redis specialists
(and walrus, f-strings are already in)
Maybe, I think it's hard to say, it does feel like python has gone surprisingly aggressive on adding new syntax at times.
walrus in particular (and I know adding walrus was very controversial, both generally and in the steering council)
function composition I'm sympathetic to in principle, but i'm just not sure it suits the language, the language can''t have real pretenses of being functional with such weak lambdas
his palms are sweaty, lambdas weak, arms are heavy...
There's vomit on his editor already, code spaghetti
He's nervous, but on the surface he looks clean and tested
He's nervous, but on the surface he's webscale-ready
To drop async, but he keeps on forgetting
What he queued down, the server goes so loud,
The server runs but the requests won't come out!
!otn a the-requests-won't-come-out
:ok_hand: Added the-requests-won’t-come-out to the names list.
where do you think names for off-topic channels come from
i have wondered that before
we have 1402 names in rotation so far
nice
I think we're adding them faster than they appear tho
wait how often are you rotating ot names?
Every day at 12 AM UTC
...speaking of vomit, why are some stdlib modules just so janky? I would've never let this code past a review
https://github.com/python/cpython/blob/main/Lib/configparser.py#L446
https://github.com/python/cpython/blob/main/Lib/configparser.py#L967
Stdlib modules' code style is honestly a free for all, I think it's more about logic than code style because it seems like it's FUBAR
example:
logging has a function called getLogger
datetime has a class called datetime, instead of Datetime
etc.
hehe this is what i think of when i imagine enterprise python code
old for the most part
well, that's public-facing stuff, not implementation details
and I guess with the lesser used modules it's mostly about what the module's maintainer let go through as it's usually just one person
Here's the thing and I hope this doesn't sound bad. When you look at open source software, even very successful, useful, amazing open source software
(Linters for the win)
The people who write it are not, IME, especially amazing coders. They're not bad coders either. But it really just boils down to who wants to do it, had an excuse to do it at work, etc etc.
Let me rephrase; they could be amazing coders, but they aren't necessarily
There was a point where I would have assumed that every line in the python standard library was pure gold but at this point I would not take it as a given
k8s codebase could be a good example of this
what's k8s?
sorry kubernetes
ah
I guess those modules also gradually erode. _read started out as this:
https://github.com/python/cpython/blob/3d20986d9664f9d6025b1f8e89fa4b3804c0cbd6/Lib/ConfigParser.py#L203
and then accumulated small changes over the years
well it's in Go so I don't need to look at it to know that 😉
yeah, reading it for the first time was a big surprise for me
half joking but I read about some of the hackery they needed to do because they wanted some kind of type registry and go's lack of generics makes a lot of this kind of stuff a headache
Likewise
I really thought that PEP8 would be pretty strict in the stdlib but I stood corrected
fingers crossed that generics release isn't fubar
From what I've found it's usually knowledgeable people in one area but then they cover more things and for the other things it's subpar; and some oss people insist on very weird things in regards on how things should be written or the code style - then if they're a maintainer it propagates through that
the guy who designed ethereum is kind of a hacky coder lol but he's definitely a strong coder as well
@grave jolt I've had many such moments over the years. I remember years ago as I was starting to get really good at C++, and the zero MQ guy had a bunch of blog posts on the problems with C++, and the posts are just objectively bad. C++ people love trashing C++ but the post was just all over the place.
And i was just confused, like, this guy wrote ZMQ which is used so many places, how can he give an argument on RAII or intrusive data structures that shows he doesn't understand them at all 🤷♂️
Most of the "[language] bad" articles I find can either be horribly written or just don't give any constructive criticism whatsoever
it does predate PEP 8 (and, well... it predates me for a few years) but I can actually read through it and not curse (much)
my latest experience like that was a guy insisting on still supporting python 2 in a (small) codebase which was a mess and could really use a refactor; apparently instead of improving the project and letting python 2 support be through the older versions of the project, they'd rather let it stagnate
IDK JavaScript criticism is usually pretty valid lol
My overall conclusion is that if you work at a place where people are well paid, the average level of a developer at your work is probably better than the average level in OSS
It's not really that surprising; most of the best developers I ever met didn't have any interest in maintaining any kind of non-trivial OSS project.
it's so much work
Also, if we're talking about language bad articles, mandatory: https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
The all time classic.
IDK i've interned at a couple of pretty well-known tech cos (so a lot of engineers) and code quality was highly variable across orgs
one of my company's source got leaked and people were surprised at how sketchy some of it was 
same lol
wait what is this, i don't know php so i don't know if the argument makes sense or not
the arguments don't really matter, everyone knows PHP sucks by now, the writing style is just funny in places
Fair enough,
Though a lot of the 'language bad' articles I've seen just fail to touch on a lot of the flaws of a language and focus on things like syntax
yeah, that's when they're written by people who don't know the language well, so they focus on superficial things
python guy learns C++ for a week - "C++ bad cause semi-colons"
to get a good article like that you have to have someone who thinks the language is flawed but has really been forced to write enough code in it, over the course of years, to understand it really well
and then still able to talk about it fairly objectively
it's super rare
there was a very good article IMHO on Scala's warts a while ago
There were a few I saw recently, I'll link one of them here:
https://medium.com/nerd-for-tech/python-is-a-bad-programming-language-2ab73b0bda5
agreed
its' one of those things that you wish were written ironically because the world would be a better place if this person didn't write this unironically
Like, posts like this leave no room for satirical medium posts
The writer of this also came off as incredibly... egotistical for a lack of a better term.
"Dynamic typing is bad, and anyone who disagrees with me probably hasn’t written enough software to realize it yet."
How could I write a blog post satirizing medium when stuff like this exists? Nobody would understand its satire.
I don't necessarily like dynamic typing, but to call someone who disagrees with you incompetent is uh
That's also true
this is also one of the better criticisms I've seen of a language: https://yager.io/programming/go.html
Imagine living in a world without dynamic typing languages tho, saying that it is bad it's like saying a toy car it's not suitable for a kid, which means the kid should learn driving with a SUV.
wait, but now you're saying that dynamically typed languages are toys?
I also don't really agree that it's necessarily better to learn with dynamically typed languages than statically typed languages. But there's not much real empirical evidence either way.
They serve a purpose, saying that they are not ok, means that they do not serve their purpose anymore. Purpose for me, it's easy prototyping and readability
I personally started learning code with C, but for most of my beginner projects, i regret not using Python earlier just for the sake of having a working code in much less time.
C is not a good example of a static language...
But whatever, non constructive criticism is actually the worst, in my honest opinion
Aren't C types known at compile-time...?
c has type coercion that is unsafe
Yeah, but the type system is really rudimentary and unsafe. For example, you have to use void* a lot of the time.
it's statically typed but (this is a subjective term) weakly typed because of type coercion/implicit conversions that more robustly typed languages like java and c++ don't allow
Well, that comes out from bad type-casting practices
i'm not a seasoned C dev but like @grave jolt said casting to void* is sometimes needed
void* casts are needed in C for extremely basic and common things
callbacks for example
which is awful
...so for this reason (and also memory unsafety) I wouldn't pick C as an introduction to static typing. Maybe something like Kotlin or Haskell. Or maybe even a gradually typed language, like TypeScript (if the person already knows JS) or Python-but-with-type-hints.
LOL
the bot was written in C and had some UB
Haskell seems like a rough start, and gradually typed to me seems more confusing
(to start)
Holy shit, what on Earth is this https://stackoverflow.com/questions/592322/php-expects-t-paamayim-nekudotayim
I would probably go with one of the bog-standard languages; Java, C#, maybe Kotlin
maybe not Java just because of the excessive OO focus
That's for the case when the person already knows the "dynamic" counterpart
sure, fair enough
i mean even null can be considered sus when it comes to typing ig
null is very sus
null's sus-ness confirmed
hey we finally agree on something @halcyon trail
my intro class was taught in scheme

hm right
i'm probably biased but I think lisps are much easier to learn than haskell
it seems like a good intro language class
parens give me nightmares now tho
lisps have weird syntax but that is pretty shallow. in terms of how the actual language works, until you start learning about macros and the fancier features enabled by homoiconicity, lisps can feel very bog standard
I guess Haskell would be way harder for a beginner to get stuff done with. Like, imagine writing a Discord bot in Haskell.
haskell you need to learn about purity, monads, from relatively early on
lol but imagine me learning to program first year and then jsut staring at 15 parentheses in a row
I can imagine 🙂
from now on I'm going to call :: paamayim nekudotayim
Haskell typing (as far as "first-level types" are concerned) is actually very easy to pick up, but it's difficult to present them without presenting other aspects of the language.
it's hebrew for "twice two-dots" basically
I'm not actually sure that nekudotayim is a real word
my hebrew is like a first grade level or so
"turbofish tail"?
but Hebrew as language, has singular, plural, and a special "two" suffix
but it can't be used with all nouns, only certain nouns
time durations, "things that come in pairs". Like: pants, bicycles, glasses, etc all have this "two" suffix.
obviously though it's insane that random bits of hebrew are coming out of error messages
I GOT CRAZY OH GOOOD
@unkempt rock do you need help?
i'm sorry i'm so lost what are you talking about lol
PHP
YES I GOT TOO CRAZY AND I CANT MORE EAT OR DRINK
PHP uses paamayim nekudotayim in user facing error messages
which is a way of referencing :: in Hebrew
AHAHHHHHHHHHHHHHHHHH
Obviously it's Jehovah himself speaking through the source of the divine language interpreter 
clearly
templeOS should've used PHP-based shell?
it's pretty embarrassing to me for how many people that's the main source of hebrew exposure 😛
This isnt the place for any of this my guy, try #ot0-psvm’s-eternal-disapproval
@unkempt rock can you stop spamming please?
ok man but im so funny
i love the funny thing
Go be funny elsewhere
Indeed, you are an award-winning comedian. But this is not the channel for this.
XD but im toooooo funny so i cant be funny in just one place
i need to be funny in python server
i became fuuny with muchs class
someone wanna be funny with me?
knock knock
Are we gonna have to ping mods or are you going to take the hint that youre offtopic
YOU ARE NOT FUNNY
<@&831776746206265384>
i hate u
!mute @unkempt rock 5h Sounds like you need to take a break. Feel free to come back when you have calmed down and stop calling someone unfunny or whatever, please stick to the channel topic.
:incoming_envelope: :ok_hand: applied mute to @unkempt rock until <t:1636072404:f> (4 hours and 59 minutes).
same here. at least i'd have expected a stricter process for core development involving code reviews, unit tests etc. - and all that starting with python <=1
at least that's what i would expect nowadays with such a project, but back then there probably wasn't even proper tools for versioning etc
buf = bytearray(8)
with view_atomically(buffer=8).as_int() as a:
x = a.load()
is this too much as?
I think as_int could really just be a kwarg
as_type=int or something along those lines perhaps
the issue with that is the types i would need there are huge :/
buf = bytearray(8)
with view_atomically(buffer=buf, as_type=AtomicIntView) as a:
x = a.load()
the other thing is idk how this works with type hinting now, will linters and IDEs correctly deduce that a has type AtomicIntView?
You could have a type mapping
what do i map for AtomicUintView?
So you'd pass 'int' or int as the arg, which would then internally be translated to its respective atomic class
Though as_<type>() is still fairly okay, tbf
ideally i'd have a good name for the function such that i can have 3 functions rather than 1 function with 3 possible as_type params
but i can't think of a good name :/
I don't remember exactly, what was wrong with exposing Atomic<type>View?
oh, we moved past that - wait lemme link you the class
Good afternoon, where can i read about packaging scripts and orchestrating them? For instance, I have 4 scripts that retrieve various data from APIs, and 4 scripts that convert JSON to CSV... what's the easiest way to create a shell to execute them? (should I make them into classes or modules? thank you)
so AtomicViewContext returns AtomicView
oh boy :/ packaging scripts like doing setuptools and distutils?
no, more like organizing them
so that instead of 8 files, I maybe put everything at one
and then of course, logging / restarting /etc
hmm... what's wrong with having 8 files?
not sure why you need 4 scripts for json to csv tho, that sounds like something you could do in a single class
each has a different structure and nesting levels
hmm
well the csv thing can be a package with 4 modules in it, each with its own class
not sure about the api yet
why can't you just use an enum or just pass int itself?
the linting thing for one (not a huge issue, but i'm not 100% happy with it)
I don't really see an issue either with view_atomically(buf, AtomicIntView)
you don't have to use keyword arguments here, there's only two arguments and they're pretty clearly two different things
you could also just have different functions, assuming this is basically always going to be hardcoded, or at least offer that for the majority case
hmm... if i don't have to use kwargs that looks nicer
if you can think of a good name for the different functions, that would be ideal but probably the hardest
view_int_atomically
view_foo_atomically
etc
basically just sticking the argument into the name lol but shorter
the issue is that i don't want the name to make the user think that the first param has to be an int or bytes
rn i'm fixing the inheritance stuff tho 🙂 easier problem
if i have Atomic, AtomicIntegral, and AtomicInt/Uint, me exposing all 3 is fine right? even though the first two are useless own, and are just there for type hinting?
atomically_view_as_int?
ehhh idk it still feels iffy, atomically_view_as_int(...) as atomic_int:?
That should be fine if it's documented. It could make sense to make them abstract as well
abstract? how do you do this in Python?
!d abc
Source code: Lib/abc.py
This module provides the infrastructure for defining abstract base classes (ABCs) in Python, as outlined in PEP 3119; see the PEP for why this was added to Python. (See also PEP 3141 and the numbers module regarding a type hierarchy for numbers based on ABCs.)
The collections module has some concrete classes that derive from ABCs; these can, of course, be further derived. In addition, the collections.abc submodule has some ABCs that can be used to test whether a class or instance provides a particular interface, for example, if it is hashable or if it is a mapping.
This module provides the metaclass ABCMeta for defining ABCs and a helper class ABC to alternatively define ABCs through inheritance:
oh hmmm
you made me realise the base classes still need to have functions for them to be useful to linters, they can't just be empty :/
I'm not sure if you can avoid that tbh. Though I doubt the var will often be named atomic_<type> in practice, I'd expect more things like num or ai, etc
hypothetical question, but if i (in the future) rewrote this whole thing in C, could i just have a type stub for the abstract classes and not implement them in C? (not 100% sure if that question makes sense)
hmm... ok i'll rethink it after doing the inheritance thingy
if they're useless on their own why would you use them in type hinting though?
I mean you might as the library maintainer, but users wouldn't
Depends one what "useless" means in this context. If they're just interfaces/base classes for actually functional classes, having them public would indeed be useful, though that falls into the ABC/protocol category
yeah that's what i realised lol, i'm trying to think of how to change them so they're not useless
like what operations i want in Atomic, in AtomicIntegral, and in AtomicInt
class AtomicInteger(Atomic):
def __init__(self, *, width: int, is_signed: bool):
super().__init__(width=width, is_integral=True, is_signed=is_signed)
class AtomicInt(AtomicInteger, IntegralOperationsMixin, IntegralPropertiesMixin):
def __init__(self, *, width: int):
super().__init__(width=width, is_signed=True)
Atomic just implements __del__ and __init__
the mixins rely on a single attribute available from Atomic, so it's just a matter of rejiggling which stage stuff is distributed in
I wouldn't spend too much time worrying about how to construct a complex inheritance hieararchy tbh
>>> class X:
... def __bytes__(self):
... print('__bytes__ called')
... return b''
...
>>> bytes(X())
__bytes__ called
b''
>>> bytearray(bytes(X()))
__bytes__ called
bytearray(b'')
>>> bytearray(X())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot convert 'X' object to bytearray
```why `__bytes__` is not called on `bytearray(...)` ?
how to implement custom conversion to bytearray?
__index__ might work even though that's not what it's meant for
(assuming the interpreter doesn't check that you return an int)
nvm you can't do that
ok, thanks...
(not so much worried about stuff off the bat, more about any gotchas down the road)
ah nvm seems python deals with diamond inheritance stuff fine 🙂
Actually, in Python all multiple inheritance is diamond inheritance.
object
^^
/ \
/ \
/ \
/ \
^ ^
A B
^ ^
\ /
\ /
\ /
\ /
^^
C
and whether or not it works fine mostly depends on whether you understand how super() works.
Python has cooperative multiple inheritance, and it's each class's job to cooperate.
Well it’s more none of the mixins have state or __init__ so I don’t need to cooperate there 🙂
Because the bytearray type expects objects to implement the Buffer interface, not __bytes__. That is to say, anything that exports a contiguous, potentially mutable memory interface, not something that can be converted to bytes()
idea: a metaclass that enforces at class-definition time that all bases of your new class are non-overlapping
that would imply that they can't have even a __init__
right, only one of them should have a user-defined __init__
otherwise you rely on MRO and nobody wants that
(unless you explicitly know you want that)
I get inheritance is tough, especially multiple
But like ive not once found myself trying to subclass from another library
Just doesn't seem like something people do. Only time I've subclassed is for classes I wrote and I specifically will make sure there's no conflicts
you never wrote Java much, I guess
even in Java, subclassing other people's classes is usually discouraged. "Prefer composition to inheritance" is a pretty general rule, it even appears in the Design Patterns book.
I think the salient point with regard to subclassing other people's code is wether or not is was designed to be subclassed. I use a library called cefpython. Its a binding around the code that makes chrome run. There's a class inside it that you can't really access. Its somewhere in there, but you normally get an instance of it by called 'createBrowser' or 'createBrowserSync', and there's a bunch of excess overhead that needs to be processed when you make one of these objects, so just instantiating one even if you did find the class won't do you much good
On the other hand, there's wxPython. Its 'App' class designed to be subclassed. That's pretty much the whole point. You subclass it, that gives you access to the main routine of the program and all the different points of contact with it, and you specify the behaviour you need
doesn't C3 already forbid this
Python has a lot of different libraries and it’s generally quite easy to write code and worry more about logic than syntax. Now for what else other than python, pythons the only language I’m decent at so
no, it doesn't it just forbids the order in which the bases appear:
In [3]: class A:
...: ...
...:
In [4]: class B:
...: ...
...:
In [5]: class C(A):
...: ...
...:
In [6]: class D(A, B):
...: ...
...:
In [7]: class E(C, D):
...: ...
...:
In [8]: class E(C, A):
...: ...
...:
In [9]: class E(A, C):
...: ...
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-23a77786bae9> in <module>
----> 1 class E(A, C):
2 ...
3
TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, C
I tend to prefer things with flexible type systems. (And also Python sometimes when I want to get things done without types.)
Any recommendation for a good profiler to use together with pytest? I've just checked out https://github.com/man-group/pytest-plugins but it looks a bit dead :(
thanks ❤️
when using selenium, wich method is faster: xpath or ID, class name ?
i just need to return a value, but every second is precious when executing the program
shouldn't take more than a millisecond or two anyway
but you should really just benchmark them in your specific case
my money's on ID though
@weary flax mention cuz it's been 2 hours
this is a good question for #web-development , this channel is about details of the python language itself
and the rule of thumb for performance optimization is: don't guess, benchmark
chances are that isn't the bottleneck in your program anyway, unless you are sure (and have verified) that i/o isn't the bottleneck
cProfile ftw 🙂
@red solarwhat is that Patreon one role?
the server has (or had i haven't kept up) a patreon
https://www.patreon.com/python_discord think this is it
not sure who pays extra for the dark colour when the light one's so much nicer
I guess - I haven’t paid much attention to it
-oo-
@unkempt rock thanks for the pointer #help-pie message - by "integer conversion" i just meant the d format string as opposed to e.g. s
oh. didn't realise that was even a thing.
as opposed to hex/bin I suppose
or when padding
annoyingly this seems to be for "full" format strings
!e ```python
import string
for literal, name, spec, conv in string.Formatter().parse('{:d}'):
print((literal, name, spec, conv))
@paper echo :white_check_mark: Your eval job has completed with return code 0.
('', '', 'd', None)
i just want the code that parses the "spec" part... blah
oh it's too useful for you? xd
lol yes
i literally just want to implement __format__!
which is what format() calls
i think you can afford the one line it takes to take it out of the tuple
or do you get a bunch of other stuff along with it as well?
I suppose you do.
In what way do you want to parse it?
i'd have to do something like "{:" + fmt + "}" which seems really flaky
f"{:{fmt}}"
i want to know the "type" (if any), as in the type pattern in the formal grammar https://docs.python.org/3/library/string.html#formatspec
oh maybe escape that.
f"{{:{fmt}}}"
for now i'm just doing fmt.endswith('s') but i'm sure that's wrong
so instead i'm gonna go shave a yak and write a standalone format specification parser using lark or something
guess i could do it in regex too
looks like it's all wrapped up in c code and the internal formatter parser thing isn't exposed publicly
annoying!
I can't even figure out where format is defined in this
def format_field(self, value, format_spec):
return format(value, format_spec)
there's a format in the class but that's... IN THE CLASS
format(value[, format_spec])```
Convert a *value* to a “formatted” representation, as controlled by *format\_spec*. The interpretation of *format\_spec* will depend on the type of the *value* argument; however, there is a standard formatting syntax that is used by most built-in types: [Format Specification Mini-Language](https://docs.python.org/3/library/string.html#formatspec).
The default *format\_spec* is an empty string which usually gives the same effect as calling [`str(value)`](https://docs.python.org/3/library/stdtypes.html#str "str").
A call to `format(value, format_spec)` is translated to `type(value).__format__(value, format_spec)` which bypasses the instance dictionary when searching for the value’s `__format__()` method. A [`TypeError`](https://docs.python.org/3/library/exceptions.html#TypeError "TypeError") exception is raised if the method search reaches [`object`](https://docs.python.org/3/library/functions.html#object "object") and the *format\_spec* is non-empty, or if either the *format\_spec* or the return value are not strings.
oh. weird.
https://github.com/python/cpython/blob/0a883a76cda8205023c52211968bcf87bd47fd6e/Objects/stringlib/unicode_format.h#L494
they reference a function in the comment that doesn't appear to exist in the source code, that's pleasant
Objects/stringlib/unicode_format.h line 494
get_field_and_spec, and renders the field into the output string.```
!e ```python
print(format(123, '05x'))
@paper echo :white_check_mark: Your eval job has completed with return code 0.
0007b
yeah so that's for a single value
yep
why?
who would ever format a single value
i do it all the time
I mean - str.format or f string would allow the same thing. but. kay.
format predates the latter and i think maybe predates the former, or at least was introduced concurrently with it
where is the builtins module defined?
→ fd builtin
Doc/library/builtins.rst
Lib/_sitebuiltins.py
Lib/test/test_builtin.py
Lib/test/test_importlib/builtin
Misc/NEWS.d/next/Core and Builtins
!e ```python
class Weird:
def format(self, fmt):
if fmt == 'z':
return '<<weird>>'
else:
raise TypeError(f'Unknown format code {fmt!r} for object of type {self.class.name!r}')
print(format(Weird(), 'z'))
print(format(Weird(), 's'))
@paper echo :x: Your eval job has completed with return code 1.
001 | <<weird>>
002 | Traceback (most recent call last):
003 | File "<string>", line 9, in <module>
004 | File "<string>", line 6, in __format__
005 | TypeError: Unknown format code 's' for object of type 'Weird'
bltinmodule.c
love you
!e ```python
class Weird:
def format(self, fmt):
if fmt == 'z':
return '<<weird>>'
else:
raise TypeError(f'Unknown format code {fmt!r} for object of type {self.class.name!r}')
print('{:z}'.format(Weird()))
print('{:s}'.format(Weird()))
@paper echo :x: Your eval job has completed with return code 1.
001 | <<weird>>
002 | Traceback (most recent call last):
003 | File "<string>", line 9, in <module>
004 | File "<string>", line 6, in __format__
005 | TypeError: Unknown format code 's' for object of type 'Weird'
so __format__ allows you to configure how format() and f"" and str.format work
the former probably being the least useful, yes, but still somewhat useful
ohh. types receive the format string themselves.
..... so you can have custom format specifiers
Date/time types use that to support strftime codes, IIRC
wait what!
!e ```python
from datetime import datetime as DateTime
print(format(DateTime.now(), '%Y-%m-%d'))
@paper echo :white_check_mark: Your eval job has completed with return code 0.
2021-11-05
!e ```python
from datetime import datetime as DateTime
print(f'{DateTime.now():%Y-%m-%d}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
2021-11-05
WHAT
how to confuse your collegues
THIS IS AMAZING
doesn't look bad though.
so you basically can't/shouldn't ever rely on the format string because it could be arbitrary
I think it skipped __format__ for empty/null specification
yes that's just str()
in which case i think the only sensible solution to my case is
def __format__(self, fmt) -> str:
try:
format(self.to_int(), fmt)
except TypeError;
format(str(self), fmt)
yeah but it doesn't even receive "" which it conceivably could have
!e ```python
from datetime import datetime as DateTime
print(f'{DateTime.now():%Y-%m-%d!r}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
2021-11-05!r
!e ```python
from datetime import datetime as DateTime
print(f'{DateTime.now()!r:%Y-%m-%d}')
@paper echo :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 2, in <module>
003 | ValueError: Invalid format specifier
!e ```python
from datetime import datetime as DateTime
print(f'{DateTime.now()!r}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
datetime.datetime(2021, 11, 5, 20, 35, 33, 488011)
i guess you can't combine !s/!r with :? i thought maybe you could somehow
but it makes sense that you can't
{x!r:otherstuff}, not that it makes much sense
I was missing the ability to do !s!r recently
I mean I guess that makes sense, lol
did it delegate to the builtin here?
it does look like you can put [ conversion ] [ format specifier ] according to the grammar https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals
¯_(ツ)_/¯
that's what i realized it probably did
print("hello")
!e ```python
from datetime import datetime as DateTime
print(f'{DateTime.now()!r:s}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
datetime.datetime(2021, 11, 5, 20, 37, 42, 473487)
tldr yes but i forget how to specify padding
wait... you can put a replacement field as the format spec?
Could it be the !r applying before and then only supplying the string as as the string to format?
!e ```python
from datetime import datetime as DateTime
fmt = '%Y-%m-%d'
print(f'{DateTime.now():{fmt}}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
2021-11-05
yes i am pretty sure that's what's happening
this is so cursed that the parser doesn't even know how to handle it
i guess it helps to read the grammar
yeah I think the most common use for that I've seen is dynamic padding
🍿
!e ```python
from datetime import datetime as DateTime
fmt1 = '%Y-'
fmt2 = '%m-%d'
print(f'{DateTime.now():{fmt1}{fmt2}}')
@paper echo :white_check_mark: Your eval job has completed with return code 0.
2021-11-05
!e
x = 42
print(f"{f'{x!s}'!r}")
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
'42'
now you're being silly ;p
i'm not silly, the grammar is silly
f'{str(x)!r}'
i'm actually a bit disappointed you can't do !s!r
similar weirdness I encountered is that you can chain ifs in a comprehension
e.g. [a for a in range(10) if a if a if a]
what does that mean
o.O
should be the same as anding them
no kidding https://docs.python.org/3/reference/grammar.html
for_if_clause:
| ASYNC 'for' star_targets 'in' ~ disjunction ('if' disjunction )*
| 'for' star_targets 'in' ~ disjunction ('if' disjunction )*
I mean, IG if really is , from set builder notation
same! how does associativity work with the ifs? that might actually be useful for reducing nesting ()s
i assume the ifs are "outermost"
wait what.. for ifs?
!e ```python
[a for a in range(10) if a or False if a or False if a or False]
is that only in comprehensions?
inner first short circuiting as far as I can tell
@paper echo :warning: Your eval job has completed with return code 0.
[No output]
!e
[a for a in range(10) if print(2) if print(1)]
@flat gazelle :white_check_mark: Your eval job has completed with return code 0.
001 | 2
002 | 2
003 | 2
004 | 2
005 | 2
006 | 2
007 | 2
008 | 2
009 | 2
010 | 2
and which versions?
it looks like the for_if_clauses only appears in comprehensions yes
listcomp, genexp, setcomp, dictcomp
k
i wonder why it's genexp and not gencomp
it's not chaining, it's additional conditions, same as additional iterations
[ result
# at least one for's and if's
]
and there i thought my idea to have conditions in for-loops came true
for some reason it isn't allowed to only have a single if
>>> [3 if True]
File "<stdin>", line 1
[3 if True]
^^^^^^^^^
SyntaxError: expected 'else' after 'if' expression
^ this needs to be fixed.
sigh.. yep
i guess it tries to parse the "named expression" first
so basically chaining them
there's some AST manipulation POC to expand foo if x to foo if x else None
ghci> [3 | True]
[3]
if you think I'm kidding, it's allowed in haskell
nobody thinks you're kidding
idk usually nobody believes me when I say things like that xD
you know, we're in #internals-and-peps here 😉
DateTime is what concerns me here
||/j||
that's the name of the class. datetime is the wrong name and i refuse to accept it
I would call it Datetime ngl
DateTime doesn't sit with me well, even though it makes more sense
hmm
I like capital T since it's a new word
The naming conventions in the stdlib are quite inconsistent
considering it's a 30 year old language they're actually not bad
well, DateTime consists of Date and Time -- that makes sense to me
the only bad ones are datetime and logger, off the top of my head. and the builtin types but i guess those are type/function hybrid things anyway
considering it's a 30 year old language, there would've been plenty of time to iron out these kinks 😉
that's not how programming languages work
yeah, you don't get to make breaking changes in a programming language
elm does it and look at how mad it makes everyone
tell that to python 3
python 3 is not an example to follow
Unless you're E... yes, you beat me to it
it's a constant battle against accumulating cruft and garbage, the fact that any programming languages can ever improve at all is a miracle
java 9 is still hard to use due to being even slightly breaking
you know, there's a recipe that works!
java 9... The current java version is java 17
ez, just write the language the right way the first time 🤷 🤷
- make an alias to have both versions work 2) deprecate the old version 3) remove the old version after 5 years of raising warnings until everyone is annoyed enough to be glad when 4) finally the old version is removed
that's what python does now, pretty much
not even writing your message write the first time
actually it's a shorter deprecation cycle (3 years i think?) and there was a discussion recently about extending it
yeah, but if you have to wait 5 years between minor changes, that's like 6 versions in 30 years, no wonder old mistakes stick around
and like, if you go around breaking everyones code every 5 years, people will stop using the language
also ironing out the kinks is kind of what python 3 did from 3.0 -> 3.5 or so
yes, that
didn't they re-capitalize SOME stuff during that?
i quipped once that they should have left map and filter as returning lists, and added imap and ifilter that were lazy
one of the core maintainers responded to my post and didn't get the joke
i was also only half joking
I'd like that so much for casual code
same
i bet the answer was "WTH ARE YOU TALKING ABOUT JUST USE COMPREHENSIONS IF YOU WANT LISTS"
no, it was "map() is lazy as of python 3" or something like that
Not rename but a kwarg would be nice
god that would be a mypy nightmare
@unkempt rock i've put this into a big utils.py before for a couple of projects
def lmap(*args):
return list(map(*args))
def dmap(*args):
return dict(map(*args))
dependent typing
did you mean "singledispatch"
still can't typecheck map(lazy=random)
actually idris 2 has a python compiler target now
Who needs types when i got eager maps
fair enough
but honestly, [*map(f, arr)] has served me well, even if it is an abomination
wait why not just list(map(f, arr))
faster to type
lol
Unpacking is way cooler
be careful, the god of typing is vengeful
i do {**a, **b} and [*a, *b]
(i also still want more of the set api for dicts but this has been discussed before and people don't agree with me)
if you mean what i think you mean, i agreed
but sadly i'm not people
Do they do it in major versions (or whatever equivalent) or some other type?
basically doing set operations on the keys and then taking elements from the rightmost operand, if multiple possibilities remain after the operation
I was wondering recently how much of an issue renaming datetime could be
more or less major versions, but there have been 19 thus far
I get not renaming methods as that can quietly break things, but an invalid name should be apparent on a version change
and every one requires a massive codebase change, due to way elm is designed
there was a bpo from several years ago to add an alias (not a rename, but a 2nd name) and it was shot down as being unnecessary/confusing
that's pretty frustrating. what's an example of such a change?
That's some very liberal major version bumping, so I get why that's annoying
i can't think of any language that has had 19 so-big-the-whole-thing-breaks breaking changes, at least not past the 1.0 mark
removing custom operators, removing native JS modules, removing signals and adding a different API to replace them are the few that I can remember
well, elm is strictly speaking still in 0. versions
ah
but it is advertised as being prod ready
so I don't think it really gets to hide behind being not a 1.0 yet
yeah that is an odd way to do things, i'm surprised companies adopt it in that state
I think edward kmett has a rant about elm somewhere
i'm told the elm ui framework is really nice, at least in principle
it is arguably useful for some frontends
it more or less removes frontend bugs
if you have something in elm, it is likely to be correct for all cases.
tldr python is better than elm
here's a question: is it possible to disable stdin buffering as much as possible, only relying on the os to buffer? -u only seems to disable output buffering
use case: cpython is beating the pants off luajit, awk, and common lisp at a task that i am surprised it is doing very well on. and i want to know if it's because it's just slurping huge amounts of input at a time and buffering it (basically cheating on the benchmark i put together), or if it's because it's actually better-optimized than people give it credit for
I kinda understand it, but it also feels like the language heavily stagnates around issues like this because of backwards compatibility and "clarity" and there's no near plan to make a release that would address those
I'm not sure if it'd even be included in python 4 if that'll be a thing
What you see as stagnation, I see as stability and usefulness.
People who own hundred or thousands of scripts really appreciate not needing to update every one every year.
i don't see it as stagnation but rather lazyness. there's a clear and proven path to modernize things
Which is?
when you add more work to your users, they will not like you, is the thing
I'm expecting to be done dealing with the Python 2 to 3 migration in 1 to 2 years. I'm still annoyed about that.
add aliases, raise a deprecation warning for a couple years and then remove the old thing. clean and simple.
DeprecationWarning doesn't work in Python. It's disabled by default.
tell that to my code, there are deprecation warnings all the time
that still adds work for everyone using the language
just because the work has a longer deadline doesn't mean it's not extra work
They're disabled in library code by default, and enabled in __main__. Most code that needs updating is not in __main__
which, in this case is done by right-click the thing, select "refactor" and be done in 5 minutes?
No, that doesn't work for code that needs to run in multiple versions.
possibly within under a minute if you use a script..
!d DeprecationWarning
exception DeprecationWarning```
Base class for warnings about deprecated features when those warnings are intended for other Python developers.
Ignored by the default warning filters, except in the `__main__` module ([**PEP 565**](https://www.python.org/dev/peps/pep-0565)). Enabling the [Python Development Mode](https://docs.python.org/3/library/devmode.html#devmode) shows this warning.
The deprecation policy is described in [**PEP 387**](https://www.python.org/dev/peps/pep-0387).
you just solved legacy code. its strange how it still exists.
"ignored by default".
!voiceverify
That can only be run in #voice-verification
im guessing packages dont necessarily use this one, since i could have sworn i've seen depreciation warnings from libraries before, but i dont think it was part of my own code.
numpy for example uses its own warning system
that might have been it. i think it was tensorflow in my case
yup
Yes breaking old code is an issue, but renaming a class is really one of the least impactful things there is and it's not like it'd be done out of the blue
There's a reason that the default behavior is ignoring DeprecationWarning, though. Users don't want to be warned that a library that they're using is doing something it shouldn't be. There are tradeoffs involved.
With how python's development is going now, these issues will persist for a long time
this is a good thing.
absolutely, but it's exactly these "issues" that give developers the confidence that things wont break any time soon
If you're concerned about breaking you can remain on the version the script was developed for for a fairly long time
4 years.
that's not very long, as far as corporations are concerned.
I have to work with code that was written multiple decades ago.
the balance of managing backward compat is a big responsibility, it's absolutely a tradeoff. people writing code on the edge dont really get to feel the pain of code that's literally written before this millennium for example.
hi @frosty saddle this is not a help channel, perhaps see #❓|how-to-get-help
i think there should be a better upgrade path, automatic transformation facilities built in
absolutely. but then people quit, deadlines happen, and the perfect world comes crumbling down
Such things are really limited, in practice. We have experience with that, in the form of 2to3.py - it mostly worked.
it also made a ton of unnecessary changes, because it didn't realize they were unnecessary.
how does 2to3 work actually?
i've never been brave enough to try those tools to be honest, it just felt so awkward giving up control
me neither
test suites would have definitely helped..but ha, what are those... sigh
For the people advocating that Python should rename the datetime class: what's the oldest codebase you've maintained? Code written in the 70s, 80s, 90s, 00s, 10s?
C#
how big of an issue would a rename(s) like that be? You mentioned the python 2 migration, but the scales of those are not comparable
Depends how many of them there are.
the 2 to 3 migration included a whole lot of little changes, and a few big ones.
little changes like breaking httplib into the separate submodules of the http package.
but even the relatively small ones - like removing the long type - have reasonably far reaching impact.
The maintenance costs should definitely be considered, but I see no harm in adding an alias. That's far from being confusing and unnecessary, considering that we do have things like collections.namedtuple vs typing.NamedTuple
so - you want the name DateTime for the class. Do you also want to rename int, float, str, list, and dict?
builtins follow a different naming convention
should they?
what if they kept the old name around as a legacy alias with a deprecation warning, giving people a couple versions to add their own datetime = DateTime change to patch it up? though on the other hand i do remember the async change to a hard keyword in 3.7 created a similar kind of mess, especially with d.py
ah nevermind, just saw this was already discussed
considering most are used and regarded as functions, yes
object is a type implemented in C, datetime is a type implemented in C - what's the difference between them in your mind?
they "feel" like functions most of the time
does object?
the only common use for it is sentinels
One doesn't duplicate its package's name
so is the complaint the duplication, or is the complaint the fact that it doesn't follow PEP 8 naming conventions?
both ^^
ok, let's focus on PEP 8. Should we rename object?
For me personally it's the first, I'm fine with built-ins not being pascal case
(Though camelcase in logging is a different story)
i never thought about this detail.. maybe?
although, maybe we need to add a chapter about types to PEP8
from that angle it would make sense to keep those generics lower case
so would you leave date and time and timezone and tzinfo alone, since they don't duplicate the module name?
If we were to rename them, I would prefer to have them pascal cased for consistency
consistency
what would you name map?
If we're pascal-casing types then that's gonna be Map
if it feels like a function..
the issue is how "functiony" something feels
consistent feeling. got it. x)
none of these things are "functiony", honestly. int is a constructor that returns an int object.
str is a constructor that returns a str object.
you could also regard it as a factory
for me the only real annoyance is when a class/function has the exact same name as the module. socket.socket for example has consistently been a bother.
they're listed as built in functions though
sure, that's what a constructor is. Every constructor is a factory.
a constructor is a factory that returns instances of its type.
My view on this is the following:
Most if not all built-in types fall either into the category of types that are used as functions (in which case, naming them in lowercase would fit the idea that API clarity is more important than technical details), or types that are integral to the language, which have an all-lowercase name or alias in most languages, so it makes sense to keep them this way. datetime, time and so forth really don't feel like either to me
there are also factory functions
They are - https://docs.python.org/3/library/functions.html - but the prose says
The Python interpreter has a number of functions and types built into it that are always available.
it's pretty handwavy about "function" versus "type" in that section.
sure. Not every factory is a constructor, but every constructor is a factory.
And every constructor is a function as well
what about set? It seems to be neither of those cases to me. Or complex for that matter.
which is my point about adding a chapter on types in PEP8 - if generic types are meant to be lowercased, there's no argument
object isn't a generic type. I'm not sure why you're bringing up generic types.
I DO
range isn't, either. Nor int, float, or complex
I think this naming convention is sometimes really confusing. For example, lots of people think that range is a generator function for some reason.
(assuming magic backwards compatibility patch)
soo. downcase everything?
what if something starts as a function, and later becomes a class - do we need to rename it and break all existing users?
They have first-class syntactic support with literals, so I don't think a rename is necessary (just as I don't think they need to be shoved into a module), but I wouldn't exactly have a lot of gripe with it either
pep8 already has builtins taken care of so that's not really necessary
I wouldn't be completely opposed to the change but it also has a far greater impact and lower benefits
ok, how about bytearray? There's no literal for that one.
You could change this function to return a class instance.
Actually... you can make this argument about any function, right?
like, the ones you write
or library authors write
yes, I am.
b[0, 1, 2] for bytearray literal? anyone? 😛
ambiguous
so you're saying we should name classes in snake_case?
could be indexing something named b
No, I'm saying that PEP 8 says "take everything I say with a grain of salt" - https://www.python.org/dev/peps/pep-0008/#a-foolish-consistency-is-the-hobgoblin-of-little-minds
Both bytes and bytearray could be int lists/tuples/etc, so I don't have a strong opinion on them tbh
I'm not asking about this whole issue in general, just about a function morphing into a class
yeah 😅 just a dumb meme idea
In what sense? The performance characteristics of a bytes object and a list (or tuple) of ints are very different.
if you need to change to a class for some reason: py def my_thing(x): ... -> ```py
def my_thing(x):
return MyThing(x)
class MyThing:
...
except that now you have two names for one thing. I don't think that's an improvement.
naming is one of the hardest problems in programming 🙂
actually, while we're on the topic - the performance characteristics of bytes are pretty close to those of array.array, which also has the duplication!
Performance characteristics are indeed very different, but I can't say they pose as types integral to the language - you could have an alternative implementation that would use int lists, the functionality isn't integral in the same sense ints and floats are integral. They are definitely less used, and, just like set, I wouldn't exactly be opposed to having them pascal cased
I actually don't know why you would ever change a function to a class, and have that be a meaningful change for the user of that function
Another argument you can make is that dict can also be reimplemented, and I can't say I have a strong answer to that
Apart from the str-like interface, they'd be pretty much the same no?
and mutability I guess
there can be many reasons for that, most often it's because you relied on some closure to maintain state, so you make it into a class, just by using __call__
well, range is your example - in Python 2 it returned a list, and in Python 3 it's a type. The type has extra features, like __contains__
It's a breaking change anyway. So why not change the name?
because it's a breaking change that affected essentially no one. All previous operations work fine on the new type.
So did the list, and in the majority of cases, range is indeed used as a function
Why force them to change?
all previous operations
Any mutable operations won't work, as well asisinstancechecks
but yeah, I guess it's very often not a breaking change
well, very nearly all.
2to3 replaces every call to range() with a call to list(range()) - but it's almost always unnecessary.
In fact, I've never found a case where that transformation was necessary, though I concede that they can exist.
oh no
However, in this case changing a function to a class is not the important change. The function will actually return an object that doesn't support operations that the previous one did.
well, you named isinstance - that statement is always true for type(x) is checks.
Last I heard, pypy is considering supporting Python 2 indefinitely. To give an idea of how much trouble the 2 to 3 migration caused.
fr?
I don't know that my info is up to date, but that was the case around a year ago.
https://doc.pypy.org/en/latest/faq.html#how-long-will-pypy-support-python2
hmm does that really count as support?
it existing isn't support
For example, if you had a partial implementation and contract like this: py def partial(fn, /, *args, **kwargs) -> Callable: # the function promises to return a callable! # not necessarily a function def _fn(*args2, **kwargs2): return fn(*args, *args2, **kwargs, **kwargs2) return _fn and then you realized that it's not picklable, you could do this ```py
def partial(fn, /, *args, **kwargs) -> Callable:
return _Partial(fn, args, kwargs)
I guess it's fair to say that every implementation detail will be relied upon by someone, but that's a separate story
that's Hyrum's Law.
yes
I think that if learning something is actually a type and not a function is a surprise to a lot of people, then being a type is likely not a very important detail to know, and the API clarity of being named like a function would possibly be better than conforming to it being a type
anyway... I badly need to go to bed
nn
we can continue the flame war tomorrow
same here
is anyone who knows about types surprised that int is a type and not a function? When you're taught types, int is one of the first ones you learn, and you learn to print(type(5)), and it prints that it's an int...
not with range and map though IME
int isn't the surprising one, range, partial, map, etc are
ah wait before you all leave, i need a quick opinion thing
although practically, it may be not that important
int is one you'd pretty much always* expect to be exactly int, coming from another language
*Terms and conditions may apply
buf = bytearray(8)
with atomicuintview(buf) as aiv:
...
buf = bytearray(8)
with atomicview(buf, AtomicUintView) as aiv:
...
any preference for either style? (hopefully before fix goes to bed)
what's the benefit of the second?
AtomicUintView is the type of aiv - there's another 4 type options
whereas the top means i have 5 separate functions
Why not with AtomicUintView(buf) as aiv?
then i'd say make the second argument into a kwarg and have a default
we already went over this :/ it's now split into 2 types, AtomicViewContext does __enter_ and __exit__ and produces an AtomicView
default would be which out of bytes, int, and uint?
whichever is most common 😄
why not take an array.array style format code? 😄
elaborate?
!d array.array
class array.array(typecode[, initializer])```
A new array whose items are restricted by *typecode*, and initialized from the optional *initializer* value, which must be a list, a [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object), or iterable over elements of the appropriate type.
If given a list or string, the initializer is passed to the new array’s [`fromlist()`](https://docs.python.org/3/library/array.html#array.array.fromlist "array.array.fromlist"), [`frombytes()`](https://docs.python.org/3/library/array.html#array.array.frombytes "array.array.frombytes"), or [`fromunicode()`](https://docs.python.org/3/library/array.html#array.array.fromunicode "array.array.fromunicode") method (see below) to add initial items to the array. Otherwise, the iterable initializer is passed to the [`extend()`](https://docs.python.org/3/library/array.html#array.array.extend "array.array.extend") method.
Raises an [auditing event](https://docs.python.org/3/library/sys.html#auditing) `array.__new__` with arguments `typecode`, `initializer`.
(i've never used array)
it takes a type code as a required argument, and has type codes for signed short, unsigned short, signed int, unsigned int, unsigned char, etc
what about a good old memoryview
so more like atomicview(buf, "uint")?
there's also the struct module with format codes.
That would also be good, yeah
ah yes, the regex of serialization
i would prefer a short enum like with numpy dtypes
strings as modes are brittle
enum would be ideal, hmmm, maybe i should do that
realistically, the best answer for your users, given that you have a constrained set of types, is probably a separate type for each at the top level. So, my vote would be for AtomicUnsignedIntView
yeah, you can type-hint enum members with Literal
no help from IDEs on typos etc
ooh i had no idea
in TypeScript you could specify struct's format language at type level 👀
but alas
so... you're advocating for atomicview(buf, AtomicIntView) or atomicview(buf, INT) (where from atomics import INT or something)?
No, I'm advocating for not having atomicview at all, or at least not exposing it to users.
buf can be a memoryview, the second parameter is for the return type of atomicview (which is an atomic type)
What is this atomicview thing btw? I’ve been hearing it here a lot
users would only see with AtomicIntView(buf) as aiv:
you're literally only hearing it from me 😂
Should’ve mentioned in this channel
hmm... i mean i had this originally, but other people brought up the issue of it not being very friendly/helpful to IDEs, so now we have atomicview() -> AtomicViewContext and AtomicViewContext.__enter__() -> AtomicView
i'd advocate for the latter, but that's just me 😉
:)
in what way is it not friendly to IDEs?
Hey sorry to bother you but i have a little probleme on Sony Vegas can someone help me pls?
Regardless though, what is it for? Pretty curious

realistically, the entire bring-your-own-buffer approach is very, very weird. Especially given that the buffer needs to be aligned, and such. You probably shouldn't expose any such API to Python users in the first place.
IIRC it's because having certain methods be available only inside a context manager is not exactly a good idea
aiv = atomicview(buf, UINT)
aiv.store(5)
@raven ridge in your version this isn't prevented by the types, it's prevented by checking internally if __enter__ has been called and then raising an exception
whereas if aiv is a type that only supports __enter__ and __exit__, it's prevented by what little type system we have
i wanted atomics for shared memory at some point like a year ago, and finally got round to finishing it
did you try asking in a help channel?
Ohh alright, do you have a GitHub repository for it?
sure
in wich that's the question
https://github.com/doodspav/atomics/tree/devel-ffi readme is out of date (also don't look at the tags, that's me messing around with github actions)
Well, then, why not just AtomicIntView.__enter__() -> EnteredAtomicView, where EnteredAtomicView has store(int)?
The question for me is, why not still have Atomic<Type>View as the main type, and then have Atomic<Type>View.__enter__ -> Atomic<Type>ContextView (Exactly what geek said, yeah)
I think a thread would be really good here ngl
idk how that works
Can we make those here?
(unless that was a pun?)
nope
Sad
that was just a thought
my reasoning for that was mainly type hinting reasons
What doesn't work about this for type hinting?
def inc(a: AtomicUintView):
a.inc()
with atomicview(buf, UINT) as aiv:
# type(aiv) -> AtomicUintView
inc(aiv)
idk seems nicer to me than AtomicUintViewContext in inc
(realistically that would be more like Union[AtomicIntegral, AtomicIntegralView] or something)
Well, 🤷 - I'm just going to go back to saying that I think the entire bring-your-own-buffer approach is awkward in Python, and not a good idea. And if you didn't have that, you wouldn't have any of these problems.
does python have a way to import enum members in a way such that you can use them without the underlying class?
AtomicInt exists if you don't need to bring your own buffer, and yes i'm aware this whole AtomicIntView thing is a pain 😂
but no way to like make enum members globals?
No, afaik
damn :/
uhhhm..
Hmm... You could have something along the lines of a prepare classmethod, so that
AtomicTypeView.prepare(buffer) -> AtomicTypeViewContext
AtomicTypeViewContext.__enter__ -> AtomicTypeView
with AtomicTypeView.prepare(buffer) as atv:
...
Like from module import TheEnum; MEMBER = TheEnum.MEMBER ?
actually, you can assign global variables to your Enum member
is this possible to actually implement? i feel like i tried something similar before but having 2 types refer to each other wasn't possible somehow
um, yeah ig
and then you can import those while still having them as members
It is, why wouldn't it be?
mostly just thinking of C's enums
idk, i probably just didn't do it right
i put enum members as class attributes in a different class, no problem
Ohh I thought you were asking directly syntactically
a C enum member isn't a first class object at all, it's just an integral value of a specific type
could i still do this tho? ^^
if i do MEMBER = TheEnum.MEMBER and then use MEMBER
ik 🙂
>>> from enum import Enum
>>> Foo = Enum("Foo", "a b c")
>>> a = Foo.a
>>> a
<Foo.a: 1>
Linters should infer the type from that, yeah
ok lemme try that, cuz honestly i'm happy with atomicview(buf, UINT)
with the .prepare() thing being close second
also @raven ridge if you don't want to provide a buffer, a = AtomicInt(width=4) is already available and you can pass it around as a normal variable 🙂
with the bring-your-own-buffer approach - is there a way to get the child process and parent to share a buffer on Windows? And, how will you share it on Unix - is it fork? If so, couldn't you just as easily fork an AtomicInt object that itself holds the buffer?
it's a nightmare in terms of guaranteeing you won't leak the memory - either the user has no access to the buffer, or the user is entirely responsible for the buffer
can't really have an inbetween
why would you ever want anything other than "the user has no access to the buffer"?
if the user looks in the buffer, it's undefined behavior, right?
yes
(other than through your APIs, that is)
but say i have a program using shared memory in C++, and then I want to also interact with that shared memory in Python, the user would need to provide a buffer of that shared memory, there's no other way
this isn't just for shared memory between python processes
"no" other way? What about a constructor that takes a shmkey?
shmkey?
ah, i've only ever used shared memory with boost::interprocess
i don't have a reason for not being able to do that... but that seems to lead to me needing to have a constructor that supports every platforms specific way of accessing shmem?
or of supporting both mmap at least? and then maybe shared_memory constructors?
I don't know Windows at all, I'm a Unix guy. But for everything-but-Windows, system v shared memory segments have a unique integer ID assigned to them, and things can attach to them using the ID.
i'd advocate for atomicview(buf, dtype.uint) (dtype as enum)
re: mmap - is there any way to share an anonymous mmap with any process other than a child process?
idk, i don't have a great answer, really it's just it was a lot of effort and seemed too specific, whereas telling the user to provide their buffer and just keeping it active for the duration of the context seemed a good balance
i'll be honest idk :/ somepoint in the past i did, but that knowledge is long gone 😦
dtype being from numpy or my own type?
your own
ok
but akin to numpy
I'm pretty sure there isn't - it doesn't have a name, so there's no way for another process to refer to it, short of inheriting the mapping from its parent
and if that's the case, there's no BYOBuffer use case for MAP_ANONYMOUS
i mean, ok i'll look through the mmap module, one sec
well, anyway: yes, my suggestion is to have a way to construct your AtomicInt with each supported platform's shared memory identifier. If your AtomicInt is in charge of doing the "attaching" and getting the pointer, it makes resource management easy, because your destructor will do the detaching.
i think it's a lot of unnecessary effort to support all the platforms instead of byob - i don't think it's worth supporting all the potential ways of constructing it, however i can yield on a special case of passing an AtomicInt to another process within python...
so either have AtomicInt allocate from shared memory, or have AtomicSharedInt... (probably the former)
but i still wanna keep byob
I think expecting Python users to byob is just gonna get you segfaults. It's a very difficult interface to use.
one sec
and one that's outside their wheel house.
ctx = atomicview(buf, dtype.uint)
# if ctx.release() is called, ctx.__enter__() will raise an exception
with ctx as a:
# ctx.release() will raise an exception here
...
print("done")
# a.load() will raise an exception (as will any usage of a)
the only way to get a segfault is if you break the contract of "keep the buffer around for the duration of the with context"
and realistically you can't even get rid of the buffer once you create ctx, CPython will raise an exception
Python prevents the buffer from being garbage collected once you create the ctx
but they allocated it in some way, and they can still free it in the same way.
munmap or shmdt or whatever.
buf has to support the buffer protocol
CPython prevents any modifications to the buffer (like resizing or releasing it) while someone else has a "reference" to it
I mean, no
the implementer is required to do that - but there's nothing that stops the implementer from getting it wrong
it's not "prevented"
it's "forbidden"
>>> buf = bytearray(8)
>>> m = memoryview(buf)
>>> buf += b'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
BufferError: Existing exports of data: object cannot be re-sized
yes, because the bytearray type gets it right.
but whatever type you're expecting the user to bring might not.
that's not Python enforcing that, it's bytearray enforcing it.
i mean, if someone gets to the point where they're using their own special made type that supports the buffer protocol, and then they mess up, i kinda feel that's on them
what else would they ever do?
use shared_memory or mmap?
there's no use case where it would ever make sense for them to use bytearray, is there?
both of which support memoryview (and the buffer protocol in general)
are you sure this isn't an implementation thing tho? CPython doesn't keep track of Py_GetBuffer and PyBuffer_Release calls?
what would it do based on that?
the bytearray needs to know that there's been more Py_GetBuffer calls on it than PyBuffer_Release calls, so that it can reject calls to __iadd__
hmm ok ig nothing
yeah
idk, i think you can screw up if you really try even by just providing shmkey or whatever it was, and this is fairly far fetched, so i think it's safe enough
interesting tho, always thought the BufferError was on the interpreter's end
Hi is anybody here alright with multiprocessing and shared memory in python?
lol
are you sure you're in the right channel? 😉
xd
i mean, seeing the past 30m of discussion...
Like i have a problem with accessing an array
@red solar for that it's worth, also - I don't agree with those who said that your original approach was unfriendly for type checkers. open() constructs a file object, the file object has a __exit__ that calls close(), and if you call a method after close() or after the context is exited, you get exceptions. Your type wouldn't be any weirder than the file objects returned by open
damn, should've been louder like 3 days ago 😂 but ironically your argument has pushed me towards splitting it into 2 types, and that the library should take every possible measure to prevent the user from screwing up accidentally
and having both the IDE warn them and an exception, rather than just an exception is ideal 🙂
this is in shared memory?
like i can't accesse the array within temp
thats a bare code i have like 400 lines between them lines xd
try putting global arr1 on the first line of the function?
oh wait the temp is run in a new process?
you pass temp to the new process, but you don't copy arr1 over... so there's no way for the new process to access it i think
you'll need to pass arr1 as an argument over to the new process
hmmm
Hey @zinc shale!
Uh-oh! It looks like your message got zapped by our spam filter. We currently don't allow .txt attachments, so here are some tips to help you travel safely:
• If you attempted to send a message longer than 2000 characters, try shortening your message to fit within the character limit or use a pasting service (see below)
• If you tried to show someone your code, you can use codeblocks
(run !code-blocks in #bot-commands for more information) or use a pasting service like:
on windows anonymous mmaps can have a tagname that you can use to reopen in any other process, though im not sure it should be called anonymous as such. on linux nah afaik, just shared memory.
python's mmaps implement the buffer protocol so if you support memoryviews then mmap support could just be as simple as converting it to a memoryview
@raven ridge ^^ 🙂
if i have calc.py and calc.cpython-310-darwin.so in the same directory, which one does python import?
apparently it's .so for anyone interested
https://paste.pythondiscord.com/iwudokizof.properties
https://paste.pythondiscord.com/atolasupiz.txt
here, have a probably-useless benchmark
when it comes to "do file i/o and a small amount of arithmetic", cpython is pretty fast. this is 3m data points
for some reason graal was really slow, maybe it doesn't buffer stdin as aggressively
(i assume cpython and other implementations buffer stdin aggressively, i don't really have a way to verify)
If you rename calc.py to calc.cpython-310-darwin.py?
i was just wondering, considering https://github.com/beartype/beartype#pep-484-deprecations (which can't really be made backwards-compatible with aliases since Optional, Union etc. comes with new syntax) - would/could/should it work that justuse only runs on python >=3.10 but if someone wants to use() a package that requires an older python version that a sub-interpreter is spawned for that package-venv?
I don’t have an answer, but is typing.List actually being deprecated?
yep
...Importing those from typing is deprecated.
Why tf tho… there’s no issue in just having them
having two ways to do something is something Python seems to move on from
like, deprecating @asyncio.coroutine
(for now let's just ignore that we have 4 ways to format strings)
Honestly how tf do people support multiple Python versions when features get deprecated left right and centre
messy ifs
and, well, those things from typing will only be removed in 2025 or so
so we have plenty of time to adapt
exactly my question about how we should deal with that in https://github.com/amogorkon/justuse - would it make sense to use sub-interpreters to bridge the gap?
I think that would be cool if feasible, since a lot of people have import issues with packages stuck on old versions of Python
But I don’t see how you would like communicate between two interpreters with different Python versions?
Hey, some libraries still support Python 2
can confirm, if sys.version ... is rather common in black's codebase
that's the problem - it's not a future thing but it's right here, right now. the temptation is great to drop python <3.10 right away, but most scientific tooling is still on 3.8 or lower (looking at conda)
.. or we just reimplement functions that are too new
babel for python when
Can u walk me through it tho? How does a python3.10 interpreter create and use a python3.8 subinterpreter?
no clue.
(And are you limited to going back to the first version subinterpreters were introduced?)
Oh
@lusty scroll might be deeper in the theory
i'm thinking of a subprocess of some sort and then communicate via stdin or somesuch
there's the subinterpreter PEP but i somewhat doubt it's for this kind of scenario
So either only support packages compatible with the current version of Python, or throw performance out the window?