HNHacker News
TopNewBestAskShowJobs

ariebovenberg

43 karma · joined January 3, 2022

submissionscomments
ariebovenberg··on Why Pendulum had to write the most cursed "+" operator in all of Python
Textbook correct use of call stack introspection

> There'd be a way to do something equivalent without peeking at the call stack, by requiring the caller to explicitly pass a descriptive & unique name

Agree with your tradeoff here. "No instrospection, ever" can also be harmful. Reminds me how 'no global mutable state' also needs to be broken in some cases.

ariebovenberg··on Why Pendulum had to write the most cursed "+" operator in all of Python
That's indeed quite the hack! Also the filename heuristic is...quite something. Certainly agrees with my experience that in build-related scripts, all notions of clean code go out the window fast.

edit: wording

ariebovenberg··on Why Pendulum had to write the most cursed "+" operator in all of Python
For Python in general, stack walking ranks medium-cursed. A frame inspection can even be used for good: namedtuple from the stdlib IIRC uses it when building the class. What made Pendulum's example cursed IMHO is the fact that it's a mathematical operator, and it leaks out unintended behavior---like calling it depends on the caller's function name.
ariebovenberg··on Why Pendulum had to write the most cursed "+" operator in all of Python
I've certainly seen things like this attempted. Developer ingenuity is endless when given a `self` variable in Python, I've noticed.

It shows just how inheritance is such a blursed way in general of extending code. Designing a base class is such an art, and even if you get it right, there's little to stop subclasses from extending beyond the carefully designed parts it is allowed to modify.

Django views are probably the place where I've seen this work the best--but certainly not foolproof

ariebovenberg··on Why Pendulum had to write the most cursed "+" operator in all of Python
Author here. I ran into this while comparing Pendulum with `whenever`, the datetime library I maintain. I sent a patch that removes the hack, but the post is about why the underlying design can't be patched the same way. Happy to answer questions.
ariebovenberg··on Whenever: Typed and DST-safe datetimes for Python
Author here. It's indeed a hard problem to parse "All ISO 8601 formats and all its weird mutant children that differ by a tiny bit." Since the ISO standard is so expansive, every library needs to decide for itself what to support. The ISO standard allows all sorts of weird things, like 2-digit years, fractional months, disallowing -00:00 offset, ordinal days, etc.

Javascript's big datetime redesign (Temporal) has an interesting overview of the decisions they made [1]. Whenever is currently undergoing an expansion of ISO support as well, if you'd like to chime in [2].

[1] https://tc39.es/proposal-temporal/#sec-temporal-iso8601gramm... [2] https://github.com/ariebovenberg/whenever/issues/204#issueco...

ariebovenberg··on Whenever: Typed and DST-safe datetimes for Python
No problem. After all, the readme does go from mentioning Pure Python directly to showing a benchmark graph where it's curiously absent
ariebovenberg··on Whenever – typed and DST-safe datetimes for Python
Author here. It's answered briefly in the FAQ

> In casual benchmarks, the pure-Python version is about 10x slower than the Rust version, making it 5x slower than the standard library but still (in general) faster than Pendulum and Arrow.

"(in general)" here since the speed compares differently per operation, while the Rust version is faster across the board. That said, there's no operation that is _significantly_ (or unnecessarily) slower than Arrow or Pendulum.

edit: I'm considering adding comparison to the pure Python version once I get the time for a more expanded "benchmarks" page in the docs

ariebovenberg··on Whenever: Typed and DST-safe datetimes for Python
Author here. To summarize the long discussion in the issue:

1. I _love_ pure Python packages. Not everybody should be forced to use Rust. I want installing pure-Python to be as easy as possible

2. Having separate names on PyPi (with or without extras) creates confusion for libraries depending on whenever: should they depend on whenever-py or whenever-rust? If one “overwrites” the other, this adds confusion.

3. Most users expect to “pip install whenever” and start using the “fast” version

For me, points (3) and (2) weigh heavy enough to make (1) slightly more cumbersome.

But: Maybe I’ve missed something. Have a read in the above issue or add your 2 cents.

edit: formatting

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
You are correct that there are improvements to be made. The current internal representation is—for the moment—simply the Python standard library.

Probably the approach of Chrono is best: allow leap seconds to be represented (i.e. 23:59:60), but not to account for them historically.

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Indeed, structural changes to timezones also need to be handled. Temporal has a good approach here https://tc39.es/proposal-temporal/docs/ambiguity.html#ambigu....

Basically:

- Store the offset and the tz ID

- When deserializing, allow explicit choice what to do: keep the offset (i.e. same moment in time) or keep the local time (i.e. same time on the 'wall clock')

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Author of the article here—

I actually did start out basically porting Chrono to Python, but decided against it for two reasons:

1. While I really liked handling local/UTC conversions with the "LocalResult" enum in Rust, it translated poorly to Python. Somewhere along the line you'd need to transition from Rust's "errors as values" to Python's exception-oriented world. I actually wish Python would go Rust's way, but I'm not going to swim against the current here...

2. Most modern libraries in other languages choose to disambiguate local datetimes. I felt it was safer to go the road more traveled here.

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Author here—

This is a conscious decision, I'll explicitly address this in the FAQ soon.

As I commented elsewhere, this is completely in line with industry standards (iCal, Unix time) and other modern libraries. I don't (yet) see any reason to deviate.

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
I wouldn't consider 'not handling leap seconds' as a pitfall. If you need to account for leap seconds, you're probably not going to use a general-purpose datetime library.

Unix time ignores leap seconds, so does RFC 5545 (iCal), and most modern libraries (Chrono, Temporal, NodaTime).

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Yeah—the perfect solution doesn't exist. The problem is that fixed-offset datetimes are very common since RFC3339 and ISO8061 don't support timezone names. The result is that you often end up with fixed-offset datetimes that should instead be linked to a IANA tz ID.
ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Author here. "Offset" is indeed relative to UTC. The problem with allowing adding timedeltas is that you give users the impression they are doing valid arithmetic, while they may not be.

Example: You receive a timestamp of an event in Paris: 2024-03-31 01:00:00+01:00. If you allow addition, you may be tempted to think you can "just add three hours" and get 04:00:00+01:00. However, because Paris has a DST transition, you'd actually want to have 05:00:00+02:00

In the end, the choice is between "users know what they're doing, just let them" and "users need to be prevented from making common mistakes". I choose the latter.

Note that also NodaTime doesn't support arithmetic on their OffsetDateTime, for the same reason.

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Author of the post here—

They are emoji. I've added plain text to the table now, so it is readable without them.

edit: I've used a workaround to display emoji as images now

ariebovenberg··on Python datetime pitfalls, and what libraries are (not) doing about it
Author of the blog post here—

1) You're absolutely right, I'll fix this mistake in the example.

2) "Made up" was perhaps stirring the pot too much ;), but the fact remains that a timestamp is created when one essentially doesn't exist. That this is meticulously documented in PEP495 doesn't change this fact.

Note that PEP495 also explicitly describes some of the other pitfalls. Documenting a 'suprise' is not the same as eliminating it.

> Finally if we disallow creating non-existent datetimes in the proposed library, how do we represent the 2am in "clock changes forwards at 2am"? Use 3am? There are tradeoffs.

Indeed, there are always tradeoffs. Often, only time can tell what was the 'least bad' decision. It is telling though that modern datetime libraries (Noda Time, Chrono, Temporal) in other languages choose to not represent these 'missing' local times.

ariebovenberg··on Ask HN: Know any validation libraries that guess whether a timestamp is in ms/s?
Was this inspired by another library or language? Or simply a reaction to the all-too-common experience of dealing with under-specified data?
ariebovenberg··on Is your Python code vulnerable to log injection? – Arie Bovenberg
Author here. I in my article I didn't touch on 'log poinsoning'[1], what they could be referring to.

Vulnerability to log poisoning really depends on _what_ you do with your logs. If you display them on a webpage, beware of XSS. And -- I suppose -- if you use them in shell commands, beware of shell command injection.

In the article my focus was on vulnerabilities specific to Python's logging library.

EDIT

as an added point: I don't think preventing log poisoning should be responsibility of the logger. It'd be madness to try and escape all possible bad interpretations (HTML, shell, SQL, etc) of the data. About as crazy as PHP's automatic escaping of strings...

[1] https://owasp.org/www-community/attacks/Log_Injection#code-e...

ariebovenberg··on Show HN: Detect broken __slots__ in Python libraries
__slots__ is a good way to make Python classes more efficient. There is a catch though: you need to use it consistently in all base classes, or you don't get the full benefits. This is easy to forget, and there's nothing warning you if you mess up!

After fixing this in the `returns` library, I decided to create a tool `slotscheck` to detect this common problem anywhere.

I ended up finding broken slots in popular libraries, and even the stdlib. (see my blog post for the findings: https://dev.arie.bovenberg.net/blog/finding-broken-slots-in-...)