-
-
Notifications
You must be signed in to change notification settings - Fork 18.1k
lib.makeAlias: init with by-name support #442066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5416614
b12b23d
8fad5a4
a1b7348
2201a5f
9a9f61e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -261,6 +261,18 @@ rec { | |
| f = if isFunction fn then fn else import fn; | ||
| fargs = functionArgs f; | ||
|
|
||
| aliasArgs = filterAttrs (name: _: autoArgs._isAlias or (_: false) name) fargs; | ||
|
|
||
| aliasErrorForArg = | ||
| arg: | ||
| let | ||
| loc = builtins.unsafeGetAttrPos arg fargs; | ||
| in | ||
| "Function expects alias \"${arg}\" at ${loc.file}:${toString loc.line}."; | ||
|
|
||
| # Only show the error for the first alias | ||
| aliasError = aliasErrorForArg (head (attrNames aliasArgs)); | ||
|
|
||
| # All arguments that will be passed to the function | ||
| # This includes automatic ones and ones passed explicitly | ||
| allArgs = intersectAttrs fargs autoArgs // args; | ||
|
|
@@ -300,7 +312,7 @@ rec { | |
| else | ||
| ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?"; | ||
|
|
||
| errorForArg = | ||
| missingErrorForArg = | ||
| arg: | ||
| let | ||
| loc = builtins.unsafeGetAttrPos arg fargs; | ||
|
|
@@ -309,17 +321,18 @@ rec { | |
| + "${loc.file}:${toString loc.line}${prettySuggestions (getSuggestions arg)}"; | ||
|
|
||
| # Only show the error for the first missing argument | ||
| error = errorForArg (head (attrNames missingArgs)); | ||
| missingError = missingErrorForArg (head (attrNames missingArgs)); | ||
|
|
||
| in | ||
| if missingArgs == { } then | ||
| makeOverridable f allArgs | ||
| # This needs to be an abort so it can't be caught with `builtins.tryEval`, | ||
| # which is used by nix-env and ofborg to filter out packages that don't evaluate. | ||
| # This way we're forced to fix such errors in Nixpkgs, | ||
| # which is especially relevant with allowAliases = false | ||
| # These need to be abort so they can't be caught with `builtins.tryEval`, | ||
| # which is used by nix-env and CI to filter out packages that don't evaluate. | ||
| # This way we're forced to fix such errors in Nixpkgs. | ||
| if aliasArgs != { } then | ||
| abort "lib.customisation.callPackageWith: ${aliasError}" | ||
| else if missingArgs != { } then | ||
| abort "lib.customisation.callPackageWith: ${missingError}" | ||
| else | ||
| abort "lib.customisation.callPackageWith: ${error}"; | ||
| makeOverridable f allArgs; | ||
|
|
||
| /** | ||
| Like callPackage, but for a function that returns an attribute | ||
|
|
@@ -365,6 +378,35 @@ rec { | |
| else | ||
| mapAttrs mkAttrOverridable pkgs; | ||
|
|
||
| makeAlias = | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: We should call this Also, I feel that “alias” may be a confusing word in general.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since I started in |
||
| let | ||
| currentRelease = lib.versions.majorMinor lib.version; | ||
| in | ||
| self: name: | ||
| { | ||
| type, | ||
| package ? null, | ||
| reason ? null, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to support multiple reasons, if we can ensure the interface remains convenient. I also think that we should ensure the reasons are structured by default rather than free‐form strings, because our existing throws are wildly inconsistent, and it’s much more convenient to write Vague draft: |
||
| release ? null, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a mild preference for |
||
| }: | ||
| assert type == "alias"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like busywork to have to set this? It should be relatively low‐ceremony to stub out a package.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, that's the part that we need to keep the typing a bit stronger than freeform. If we ever want to extend this to other things like scopes or so, we better have |
||
| if release == null then | ||
| self.${package} | ||
| else if release != currentRelease then | ||
| if package == null then | ||
| abort "Throw for '${name}' was added in ${release}. The alias must now be removed." | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A warning seems like it may be better? Then you can scoop them all up at once, and perhaps do something with |
||
| else | ||
| abort "Warning for '${name}' was added in ${release}. The alias must now be converted to a throw." | ||
|
Comment on lines
+398
to
+399
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? We know what the current release is and when the warning was added. We can automatically turn it into a throwing alias without making the release manager do busywork. Complete removal can’t be done in this way, of course, but the automatic transition from warning to throw is IMO one of the nicest advantages of a more structured alias system. You can say that it causes issues if the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I consider Nixpkgs versions mostly freeform, so we can only say "still matches the current release" or "was added in a previous release". Now, if we don't want to stick with these forever, then we need two points where things change:
If we only have one piece of information, we can't identify both. To be able to identify both, we must put "structure" into the Nixpkgs version, too. Aka we must give it a semantic meaning, saying "25.11" is "25.05 + 1" and "26.05" is "25.05 + 2". We can do that, but I'm not sure if and how, yet. |
||
| else if package == null || !self.config.allowAliases then | ||
| { | ||
| type = "error"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea is to say we already have Aka we never want something like a derivation with a different |
||
| meta = throw "'${name}' was removed because it was ${reason}."; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the choice of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
(we should probably also add |
||
| } | ||
| else | ||
| lib.warnOnInstantiate | ||
| "'${name}' was renamed to '${package}'. The alias will be removed in the next release." | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should at least say “the next release after […]”. |
||
| self.${package}; | ||
|
|
||
| /** | ||
| Add attributes to each output of a derivation without changing | ||
| the derivation itself and check a given condition when evaluating. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "broken and unmaintained"; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "renamed to folo"; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| package = "opentimelineio"; | ||
| } | ||
|
Comment on lines
+1
to
+5
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah… so the reason for the mandatory But this is no good: you can have I know this ties in to supporting more non‐package stuff in Is the idea that this makes
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So there are a couple of things going on here:
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -771,7 +771,6 @@ mapAliases { | |
| docker_27 = throw "'docker_27' has been removed because it has been unmaintained since May 2025. Use docker_28 or newer instead."; # Added 2025-06-15 | ||
| docker-compose_1 = throw "'docker-compose_1' has been removed because it has been unmaintained since May 2021. Use docker-compose instead."; # Added 2024-07-29 | ||
| docker-distribution = distribution; # Added 2023-12-26 | ||
| docker-sync = throw "'docker-sync' has been removed because it was broken and unmaintained"; # Added 2025-08-26 | ||
| dolphin-emu-beta = dolphin-emu; # Added 2023-02-11 | ||
| dolphinEmu = throw "'dolphinEmu' has been renamed to/replaced by 'dolphin-emu'"; # Converted to throw 2024-10-17 | ||
| dolphinEmuMaster = throw "'dolphinEmuMaster' has been renamed to/replaced by 'dolphin-emu-beta'"; # Converted to throw 2024-10-17 | ||
|
|
@@ -926,7 +925,6 @@ mapAliases { | |
| fmt_8 = throw "fmt_8 has been removed as it is obsolete and was no longer used in the tree"; # Added 2024-11-12 | ||
| fntsample = throw "fntsample has been removed as it is unmaintained upstream"; # Added 2025-04-21 | ||
| foldingathome = throw "'foldingathome' has been renamed to/replaced by 'fahclient'"; # Converted to throw 2024-10-17 | ||
| follow = lib.warnOnInstantiate "follow has been renamed to folo" folo; # Added 2025-05-18 | ||
| forgejo-actions-runner = forgejo-runner; # Added 2024-04-04 | ||
| fornalder = throw "'fornalder' has been removed as it is unmaintained upstream"; # Added 2025-01-25 | ||
| foundationdb71 = throw "foundationdb71 has been removed; please upgrade to foundationdb73"; # Added 2024-12-28 | ||
|
|
@@ -1839,7 +1837,6 @@ mapAliases { | |
| openssl_3_0 = openssl_3; # Added 2022-06-27 | ||
| opensycl = lib.warnOnInstantiate "'opensycl' has been renamed to 'adaptivecpp'" adaptivecpp; # Added 2024-12-04 | ||
| opensyclWithRocm = lib.warnOnInstantiate "'opensyclWithRocm' has been renamed to 'adaptivecppWithRocm'" adaptivecppWithRocm; # Added 2024-12-04 | ||
| open-timeline-io = lib.warnOnInstantiate "'open-timeline-io' has been renamed to 'opentimelineio'" opentimelineio; # Added 2025-08-10 | ||
| opentofu-ls = lib.warnOnInstantiate "'opentofu-ls' has been renamed to 'tofu-ls'" tofu-ls; # Added 2025-06-10 | ||
| openvdb_11 = throw "'openvdb_11' has been removed in favor of the latest version'"; # Added 2025-05-03 | ||
| opera = throw "'opera' has been removed due to lack of maintenance in nixpkgs"; # Added 2025-05-19 | ||
|
|
@@ -1958,7 +1955,6 @@ mapAliases { | |
| pgroonga = throw "'pgroonga' has been removed. Use 'postgresqlPackages.pgroonga' instead."; # Added 2025-07-19 | ||
| pgtap = throw "'pgtap' has been removed. Use 'postgresqlPackages.pgtap' instead."; # Added 2025-07-19 | ||
| plv8 = throw "'plv8' has been removed. Use 'postgresqlPackages.plv8' instead."; # Added 2025-07-19 | ||
| postcss-cli = throw "postcss-cli has been removed because it was broken"; # added 2025-03-24 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it intentional that this was removed in this PR without replacement?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, because it's exactly the case that would hit |
||
| postgis = throw "'postgis' has been removed. Use 'postgresqlPackages.postgis' instead."; # Added 2025-07-19 | ||
| tegaki-zinnia-japanese = throw "'tegaki-zinnia-japanese' has been removed due to lack of maintenance"; # Added 2025-09-10 | ||
| tet = throw "'tet' has been removed for lack of maintenance"; # Added 2025-10-12 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,8 +19,12 @@ let | |
| mergeAttrsList | ||
| ; | ||
|
|
||
| # Package files for a single shard | ||
| # Type: String -> String -> AttrsOf Path | ||
| inherit (lib.customisation) | ||
| makeAlias | ||
| ; | ||
|
|
||
| # Package imports for a single shard | ||
| # Type: String -> String -> AttrsOf Any | ||
| namesForShard = | ||
| shard: type: | ||
| if type != "directory" then | ||
|
|
@@ -32,27 +36,35 @@ let | |
| # Additionally in either of those alternatives, we would have to duplicate the hardcoding of "README.md" | ||
| { } | ||
| else | ||
| mapAttrs (name: _: baseDirectory + "/${shard}/${name}/package.nix") ( | ||
| mapAttrs (name: _: import (baseDirectory + "/${shard}/${name}/package.nix")) ( | ||
pbsds marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| readDir (baseDirectory + "/${shard}") | ||
| ); | ||
|
|
||
| # The attribute set mapping names to the package files defining them | ||
| # The attribute set mapping names to the package expressions defining them | ||
| # This is defined up here in order to allow reuse of the value (it's kind of expensive to compute) | ||
| # if the overlay has to be applied multiple times | ||
| packageFiles = mergeAttrsList (mapAttrsToList namesForShard (readDir baseDirectory)); | ||
| packages = mergeAttrsList (mapAttrsToList namesForShard (readDir baseDirectory)); | ||
| in | ||
| # TODO: Consider optimising this using `builtins.deepSeq packageFiles`, | ||
| # which could free up the above thunks and reduce GC times. | ||
| # Currently this would be hard to measure until we have more packages | ||
| # and ideally https://github.com/NixOS/nix/pull/8895 | ||
| self: super: | ||
| { | ||
| _isAlias = name: packages.${name}.type or null == "alias"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should use double underscores for this, to match
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think double underscores are wrong, my understanding is that double underscores mean "internal to Nix", while single underscore means "internal to Nixpkgs". |
||
|
|
||
| # This attribute is necessary to allow CI to ensure that all packages defined in `pkgs/by-name` | ||
| # don't have an overriding definition in `all-packages.nix` with an empty (`{ }`) second `callPackage` argument. | ||
| # It achieves that with an overlay that modifies both `callPackage` and this attribute to signal whether `callPackage` is used | ||
| # and whether it's defined by this file here or `all-packages.nix`. | ||
| # TODO: This can be removed once `pkgs/by-name` can handle custom `callPackage` arguments without `all-packages.nix` (or any other way of achieving the same result). | ||
| # Because at that point the code in ./stage.nix can be changed to not allow definitions in `all-packages.nix` to override ones from `pkgs/by-name` anymore and throw an error if that happens instead. | ||
| _internalCallByNamePackageFile = file: self.callPackage file { }; | ||
| _internalCallByNamePackageFile = fn: self.callPackage fn { }; | ||
| } | ||
| // mapAttrs (name: self._internalCallByNamePackageFile) packageFiles | ||
| // mapAttrs ( | ||
| name: value: | ||
| if value.type or null == "alias" then | ||
| makeAlias self name value | ||
| else | ||
| self._internalCallByNamePackageFile value | ||
| ) packages | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -290,31 +290,116 @@ in | |
|
|
||
| linux_hardened = hardenedKernelFor packageAliases.linux_default.kernel { }; | ||
| } | ||
| // lib.optionalAttrs config.allowAliases { | ||
| linux_4_19 = throw "linux 4.19 was removed because it will reach its end of life within 24.11"; | ||
| linux_6_9 = throw "linux 6.9 was removed because it has reached its end of life upstream"; | ||
| linux_6_10 = throw "linux 6.10 was removed because it has reached its end of life upstream"; | ||
| linux_6_11 = throw "linux 6.11 was removed because it has reached its end of life upstream"; | ||
| linux_6_13 = throw "linux 6.13 was removed because it has reached its end of life upstream"; | ||
| linux_6_14 = throw "linux 6.14 was removed because it has reached its end of life upstream"; | ||
| linux_6_15 = throw "linux 6.15 was removed because it has reached its end of life upstream"; | ||
|
|
||
| linux_5_10_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| linux_5_15_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| linux_6_1_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| linux_6_6_hardened = throw "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
|
|
||
| linux_4_19_hardened = throw "linux 4.19 was removed because it will reach its end of life within 24.11"; | ||
| linux_5_4_hardened = throw "linux_5_4_hardened was removed because it was broken"; | ||
| linux_6_9_hardened = throw "linux 6.9 was removed because it has reached its end of life upstream"; | ||
| linux_6_10_hardened = throw "linux 6.10 was removed because it has reached its end of life upstream"; | ||
| linux_6_11_hardened = throw "linux 6.11 was removed because it has reached its end of life upstream"; | ||
| linux_6_13_hardened = throw "linux 6.13 was removed because it has reached its end of life upstream"; | ||
| linux_6_14_hardened = throw "linux 6.14 was removed because it has reached its end of life upstream"; | ||
| linux_6_15_hardened = throw "linux 6.15 was removed because it has reached its end of life upstream"; | ||
|
|
||
| linux_ham = throw "linux_ham has been removed in favour of the standard kernel packages"; | ||
| } | ||
| // ( | ||
| let | ||
| aliases = { | ||
| linux_4_19 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it will reach its end of life within 24.11"; | ||
| }; | ||
| linux_6_9 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_10 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_11 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_13 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_14 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_15 = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "it has reached its end of life upstream"; | ||
| }; | ||
|
|
||
| linux_5_10_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| }; | ||
| linux_5_15_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| }; | ||
| linux_6_1_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| }; | ||
| linux_6_6_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux_hardened on nixpkgs only contains latest stable and latest LTS"; | ||
| }; | ||
|
|
||
| linux_4_19_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 4.19 was removed because it will reach its end of life within 24.11"; | ||
| }; | ||
| linux_5_4_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux_5_4_hardened was removed because it was broken"; | ||
| }; | ||
| linux_6_9_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 6.9 was removed because it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_10_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 6.10 was removed because it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_11_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 6.11 was removed because it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_13_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 6.13 was removed because it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_14_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 6.14 was removed because it has reached its end of life upstream"; | ||
| }; | ||
| linux_6_15_hardened = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "linux 6.15 was removed because it has reached its end of life upstream"; | ||
| }; | ||
|
|
||
| linux_ham = { | ||
| type = "alias"; | ||
| release = "25.11"; | ||
| reason = "in favour of the standard kernel packages"; | ||
| }; | ||
| }; | ||
| in | ||
| (lib.mapAttrs (lib.makeAlias kernels) aliases) // { _isAlias = name: aliases ? ${name}; } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yuck. This is too much ceremony – I think we have to find something better here. Whether that’s just defining these under an
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I am not happy with this, yet, either. I added this to have a look at how this would look like... but yeah, don't like it, yet. My current idea would be: These kinds of aliases don't need to support non by-name structures at all. Let's implement them with by-name in mind, and then work on migrating everything to by-name. This renders this case void. |
||
| ) | ||
| ) | ||
| ); | ||
| /* | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we made aliases become
throws when!config.allowAliases, would we need this? i.e., they would be filtered out by CI, but would it also just filter out packages that use those aliases? (Just thinking about if we can minimize the number of places that have to know about aliases, for both cleanliness and performance.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would still be possible to add aliases to the package arguments, if eval doesn't hit them.
We had this case for
python3Packages, where this was already tried - somone tried to somehow overridepython3Packagesin the python scope with aliases turned on or so, to prevent this from being used - but it didn't work, because Ci is swallowing those errors.This could be hacked by putting
abortin that place, I guess - but here I just demonstrated how we could use the structured alias information to implement such a check. This has a tiny effect on performance, so we can also entirely leave this part out, if we want to.