certbot/tools/pip_install.py
ohemorange 00a51ab22b
Drop in uv for pip (#10428)
It's a [drop-in
replacement](https://docs.astral.sh/uv/pip/compatibility/) that speeds
things up. I don't see any reason why not.

`--use-pep517` is [set by default](
https://docs.astral.sh/uv/pip/compatibility/#pep-517-build-isolation),
so we don't need it.

`--disable-pip-version-check` also does nothing on uv.

`uv` [uses
separate](https://docs.astral.sh/uv/pip/compatibility/#build-constraints)
`UV_BUILD_CONSTRAINT` and `UV_CONSTRAINT`. I just added it to both to do
the simplest thing here. We could split them.

We probably don't actually need to pipstrap pip anymore, I could take
that out.

What's happening with `parsedatetime` and `python-digitalocean` is that
they were always secretly wrong. Since `pip` compiles bytecode by
default, it was suppressing the errors. If you add the
`--compile-bytecode` flag to `uv`, it passes, but I don't think we
should do that. You can see the failure happen on main by passing
`--no-compile` to the pip args and running `certbot -r -e oldest`.

Now what I don't understand is that some places seem to say the `'\/'`
error from `parsedatetime` only started in python 3.12, whereas others
see it on earlier python. Perhaps pytest is vendorizing python or
something. Not too worried about that, needed to get updated anyway, and
it's an accurate oldest version based on our oldest OSes.
`python-digitalocean` is techincally newer than debian 11, but we've
made that decision before so it seems fine to me.
2025-08-18 13:17:02 -07:00

74 lines
2.4 KiB
Python
Executable file

#!/usr/bin/env python
# pip installs packages using pinned package versions. If CERTBOT_OLDEST is set
# to 1, tools/oldest_constraints.txt is used, otherwise, tools/requirements.txt
# is used. Before installing the requested packages, core Python packaging
# tools like pip, setuptools, and wheel are updated to pinned versions to
# increase stability of the install.
#
# cryptography is currently using this script in their CI at
# https://github.com/pyca/cryptography/blob/14d45c2259b01f1459eeab8bb7d85ce4cfb0841b/.github/downstream.d/certbot.sh#L8-L9.
# We should try to remember to keep their repo updated if we make any changes
# to this script which may break things for them.
from __future__ import absolute_import
from __future__ import print_function
import os
import subprocess
import sys
def find_tools_path():
return os.path.dirname(os.path.realpath(__file__))
def call_with_print(command, env):
assert env is not None
print(command)
subprocess.check_call(command, shell=True, env=env)
def uv_install_with_print(args_str, env):
command = ['"', sys.executable, '" -m uv pip install ', args_str]
call_with_print(''.join(command), env=env)
def pip_install_with_print(args_str, env):
command = ['"', sys.executable, '" -m pip install --disable-pip-version-check --use-pep517 ', args_str]
call_with_print(''.join(command), env=env)
def pip_constrained_environ():
tools_path = find_tools_path()
repo_path = os.path.dirname(tools_path)
if os.environ.get('CERTBOT_OLDEST') == '1':
constraints_path = os.path.normpath(os.path.join(
repo_path, 'tools', 'oldest_constraints.txt'))
else:
constraints_path = os.path.normpath(os.path.join(
repo_path, 'tools', 'requirements.txt'))
env = os.environ.copy()
# We set constraints for pip using an environment variable so that they
# are also used when installing build dependencies. See
# https://github.com/certbot/certbot/pull/8443 for more info.
env["PIP_CONSTRAINT"] = constraints_path
env["UV_CONSTRAINT"] = constraints_path
env["UV_BUILD_CONSTRAINT"] = constraints_path
return env
def pipstrap(env=None):
if env is None:
env = pip_constrained_environ()
pip_install_with_print('pip setuptools wheel uv', env=env)
def main(args):
env = pip_constrained_environ()
pipstrap(env)
uv_install_with_print(' '.join(args), env=env)
if __name__ == '__main__':
main(sys.argv[1:])