-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: split __init__.py into logical modules #14
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
Changes from all commits
356a419
3d8e1b0
5ff7335
697eede
f01dd78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| """C extension loader with error handling for cfd_python.""" | ||
|
|
||
| import os | ||
|
|
||
| __all__ = ["load_extension", "ExtensionNotBuiltError"] | ||
|
|
||
|
|
||
| class ExtensionNotBuiltError(ImportError): | ||
| """Raised when C extension is not built (development mode).""" | ||
|
|
||
| pass | ||
|
|
||
|
|
||
| def _check_extension_exists() -> bool: | ||
| """Check if compiled extension files exist in package directory.""" | ||
| package_dir = os.path.dirname(__file__) | ||
| return any( | ||
| f.startswith("cfd_python") and (f.endswith(".pyd") or f.endswith(".so")) | ||
| for f in os.listdir(package_dir) | ||
| ) | ||
|
|
||
|
|
||
| def load_extension(): | ||
| """Load the C extension module and return exports. | ||
|
|
||
| Returns: | ||
| tuple: (exports_dict, solver_constants) | ||
|
|
||
| Raises: | ||
| ImportError: If extension exists but fails to load | ||
| ExtensionNotBuiltError: If extension is not built (dev mode) | ||
| """ | ||
| try: | ||
| from . import cfd_python as _cfd_module | ||
| from .cfd_python import ( | ||
| OUTPUT_CSV_CENTERLINE, | ||
| OUTPUT_CSV_STATISTICS, | ||
| OUTPUT_CSV_TIMESERIES, | ||
| OUTPUT_FULL_FIELD, | ||
| OUTPUT_PRESSURE, | ||
| OUTPUT_VELOCITY, | ||
| create_grid, | ||
| get_default_solver_params, | ||
| get_solver_info, | ||
| has_solver, | ||
| list_solvers, | ||
| run_simulation, | ||
| run_simulation_with_params, | ||
| set_output_dir, | ||
| write_csv_timeseries, | ||
| write_vtk_scalar, | ||
| write_vtk_vector, | ||
| ) | ||
|
|
||
| # Collect all exports | ||
| exports = { | ||
| # Simulation functions | ||
| "run_simulation": run_simulation, | ||
| "run_simulation_with_params": run_simulation_with_params, | ||
| "create_grid": create_grid, | ||
| "get_default_solver_params": get_default_solver_params, | ||
| # Solver functions | ||
| "list_solvers": list_solvers, | ||
| "has_solver": has_solver, | ||
| "get_solver_info": get_solver_info, | ||
| # Output functions | ||
| "set_output_dir": set_output_dir, | ||
| "write_vtk_scalar": write_vtk_scalar, | ||
| "write_vtk_vector": write_vtk_vector, | ||
| "write_csv_timeseries": write_csv_timeseries, | ||
| # Output type constants | ||
| "OUTPUT_PRESSURE": OUTPUT_PRESSURE, | ||
| "OUTPUT_VELOCITY": OUTPUT_VELOCITY, | ||
| "OUTPUT_FULL_FIELD": OUTPUT_FULL_FIELD, | ||
| "OUTPUT_CSV_TIMESERIES": OUTPUT_CSV_TIMESERIES, | ||
| "OUTPUT_CSV_CENTERLINE": OUTPUT_CSV_CENTERLINE, | ||
| "OUTPUT_CSV_STATISTICS": OUTPUT_CSV_STATISTICS, | ||
| } | ||
|
|
||
| # Collect dynamic SOLVER_* constants | ||
| solver_constants = {} | ||
| for name in dir(_cfd_module): | ||
| if name.startswith("SOLVER_"): | ||
| solver_constants[name] = getattr(_cfd_module, name) | ||
|
|
||
| return exports, solver_constants | ||
|
|
||
| except ImportError as e: | ||
| if _check_extension_exists(): | ||
| # Extension file exists but failed to load - this is an error | ||
| raise ImportError( | ||
| f"Failed to load cfd_python C extension: {e}\n" | ||
| "The extension file exists but could not be imported. " | ||
| "This may indicate a missing dependency or ABI incompatibility." | ||
| ) from e | ||
| else: | ||
| # Development mode - module not yet built | ||
| raise ExtensionNotBuiltError( | ||
| "C extension not built. Run 'pip install -e .' to build." | ||
| ) from e | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,28 @@ | ||||||||
| """Version detection for cfd_python package.""" | ||||||||
|
|
||||||||
| __all__ = ["get_version"] | ||||||||
|
|
||||||||
|
|
||||||||
| def get_version() -> str: | ||||||||
| """Get package version from metadata or C module.""" | ||||||||
| # Try importlib.metadata first (works when package is installed) | ||||||||
| try: | ||||||||
| from importlib.metadata import PackageNotFoundError, version | ||||||||
|
|
||||||||
| try: | ||||||||
| return version("cfd-python") | ||||||||
| except PackageNotFoundError: | ||||||||
| pass # Package not installed via pip, try C module next | ||||||||
| except ImportError: | ||||||||
|
||||||||
| except ImportError: | |
| except ImportError: | |
| # importlib.metadata not available; fallback to C module version below |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new get_version() function and load_extension() function introduce new behavior and error handling logic but lack direct test coverage. The existing tests in test_import_handling.py and test_module.py test the overall module behavior, but don't test the internal _version.py and _loader.py modules directly.
Consider adding tests that:
- Test
get_version()with mockedimportlib.metadatascenarios - Test
load_extension()directly with mocked extension states - Test
ExtensionNotBuiltErroris raised appropriately - Test
_check_extension_exists()with various file patterns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
load_extension()function and_check_extension_exists()function introduce new error handling logic but lack direct test coverage. Whiletest_import_handling.pytests similar behavior at the module level, these internal functions are not directly tested.Consider adding tests that:
_check_extension_exists()with various directory states (no files, .so files, .pyd files, etc.)load_extension()behavior when extension import succeedsExtensionNotBuiltErroris raised when extension doesn't existImportErroris raised with appropriate message when extension exists but fails to load