The easy route is to not change the default. So the more interesting discussion is around how to change it with as little disruption as possible, why it makes sense to do so. After that you can decide if the amount of work over a long time period is worth tracking & doing for this.
my version of how:
(this could easily be defeated by my why below… but the how is illustrative regardless)
- Having
pathlib.Path.glob()
raise a DeprecationWarning
when follow_symlinks=
is not explicitly specified is a good way to warn owners of existing code that we’d like them to always explicitly add follow_symlinks=
parameter. Goal: Existing users add an explicit follow_symlinks= parameter.
- As code explicitly setting
follow_symlinks=None
reads awkward (most people are unfamiliar with the API at this level of detail and would read that wrong and think it’d be the same as =False
)… this also means we should: (see TODO on value naming below…)
- Add an additional direct behavioral spelling for the parameter.
follow_symlinks=NonRecursive
or similarly bikesheded name.
- Once (3) has shipped in a few releases, start the (1) deprecation cycle, so the default can change two releases later.
This is a long process. Longer than our minimum two-release deprecation cycle as described in PEP 387 – Backwards Compatibility Policy | peps.python.org. Why? So that people writing code running across a wide range of Python versions do not need to add conditional logic to alter their API calls. ie: A distro that ships with 3.13 can be assumed to be in use for 5 years, and the simplest scripts using whatever random os-distro-stale /usr/bin/python3 are not the kind of place people want to think about API versions. So not changing the default until a Python that’ll wind up in the latest long term supported distro 5-6 years from now is helpful.
If the change were more urgent it could be pulled in and done faster, but this default API behavior change doesn’t have an urgent feel to it. It’s a nice consistent thing to have at most.
TODO: Today 3.13alpha has follow_symlinks=None
… lets change that to NonRecursive
or similarly bikeshedded usefully named/defined behavior constant other than None
. The key reason being that someone reading code explicitly specifying =None can’t understand what it does. I left a note about this on the issue.
my attempt at “why?”
This is where I’m unclear and not helping you answer… symlinks blindly being followed are notorious for leading to mistakes and security problems. From that perspective, I like the existing behavior or possibly even =False behavior as a default. Putting the onus on symlink support requirements as needing to be explicitly specified by the API user.
Consistency with glob.glob()
is at least nice… But for me, if designing an API new, I’d call glob.glob()
's always symlink-following behavior introduced with **
support in 3.5 the undesirable default. (it could be changed via the same mechanism, and if that is going to happen, it should gain an equivalently spelled follow_symlinks= feature)
But this differs from what people might want or expect as a default. What do they compare recursive **
glob behaviors to? You mentioned zsh having a ***
concept to explicitly ask for recursive subdirectory following. zsh does not default to recursive symlink following for **
. I’d take that as a sign that for consistency we might want to move to match it. Research into other commonly used things supporting **
could balance or change that thought.
Feature wise, it’d also be entirely reasonable for us to gain ***
support. Though it seems awkward to support both follow_symlinks= and ***
support (if they conflicted would that be an error?). I like the new keyword argument, it is easy for the reader to understand.