122 comments

[ 2.9 ms ] story [ 205 ms ] thread
I'm excited about some of these Django updates - especially models.GeneratedField()
Is there a PEP 8106 alternative coming for the unittest module too? The naming scheme really looks odd.
It is interesting to see just how conservative the core devs are against even the most benign way forward (including more consistent aliases without immediate deprecation).

Indeed, not a hill worth dying on either way but it’s a little wild the counter argument is “increased support costs” when, let’s be real, there is no significant increased support beyond the initial scope of work.

If core Python ever plans on consistency, introducing these aliases early is the main way for them to achieve it. Even if there is no direct plan for deprecation. Something something about the best time to plant a tree.

As much as I like to defend Python against the "Python bad!!" nonsense here on HN, I agree with this, and with similar complaints about naming in the 'datetime' module.
The time to have done it was the first release of Python 3 when everything else was breaking anyway. The ship has sailed.
Adding new aliases to be consistent with Python's prevalent coding style? Increased support costs, not worth it.

Deprecating often-used APIs like datetime.datetime.utcnow() because they're ugly? Sure, we'll do that, that won't cause anyone problems unless their code is wrong. (At least they didn't set the removal date to be +2 releases = +2 years, as they usually do.)

The Python standard library is primarily managed by volunteers, and different sections have distinct maintainers, resulting in diverse choices.

When there's no strong advocate for a module, implementing changes becomes a challenging task. However, modules with dedicated champions, such as datetime by Paul Ganssle or pathlib by Barney Gale, may undergo significant modifications after consideration and discussion.

Not everyone in the broader Python community will be pleased with these alterations, but they aren't made hastily. I suggest we show empathy towards those who willingly take on the responsibilities of being open-source maintainers, it's a fiery task.

While I've personally expressed dissatisfaction with the utcnow change on the Python discussion page, I also acknowledge that I'm not responsible for maintaining this module. Consequently, I've updated my code in a completely backwards compatible way: datetime.datetime.utcnow() -> datetime.datetime.now(datetime.UTC).replace(tzinfo=None).

No matter how many maintainers there are, the policy to eagerly deprecate and quickly remove things is something common to all of stdlib. And I think that’s not a good policy for a programming language. If you look at Java, for example, only very few APIs were removed between Java 9 and 20, many of which minor or broken/useless (Pack200, RMI): https://docs.oracle.com/en/java/javase/20/migrate/removed-ap...
There has been a recent push to remove completely unmaintained modules with PEP 594, but the steering council has made it clear that PEP was an exception and all future module deprecations will have to be done on a case by case basis. The PEP 594 modules were discussed for well over two years before the PEP was accepted, and includes unmaintained modules that were technically deprecated as of Python 2.0.

I also rarely see methods removed at all, which is why the utcnow one sticks out so sharply for myself and others.

I can't reconcile this with the statement of "policy to eagerly deprecate and quickly remove things", but maybe you have some evidence?

Further there is a clear path discussed on the Python board of how to move any pure Python modules to PyPI for any part of the community that wish to maintain them. In the earlier years of Python it was not a serious option to ask everyone to use third party libraries, but now for almost all use cases it is a reasonable option.

That was painful to read. Logging definitely rates as the least favorite module I have to regularly use. The Java ancestry is obvious, and making some free incremental improvements should have been done a decade ago.
If you read nothing else, the commit message adding JIT support is worth your time: https://github.com/python/cpython/pull/113465
Yeah, I'm getting old. I would prefer TLDR formal version and then the fun xmas version for people that feel festive. But hey I'm not paying for this so who am I to complain :)
[flagged]
I'm certain the poetry wasn't GPT generated.
Why do you suspect that? I really doubt it, because it's actually good. Do you think that nobody is able to write good poetry without help from machine? Like... I've written stuff like that in my life. It's not even particularly hard, if you believe you can do it and workshop it for a while.
Yeah, ChatGPT can't reliably generate poetry which scans. (It can't count syllables in words, so this would be a bit much to expect of it.) I haven't read the entire poem, but the bits I have seen at least have the right syllable counts (although some rather odd stress patterns).
To the guy who said the pull was horrible:

IMO, the most important thing about a pull request is to... actually be productive. I've worked with people in the past who would nit-pick my commit messages wanting me to waste hours of my time trying to use arcane Git commands. Any of which might and probably will clobber my work.

If you're doing Git reviews a good use of resources is to look for security problems, performance issues, and general engineering problems with someone's code, etc.

A BAD use of Git reviews is to spend the time making stylistic comments 'I would have written it like this, it looks much better', being overly pedantic about code formatting, or forcing your OCD on someone for their Git history. The reason people hate code reviews is somehow they're always done by this latter group of person.

If you're forcing people to waste time for silly reasons then you can count that they'll eventually leave your silly company. I know I have. I was once about to work at a company but saw that they literally used a committee of people to review every commit message wherein they would force every engineer to rewrite code for reasons that seemed to make astrology seem like a hard science. Consider not doing that.

A good reason for enforcing some rule on git commit messages though is to have a message that helps when bisecting to find where an issue was introduced in the past. If the commit message is too meanless or too different from whatever is the convention, it makes you spend more time when tracking and solving issues.
If you’ve a test checking the regression you can use that directly to find where the regression occurred without relying on the message, no?
No, the message should tell the why of the change, if you don't know you risk doing a fix that is simply removing the change and then you are back at the issue that motivate such change in first place. This is even harder if the person put the commit along others that are merged separately or worse, work directly on the main/master branch. I've been there a lot, it's not hard to write a good commit message, if you're in a project and everyone does their part except that one programmer, you will notice a lot every time a bug turns out to be introduced by that one person.
The reason one should write commit messages in the common form is to shave off a few seconds for every reviewer to immediately understand what is going on.

It's not unreasonable (within the limits of sanity, of course), it's just a matter of respecting other people's time.

If someone who made the changes can't explain things clearly, I'd even wager that they didn't understand what they're changing properly. A good commit message is needed as the author might be gone but software is maintained for decades. Productivity is easy, writing a good message isn't, as the latter seems to be hard for many and it's telling of their understanding of systems they change.
Many teams will just use squash merges to avoid wasting time on commit messages and end up with just one commit to the main branch and cleaner history.
That's like returning to publishing tarballs instead of having single, revertable commits.
When I'm having to wade back through previous commits trying to debug a problem, there's nothing I hate more than finding someone's large squashed commit. Instead of using automated bisect tooling, I have to try and understand what they did and untangle it. This might be an area of the codebase I'm unfamiliar with and it'll take even longer. Compared to this, writing a few extra commit messages costs nothing. I really don't get it.
`git rebase -i develop` is arcane? An editor opens where you put an 'r' in front of every commit that needs rewording. Save and close, and Git will successively open an editor for every commit message. Force Push and you're done.

If you're not willing to bother with command line: the Git client in Jetbrains also lets you edit commit messages in a very straightforward way.

Force push can be scary to some. Some nitpickers may also ask you to squash/reorder/split commits to satisfy their OCD.
Those nitpickers are probably people who have tried to track a regression in a big codebase before. It's not OCD, it's just useful version control.
I am one of those who would insist on correctly splitting commits. Commits are a communication tool, and a well-crafted series of commits makes reviewing pull requests, which is a chore for most people, a lot easier. Months or years later, it is still important to easily review changes.

In a Gitflow repository I don't particularly like squashing feature branches since a sequence of commits allows the author to better document what they were thinking about. Squashing is fine in Trunk-based development since feature branches are usually less extensive.

I hate intermediary merges on feature branches because they tend to make up a large portion of the branch history and are harder to review than normal commits.

400+ commits with a ton of them being "catch up to main"? Wow, I guess even good programmers don't know how to rebase/use git properly.
Do we have any idea how the introduction of the JIT compiler in CPython 3.13 will impact the performance?
From the youtube talk it will be a small improvement (5-10%). It's more of a proof of concept for future things.
[flagged]
What does the term "scripting language" mean to you?
To me, it means that the person who wrote "scripting language" probably doesn't know what they're talking about.
Probably something along the lines of "something I don't like, but don't have any objective reasons to prove why it is bad".
Not the original poster, but to me it usually refers to a language that is expressive and high-level but usually not fast or efficient enough to implement the actual heavy lifting. It seems fair to call Python a scripting language. This is not a derogatory term, rather it actually describes a great way to build software and explains Python's success.
I prefer compiled and statically typed languages myself, but it seems a bit absurd to not consider Python a general purpose programming language. It's Turing complete, has one of the most fully-featured standard libraries in existence, and can interface with native libraries.
(comment deleted)
Python is like anything in that it rewards experience. If you know about asyncio you can write beautiful, performant code that can deal with networking, files, and other blocking resources without halting the program every time. If you know about processor executor pools -- you can easily execute CPU-intensive operations on different cores even though your main program is single-threaded. If you know a little about databases you can write highly portable and simple queries with SQLite.

You can use Python in the same way that other languages allow you to write performant servers, desktop applications, websites, and even software that runs on phone. But you need to know what the best approaches are. The thing about Python is that its a very old language. It didn't always have things like asyncio which is now arguably the best approach for dealing with concurrency and the modern challenges of blocking I/O. New libraries appear all the time, and the language and tooling continue to evolve. I think older developers who may have only dabbled in Python might have out-dated views about the language because there definitely were times in Python's history where it lagged far behind other languages.

Can you elaborate on the issues you've seen? Was the code haphazardly thrown together, or did it follow the usual modern practices (pip-tools or Poetry, dataclasses, type checking, Pydantic, etc.) and still suffer the problems?
Python is not a scripting language, it's a weakly-typed general-purpose programming language. I too dislike the lack of strong-typing, but there are dozens of good options if that's what I need in a codebase.

It sounds like your problem is with people who write Python, not Python itself. Not every person who writes code has the time or ability to learn all the nuances of strongly-typed functional languages. In my opinion, people outside of software engineering shouldn't bother with such esoteric domain knowledge. "Real" programmers like yourself are there for that reason - to rewrite their prototyped code in whatever style you see fit.

Complaining that they don't know how to program is a great way to alienate smart people in other domains. Knowledge of computer science tends to blow up people's egos in a way that I have observed in few other fields.

Python’s strongly, dynamically typed. Try adding “12”+3 and it will throw a TypeError at you.
That only works with a few built in types, like numbers. For any other type, you had better hope that the author has added such checks.
This isn't true, even if you define your own types/classes you still can't add them together willy nilly unless you (or a superclass) explicitly defined an addition operator. The Python language itself will never implicitly coerce a type for you, not even for floating point and integer addition. [0]

[0] https://www.pythonmorsels.com/type-coercion/

You're right. Classes don't even provide such operators by default:

  >>> class Foo:
  ...     ...
  ...
  >>> class Bar:
  ...     ...
  ...
  >>> a = Foo()
  >>> b = Bar()
  >>> a+b
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: unsupported operand type(s) for +: 'Foo' and 'Bar'
If anything, the complaint is that pre-type-hinted Python was too quick to raise a TypeError without helping you know what types it was expecting. The only case I can think of where it was too lenient was where Python 2 conflated strings and bytes. That change was 90% of the pain of the Python 3 upgrade, and now they're different types.
I was speaking generally not specifically about addition. If you create new types and especially new operations on those types, then it will be up to you to add runtime "type checks" to avoid other failures. Try defining equality for a Point class for an example.
If you use UUIDField and MariaDB >= 10.7, read Django 5 release notes carefully. Other than that, smooth upgrade :-)
The deprecation of "crypt" could have been handled a bit better, IMHO.

It recommends to use "hashlib" instead, which isn't API compatible to crypt, and if you load it on a new enough python... triggers a deprecation warning about "crypt" being deprecated. Oh, and it seems unmaintained.

Did you mean "passlib", the third-party module they link to? The built-in "hashlib" doesn't generate any warnings for me on Python 3.11 and is presumably maintained as part of Python.

Anyway, the PEP mentions that "crypt" is not secure, not thread-safe, not cross-platform and not useful for modifying the system password database... so it sounds like you really shouldn't use it for much of anything. What's your usecase?

Yes, passlib, sorry for the confusion.

> What's your usecase?

We need to store hashed passwords that are then used by third-party programs (like Apache or exim) to authenticate users, so we need to generate salts and hashes in formats compatible to them.

It works with passlib after some fiddling, it was just way more fiddly than I'd expect from python.

I'm very excited to see 2FA become mandatory.

It's worth noting that that 2FA requirement will have (virtuous) knock-on effects: package uploads will require an API token instead of allowing a password, meaning one less place where a user can accidentally expose control over their entire account. For packages published through GitHub Actions, PyPI's Trusted Publishing goes a step further and removes the need for a shared API token entirely[1].

[1]: https://docs.pypi.org/trusted-publishers/

Will PyPi Passkey sign in be supported?

Edit: Thank you!

It should already be (we support passkeys as an MFA method, but not as a password replacement yet).
To create a new package, you MUST generate a global token that can also do whatever on all existing packages on the account.

How many people do you think will bother to delete the global token after having used it, and then generate a scoped one? 1%? Probably much less than that.

You can create a new package via a "pending publisher"[1], which does not require a user-scoped token.

(Note: even though PyPI calls them "user-scoped tokens," they have less access than a password does, since they can't manage the user's account itself. So, while not ideal, they are still a better choice than a user/pass combination.)

[1]: https://docs.pypi.org/trusted-publishers/creating-a-project-...

Oh they've listened to me at least.
2FA but still no namespaces? Dependency confusion attacks are still trivial on PyPI.
Namespacing does not prevent (or even significantly complicate) dependency confusion, unless we think that there's some difference in confusability between these two errors:

    requestss
and

    requestss/requests
(I think namespacing is a good idea in general, but dependency confusion is mostly a disjoint namespaces problem, not a depth problem. Python could solve the former by doing what Go does and make the source repository itself be the namespace, but this a significant incompatible breakage.)
It helps in some cases. If I type `npm i @google/cloud-sotrage`, I'm still safe. Same with `@google/gcs` (typo vs. misremembering the name). I just have to get the organization name right.
It does help in some cases.

For example, I know that "kotlin-stdlib-jdk8" in Maven Central is the official package for Kotlin standard library, but what about "kotlin-stdlib-wasm-wasi", "kotlin-jdk-annotations" and "kotlin-native-compiler-embeddable"? Here it helps to know that they're all in the "org.jetbrains.kotlin" group.

I think you have the wrong idea of what dependency confusion is. Here's the scenario:

1. Company develops package `company_secret_project_stuff` and publishes version 1 on their internal private PyPI instance.

2. They tell their employees to install it via `python3 -m pip install --extra-index-url https://pypi.intranet.company.com company_secret_project_stuff`

3. pip dutifully goes and installs the hacker's version of `company_secret_project_stuff` (version 999999) from the global PyPI index.

I know for a fact that my company is vulnerable to this. The only solution currently is for the company to also register `company_secret_project_stuff` on the global PyPI. But you can guess how happy they were about exposing internal package names. They opted to remain vulnerable instead (yes; stupid decision but I can kind of see their point).

Namespaces trivially fix this. You just register the `@company` namespace on the global PyPI index and then make sure all your private packages are in that namespace. Attackers can't publish packages with the same name as yours, and you don't need to make them all public.

2 pip installs can trivially solve this issue and I use this at work.

One pip install only for private packages using the --index-url (NOT --extra-index-url) and then the other pip install for public packages no index modifiers needed.

I don't think that works if the private packages depend on public ones, which is quite likely.
You are completely correct. I neglected to mention that we mirror/cache the dependencies we need in our private index.
OK, a Django update from me.

I heavily used Django since version 0.96 (2007) until 1.5 (2014) (with Python 3)! Then came a long break with lower-level infrastructure work: linux kernel, perf tuning, some C, some Go and zig.

Last week I picked up Django again. After 10 years (!!!) of not even looking at it. It felt like meeting a good old friend: they are the same, but older and more mature. Conversations are the same. But better.

Things change in the tech world, often for the worse. Django changes, as it matures, for the better. The website layout, tutorial, colors, excellent release notes, `./manage.py runserver` are all the same as I remember them.

Except today it's easier, since I am much wiser in deploying and maintaining things than I was a decade ago. :)

Similar experience. Started on 0.96, used daily until about 2.x and then took a break. Came back last year and was delighted to find most of the API remained stable. Before reading the release notes for Django 5 I was expecting at least a few breaking changes for my 4.2 apps, but there's almost none.

Part of the reason I took a break from tech in the first place was the relentless upgrade cycle. Thrilled that we've solved at least a few of the problems in sustainable ways.

Same experience from me. I stopped working with Django around 2016 and then picked up a project last year where we picked Django as the framework and it was like I never left. They added new features, improved documentation and all that, but it was so amazingly easy to come to.

It probably does help that we stick to Django 3.X as that's what's currently in Debian.

I do like the smaller frameworks like Flask or Bottle, but if I need a database or anything remotely more complex than answering a few API calls, then I don't see a reason to not pick Django.

I'm still annoyed that they are deprecating datetime.datetime.utcnow(). I have over 1000 references to that function in my projects folder. I understand the footguns that naive datetimes present to the unwary, and yet I still prefer to work with naive always-UTC datetimes. Alas I will end up doing some kind of crazy find-and-replace (at least in the Python 3 code) to something like `datetime.datetime.now(tz=datetime.UTC).replace(tz=None)`. Then of course I'll have to track down all of the bugs from other people doing `from datetime import datetime` and refactor so I now import the whole module just to get a reference to UTC. Grr.
Wouldn't it be easier just to write a utcnow() function of your own in a support module and do a find-and-replace to use that?
Another solution is to make a file called "my_patches.py":

    import datetime

    class my_datetime(datetime.datetime):
        @staticmethod
        def utcnow():
            return datetime.datetime.now(tz=datetime.timezone.utc).replace(tzinfo=None)

    datetime.datetime = my_datetime
And then in your codebase make sure you import my_patches whenever you use datetime. E.g.:

    import my_patches
    import datetime

    print(datetime.datetime.utcnow())
That solves the specific problem, but if you were my coworker, I’d have to toss you off the nearest bridge.

Don’t monkeypatch Python, m’kay?

I think it's fine and pythonic[1,2] to monkey patch when used in moderation and done explicitly:

   from my_patches import monkey
   monkey.patch_datetime_utcnow()
I wouldn't do it as a side-effect of an import. Down that path lies Ruby. :-)

[1]: https://www.gevent.org/api/gevent.monkey.html

[2]: https://docs.pytest.org/en/6.2.x/monkeypatch.html

I disagree in general. A big part of gevent's raison d'etre was patching the stdlib to be async, so if a user read its docs at all, they’d be warned that it was making deep changes to the runtime. It's also very widely used and tested, so its changes are well exercised. Pytest helps you monkey patch code that can't easily be mocked in a different way, but it also helps you un-patch the code after your tests have finished. (Side note: if you find yourself patching a whole lot of things with pytest, it's probably time to look into techniques like dependency injection that can help free you from the need to patch in the first place.)

But if you're not writing gevent or pytest, you should probably avoid it. It's much better to explicitly import or create the modified version of the code inside your own namespace, like:

  from helpers import my_datetime_utcnow
or

  import datetime as dt
  def my_datetime_utcnow(): return dt.datetime.whatever...
If you're going out of your way to patch the `datetime` namespace in such a way that other modules importing it get your patched version, it's quite likely that all hell will break loose when you least expect it.
(comment deleted)
> I still prefer to work with naive always-UTC datetimes.

Why prefer to work with naive UTC datetimes, rather than explicit UTC datetimes?

What's wrong with plain `datetime.datetime.now(datetime.UTC)`?

I’m also curious to know why OP prefers naive to tz aware datetimes. IMO naive datetimes are a bad default, and `utcnow()` deserves to be deprecated.
Because many engineers decided long ago that you’d handle these concerns at the perimeter and assume UTC everywhere internally. Should and can be a decision left to the developer, no reason to take this away.
Datetimes are naive in my database. The fundamental problem with the change you recommend is that I cannot then compare those two different datetimes. For example, today I might do:

user_over_30d_old = user.created_at < datetime.datetime.utcnow() - datetime.timedelta(30)

But in the future, I would need to do:

user_over_30d_old = user.created_at.replace(tzinfo=datetime.UTC) < datetime.datetime.now(datetime.UTC) - datetime.timedelta(30)

Which isn't any better than the solution I proposed above, of removing UTC from the now() datetime. Alternatively, I could modify my DAL code to promote datetimes from naive to timezoned in the database at the edge of the python layer, but that would have a lot of knock-on effects in things like isoformat() now appending timezone information, which has caused issues in other broken APIs that I use.

And for no particularly good reason! Sure, it's not great, but lots of things aren't. It's at worst a possible footgun, otherwise mostly cosmetic.

It should never be acceptable to break working software for anything else than critical security problems.

Not sure I would go that far. APIs need to be able to be deprecated as better forms are identified. That being said, the churn had better be worth it. This datetime change does not qualify, and feels like it is going to cause more immediate pain than it solves.
It is absolutely fine to deprecate badly designed APIs. It is fine if my 5-year-old program is full of deprecation warnings. It is not okay to delete APIs, breaking many programs, unless the APIs are well-known to be totally broken, infeasible to fix/maintain, and barely used.
This is one small benefit to working on a lot of Python 2.7 software. It never breaks anymore. Of course the deps are no longer updated and security issues are starting to pile up, but if your software doesn't process the wrong kinds of untrusted input, it will sure be more reliably run in python 2.7 in 5 years than if you wrote it in some flavor of python 3.
I share your sentiment. I prefer naive datetimes that are always UTC. Fortunately I wrapped all of these methods in a core utility module ages ago so changing it won’t be very hard for our project… but still feels like a silly thing to deprecate for seemingly no reason.
While I'm not against security and 2FA in general, making PyPI 2FA mandatory ahead of any kind of org support is a major pain for big projects with more than one maintainer. This week I was forced to link my company's pypi account to a personal device to unblock our latest release and now none of the dozen other maintainers I work with can get access. Things will get spicy if someone in my position were to die, leave the company on bad terms, etc and a big project can no longer be managed.

PyPI announced orgs back in April, but it seems they still haven't figured out the details on pricing, etc. No telling when those will roll out, but I sure hope it's soon. I'm cynical, but the sequencing of work here very much feels like somebody at Google (or wherever) wanted to push a big open source security project to advance their personal promo case rather than thinking through the needs of serious project maintainers.

You can have centralized TOTP too, I believe e.g. Vault or 1password can do that?
Good to know, I wasn't aware. But if you're storing passwords, TOTP seed, and recovery codes all in the same shared password vault, it's not really multi-factor anymore. It's security theatre.
financial security if you can pin it all on your paid password manager service and they remain solvent enough to juice
No, it’s not theater.

2FA was not created as a defense against password manager compromise. That is not its purpose. It protects against password reuse attacks and helps to protect against total compromise of people who have been phished.

Even better, a password manager can avoid giving up a TOTP code to a phisher in the first place because it is checking the domain.

If your password manager is compromised, you’ve got big problems regardless of 2FA tokens being in there or not.

The extremely marginal security benefit of storing the 2FA tokens separate from your password manager is just not even worth discussing in most scenarios. It exists, but doing that causes the additional risks of losing access to your 2FA token or having your 2FA code phished, both of which seem a lot more likely than your password manager being compromised. At least, as long as you’re using any halfway decent password manager.

Long term, the goal is to get rid of passwords and 2FA altogether by switching to Passkeys. Each Passkey will naturally be stored in a single place, since they can’t be split into multiple parts anyways.

> If your password manager is compromised, you’ve got big problems regardless of 2FA tokens being in there or not.

That doesn't check for me:

- 2FA tokens being there -> total compromise

- 2FA tokens not being there -> no compromise of 2FA-protected accounts

Or did you mean something else?

> having your 2FA code phished

What would be a realistic scenario? If I'm using a password manager, it won't recognize the phishing domain, which means I won't get to the 2FA step.

It's important to think about threat vectors. A general concept like "the password manager getting compromised" is not really a threat vector, it's more the outcome of a threat vector. How exactly do you think a password manager is getting compromised? To identify the threat vector, we need to talk about the actual method of compromise here.

A 1Password vault is fully encrypted and protected by several layers of security. The most important layer of protection: the 1Password vault is encrypted with a combination of your password and your Secret Key[0], which is a long key generated uniquely for each vault. Even with a weak password, the vault has very strong encryption because of the Secret Key, which you don't get the opportunity to mess up and make weak by accident. Without both, the Vault cannot be decrypted, and nothing is stored in plain text; everything is stored in the encrypted vault. An additional layer of security is that they can't even get the vault from 1Password's servers without both your password and a second factor, assuming 1Password hasn't been compromised, but this is not critical. Even if the attacker got their hands on the vault, the vault itself is very secure. No attacker is going to be able to brute force the encryption key.

The most likely way (probably the only realistic way) for a well-secured password manager to be compromised is for someone to gain access to your machine while your password manager is unlocked. A simple keylogger is not enough, since it won't capture your Secret Key unless this machine has been deeply compromised since the day you set up 1Password on it for the first time. But, even then... that would mean they already own your machine.

So, total access to your fully unlocked machine, with your password manager also unlocked. That's what password manager compromise means in this context, at least to me. Remote access or physical access, it doesn't matter. As I said in my previous comment, if they have access to your password manager, "you've got big problems", because they probably have access to a lot more than just your password manager. If they have access to your machine, and your password manager is unlocked at the same time, it's game over for virtually anyone at that point.

It doesn't matter if the 2FA tokens are in there or not. It doesn't even matter if the passwords are stored in there, although I'm sure they wouldn't complain about having access to the passwords. Most services will allow the threat actor to reset your 2FA token (and password) simply by requesting a reset email with a verification link. Since the threat actor already has access to your machine, they almost certainly have access to your email, which the vast majority of people leave signed in. The password manager contains the username you use for each service, which is all they need to start firing off reset emails.

A very few websites won't let you reset your 2FA token, of course, but it's much fewer than the number of websites with 2FA. Anything other than verification emails (or never letting you sign in again) is very expensive for a website operator. Plus, what are the odds that you're not already signed into those sensitive services on this compromised machine? They may not even need your 2FA for whatever they're trying to do here. They own your machine. In the absolute worst case scenario (for the attacker), they just leave a RAT (remote access trojan) on your machine and walk away. They would just wait for you to sign into whatever they need, while you're completely oblivious to the attack. The password manager is an irrelevance.

The thing is... very few people get compromised this way in the first place. It's not worth losing sleep over unless you need to protect some extremely important asset. Certificate Authorities lose sleep over these kinds of threat vectors when it comes...

You should probably not do that, but as coder543 says in another comment, there are reasons why even that is preferable to not having TOTP. And assuming you enforce multi-factor authentication to access your vault, it is sort of transitively multiple factors (except for security vulnerabilities affecting the vault).

It’s not ideal, individual accounts seems like the only reasonable solution for legal and auditing reasons, but at least it’s possible to conveniently share users with 2FA enabled if you need to.

From the same team that decided to drop signatures… unsurprising.
You can do the same with passkeys with something like Vaultwarden/Bitwarden, as well.
you can also just screenshot the QR code they give you to register your TOTP authenticator, and share it with the other maintainers.

sites implementing 2fa don't make it easy to share the keys (because they shouldn't, that's bad!) but a shared totp key is better than no key.

> sites implementing 2fa don't make it easy to share the keys

Sites that offer TOTP as a second factor normally either have the seed printed out next to the QR code, or have a button (or link) to show it.

It's a major hassle to scan a QR code from the laptop screen without leaving the laptop, whereas copy-pasting the seed into the password manager is easy. Pasting it somewhere you can share with other people is just as easy since the seed is just a string of characters.

There's also the fact that TOTP is an open standard, so one could very easily implement a bit of software that translated the QR code into the seed, so there's really no point at all for websites to try to protect the seed from the user. The user owns the seed and the code.

You were not forced to do that because TOTP is manageable via password manager.

TOTP and yubikey are excellent technologies that way. They allow two-factor authentication without breaking privacy.

Everyone within the sound of my voice: get a password manager. It sounds like a hassle but it makes your life infinitely better. It allows you to keep your life private and more secure than it was while providing more convenience than you had before.

I recommend KeepassXC. Open source, audited, fully featured, and can be paired with one of several different kinds of syncing technologies depending on your risk appetite.

I think it's odd that PyPI doesn't list any desktop programs, like KeepassXC, at https://pypi.org/help/#twofa , only mobile ones. That makes it seem like 2FA is mobile-only.

I expect some people don't want to mix work accounts on their personal phone ("keep your life private"), and because smart phones are still not yet universal, even among developers.

Many people seem to believe that keeping your 2FA keys in an un-backupable mobile app and away from your computer is safer than keeping it in your backupable and multi-device password manager.
Unless you think PyPI is guided by that belief, that doesn't explain why they don't list desktop solutions.
PyPI doesn't list desktop solutions because I made that list back in 2019 and didn't think to list them. If you have some reputable desktop password managers that support TOTP that you'd like to see listed, you should open a PR for them!
You are certainly far more qualified than I to know which desktop password managers are reputable.

I only installed KeepassXC two weeks ago to try it out because several people here on HN mentioned it, and because it was free software not connected to for-profit companies.

It is the only one I've tried, and I've only used it once, to see what it was like.

I think your historical comment omits something. When I made this complaint back in 2019 you replied at https://news.ycombinator.com/item?id=20058199 saying "I've forwarded this thread along to others working on PyPI as part of the OTF grant, and we'll be figuring out how best to explain using TOTP without being too mobile-centric."

That mobile-centric list hasn't changed, and I still don't have, nor want, a smart phone.

So KeepassXC can do TOTP like authy? Cause I would love to switch from that app if I can.
I suspect it has more to do with the legal backchatter on supply-chain attacks in opensource. The likes of GitHub and GitLab already have a bunch of features they can point at, should a lawyer come knocking; PyPi doesn't have anything.
django's main advantage is how consistent the API is, which enables a lot of plugins and libraries to be built around it and they stay valid for a very long time.

This makes development to be insanely productive, I joke that to create a new feature in django is "pip install <new feature>", check out your options here: https://djangopackages.org/

> It's also a good time to remind you once again that 3.13 will deprecate a lot of things

People get this wrong more often than they should. The link says things will get removed in 3.13, not just deprecated. So many people seem to think deprecate is just some fancy word for remove. I really don't get it. Remove means remove. Deprecate does not mean remove.