Skip to content
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

Only return Python factor on base_python conflict #2840

Merged
merged 1 commit into from Jan 10, 2023

Conversation

stephenfin
Copy link
Contributor

Consider the following tox.ini file:

[tox]
ignore_base_python_conflict = true

[testenv]
base_python = python3
commands = ...

[testenv:functional{,-py38,-py39,-py310}]
commands = ...

There is a conflict between the base_python value specified in [testenv] base_python and the value implied by the pyXY factors in the functional-pyXY test envs. The Python._validate_base_python function is supposed to resolve this for us and either (a) raise an error if [tox] ignore_base_python_conflict is set to false (default) or (b) ignore the value of [testenv] base_python in favour of the value implied by the pyXY factor for the given test env if [tox] ignore_base_python_conflict is set to true. There's a bug though. Rather than returning the pyXY factor, we were returning the entire test env name (functional-pyXY). There is no Python version corresponding to e.g. functional-py39 so this (correctly) fails.

We can correct the issue by only returning the factor that modified the base_python value, i.e. the pyXY factor. To ensure we do this, we need some additional logic. It turns out this logic is already present in another helper method on the Python class, extract_base_python, so we also take the opportunity to de-duplicate and reuse some logic.

Note that this change breaks the ability of users to use a testenv name like py38-64 (to get the 64 bit version of a Python 3.8 interpreter). Continuing to support this would require much larger change since we'd no longer be able to strictly delimit factors by hyphens (in this case, the entirety of py38-64 becomes a factor).

Also note that this change emphasises issue #2657, as this will now be raised for a factor like py38-64 since tox (or rather, virtualenv) is falsely identifying 64 as a valid Python interpreter identifier. We will fix this separately so the offending test are skipped for now.

Signed-off-by: Stephen Finucane stephen@that.guru
Fixes: #2838

Thanks for contribution

Please, make sure you address all the checklists (for details on how see
development documentation)!

  • ran the linter to address style issues (tox -e fix)
  • wrote descriptive pull request text
  • ensured there are test(s) validating the fix
  • added news fragment in docs/changelog folder
  • updated/extended the documentation

@gaborbernat
Copy link
Member

Note that this change breaks the ability of users to use a testenv name like py38-64 (to get the 64 bit version of a Python 3.8 interpreter). Continuing to support this would require much larger change since we'd no longer be able to strictly delimit factors by hyphens (in this case, the entirety of py38-64 becomes a factor).

We must support this, and I cannot accept a change that would introduce this regression.

Copy link
Member

@gaborbernat gaborbernat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must support this, and I cannot accept a change that would introduce this regression.

@stephenfin
Copy link
Contributor Author

stephenfin commented Jan 9, 2023

Note that this change breaks the ability of users to use a testenv name like py38-64 (to get the 64 bit version of a Python 3.8 interpreter). Continuing to support this would require much larger change since we'd no longer be able to strictly delimit factors by hyphens (in this case, the entirety of py38-64 becomes a factor).

We must support this, and I cannot accept a change that would introduce this regression.

But why? Who is the target user here? Who needs this functionality? fwiw, I added documentation on how factors worked (since there wasn't any before then) way back in #1573 that seems to have been lost in the rewrite, but when researching that there was no suggesting that e.g. py310-64 was a valid factor.

If you need to support this, how do you propose determining whether something is a factor or not? For example, what would the Python versions used in each of the below be?

  • py310-64
  • py310-65
  • functional-py310-1
  • functional-py310-a1
  • foo-3.10-1-bar
  • foo-py3.10.1.2.3
  • py-3-10

While you're considering answers for these, please note how much cognitive effort is required for each, compared to simply supporting pyXY.

Personally, I think we're tacking too close to what virtualenv supports which is super loose. We're not talking about virtualenv, we're talking about tox. There's no reason they need to behave identically. If people want to get virtualenv's specific behavior, they can just set base_python:

[testenv:py310]
base_python = python3.10-64

@gaborbernat
Copy link
Member

gaborbernat commented Jan 9, 2023

If you need to support this, how do you propose determining whether something is a factor or not? For example, what would the Python versions used in each of the below be?

  • py310-64
  • py310-65
  • functional-py310-1
  • functional-py310-a1
  • foo-3.10-1-bar
  • foo-py3.10.1.2.3
  • py-3-10

https://virtualenv.pypa.io/en/latest/user_guide.html#python-discovery

the architecture is either -64 or -32 (missing means any).

So only envs with either of those two factors should be accepted and the rest not.

Personally, I think we're tacking too close to what virtualenv supports which is super loose. We're not talking about virtualenv, we're talking about tox. There's no reason they need to behave identically. If people want to get virtualenv's specific behavior, they can just set base_python:

I'd actually consider that a feature, not a bug. I want tox to differ as little as possible from virtualenv to have only one way of doing thins.

@stephenfin
Copy link
Contributor Author

If you need to support this, how do you propose determining whether something is a factor or not? For example, what would the Python versions used in each of the below be?

  • py310-64
  • py310-65
  • functional-py310-1
  • functional-py310-a1
  • foo-3.10-1-bar
  • foo-py3.10.1.2.3
  • py-3-10

virtualenv.pypa.io/en/latest/user_guide.html#python-discovery

the architecture is either -64 or -32 (missing means any).

So only envs with either of those two factors should be accepted and the rest not.

As I noted above though, this means we can no longer delimit by hyphens alone, yes? We need to lookahead, check if any of the "factors" are 64 or 32, and if so see if we can combine that with the previous factor (if any).

Can you propose something we can slot into the documentation because I'm struggling to explain this in a way that doesn't make tox factors sound even more "magical" (in a bad way).

Personally, I think we're tacking too close to what virtualenv supports which is super loose. We're not talking about virtualenv, we're talking about tox. There's no reason they need to behave identically. If people want to get virtualenv's specific behavior, they can just set base_python:

I'd actually consider that a feature, not a bug. I want tox to differ as little as possible from virtualenv to have only one way of doing thins.

I respectfully disagree. This isn't a helpful goal for normal end-users who only care about tox for its automation of virtualenvs. If power users want a very specific python version (say, the 32 bit version of Python), they can specify base_python as noted above. I just don't see how this is something that's important enough to break the "hyphens are how we delimit" rule.

@gaborbernat
Copy link
Member

gaborbernat commented Jan 9, 2023

As I noted above though, this means we can no longer delimit by hyphens alone, yes? We need to lookahead, check if any of the "factors" are 64 or 32, and if so see if we can combine that with the previous factor (if any).

You are correct 😊

. I just don't see how this is something that's important enough to break the "hyphens are how we delimit" rule.

Hmm, I never considered this a hard rule 🤔 and this still can be the case, no; just look ahead. I personally consider it a feature that you can use the same names in virtualenv spec as your tox env names 🤔 So seem we will need to disagree on this.

@stephenfin
Copy link
Contributor Author

stephenfin commented Jan 9, 2023

I had a go at doing ☝️ Just to note, I don't like this in the slightest. I feel it's too confusing and reinforces what I feel is a UX regression in tox 4. IMO, the call to PythonSpec.from_string_spec (in tox.tox_env.python.api.Python.extract_base_python) is a mistake that conflicts with the historical definition of what testenv factors look like (hyphen-separated alphanumeric slugs) and it makes our factor parsing too complicated and factors as a concept much more difficult to explain. I feel we should be stricter in supporting pyXY(Y)-style factors only and anything else should be configured via base_python (which by itself would resolve e.g. #2535). Our looseness here has caused multiple issues already (#2657, #2838). But, it's not my project. Do as you wish. At least this fixes the bug.

@gaborbernat
Copy link
Member

I had a go at doing ☝️ Just to note, I don't like this in the slightest. I feel it's too confusing and reinforces what I feel is a UX regression in tox 4. IMO, the call to PythonSpec.from_string_spec (in tox.tox_env.python.api.Python.extract_base_python) is a mistake that conflicts with the historical definition of what testenv factors look like (hyphen-separated alphanumeric slugs) and it makes our factor parsing too complicated and factors as a concept much more difficult to explain. I feel we should be stricter in supporting pyXY(Y)-style factors only and anything else should be configured via base_python

Understood, I'll think about it. I'll also invite the other maintainers, @jugmac00 and @asottile, to comment on their opinions.

@stephenfin
Copy link
Contributor Author

Thanks, I appreciate it 👍

@gaborbernat
Copy link
Member

Let's remove the arch support in factors, for now, the 🤔 (the only support I could find was https://tox.wiki/en/legacy/example/basic.html#using-generative-section-names, but that's also just setting basepython instead).

@gaborbernat
Copy link
Member

If you remove the last commit I'll accept this 👍 @stephenfin

@@ -0,0 +1,2 @@
A testenv with multiple factors, one of which conflicts with a ``base_python`` setting in ``tox.ini``, will now use the
correct Python interpreter version - by :user:`stephenfin`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the correct Python version" - that would be which one? The one from base_python or from the factor? And while I could read the source code, I'd prefer to have it here, too.

As you are very involved in that topic... is this properly documented? Or do you think it would make sense to update the documentation, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be the version derived from the factor. If I run tox -e py310, I expect to get python3.10.

I did have this documented as part of #841 but that seems to have been lost in the rewrite. I can do another PR to (re-)flesh out the documentation. I also need to re-add docs explaining how factors work, which I'd done previously in #1573.

@jugmac00
Copy link
Member

@gaborbernat Unfortunately, I am currently lacking the time to dig deeper in this topic. I rarely used base_python before and I just had to look up what ignore_base_python_conflict even means.

I am very happy that there is some in-depth discussion going on, as I think we really should be careful about introducing more breaking changes.

@stephenfin
Copy link
Contributor Author

Let's remove the arch support in factors, for now, the thinking (the only support I could find was tox.wiki/en/legacy/example/basic.html#using-generative-section-names, but that's also just setting basepython instead).

I think the docs you want are here https://tox.wiki/en/legacy/config.html#tox-environments ? That details the "special'ness" of pyXY factors and how tox generates a factor matrix.

Note, I wrote those based on reverse engineering how tox worked so obviously I'm not a neutral party here, but I already had many years of experience using tox so it wasn't a totally uninformed take on thing 😄

Consider the following 'tox.ini' file:

  [tox]
  ignore_base_python_conflict = true

  [testenv]
  base_python = python3
  commands = ...

  [testenv:functional{,-py38,-py39,-py310}]
  commands = ...

There is a conflict between the base_python value specified in
'[testenv] base_python' and the value implied by the 'pyXY' factors in
the 'functional-pyXY' test envs. The 'Python._validate_base_python'
function is supposed to resolve this for us and either (a) raise an
error if '[tox] ignore_base_python_conflict' is set to 'false' (default)
or (b) ignore the value of '[testenv] base_python' in favour of the
value implied by the 'pyXY' factor for the given test env if '[tox]
ignore_base_python_conflict' is set to 'true'. There's a bug though.
Rather than returning the 'pyXY' factor, we were returning the entire
test env name ('functional-pyXY'). There is no Python version
corresponding to e.g. 'functional-py39' so this (correctly) fails.

We can correct the issue by only returning the factor that modified the
base_python value, i.e. the 'pyXY' factor. To ensure we do this, we need
some additional logic. It turns out this logic is already present in
another helper method on the 'Python' class, 'extract_base_python', so
we also take the opportunity to de-duplicate and reuse some logic.

Note that this change breaks the ability of users to use a testenv name
like 'py38-64' (to get the 64 bit version of a Python 3.8 interpreter).
Continuing to support this would require much larger change since we'd
no longer be able to strictly delimit factors by hyphens (in this case,
the entirety of 'py38-64' becomes a factor).

Also note that this change emphasises issue tox-dev#2657, as this will now be
raised for a factor like 'py38-64' since 'tox' (or rather, virtualenv)
is falsely identifying '64' as a valid Python interpreter identifier. We
will fix this separately so the offending test are skipped for now.

Signed-off-by: Stephen Finucane <stephen@that.guru>
Fixes: tox-dev#2838
@stephenfin
Copy link
Contributor Author

If you remove the last commit I'll accept this +1 @stephenfin

Done. I had to force push so I also took the opportunity to rebase.

@gaborbernat gaborbernat merged commit 34b79a2 into tox-dev:main Jan 10, 2023
@stephenfin stephenfin deleted the issues/2838 branch January 10, 2023 17:44
descope bot added a commit to descope/django-descope that referenced this pull request Jan 28, 2023
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
| [tox](https://togithub.com/tox-dev/tox)
([changelog](https://tox.wiki/en/latest/changelog.html)) | dev | patch |
`4.2.6` -> `4.2.8` | `4.4.2` (+8) |

---

### Release Notes

<details>
<summary>tox-dev/tox</summary>

### [`v4.2.8`](https://togithub.com/tox-dev/tox/releases/tag/4.2.8)

[Compare Source](https://togithub.com/tox-dev/tox/compare/4.2.7...4.2.8)

#### What's Changed

- Allow package names with env markers with pip binary options by
[@&#8203;q0w](https://togithub.com/q0w) in
[tox-dev/tox#2853

**Full Changelog**: tox-dev/tox@4.2.7...4.2.8

### [`v4.2.7`](https://togithub.com/tox-dev/tox/releases/tag/4.2.7)

[Compare Source](https://togithub.com/tox-dev/tox/compare/4.2.6...4.2.7)

#### What's Changed

- Add release notes project URL for quick access in PyPI web by
[@&#8203;scop](https://togithub.com/scop) in
[tox-dev/tox#2835
- Document colorization regression on Windows by
[@&#8203;adamchainz](https://togithub.com/adamchainz) in
[tox-dev/tox#2837
- The tests actually require wheel by
[@&#8203;hroncok](https://togithub.com/hroncok) in
[tox-dev/tox#2843
- Only return Python factor on base_python conflict by
[@&#8203;stephenfin](https://togithub.com/stephenfin) in
[tox-dev/tox#2840
- Revert to supporting simple Python factors by
[@&#8203;stephenfin](https://togithub.com/stephenfin) in
[tox-dev/tox#2849

**Full Changelog**: tox-dev/tox@4.2.6...4.2.7

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xMDEuMCIsInVwZGF0ZWRJblZlciI6IjM0LjEwMS4wIn0=-->

Co-authored-by: descope[bot] <descope[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

tox 4 breaks generative env def with -pyXXX fragments if basepython is defined
3 participants