Skip to content

feat: Initial bulk of type checking + setup#4761

Open
Gobot1234 wants to merge 87 commits intomainfrom
jhilton/typing-improvements
Open

feat: Initial bulk of type checking + setup#4761
Gobot1234 wants to merge 87 commits intomainfrom
jhilton/typing-improvements

Conversation

@Gobot1234
Copy link
Copy Markdown
Collaborator

Context

Duplicate of #4500 but on the ansys remote. Looking at this code more, I realise I've ran pyupgrade on this so don't merge this till I get the rest of the ruff stuff set up. I'm also realising there are 3 issues tied up in this, apologies for that.
Fixes #4489 and fixes #4490
Helps with #4543

Change Summary

Added a bunch of initial types for the public facing library part of #4738

Comment on lines +187 to +200
}
self.argvals, self.new_session = _get_argvals_and_session(argvals)
if self.argvals["start_timeout"] is None:
self.argvals, self.new_session = _get_argvals_and_session(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This was changed as sadly there's no way to type transform a typedict to have optional keys (python isn't typescript, sad)

Comment thread src/ansys/fluent/core/launcher/launcher.py Outdated
Comment thread src/ansys/fluent/core/session_pure_meshing.py
Comment thread src/ansys/fluent/core/session_solver.py Outdated
@Gobot1234
Copy link
Copy Markdown
Collaborator Author

I'll try and get to the conflicts soonish, probably more useful to get the ruff changes in first

@github-actions github-actions Bot added documentation Documentation related (improving, adding, etc) examples Publishing PyFluent examples maintenance General maintenance of the repo (libraries, cicd, etc) dependencies Related to dependencies labels Jan 15, 2026
Comment thread src/ansys/fluent/core/launcher/slurm_launcher.py Outdated
@Gobot1234 Gobot1234 marked this pull request as ready for review January 15, 2026 03:19
Copilot AI review requested due to automatic review settings January 15, 2026 03:19
Copilot AI review requested due to automatic review settings March 23, 2026 14:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 94 out of 96 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

src/ansys/fluent/core/services/_protocols.py:38

  • ServiceProtocol currently defines an __init__(channel, metadata) signature (under TYPE_CHECKING), but many concrete service classes inheriting it require additional constructor parameters (for example fluent_error_state). Type checkers typically treat protocol inheritance like normal inheritance for signature compatibility, so this is likely to introduce a large number of incompatible-override errors (and StreamingService also doesn’t match channel/metadata). Consider removing __init__ from the protocol entirely, or widening it to accept *args, **kwargs (or adding overloads) so all service implementations can conform.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"VectorFieldDataRequest",
)

_to_field_name_str = naming_strategy().to_string
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

_to_field_name_str is assigned twice in a row; the first assignment is immediately overwritten. This is dead code and can confuse readers about which naming strategy instance is intended. Consider keeping only one assignment (either create a single _naming_strategy_instance and derive _to_field_name_str from it, or inline the call once).

Suggested change
_to_field_name_str = naming_strategy().to_string

Copilot uses AI. Check for mistakes.
Comment on lines 173 to 177
api_tree_data_file_path = _get_api_tree_data_file_path()
if api_tree_data_file_path.exists():
json_file = open(api_tree_data_file_path, "r")
json_file = open(api_tree_data_file_path)
api_tree_data = json.load(json_file)
return api_tree_data
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

_get_api_tree_data() opens the JSON file without a context manager, so the file handle may remain open until GC. Use with open(...) as f: (or explicitly close the file) to avoid leaking file descriptors, especially since this function is cached and could be called in long-lived processes.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to 32
from ansys.fluent.core.module_config import *

# Logging has to be imported before importing other PyFluent modules
from ansys.fluent.core.logger import set_console_logging_level # noqa: F401
from ansys.fluent.core.logger import *

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

Using from ... import * in the package ansys.fluent.core.__init__ makes the exported namespace depend entirely on each submodule’s __all__ and also stops submodules themselves (e.g., module_config, logger, services, etc.) from being exposed as attributes unless they’re explicitly imported as modules. This conflicts with the public API expectations in tests/test_public_api.py (it expects many submodules to be present in dir(ansys.fluent.core)) and is likely to cause API regressions. Consider switching back to explicit imports/aliases for public symbols and explicitly importing the intended public submodules (or defining a package-level __all__) instead of wildcard imports.

Copilot uses AI. Check for mistakes.
Comment thread tests/test_public_api.py
Comment on lines +93 to +110
"data_model_cache",
"docker",
"examples",
"exceptions",
"field_data_interfaces",
"filereader",
"fluent_connection",
"generated",
"get_build_details",
"get_build_version",
"get_build_version_string",
"journaling",
"launch_fluent",
"launcher",
"logger",
"module_config",
"parametric",
"pyfluent_warnings",
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

This test assumes many submodules (e.g., docker, exceptions, module_config, logger, etc.) are present in dir(ansys.fluent.core), but the updated ansys.fluent.core.__init__ now mainly does wildcard imports of selected symbols and does not import most submodules as module attributes. As written, this will likely report a large set of “missing symbols” even if the submodules still exist as importable packages. Consider either (1) explicitly importing/exposing those submodules in ansys.fluent.core.__init__, or (2) changing this test to validate importability via importlib.import_module('ansys.fluent.core.<name>') rather than relying on dir().

Copilot uses AI. Check for mistakes.
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 2, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copilot AI review requested due to automatic review settings April 2, 2026 15:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 94 out of 96 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

src/ansys/fluent/core/launcher/launcher.py:125

  • The create_launcher docstring says it raises ValueError for an unknown launch mode, but the implementation raises DisallowedValuesError. Please align the docstring (or change the exception type) so user-facing docs and behavior match.
    Raises
    ------
    ValueError
        If an unknown Fluent launch mode is passed.
    """
    launchers = {
        LaunchMode.STANDALONE: StandaloneLauncher,
        LaunchMode.CONTAINER: DockerLauncher,
        LaunchMode.PIM: PIMLauncher,
        LaunchMode.SLURM: SlurmLauncher,
    }

    if fluent_launch_mode in launchers:
        return launchers[fluent_launch_mode](**kwargs)
    else:
        raise DisallowedValuesError(
            "launch mode",
            fluent_launch_mode,
            [f"LaunchMode.{m.name}" for m in LaunchMode],
        )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 507 to 510
zones_svar_data = dict[Any, npt.NDArray[Any] | None]()
for array in solution_variables_data:
if array.WhichOneof("array") == "payloadInfo":
zones_svar_data[array.payloadInfo.zone] = _extract_svar(
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

dict[Any, ...]() attempts to call a parameterized generic alias and will raise TypeError: 'types.GenericAlias' object is not callable at runtime. Initialize with {} (or dict()) and keep the type via a variable annotation instead.

Copilot uses AI. Check for mistakes.
Comment on lines 1172 to 1175
return field_arr

fields_data = {}
fields_data = dict[Any, dict[str, npt.NDArray[Any]]]()
for chunk in chunk_iterator:
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

dict[Any, ...]() is a parameterized generic alias and is not callable at runtime (TypeError). Use {}/dict() and annotate the variable type separately.

Copilot uses AI. Check for mistakes.
Comment on lines +399 to 409
def _get_argvals_and_session(
argvals: LauncherArgsT,
) -> tuple[
LauncherArgsT, type["Meshing | PureMeshing | Solver | SolverIcing | SolverAero"]
]:
_validate_gpu(argvals.get("gpu"), argvals.get("dimension"))
argvals["graphics_driver"] = _get_graphics_driver(
argvals["graphics_driver"], argvals["ui_mode"]
argvals.get("graphics_driver"), argvals.get("ui_mode")
)
argvals["mode"] = FluentMode(argvals["mode"])
del argvals["self"]
argvals["mode"] = FluentMode(argvals.get("mode"))
new_session = argvals["mode"].get_fluent_value()
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

_get_argvals_and_session calls _validate_gpu(argvals.get('gpu'), argvals.get('dimension')), but when launchers are constructed from **kwargs (e.g., SessionBase.from_install()), dimension may be absent/None. Dimension(dimension) will raise ValueError in that case. Consider defaulting/normalizing required values (dimension, precision, ui_mode, etc.) inside _get_argvals_and_session (or before calling it) so callers can omit them safely.

Copilot uses AI. Check for mistakes.
Comment on lines 172 to 177
"""Get API tree data."""
api_tree_data_file_path = _get_api_tree_data_file_path()
if api_tree_data_file_path.exists():
json_file = open(api_tree_data_file_path, "r")
json_file = open(api_tree_data_file_path)
api_tree_data = json.load(json_file)
return api_tree_data
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

open(api_tree_data_file_path) is not closed, which can leak file descriptors. Use a context manager (with open(...) as f:) when loading the JSON.

Copilot uses AI. Check for mistakes.
"VectorFieldDataRequest",
)

_to_field_name_str = naming_strategy().to_string
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

_to_field_name_str is assigned twice in a row; the first assignment is immediately overwritten. Remove the redundant assignment to avoid confusion.

Suggested change
_to_field_name_str = naming_strategy().to_string

Copilot uses AI. Check for mistakes.
Comment on lines +333 to +340
def _get_nodes(self, surface_id: int) -> tuple[npt.NDArray[np.uint32], np.int16]:
min_id, max_id = self.get_surface_locs(surface_id)
nnodes = self._file_handle["meshes"]["1"]["faces"]["nodes"]["1"]["nnodes"]
nodes = self._file_handle["meshes"]["1"]["faces"]["nodes"]["1"]["nodes"]
previous = np.sum(nnodes[0:min_id])
nnodes = nnodes[min_id : max_id + 1]
nodes = nodes[previous : previous + np.sum(nnodes)]
return [nodes, nnodes]
return (nodes, nnodes)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

_get_nodes returns (nodes, nnodes) where both values are array-like slices, but the return type annotates nnodes as np.int16 (a scalar). This should be an ndarray type (e.g., npt.NDArray[np.integer[Any]] or similar) to match the returned value.

Copilot uses AI. Check for mistakes.
- Add .ci/pylock.toml (PEP 751 format) with ci_types extras pinned
- Ensures consistent package versions across local and CI environments
- Update basedpyright baseline with locked dependencies
- CI workflow now uses 'uv pip sync .ci/pylock.toml' for reproducible type checking
Copilot AI review requested due to automatic review settings April 7, 2026 17:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 94 out of 97 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

src/ansys/fluent/core/launcher/container_launcher.py:285

  • DockerLauncher.__call__ is annotated to return only session types, but it returns config_dict (a dict) when dry_run is true. Either include the dict in the return annotation (and propagate that to launch_fluent) or refactor dry-run handling so the annotation matches behavior.
    def __call__(self) -> "Meshing | PureMeshing | Solver | SolverIcing | SolverAero":
        if self.argvals["dry_run"]:
            config_dict, *_ = configure_container_dict(
                self._args,
                compose_config=self._compose_config,
                **self.argvals["container_dict"],
            )
            dict_str = dict_to_str(config_dict)
            print("\nDocker container run configuration:\n")
            print("config_dict = ")
            print(dict_str)
            return config_dict

src/ansys/fluent/core/services/_protocols.py:38

  • ServiceProtocol's __init__ only allows (channel, metadata), but many service classes in this PR require additional required parameters (for example fluent_error_state). This makes the protocol inaccurate and can trigger incompatible override / structural typing issues. Consider widening __init__ to accept *args, **kwargs (or using a ParamSpec-based protocol / removing __init__ from the protocol) so it matches all service constructors used by FluentConnection.create_grpc_service.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 173 to 177
api_tree_data_file_path = _get_api_tree_data_file_path()
if api_tree_data_file_path.exists():
json_file = open(api_tree_data_file_path, "r")
json_file = open(api_tree_data_file_path)
api_tree_data = json.load(json_file)
return api_tree_data
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

_get_api_tree_data() opens the JSON file without a context manager, so the file handle is never closed. Use a with open(...) as f: block (or Path.read_text()/json.loads) to avoid leaking descriptors.

Copilot uses AI. Check for mistakes.
Comment on lines +348 to +352
) -> (
Meshing
| PureMeshing
| Solver
| SolverIcing
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The declared return type for launch_fluent is missing the container dry-run return (dict from DockerLauncher.__call__), so the annotation disagrees with runtime behavior. Update the union return type accordingly (and keep it consistent with the overloads).

Copilot uses AI. Check for mistakes.
"""Working directory for the Fluent client."""
fluent_path: str | None
"""User provided Fluent installation path."""
topy: str | list[Any] | None
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

LaunchFluentArgs.topy (and the launch_fluent parameter) is typed as str | list[Any] | None, but _build_journal_argument expects None | bool | str and treats non-str truthy values as the -topy flag. Consider changing the type to bool | str | None (and aligning all TypedDicts/launchers) to reflect actual supported inputs and avoid type-checker confusion.

Suggested change
topy: str | list[Any] | None
topy: bool | str | None

Copilot uses AI. Check for mistakes.
@seanpearsonuk seanpearsonuk self-requested a review April 28, 2026 16:51
Copy link
Copy Markdown
Collaborator

@seanpearsonuk seanpearsonuk left a comment

Choose a reason for hiding this comment

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

@prmukherj Someone in the team ought to check each of the Copilot comments. @Gobot1234 might not have time to go through them all.

cc: @mkundu1

@mkundu1
Copy link
Copy Markdown
Contributor

mkundu1 commented Apr 29, 2026

@copilot Please open a github issue by listing all copilot suggestions at the latest revision of the branch.

Copilot AI review requested due to automatic review settings April 29, 2026 19:57
auto-merge was automatically disabled April 29, 2026 19:57

Head branch was pushed to by a user without write access

@Gobot1234 Gobot1234 review requested due to automatic review settings April 29, 2026 19:57
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 29, 2026

@copilot Please open a github issue by listing all copilot suggestions at the latest revision of the branch.

I don't have the ability to create GitHub issues directly, but I've addressed all actionable Copilot suggestions in commit 66d4c68. Here's a summary of all suggestions from the latest revision that could be tracked as future issues:

Fixed in 66d4c68:

  1. search.py:173-177_get_api_tree_data() opened JSON file without a context manager (file descriptor leak)
  2. field_data_interfaces.py:48_to_field_name_str was assigned twice; first assignment was dead code
  3. services/solution_variables.py:507dict[Any, ...]() is not callable at runtime; fixed to dict: annotation = {}
  4. services/field_data.py:1174 – Same invalid dict[Any, ...]() pattern; fixed to dict: annotation = {}
  5. launcher/container_launcher.py:273DockerLauncher.__call__ missing dict[str, Any] return type for dry-run path
  6. launcher/launcher.py:286dry_run=True overload claimed tuple[str, str] but container dry-run returns dict; updated to tuple[str, str] | dict[str, Any]
  7. launcher/launcher.py:528cast() excluded container dry-run dict return; updated to include dict[str, Any]
  8. launcher/launcher.py:197topy typed as str | list[Any] | None; corrected to bool | str | None
  9. module_config.py:354-363inspect.getmembers_static is Python 3.11+; added version guard with fallback to inspect.getmembers

Remaining open items (not yet addressed, suitable for a GitHub issue):

  • launcher/launcher.py:366 – Docstring "Returns" section says "configuration dictionary" but should say tuple[str, str] | dict[str, Any] for dry_run=True
  • launcher/launch_options.py:399-409_get_argvals_and_session may receive dimension=None from certain callers, causing ValueError in _validate_gpu
  • filereader/case_file.py:333-340_get_nodes annotates nnodes as np.int16 but returns an ndarray slice
  • __init__.py:28-32 – Wildcard imports may hide submodules from dir(), breaking test_public_api.py
  • tests/test_public_api.py:93-110 – Test relies on submodules being in dir(ansys.fluent.core) but wildcard imports don't guarantee that

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

Labels

CI/CD dependencies Related to dependencies documentation Documentation related (improving, adding, etc) examples Publishing PyFluent examples maintenance General maintenance of the repo (libraries, cicd, etc) new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid having default None where a more informative default can be provided Make launch/connect_to_fluent and kwarg only

8 participants