Skip to content

[Proposal] Project-wide refactor of relative imports to resolve circular dependencies #756

@adendek

Description

@adendek

Is your feature request related to a problem? Please describe.

While working on the Coverage tests #658 , I discover the following issue. The PINA project currently makes extensive use of deep relative imports (e.g., from ... import, from ..import) across almost all modules. While convenient in small scripts, this has created a highly coupled architecture that triggers ImportError (circular imports) when attempting to implement new features, such as factories.

Describe the solution you'd like
Shift to Absolute Imports Following the Acyclic Dependencies Principle and Python best practices, I propose a project-wide refactor:

Replace Relative with Absolute:

Change all internal imports to use the full path (e.g., from pina.problem import AbstractProblem instead of from ..problem import AbstractProblem).

Define a Clear Hierarchy: Ensure that "low-level" modules (utils, domains, basic equations) never import from "high-level" modules.

Refactor init.py Files: Ensure that package-level init files do not perform "eager" imports of every sub-module, which is often the catalyst for circular loops.

Example of the necessary change: Current (Fragile):

from ... import Condition
from ...equation import FixedValue, Helmholtz
from ...utils import check_consistency
from ...domain import CartesianDomain
from ...problem import SpatialProblem

Proposed (Robust):

from pina.condition import Condition
from pina.equation import FixedValue, Helmholtz
from pina.utils import check_consistency
from pina.domain import CartesianDomain
from pina.problem import SpatialProblem

Describe alternatives you've considered

Implementing a "Private Core" Structure (The JAX Approach) A more robust alternative—and my primary recommendation—is to adopt a project structure similar to JAX.

JAX manages a massive codebase by utilizing a strict separation between internal implementation and the public interface:

The _src pattern: JAX hosts the actual logic in a hidden sub-directory (e.g., jax/_src/). Internal modules within _src can reference each other more freely without polluting the public namespace.

The Interface Layer: The top-level modules (e.g., jax/lax/, jax/numpy/) then import from _src to expose the public API.

How this would look for PINA: We could migrate the core logic to pina/_src/ and use the top-level pina/problem/ or pina/model/ directories purely as clean interfaces. This structure naturally enforces an Acyclic Dependencies Principle because:

High-level modules in pina/ only point "down" into _src.

Absolute imports are used throughout _src to ensure that moving a file doesn't break the entire library.

Circular dependencies become physically harder to create because the "definition" of a class and the "export" of a class live in different layers.

Additional context

Here are the key repositories that follow this exact pattern:

  1. Haiku (dm-haiku)
    Haiku is a great example because it deals with a high number of object-oriented modules (similar to PINA's problems).

The Structure: All the heavy lifting (initializers, modules, state management) is inside haiku/_src/.

The Interface: The top-level haiku/__init__.py and sub-module __init__.py files then selectively import from _src using absolute paths. This prevents circularity because the "public" layer never imports from itself; it only pulls "up" from the private core.

  1. Optax
    Optax is DeepMind's optimization library.

The Structure: Look at optax/_src/. It contains the actual implementations of Adam, RMSProp, and loss functions.

Why they do it: It allows them to maintain a flat, clean API (e.g., optax.adam) while having a deeply nested and organized internal file system.

  1. Chex
    Chex is their library for testing and debugging JAX code.

The Structure: It follows the same chex/_src/ pattern.

The Benefit: Since Chex is a testing utility, it must be extremely stable. The _src pattern ensures that internal refactoring doesn't accidentally break the public-facing testing assertions that thousands of researchers rely on.

Metadata

Metadata

Labels

0.3Related to 0.3 releaseenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions