Skip to content

UV migration - #89

Merged
DanielaBreitman merged 22 commits into
mainfrom
uv_migration
Sep 24, 2026
Merged

DanielaBreitman merged 22 commits into
mainfrom
uv_migration

Conversation

@DanielaBreitman

@DanielaBreitman DanielaBreitman commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor
  • Repo now uses UV, though testing still uses conda+pip for compiled packages (21cmFAST, multinest, etc.)
  • Linting now done with ruff rather than flake8

Summary by Sourcery

Migrate project dependency management and linting to UV and Ruff while modernizing supported Python versions, development tooling, and CI environments.

Bug Fixes:

  • Align package metadata and CI with the supported Python 3.10–3.12 range.

Enhancements:

  • Migrate project dependency locking and development workflows to UV while retaining conda-based installation for compiled dependencies.
  • Replace Flake8, Black, isort, and pyupgrade pre-commit checks with Ruff linting and formatting.
  • Modernize project code, tests, and logging to satisfy the expanded linting and formatting configuration.
  • Expose the public package API explicitly and add Zeus-MCMC to the optional sampler dependencies.

Build:

  • Add the UV lockfile and restructure optional and development dependency groups in pyproject.toml.
  • Remove the legacy Flake8 configuration and update package/build metadata.

CI:

  • Update the test matrix and GitHub Actions dependencies, including newer checkout, Miniconda, and Codecov actions.

Deployment:

  • Update Read the Docs to newer Ubuntu, Mambaforge, and project environment settings.

Documentation:

  • Refresh installation and contribution guidance for the updated development and dependency workflow.

Chores:

  • Update pre-commit hooks and configure monthly automated hook updates.

@DanielaBreitman DanielaBreitman added the type: maintenance Infrastructure or maintenance label Sep 21, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 5 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/py21cmmc/core.py" line_range="1343" />
<code_context>
+                        values.append(astro_params[k])
+                    except KeyError:
+                        if k == "L_X_MINI":
+                            values.append(ap["L_X"])
+                        else:
+                            values.append(self.astro_param_defaults[k])
+        elif isinstance(astro_params, p21.AstroParams):
</code_context>
<issue_to_address>
**issue (bug_risk):** Core21cmEMU.build_model_data raises NameError because the dictionary-input fallback reads `ap["L_X"]`, but `ap` is never defined in that branch.

**Triggers:** When `astro_params` is a dictionary missing `L_X_MINI` but containing `L_X`.

**Suggested fix:** Use `astro_params["L_X"]` or construct the local parameter dictionary before applying defaults.

```suggestion
                            values.append(astro_params["L_X"])
```
</issue_to_address>

### Comment 2
<location path="src/py21cmmc/likelihood.py" line_range="933" />
<code_context>
+        # If redshift is provided, evaluate the arcade model now
+        # Otherwise will be evaluated every time on emulator zs
+        if redshift is not None:
+            self.arcade = get_T_arcade(redshift)
+
+    def get_T_arcade(self, z):
</code_context>
<issue_to_address>
**issue (bug_risk):** LikelihoodArcade.__init__ raises NameError because it calls `get_T_arcade(redshift)` as an unqualified function even though the method is defined on the instance.

**Triggers:** When `LikelihoodArcade` is constructed with a non-None `redshift`.

**Suggested fix:** Call `self.get_T_arcade(redshift)`.

```suggestion
            self.arcade = self.get_T_arcade(redshift)
```
</issue_to_address>

### Comment 3
<location path="src/py21cmmc/likelihood.py" line_range="1626-1628" />
<code_context>
         return paired[0]


+class LikelihoodArcade(LikelihoodBase):
+    """
+    A likelihood based on the measured radio temperature at a range of redshifts.
</code_context>
<issue_to_address>
**issue (bug_risk):** The newly added LikelihoodNeutralFractionTwoSided implementation is overwritten by the second class declaration with the same name later in the module, so its clipped two-sided likelihood is never used.

**Triggers:** Whenever callers import or instantiate `LikelihoodNeutralFractionTwoSided`.

**Suggested fix:** Remove or rename the duplicate later class, or merge the intended implementation into the single exported class.

```suggestion

```
</issue_to_address>

### Comment 4
<location path="src/py21cmmc/likelihood.py" line_range="4" />
<code_context>
 """Module containing 21CMMC likelihoods."""
 import logging
 import numpy as np
+import pspec_likelihood as pslike
+from astropy import cosmology
+from astropy import units as un
</code_context>
<issue_to_address>
**issue (bug_risk):** Importing `py21cmmc.likelihood` raises ModuleNotFoundError in environments without pspec_likelihood, so the entire package fails to import even when the optional LikelihoodPspec feature is unused.

**Triggers:** When a normal installation does not separately install pspec_likelihood.

**Suggested fix:** Declare pspec_likelihood as an optional dependency and import it lazily inside LikelihoodPspec, or provide a guarded optional import.

```suggestion
try:
    import pspec_likelihood as pslike
except ImportError:
    pslike = None
```
</issue_to_address>

### Comment 5
<location path="src/py21cmmc/mcmc.py" line_range="393" />
<code_context>

+    if use_nautilus:
+        try:
+            import nautilus
+        except ImportError:
+            raise ImportError("You need to install nautilus to use this function!")
</code_context>
<issue_to_address>
**issue (bug_risk):** The new Nautilus sampler path cannot be installed through the declared sampler dependencies: run_mcmc imports `nautilus`, but the `samplers` extra still declares only pymultinest, ultranest, and zeus-mcmc.

**Triggers:** When users enable `use_nautilus=True` after installing the documented sampler extra.

**Suggested fix:** Add `nautilus` to the samplers optional dependency group.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 5 findings to address first, and this changes emulator outputs, likelihood calculations, sampler behavior, and the dependency/runtime environment across a large portion of the library; an implementation error could produce incorrect inference results or unusable installations. Reverting restores the prior code, but any chains, cached emulator results, or other analysis outputs produced while it was deployed would need to be identified and regenerated.

Blocking findings: src/py21cmmc/core.py:1343, src/py21cmmc/likelihood.py:933, src/py21cmmc/likelihood.py:1628, src/py21cmmc/likelihood.py:4, src/py21cmmc/mcmc.py:393


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/py21cmmc/core.py Outdated
Comment thread src/py21cmmc/likelihood.py Outdated
Comment thread src/py21cmmc/likelihood.py
Comment thread src/py21cmmc/likelihood.py Outdated
Comment thread src/py21cmmc/mcmc.py Outdated
@21cmfast 21cmfast deleted a comment from sourcery-ai Bot Sep 21, 2026
sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 21, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sourcery assessment

Approved.

@sourcery-ai
sourcery-ai Bot dismissed their stale review September 21, 2026 04:09

Sourcery withdrew this approval because the latest commits introduced blocking findings.

sourcery-ai[bot]
sourcery-ai Bot previously approved these changes Sep 21, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sourcery assessment

Approved.

@sourcery-ai
sourcery-ai Bot dismissed their stale review September 21, 2026 04:36

Sourcery withdrew this approval because it has stopped reviewing this pull request.

@sourcery-ai

sourcery-ai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Sourcery has withdrawn its approval of this pull request. It auto-reviews a pull request 5 times, and this push is past that limit, so the approval no longer reflects code Sourcery has read.

Comment @sourcery-ai review to get a fresh review, which can approve again.

Re-reviews, rate limits and approvals

- CoreForest.build_model_data: strip astropy units from lightcone_distances
- conftest.py: import torch before py21cmfast to avoid OpenMP init-order segfault
- Likelihood1DPowerLightcone(Upper): default datafile to None instead of "",
  which was causing simulate=True runs with no datafile to np.savez('') a
  stray '.npz' file into cwd
- gitignore data/SimpleTest.LCC.yml, data/simple_mcmc_data_*.npz(.bk) and the
  stray .npz -- these are regenerated test_zeus()/test_lightcone_core
  artifacts, not source data
- core.py: lc.lightcone_distances may be a plain ndarray (already Mpc)
  or an astropy Quantity depending on py21cmfast version; only call
  .to_value() when it's actually a Quantity.
- likelihood.py (LikelihoodLuminosityFunction.computeLikelihood): guard
  against extreme astro params leaving the luminosity function almost
  entirely NaN at a redshift (too few points to build the spline -> was
  crashing with a scipy dfitpack 'm=0' error, uncaught in ultranest's
  vectorized likelihood path) by rejecting the point (-inf) instead.
  Also stop evaluating the spline outside the Muv range the model
  actually covers, since extrapolating it for extreme params can
  over/underflow to +-inf or ~0, producing wildly unstable
  log-likelihoods that were corrupting MultiNest's live-point/output
  handling (malformed floats like '-0.139...-308' in its text output).
@codecov

codecov Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 72.05882% with 38 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@31b6e0e). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/py21cmmc/likelihood.py 68.62% 16 Missing ⚠️
src/py21cmmc/core.py 78.37% 8 Missing ⚠️
src/py21cmmc/mcmc.py 68.42% 6 Missing ⚠️
src/py21cmmc/ensemble.py 28.57% 5 Missing ⚠️
src/py21cmmc/analyse.py 50.00% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #89   +/-   ##
=======================================
  Coverage        ?   73.99%           
=======================================
  Files           ?        8           
  Lines           ?     2123           
  Branches        ?        0           
=======================================
  Hits            ?     1571           
  Misses          ?      552           
  Partials        ?        0           
Flag Coverage Δ
unittests 73.99% <72.05%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…ility

ultranest requires every returned log-likelihood to be finite and aborts
the whole run if it sees -inf/nan (AssertionError: returned non-finite
number). MultiNest can also become numerically unstable and corrupt its
own text output when fed astronomically large-but-finite values (e.g.
from cubic-spline overshoot when fitting an ill-conditioned luminosity
function with few valid points).

Floor LikelihoodLuminosityFunction.computeLikelihood's per-point result to
a large-but-safe finite value (_LOGLIKE_FLOOR = -1e10) instead of -inf in
these cases.

@steven-murray steven-murray left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @DanielaBreitman !!! I have a few small comments then it should be gtg

Comment thread .github/workflows/deploy.yaml Outdated
Comment thread .github/workflows/deploy.yaml Outdated
Comment thread .github/workflows/test_suite.yaml Outdated
Comment thread devel/mwe_memory_leak.py Outdated
Comment thread .gitignore Outdated
Comment thread setup.py Outdated
@steven-murray

Copy link
Copy Markdown
Member

@DanielaBreitman approved but we might have to consider changing the docs build

@DanielaBreitman
DanielaBreitman merged commit aae77e5 into main Sep 24, 2026
11 of 12 checks passed
@DanielaBreitman
DanielaBreitman deleted the uv_migration branch September 24, 2026 08:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: maintenance Infrastructure or maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants