I’m still against the idea of programmatically deprecating contextlib.chdir
in the near term. Maybe document it as deprecated and suggest importing the equivalent functionality from shutil
instead, but the earliest that programmatic deprecation should be considered is when the last version without the shutil
interface is no longer supported (which would be 3.13 assuming the shutil
interface is added in 3.14, so it would drop out of support when 3.18 was released).
Regarding chdir
as the verb form vs cwd
as the noun form, that distinction already exists in the os
module, due to os.getcwd()
being the query counterpart to os.chdir(dirpath)
. cwd
also shows up as a parameter name in the os.startfile
Windows-only API, as well as in the cross-platform subprocess
APIs.
I do like the idea of a common naming convention for these kinds of CM wrappers, but given the umask
and chdir
examples, my preferred convention would actually be ensure_{NOUN}
, with the name being based on the related query API, rather than the modification API.
For umask
, the modification API is the query API, so it’s ensure_umask
either way.
For chdir
, the corresponding query API is getcwd
, so that convention gives ensure_cwd
.
Until contextlib.chdir
is actively deprecated (in 3.18 or so), the implementation of the latter can just be:
from contextlib import chdir as _ensure_cwd_impl
class ensure_cwd(_ensure_cwd_impl):
pass
Alternatively, the implementation could be moved to shutil
immediately, and the __getattr__
approach could be added to contextlib
without the programmatic deprecation warning[1]:
def __getattr__(name):
global chdir
if name == 'chdir':
# This will be deprecated once 3.18 is released and 3.13 is no longer supported
# (as all still supported versions will provide shutil.ensure_cwd at that point)
from shutil import ensure_cwd as chdir
return chdir
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
While the latter technically breaks pickle compatibility (since only targets with shutil.ensure_cwd
will be able to unpickle the result), this isn’t the kind of object that anyone is likely to try to transmit or save via pickle.
import statements (with or without
as
clauses) can bind global names directly, so there’s no need for a separate local variable name. ↩︎