Skip to content

Conversation

@aman-coder03
Copy link

@aman-coder03 aman-coder03 commented Dec 3, 2025

this PR addresses issue #7972 by consolidating the typing of coords across the PyMC codebase.

Previously, coords appeared with a mix of types such as:

  • Sequence
  • Sequence | np.ndarray
  • dict[str, Any]

this PR introduces explicit and consistent type aliases:

  • CoordValue
  • Coords
  • StrongCoordValue
  • StrongCoords

(similar to the existing Shape, Dims, and StrongDims aliases in shape_utils)

Key changes

  • standardizes Model.coords to return StrongCoords
  • updates ArviZ conversion to return StrongCoords instead of dict[str, Any}
  • removes the mixed use of Sequence, Sequence | np.ndarray, and untyped dictionaries
  • improves static typing and downstream library compatibility

Notes

while testing this change, a runtime circular import involving:
pymc.model.core
pymc.distributions.shape_utils
from pymc.model import modelcontext
pymc.model (partially initialized)
was encountered.

Fixes #7972

Comment on lines 188 to 192
# Lazy import to break circular dependency
if model is None:
from pymc.model.core import modelcontext

model = modelcontext(None)
Copy link
Member

Choose a reason for hiding this comment

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

Why this functional change? Doesn't seem necessary or a good idea

Copy link
Author

Choose a reason for hiding this comment

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

i introduced the lazy import only to work around the circular import that surfaced during the typing consolidation (shape_utils -> model -> distributions -> shape_utils). I agree that changing runtime behavior here is not ideal
if you prefer, i can revert this functional change and instead resolve the circular dependency purely by relocating the typing aliases to a more independent module

Comment on lines 100 to 104
CoordValue: TypeAlias = Sequence[Hashable] | np.ndarray | None
Coords: TypeAlias = Mapping[str, CoordValue]

StrongCoordValue: TypeAlias = tuple[Hashable, ...] | None
StrongCoords: TypeAlias = Mapping[str, StrongCoordValue]
Copy link
Member

Choose a reason for hiding this comment

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

Put these in a more independent place to avoid the new circular import issues. Coordinates are not really distribution specific anyway

Copy link
Author

Choose a reason for hiding this comment

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

i can move CoordValue, Coords, StrongCoordValue, and StrongCoords to a more independent location and update downstream imports accordingly. Let me know if you have a preferred target module for these.

@aman-coder03
Copy link
Author

@ricardoV94 it would be really helpful if you could review the changes!

@ricardoV94
Copy link
Member

ricardoV94 commented Dec 6, 2025

I'll ping some folks who are bigger fans of type-hints than me for review.

A whole new file seems a bit cluttering, although it could be useful to move more things in the future. My gut feeling would be to just throw this into one of the utils.py files for now.

@aman-coder03
Copy link
Author

@ricardoV94 Thanks for the feedback!! I have implemented the changes!!

@williambdean
Copy link
Contributor

williambdean commented Dec 6, 2025

Thoughts on a pymc.typing module?

from pymc.typing import Coords
import pymc as pm


coords: Coords = {"covariate": ["A", "B", "C"]}
model = pm.Model(coords=coords)

Or directly from pm

Seems out of place in the utils module.

@ricardoV94
Copy link
Member

What would go in it? If it's just a handful doesn't seem worth it

@codecov
Copy link

codecov bot commented Dec 6, 2025

Codecov Report

❌ Patch coverage is 97.95918% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.50%. Comparing base (87f80f9) to head (27b010d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pymc/distributions/shape_utils.py 93.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #7987   +/-   ##
=======================================
  Coverage   91.49%   91.50%           
=======================================
  Files         116      116           
  Lines       18963    18992   +29     
=======================================
+ Hits        17350    17378   +28     
- Misses       1613     1614    +1     
Files with missing lines Coverage Δ
pymc/backends/arviz.py 96.09% <100.00%> (+0.04%) ⬆️
pymc/model/core.py 93.30% <100.00%> (ø)
pymc/printing.py 87.66% <100.00%> (+0.16%) ⬆️
pymc/step_methods/state.py 95.52% <100.00%> (ø)
pymc/util.py 82.18% <100.00%> (+1.07%) ⬆️
pymc/distributions/shape_utils.py 91.41% <93.33%> (-0.47%) ⬇️

... and 1 file with indirect coverage changes

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

@aman-coder03
Copy link
Author

Thanks for the feedback! @ricardoV94 @williambdean

Right now it’s just the coord/shape aliases (Coords, CoordValue, StrongCoords, etc.).
So I agree it might feel too small to justify a standalone pymc.typing module at the moment.

Reason for grouping them was:
They do not really fit semantically into util.py
They are used across several modules (model, backends, shape_utils)
A dedicated namespace keeps things cleaner as more typing-related additions come in later

But I'm also happy to keep everything inside pymc.util
Let me know which direction you would like, and I will update the PR accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consolidate typing for coords

3 participants