pip - Add break_system_packages option (#82097)

pull/82101/head
Matt Clay 2 years ago committed by GitHub
parent 3ea5304a57
commit 89cda0bcae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -110,6 +110,13 @@ options:
to specify desired umask mode as an octal string, (e.g., "0022"). to specify desired umask mode as an octal string, (e.g., "0022").
type: str type: str
version_added: "2.1" version_added: "2.1"
break_system_packages:
description:
- Allow pip to modify an externally-managed Python installation as defined by PEP 668.
- This is typically required when installing packages outside a virtual environment on modern systems.
type: bool
default: false
version_added: "2.17"
extends_documentation_fragment: extends_documentation_fragment:
- action_common_attributes - action_common_attributes
attributes: attributes:
@ -121,7 +128,7 @@ attributes:
platforms: posix platforms: posix
notes: notes:
- Python installations marked externally-managed (as defined by PEP668) cannot be updated by pip versions >= 23.0.1 without the use of - Python installations marked externally-managed (as defined by PEP668) cannot be updated by pip versions >= 23.0.1 without the use of
a virtual environment or setting the environment variable ``PIP_BREAK_SYSTEM_PACKAGES=1``. a virtual environment or setting the O(break_system_packages) option.
- The virtualenv (U(http://www.virtualenv.org/)) must be - The virtualenv (U(http://www.virtualenv.org/)) must be
installed on the remote host if the virtualenv parameter is specified and installed on the remote host if the virtualenv parameter is specified and
the virtualenv needs to be created. the virtualenv needs to be created.
@ -685,6 +692,7 @@ def main():
chdir=dict(type='path'), chdir=dict(type='path'),
executable=dict(type='path'), executable=dict(type='path'),
umask=dict(type='str'), umask=dict(type='str'),
break_system_packages=dict(type='bool', default=False),
), ),
required_one_of=[['name', 'requirements']], required_one_of=[['name', 'requirements']],
mutually_exclusive=[['name', 'requirements'], ['executable', 'virtualenv']], mutually_exclusive=[['name', 'requirements'], ['executable', 'virtualenv']],
@ -789,6 +797,11 @@ def main():
if extra_args: if extra_args:
cmd.extend(shlex.split(extra_args)) cmd.extend(shlex.split(extra_args))
if module.params['break_system_packages']:
# Using an env var instead of the `--break-system-packages` option, to avoid failing under pip 23.0.0 and earlier.
# See: https://github.com/pypa/pip/pull/11780
os.environ['PIP_BREAK_SYSTEM_PACKAGES'] = '1'
if name: if name:
cmd.extend(to_native(p) for p in packages) cmd.extend(to_native(p) for p in packages)
elif requirements: elif requirements:

@ -1,2 +1,3 @@
destructive destructive
shippable/posix/group2 shippable/posix/group2
needs/root

@ -0,0 +1,7 @@
[project]
name = "sample-project"
version = "1.0.0"
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

@ -0,0 +1,59 @@
- name: Get the pip version
command: "{{ ansible_python_interpreter }} -c 'import pip; print(pip.__version__)'"
register: pip_version
- when: pip_version.stdout is version("23.0.1", ">=")
block:
- name: Locate the Python externally-managed marker file
command: |
{{ ansible_python_interpreter }} -c 'import sys, sysconfig; print(f"""{sysconfig.get_path("stdlib", sysconfig.get_default_scheme()
if sys.version_info >= (3, 10) else sysconfig._get_default_scheme())}/EXTERNALLY-MANAGED""")'
register: externally_managed_marker
- name: Detect if Python is externally-managed
stat:
path: "{{ externally_managed_marker.stdout }}"
register: externally_managed
- name: Mark Python as externally managed
file:
path: "{{ externally_managed_marker.stdout }}"
state: touch
when: not externally_managed.stat.exists
- block:
- name: Copy the sample project to the target
copy:
src: sample-project/
dest: "{{ remote_sample_project }}"
- name: Attempt to pip install the sample project without a venv
pip:
name: "{{ remote_sample_project }}"
register: pip_install
failed_when: pip_install is success
- name: Attempt to pip install the sample project without a venv using break_system_packages
pip:
name: "{{ remote_sample_project }}"
break_system_packages: true
- name: Remove the sample project without using break_system_packages
pip:
name: sample-project
state: absent
register: pip_uninstall
failed_when: pip_uninstall is success
- name: Remove the sample project using break_system_packages
pip:
name: sample-project
state: absent
break_system_packages: true
always:
- name: Unmark Python as externally managed
file:
path: "{{ externally_managed_marker.stdout }}"
state: absent
when: not externally_managed.stat.exists

@ -1,6 +1,9 @@
# Current pip unconditionally uses md5. # Current pip unconditionally uses md5.
# We can re-enable if pip switches to a different hash or allows us to not check md5. # We can re-enable if pip switches to a different hash or allows us to not check md5.
- include_tasks:
file: break_system_packages.yml
- name: Python 2 - name: Python 2
when: ansible_python.version.major == 2 when: ansible_python.version.major == 2
block: block:

@ -11,3 +11,4 @@ pip_test_pkg_ver_unsatisfied:
pip_test_modules: pip_test_modules:
- sample - sample
- jiphy - jiphy
remote_sample_project: "{{ remote_tmp_dir }}/sample-project"

Loading…
Cancel
Save