Skip to content

Allow Python distributors to add custom site install schemes #88142

Description

@FFY00
BPO 43976
Nosy @malemburg, @jaraco, @tiran, @encukou, @stefanor, @zooba, @FRidh, @hroncok, @frenzymadness, @FFY00, @jakirkham
PRs
  • bpo-43976: add vendor config #25718
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-04-29.16:19:02.410>
    labels = ['type-feature', 'library', '3.11']
    title = 'Allow Python distributors to add custom site install schemes'
    updated_at = <Date 2022-02-15.23:11:21.853>
    user = 'https://github.com/FFY00'

    bugs.python.org fields:

    activity = <Date 2022-02-15.23:11:21.853>
    actor = 'stefanor'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2021-04-29.16:19:02.410>
    creator = 'FFY00'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 43976
    keywords = []
    message_count = 38.0
    messages = ['392326', '392350', '392367', '392391', '392823', '392828', '392832', '392884', '392887', '392941', '392942', '392946', '392948', '392950', '392951', '392984', '392986', '392987', '392989', '392994', '393022', '393041', '393044', '399095', '399127', '399129', '399131', '399132', '399159', '399363', '399364', '399365', '400833', '402339', '402470', '409677', '409808', '411657']
    nosy_count = 12.0
    nosy_names = ['lemburg', 'jaraco', 'christian.heimes', 'petr.viktorin', 'stefanor', 'steve.dower', 'Frederik Rietdijk', 'hroncok', 'frenzy', 'FFY00', 'jakirkham', 'xrcg']
    pr_nums = ['25718']
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue43976'
    versions = ['Python 3.11']

    Activity

    1. FFY00 commented on Apr 29, 2021

      @FFY00
      MemberAuthor

      As part of the distutils migration we plan to add a mechanism to let Python distributors to add site install schemes.

      Currently, Python distributors are patching distutils to add custom install schemes for their packages. I think most of the reasoning boils down to them wanting to stop Python installers, such as pip, to modify/interfere with their packages.

      With the distutils deprecation, and it becoming a 3rd party module, Python distributors can no longer patch it. Because of this, we made distutils use the sysconfig module instead, which fixes the issue at the moment -- Python distributors can now patch sysconfig itself -- but is not a long term solution.
      To prevent Python distributors from having to patch implementation details, and have things break unexpectedly, we aim to introduce a system that distributors can use for this purpose.

      The idea is that they have a config file, which they can pass to configure, and in that config file they can specify some extra install schemes. These install schemes will get added in sysconfig, and will be loaded in the site module initialization.

      In practice, it will look something like this:

      config.py

      EXTRA_SITE_INSTALL_SCHEMES = {
          'posix_prefix': {
              'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
              'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
              'purelib': '{base}/lib/python{py_version_short}/vendor-packages',
              'platlib': '{platbase}/{platlibdir}/python{py_version_short}/vendor-packages',
              'include':
                  '{installed_base}/include/python{py_version_short}{abiflags}',
              'platinclude':
                  '{installed_platbase}/include/python{py_version_short}{abiflags}',
              'scripts': '{base}/bin',
              'data': '{base}',
          },
      }
      

      ./configure --with-vendor-config=config.py

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-featureA feature request or enhancement
      on Apr 29, 2021
    3. zooba commented on Apr 29, 2021

      @zooba
      Member

      Any reason this couldn't be in sitecustomize.py? Either by poking values into sysconfig directly (for back-compat) or we train sysconfig to look inside sitecustomize for a well-known name.

    4. FFY00 commented on Apr 30, 2021

      @FFY00
      MemberAuthor

      Making sysconfig look at sitecustomize seems like the wrong approach. It is behavior I would never expect, and there are use-cases where I still want the schemes to be present when the site module initialization is disabled.

      I would also argue that having this mechanism available will be useful for other things.

    5. hroncok commented on Apr 30, 2021

      hroncokmannequin
      Mannequin
    6. changed the title [-]Introduce mechanism to allow Python distributors to add custom site install schemes[/-] [+]Allow Python distributors to add custom site install schemes[/+] on Apr 30, 2021
    7. changed the title [-]Introduce mechanism to allow Python distributors to add custom site install schemes[/-] [+]Allow Python distributors to add custom site install schemes[/+] on Apr 30, 2021
    8. zooba commented on May 3, 2021

      @zooba
      Member

      Making sysconfig look at sitecustomize seems like the wrong approach.

      I mean, you're literally customizing the site, so having it be done from sitecustomize doesn't seem terribly wrong. But I agree, I'd rather see the code in sitecustomize poke paths into sysconfig, rather than the other way around.

      The problem then would be that -S bypasses the path configuration entirely, which is likely going to point at non-existent paths. So yeah, for this case you need an override that isn't tied to the site module. Having a similar-but-different mechanism in sysconfig seems fine. I have a *slight* preference for non-executable code, mostly to avoid the risk of import hijacking, but it's only slight.

    9. FFY00 commented on May 3, 2021

      @FFY00
      MemberAuthor

      FYI, I have change the implementation to split the extra install schemes and extra schemes activated on site. This still makes sense over sitecustomize because we want the packages to be included in site.getsitepackages -- we want the vendor packages to essentially be the same as site-packages.

      I have also moved sysconfig._get_preferred_schemes to the vendor config, instead of asking distributors to patch sysconfig -- this is why I prefer having it as executable code, we customize using functions, etc.
      https://docs.python.org/3.10/library/sysconfig.html#sysconfig.\_get_preferred_schemes

      A config taking advantage of all these mechanisms should look like this:

      EXTRA_INSTALL_SCHEMES = {
          'vendor': {
              'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
              'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
              'purelib': '{base}/lib/python{py_version_short}/vendor-packages',
              'platlib': '{platbase}/{platlibdir}/python{py_version_short}/vendor-packages',
              'include':
                  '{installed_base}/include/python{py_version_short}{abiflags}',
              'platinclude':
                  '{installed_platbase}/include/python{py_version_short}{abiflags}',
              'scripts': '{base}/bin',
              'data': '{base}',
          },
      }
      
      EXTRA_SITE_INSTALL_SCHEMES = [
          'vendor',
      ]
      
      def get_preferred_schemes(...):
          ...
      

      Do you have any thoughts on this?

    10. zooba commented on May 3, 2021

      @zooba
      Member

      Yes, I saw some of the latest changes in the PR.

      My biggest concern is with the bare "import _vendor_config", which I'd prefer to have restricted to a fixed location, rather than being influenced by environment variables and other options. We already have an issue with readline being imported from anywhere it can be found.

      A native flag to suppress it (i.e. something in sys.flags) could also become important for embedders, though it may matter more at a higher level (i.e. should an embedded CPython *ever* be using sysconfig? Probably not...). I wouldn't add a new flag for it right now, but I feel like sys.flags.isolated should probably imply that this should be ignored.

      Though then we hit the issue again that these patches are about changing the "safe default" behaviour, which is what you want to get back when you run with -S or -I. And I'm not totally sure how to resolve this.

      So basically, my concerns are:

      • don't import arbitrary files
      • ensure -S/-I options remain useful (or become even more useful)
    11. encukou commented on May 4, 2021

      @encukou
      Member

      Sorry for not getting to this sooner, but 5 days is really tight for such a change.

      With -S/-I, It would be great if sys.path only included packages installed as part of the OS, and not those installed by sudo pip. (Or pip --user, but that's covered).

      It seems that with the current patch, pip will install into site-packages and there's no way to disable/change site-packages. Is that the case?

    12. FFY00 commented on May 4, 2021

      @FFY00
      MemberAuthor

      My biggest concern is with the bare "import _vendor_config", which I'd prefer to have restricted to a fixed location, rather than being influenced by environment variables and other options. We already have an issue with readline being imported from anywhere it can be found.

      Oh, I share the same concern! Though users could already mess up Python pretty badly by shadowing/overwriting parts of it, so I didn't thought it would be that big of an issue. Is there a way to achieve this while still allowing us to do everything we want?

      Sorry for not getting to this sooner, but 5 days is really tight for such a change.

      No worries. It was my fault, I should have been more attentive to the Python release timeline.

      With -S/-I, It would be great if sys.path only included packages installed as part of the OS, and not those installed by sudo pip. (Or pip --user, but that's covered).

      Perhaps we could add an option to enable only vendor site schemes?

      It seems that with the current patch, pip will install into site-packages and there's no way to disable/change site-packages. Is that the case?

      I mean, there is, though not as straightforward as -S/-I. I was planning on using it to build the distro entrypoint scripts, so that they only include the distro packages.

      $ python -S
      > site.addsitedir(sysconfig.get_path('purelib', 'vendor'))
      > site.addsitedir(sysconfig.get_path('platlib', 'vendor'))

      As I mentioned above, we could add a cli flag to do essentially the same.

    13. zooba commented on May 4, 2021

      @zooba
      Member

      The best option for restricting the import while still having it be a Python import is to find the file (if it's present in the expected location under sys.whatever), and then use importlib to import it: https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly

      I'd rather not have a new option here, I would much prefer "-S" in this context to mean "run Python with only core libraries" and "-s" to mean "run Python with only core and distro libraries" (and neither to mean "run Python with core, distro and user libraries").

      That may be a bigger change, but there's enough angst around this issue that we would be better off getting it right this time, even if it changes things, than continuing to preserve the system that people dislike so much.

    14. 26 remaining items

    15. FFY00 commented on Sep 1, 2021

      @FFY00
      MemberAuthor

      Matthias, can you check if bpo-44982 solves your issues related to the conflicts you were experiencing for the Debian patching?

      If so, it would unblock this issue.

      I am probably gonna discuss this proposal with the conda-forge folks next week, to get some feedback from the Conda perspective.
      I would like to have this unblocked so that we can move forward, as far as I know the only issues are the ones Debian is experiencing about this proposal alone not being able to completely replace the downstream patching.

    16. jaraco commented on Sep 21, 2021

      @jaraco
      Member

      In the short term, and possible for the long term, Debian can continue to patch the install routine...

      The problem with this approach is Setuptools is attempting to adopt distutils by exposing its own vendored copy of distutils as distutils (top-level name). By doing this, it bypasses the Debian's patching of distutils as found in CPython. Because this bypass behavior breaks distutils for Debian users, the functionality has been disabled (opt-in).

      Setuptools would like to be able to present a version of distutils that, unpatched, runs on all the major platforms, and thus make it default.

      That won't be possible until Debian can stop relying on its patching of distutils.

    17. jaraco commented on Sep 22, 2021

      @jaraco
      Member

      Here's what I propose:

      1. In pypa/distutils, add support for honoring the proposed install schemes (based on PR 25718). Merge with Setuptools.
      2. Add whatever ugly hacks are needed to pypa/distutils to honor other Debian-specific behaviors (revive Integrate Debian patches pypa/distutils#4 but properly match Debian expectations). Mark these ugly hacks as deprecated.
      3. In Debian, Fedora, etc, provide patches that configure the install schemes. Test with latest Setuptools and SETUPTOOLS_USE_DISTUTILS=local.
      4. Formalize the install schemes support in CPython (as in PR 25718).
      5. Ask Debian to propose more a cleaner interface for Debian-specific needs.
    18. hroncok commented on Jan 4, 2022

      hroncokmannequin
      Mannequin

      In Fedora 36+ / Python 3.10+ we now use an install_scheme that looks like this:

      'purelib': '{base}/local/lib/python{py_version_short}/site-packages',
      'platlib': '{platbase}/local/{platlibdir}/python{py_version_short}/site-packages',
      'scripts': '{base}/local/bin',
      'data': '{base}/local',
      ...
      

      We got a user report [1] saying that pip install --root ... --prefix /usr the prefix is not respected at all.

      That is, users expect that /usr/local is the prefix, and when they explicitly set it to /usr, the /local/ bit will not be there, while in reality, /local/ is not a part of the prefix, but it is a part of the installation scheme.

      I can somehow relate to that assumption.

      Now I wonder whether we should have adapted prefix instead of the installation scheme :/

      Any ideas on how to approach this problem? I am quite clueless.

      [1] https://bugzilla.redhat.com/show_bug.cgi?id=2026979

    19. jaraco commented on Jan 5, 2022

      @jaraco
      Member

      I don't have a good answer, but given the title of this issue (which is specifically scoped to site install schemes), I'm tempted to say we should deal with prefixes in a separate, perhaps broader issue, and there address the reported issue (that a user's prefix override isn't honored by the scheme) and maybe more broadly the issue that there's not a design/spec for python installations (and probably there should be).

    20. FRidh commented on Jan 25, 2022

      FRidhmannequin
      Mannequin

      In Nixpkgs we install every Python package under a unique prefix, a so-called Nix store path. If we were to use sysconfig for installing packages, then we'd need to be able to dynamically set the paths. This was also discussed as part of the Installer project. https://github.com/pradyunsg/installer/issues/98

      We could use a custom scheme, however, we do need to be able to dynamically set a certain variable, e.g. base.

      variables = {"installed_base": "$out", "base": "$out", "platbase": "$out", "installed_platbase": "$out"}
      # Note there is no `sysconfig.get_default_scheme()`
      sysconfig._expand_vars("posix_prefix", variables)
      

      I could imagine we do something like

      # check whether we're in a nix build and want to install in a prefix
      if "IN_NIX_BUILD" in os.environ:
          base = os.environ["out"]
      
          scheme = {...}
      

      We'd then need to update the base variable in sysconfig or partially expand our own scheme using this variable.

    21. transferred this issue fromon Apr 10, 2022
    22. hroncok commented on May 10, 2022

      @hroncok
      Contributor

      I don't have a good answer, but given the title of this issue (which is specifically scoped to site install schemes), I'm tempted to say we should deal with prefixes in a separate, perhaps broader issue, and there address the reported issue (that a user's prefix override isn't honored by the scheme) and maybe more broadly the issue that there's not a design/spec for python installations (and probably there should be).

      Technically, I guess we could (instead of redefining the default installation scheme) redefine the default {base} and {platbase} in sysconfig.get_config_vars(). However, I suspect that would require further changes to distutils and pypa/distutils to respect that :/

      I'll start a discussion on https://discuss.python.org/ trying to sum up what went wrong with our custom installation scheme and what we want to achieve instead.

    23. FFY00 commented on Oct 26, 2022

      @FFY00
      MemberAuthor

      From the feedback I have gathered so far, I think this suggestion is a hard sell for some people due to the performance impact, so I think that's the first thing we have to work on if we want to implement this. There is some duplication in getpath and sysconfig that could be removed, which seems like a good starting point.

    24. FFY00 commented on Oct 26, 2022

      @FFY00
      MemberAuthor

      I created #98718 to keep track of sysconfig speed-up efforts.

    25. added
      3.12only security fixes
      and removed
      3.11only security fixes
      on Apr 3, 2023
    26. added
      3.13only security fixes
      and removed
      3.12only security fixes
      on Jan 5, 2024
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.13only security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-sysconfigtype-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions