From 5dad4cac7b5d8acb7169da206880006f9374e6ac Mon Sep 17 00:00:00 2001 From: Andrzej Novak Date: Tue, 18 Nov 2025 10:12:47 +0100 Subject: [PATCH] fix: wip --- .gitignore | 2 + CONTRIBUTING.md | 34 ++++++++++++++++ pyproject.toml | 62 ++++++++++++++++++++++++++++- src/mplhep/_dev.py | 53 +++++++++++++++++++----- tests/baseline/test_issue_594.png | Bin 0 -> 35616 bytes tests/from_issues/test_issue594.py | 19 +++++++++ 6 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 tests/baseline/test_issue_594.png create mode 100644 tests/from_issues/test_issue594.py diff --git a/.gitignore b/.gitignore index 00e37a55..4b35ed49 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,5 @@ venv.bak/ /docs/source/_generated/ /tmp/ /docs/source/_static/_generated/ +# pixi environments +.pixi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9084137e..8b4efa01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,40 @@ Please open an [issue](https://github.com/scikit-hep/mplhep/issues). ## Installing the development environment ```bash +### Using pixi (recommended) + +[Pixi](https://prefix.dev/docs/pixi/overview) provides a fast, reproducible development environment: + +```bash +```bash +```bash +# Install the default environment (includes all development tools) +pixi install + +# Activate a shell with all tools +pixi shell + +# Or run commands directly +pixi run test-basic +``` + +Available pixi tasks (now just `pixi run `): +- `pixi run test` - Run full test suite with visual comparison +- `pixi run test-parallel` - Run tests in parallel (auto-detects optimal worker count) +- `pixi run test-basic` - Run basic tests without visual comparison +- `pixi run generate-baseline` - Generate new baseline images +- `pixi run lint` - Check code with ruff +- `pixi run format` - Format code with ruff +- `pixi run format-check` - Check formatting without changes + +Benchmarking tasks (requires benchmark environment): +- `pixi run -e benchmark benchmark` - Run benchmark tests +- `pixi run -e benchmark benchmark-run` - Run and save benchmark results +- `pixi run -e benchmark benchmark-compare` - Compare benchmark results + +**Note:** For development work, use the default environment (`pixi install`) which includes all tools. The specialized environments (`dev`, `test`, `docs`, `benchmark`) are available for specific use cases. + +``` python -m pip install --upgrade --editable ".[all]" ``` Also conveniently accessible as `bash install.sh`. diff --git a/pyproject.toml b/pyproject.toml index 0862b194..eb950a17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,6 @@ test = [ "pytest-mock", "pytest-mpl", "pytest-xdist", - "pytest-benchmark", "pytest>=6.0", "scikit-hep-testdata", "scipy>=1.1.0", @@ -66,6 +65,9 @@ test = [ "uproot4", "seaborn", ] +benchmark = [ + "pytest-benchmark", +] all = [ "mplhep[dev,test,docs]", ] @@ -199,3 +201,61 @@ ignore = [ "src/mplhep/_dev.py" = ["T20"] "test_*.py" = ["T20"] "src/mplhep/styles/*.py" = ["FLY002"] + +[tool.pixi.workspace] +channels = ["conda-forge"] +platforms = ["linux-64"] + +[tool.pixi.environments] +default = { features = ["dev", "test", "docs"], solve-group = "default" } +dev = { features = ["dev", "test"], solve-group = "default" } +docs = { features = ["docs"], solve-group = "default" } +test = { features = ["test"], solve-group = "default" } +benchmark = { features = ["test", "benchmark"], solve-group = "default" } + +[tool.pixi.tasks] + +[tool.pixi.feature.test.tasks] +test = "pytest -r sa --mpl --mpl-results-path=pytest_results" +test-parallel = "pytest -r sa --mpl --mpl-results-path=pytest_results -n auto" +test-basic = "pytest tests/" +test-single = "pytest" +generate-baseline = "pytest -r sa --mpl --mpl-generate-path=tests/baseline" + +[tool.pixi.feature.benchmark.tasks] +benchmark = "pytest --benchmark-only --benchmark-sort=mean" +benchmark-run = "pytest --benchmark-only --benchmark-sort=mean --benchmark-save=latest" +benchmark-compare = "pytest --benchmark-only --benchmark-compare=latest" + +[tool.pixi.feature.dev.tasks] +lint = "ruff check src/" +format = "ruff format src/" +format-check = "ruff format --check src/" + +[tool.pixi.dependencies] +python = ">=3.9,<3.14" +pytest = ">=9.0.1,<10" +matplotlib = ">=3.4" +numpy = ">=1.16.0" +packaging = "*" + +[tool.pixi.pypi-dependencies] +mplhep = { path = ".", editable = true } + +[tool.pixi.feature.test.dependencies] +pytest-mock = "*" +pytest-mpl = "*" +pytest-xdist = "*" +scipy = ">=1.1.0" +seaborn = "*" + +[tool.pixi.feature.benchmark.dependencies] +pytest-benchmark = "*" + +[tool.pixi.feature.dev.dependencies] +jupyter = "*" +twine = "*" +ruff = "*" +pre-commit = "*" +questionary = "*" +mkdocs = ">=1.6" diff --git a/src/mplhep/_dev.py b/src/mplhep/_dev.py index e8b029cd..00da7e29 100644 --- a/src/mplhep/_dev.py +++ b/src/mplhep/_dev.py @@ -78,11 +78,14 @@ def _get_terminal_width(self) -> int: return 80 def _run_command_with_confirmation( - self, cmd: list[str], prompt: str = "Confirm command (editable):" + self, + cmd: list[str], + prompt: str = "Confirm command (editable):", + env: Optional[dict] = None, ) -> bool: """Run a command with user confirmation and editing capability.""" if not HAS_QUESTIONARY or questionary is None: - return self._run_command(cmd) + return self._run_command(cmd, env=env) modified_cmd_str = questionary.text( prompt, default=" ".join(cmd), style=self.style @@ -98,9 +101,12 @@ def _run_command_with_confirmation( self._print_error(f"Invalid command syntax: {e}") return False - return self._run_command(cmd) + return self._run_command(cmd, env=env) def _run_command(self, cmd: list[str], cwd: Path | None = None) -> bool: + def _run_command( + self, cmd: list[str], cwd: Optional[Path] = None, env: Optional[dict] = None + ) -> bool: """Run a command and return True if successful.""" self._print_header(f"Running: {' '.join(cmd)}") separator = 3 * ("=" * self._get_terminal_width() + "\n") @@ -108,6 +114,18 @@ def _run_command(self, cmd: list[str], cwd: Path | None = None) -> bool: try: result = subprocess.run(cmd, cwd=cwd or self.project_root, check=True) + self._print_header(f"Running: {' '.join(cmd)}") + separator = 3 * ("=" * self._get_terminal_width() + "\n") + print(separator) + # Merge environment variables if provided + run_env = os.environ.copy() + if env: + run_env.update(env) + result = subprocess.run( + cmd, cwd=cwd or self.project_root, env=run_env, check=True + ) + print(separator) + return result.returncode == 0 except subprocess.CalledProcessError as e: self._print_error(f"Command failed with exit code {e.returncode}") return False @@ -200,15 +218,30 @@ def cmd_test( sys.executable, "-m", "pytest", - "-r", - "sa", - "--mpl", - "--mpl-results-path=pytest_results", ] - # Only add -n flag if using parallelism (jobs > 1) + # Handle parallel execution - now works normally without conflicts if jobs > 1: - cmd.extend(["-n", str(jobs)]) + cmd.extend( + [ + "-r", + "sa", + "--mpl", + "--mpl-results-path=pytest_results", + "-n", + str(jobs), + ] + ) + else: + # Non-parallel execution - use normal config + cmd.extend( + [ + "-r", + "sa", + "--mpl", + "--mpl-results-path=pytest_results", + ] + ) if filter_pattern: cmd.extend(["-k", filter_pattern]) @@ -1062,7 +1095,7 @@ def make_menu_item(title, command_text): ( make_menu_item( "🧪 Run pytest", - "python -m pytest -r sa --mpl --mpl-results-path=pytest_results", + f"python -m pytest -r sa --mpl --mpl-results-path=pytest_results{' -n ' + str(self.default_jobs) if self.default_jobs > 1 else ''}", ), "test", ), diff --git a/tests/baseline/test_issue_594.png b/tests/baseline/test_issue_594.png new file mode 100644 index 0000000000000000000000000000000000000000..cd4b1bce2ebd3ff6ee73f015fc17b45b01ceefb3 GIT binary patch literal 35616 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 V?fUqqcw`K%ExMZ%H|;z1KL95Q!MFeb literal 0 HcmV?d00001 diff --git a/tests/from_issues/test_issue594.py b/tests/from_issues/test_issue594.py new file mode 100644 index 00000000..bef3cb16 --- /dev/null +++ b/tests/from_issues/test_issue594.py @@ -0,0 +1,19 @@ +import hist +import numpy as np +import pytest + +import mplhep as hep + + +@pytest.mark.mpl_image_compare(remove_text=False) +def test_issue_594(): + np.random.seed(42) # Set seed for reproducible results + h1 = hist.Hist(hist.axis.Regular(10, 0, 10, underflow=True, overflow=True)) + h1.fill(np.random.normal(5, 2, 1000)) + h2 = hist.Hist(hist.axis.Regular(10, 0, 10, underflow=True, overflow=True)) + h2.fill(np.random.normal(5, 2, 1000)) + + fig, ax, rax = hep.comparison_plotters.data_model( + h1, unstacked_components=[h2], flow="show" + ) + return fig