-
Notifications
You must be signed in to change notification settings - Fork 261
python-math #13: refactor(math): move impl-flag resolver to polismath/utils/env_flags.py #2641
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
Draft
jucor
wants to merge
1
commit into
spr/edge/18c7048f
Choose a base branch
from
spr/edge/bc0518d7
base: spr/edge/18c7048f
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| """ | ||
| Shared resolver for legacy-vs-improved implementation switches. | ||
|
|
||
| Pattern for env-var implementation switches (POLISMATH_PCA_IMPL, | ||
| POLISMATH_ENGINE_MODE, and future ones like a k-means solver switch): a | ||
| module-level env var name + default + allowed values, resolved by | ||
| `resolve_impl_flag` AT CALL TIME (never at import time), so tests and | ||
| operators can flip the env var without re-importing. Unknown values fall back | ||
| to the default with a warning (defensive: a typo in a deployment env must not | ||
| crash the math worker). | ||
|
|
||
| This lives in polismath.utils (not pca.py, where it originated) so that | ||
| lightweight consumers — e.g. `utils.engine_mode`, read on every conv-update | ||
| tick — do not drag in the numpy/pandas pca import chain, and resolution | ||
| warnings are logged under this module's logger rather than pca's. | ||
|
jucor marked this conversation as resolved.
|
||
| """ | ||
|
|
||
| import logging | ||
| import os | ||
| from typing import Sequence | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def resolve_impl_flag(env_var: str, default: str, choices: Sequence[str]) -> str: | ||
| """ | ||
| Resolve a legacy-vs-improved implementation switch from the environment. | ||
|
|
||
| Args: | ||
| env_var: Environment variable name to read (at call time). | ||
| default: Value to use when the variable is unset or invalid. | ||
| choices: Allowed values (lowercase). | ||
|
|
||
| Returns: | ||
| One of `choices`. | ||
| """ | ||
| raw = os.environ.get(env_var) | ||
| if raw is None: | ||
| return default | ||
| value = raw.strip().lower() | ||
| if value not in choices: | ||
| logger.warning("%s=%r is not one of %s; falling back to %r", | ||
| env_var, raw, tuple(choices), default) | ||
| return default | ||
| return value | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| """ | ||
| Tests for polismath.utils.env_flags — the shared legacy-vs-improved | ||
| implementation-switch resolver. | ||
|
|
||
| The resolver started life as `pca._resolve_impl_flag` (pca.py) and was imported | ||
| from there by `utils.engine_mode`, which dragged the whole numpy/pandas pca | ||
| import chain into anything that only wanted to read POLISMATH_ENGINE_MODE, and | ||
| emitted resolution warnings under the pca logger. These tests pin the move to | ||
| `polismath.utils.env_flags`: identical resolution rules, warnings under the | ||
| env_flags logger, and a light `utils.engine_mode` import. | ||
| """ | ||
|
|
||
| import logging | ||
| import subprocess | ||
| import sys | ||
|
|
||
| import pytest | ||
|
|
||
| from polismath.utils.env_flags import resolve_impl_flag | ||
|
|
||
|
|
||
| class TestResolveImplFlag: | ||
| """Resolution rules (identical to the original pca._resolve_impl_flag).""" | ||
|
|
||
| ENV = 'POLISMATH_TEST_FLAG' | ||
| CHOICES = ('legacy', 'improved') | ||
|
|
||
| def test_unset_returns_default(self, monkeypatch): | ||
| monkeypatch.delenv(self.ENV, raising=False) | ||
| assert resolve_impl_flag(self.ENV, 'legacy', self.CHOICES) == 'legacy' | ||
|
|
||
| def test_valid_value_returned(self, monkeypatch): | ||
| monkeypatch.setenv(self.ENV, 'improved') | ||
| assert resolve_impl_flag(self.ENV, 'legacy', self.CHOICES) == 'improved' | ||
|
|
||
| def test_value_stripped_and_lowercased(self, monkeypatch): | ||
| monkeypatch.setenv(self.ENV, ' IMPROVED ') | ||
| assert resolve_impl_flag(self.ENV, 'legacy', self.CHOICES) == 'improved' | ||
|
|
||
| def test_invalid_value_falls_back_with_warning(self, monkeypatch, caplog): | ||
| monkeypatch.setenv(self.ENV, 'bogus') | ||
| with caplog.at_level(logging.WARNING, logger='polismath.utils.env_flags'): | ||
| assert resolve_impl_flag(self.ENV, 'legacy', self.CHOICES) == 'legacy' | ||
| records = [r for r in caplog.records | ||
| if r.name == 'polismath.utils.env_flags'] | ||
| assert len(records) == 1 | ||
| assert 'POLISMATH_TEST_FLAG' in records[0].getMessage() | ||
|
|
||
| def test_read_at_call_time(self, monkeypatch): | ||
| monkeypatch.setenv(self.ENV, 'improved') | ||
| assert resolve_impl_flag(self.ENV, 'legacy', self.CHOICES) == 'improved' | ||
| monkeypatch.setenv(self.ENV, 'legacy') | ||
| assert resolve_impl_flag(self.ENV, 'legacy', self.CHOICES) == 'legacy' | ||
|
|
||
|
|
||
| class TestSharedResolver: | ||
| """Both switch modules resolve through the ONE shared function.""" | ||
|
|
||
| def test_pca_uses_shared_resolver(self): | ||
| from polismath.pca_kmeans_rep import pca | ||
| from polismath.utils import env_flags | ||
| assert pca.resolve_impl_flag is env_flags.resolve_impl_flag | ||
|
|
||
| def test_engine_mode_uses_shared_resolver(self): | ||
| from polismath.utils import engine_mode, env_flags | ||
| assert engine_mode.resolve_impl_flag is env_flags.resolve_impl_flag | ||
|
|
||
| def test_engine_mode_import_does_not_load_pca(self): | ||
| # The point of the move: reading POLISMATH_ENGINE_MODE must not drag | ||
| # the numpy/pandas pca import chain. Fresh interpreter so this | ||
| # process's already-imported modules can't mask a regression. | ||
| code = ( | ||
| "import sys; import polismath.utils.engine_mode; " | ||
| "sys.exit(1 if 'polismath.pca_kmeans_rep.pca' in sys.modules else 0)" | ||
| ) | ||
| proc = subprocess.run([sys.executable, '-c', code], | ||
| capture_output=True, text=True) | ||
| assert proc.returncode == 0, ( | ||
| "importing polismath.utils.engine_mode pulled in " | ||
| "polismath.pca_kmeans_rep.pca:\n" + proc.stderr | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| pytest.main([__file__, '-v']) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.