Skip to content

Conversation

@FBumann
Copy link
Member

@FBumann FBumann commented Nov 15, 2025

Description

Renaming some parameters in linear_converters.py

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Code refactoring

Related Issues

Closes #(issue number)

Testing

  • I have tested my changes
  • Existing tests still pass

Checklist

  • My code follows the project style
  • I have updated documentation if needed
  • I have added tests for new functionality (if applicable)

Summary by CodeRabbit

  • Refactor

    • Streamlined type system with new dimension-aware type aliases (Numeric_TPS, Numeric_PS, Bool_TPS, etc.) for clearer, more consistent type hints throughout the library.
    • Renamed component parameters in linear converters (e.g., Q_fufuel_flow, Q_ththermal_flow, P_elpower_flow) with backward compatibility maintained.
  • Documentation

    • Enhanced type annotations across all public APIs for improved IDE support and type checking.

FBumann and others added 30 commits November 4, 2025 12:14
* Add truncation to repr of containers

* Add truncation to results.py

* Changes Made

  1. ContainerMixin in structure.py

  - Changed truncate_repr from bool to int | None
  - None = show all items (no truncation)
  - Integer value = maximum number of items to show in repr
  - Default is None (no truncation)

  2. Updated _get_repr() method

  - Simplified parameters from (truncate: bool, max_items: int) to just (max_items: int | None)
  - Uses instance's _truncate_repr as default if max_items is not provided
  - Cleaner logic: truncates only when limit is not None and limit > 0

  3. Updated __repr__() method

  - Now simply calls self._get_repr() without arguments
  - Respects the instance's truncate_repr setting

  4. Simplified _format_grouped_containers()

  - Removed the conditional logic checking for _truncate_repr
  - Now just calls repr(container) which automatically respects each container's setting

  5. Updated all call sites

  - flow_system.py: Changed truncate_repr=True → truncate_repr=10 (4 locations)
  - results.py: Changed truncate_repr=True → truncate_repr=10 (4 locations)
  - effects.py: Changed truncate_repr: bool = False → truncate_repr: int | None = None and added docstring

* Update CHANGELOG.md
* Resample a single concatenated dataarray instead of a Dataset

* Performance improvements

* Use helper method for resampling speed up resampling

* Improve docstring

* Improve docstring

* avoiding attribute conflicts and empty merge errors

* moving method validation earlier for fail-fast behavior

* Update CHANGELOG.md

* Add new combined select and resample method

* Remove code duplication

* Add benchmark

* Improve becnhmark

* Improve becnhmark

* Add power user chaining options

* Remove becnhmark

* Use dask chunking in resample

* Make the new methods class methods

* Update benchmark_bottleneck.py

* Use dataframe based approach

* registry pattern

* registry pattern

* Improve benchmark

* Benchmark datarray version

* Use dataarray conversion before resampling

* Benchmark dask speedup

* Add dask chunking

* Remove dask chunking due to negligible improvements

* Remove benchmark_bottleneck.py

* Update CHANGELOG.md

* Make ._dataset_... methods self contained, handling time index stuff directly

* Use helper method

* further deduplication and consistency improvements

* improve docstrings

* ruff format

* fixed the metadata preservation issue in flow_system.py:352-369

* Typo

* Add test

* Speed up tests

* ruff format

* Improve tests

* Linting fixes

* Fix tests
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

This PR introduces a centralized type system module (flixopt/types.py) with dimension-aware type aliases and systematically refactors type annotations across the codebase, replacing legacy domain-specific types with Numeric_TPS, Numeric_PS, Numeric_S, Bool_TPS, Bool_PS, Bool_S, Effect_TPS, Effect_PS, Effect_S, and NumericOrBool. Component and parameter class signatures are updated to use these new types, and linear converters are renamed with backward compatibility via deprecation handling.

Changes

Cohort / File(s) Change Summary
New Type System Module
flixopt/types.py
Created new module defining dimension-aware type aliases: Numeric_TPS, Numeric_PS, Numeric_S, Bool_TPS, Bool_PS, Bool_S, Effect_TPS, Effect_PS, Effect_S, Scalar, NumericOrBool with public __all__ export.
Public API Type Exports
flixopt/__init__.py
Added imports of new type aliases (Bool_PS, Bool_S, Bool_TPS, Effect_PS, Effect_S, Effect_TPS, Numeric_PS, Numeric_S, Numeric_TPS, Scalar) from flixopt.types to public surface.
Core Type System Updates
flixopt/core.py
Replaced inline type unions with NumericOrBool alias in DataConverter.to_dataarray signatures; removed legacy public aliases (TemporalDataUser, TemporalData, NonTemporalDataUser, NonTemporalData).
Effect Type Modernization
flixopt/effects.py
Replaced historical effect aliases (TemporalEffectsUser, PeriodicEffectsUser, TemporalEffects, PeriodicEffects) with Effect_TPS, Effect_PS, Effect_S across Effect and EffectCollection class signatures and internals.
Component Type Updates
flixopt/components.py
Updated LinearConverter.conversion_factors to Numeric_TPS, Storage capacity and charge-state parameters to Numeric_PS/Numeric_TPS, and Transmission losses to Numeric_TPS; changed _absolute_charge_state_bounds return from TemporalData to xr.DataArray.
Flow & Bus Type Refactoring
flixopt/elements.py
Updated Flow constructor (size→Numeric_PS, bounds→Numeric_TPS, effects→Effect_TPS), Bus.excess_penalty_per_flow_hour to Numeric_TPS; changed bounds/previous-state property return types from TemporalData to xr.DataArray.
Feature Parameter Types
flixopt/features.py
Updated OnOffModel.previous_states to Numeric_TPS and ShareAllocationModel bounds to Numeric_PS/Numeric_TPS.
Interface Parameter Classes
flixopt/interface.py
Refactored Piece, InvestParameters, and OnOffParameters constructor signatures to use Numeric_PS, Numeric_TPS, Effect_PS, Effect_TPS instead of legacy temporal/periodic types; updated property return types.
Flow System Type Simplification
flixopt/flow_system.py
Simplified public exports (removed periodic/temporal variants); updated FlowSystem.__init__ weights, fit_to_model_coords, and fit_effects_to_model_coords to use Numeric_PS, NumericOrBool, Effect_TPS with return type xr.DataArray or Effect_TPS.
Data Conversion Type Refinement
flixopt/io.py, flixopt/modeling.py
Updated numeric_to_str_for_repr to use Numeric_TPS parameter; replaced TemporalData with xr.DataArray in modeling utility function signatures across compute_consecutive_hours_in_state, bounds, and duration tracking.
Calculation Result Type
flixopt/calculation.py
Changed Calculation.main_results return type from dict[str, Scalar | dict] to dict[str, int | float | dict]; removed Scalar from public imports.
Linear Converter Refactoring
flixopt/linear_converters.py
Renamed attributes in Boiler (Q_fu→fuel_flow, Q_th→thermal_flow, eta→eta), Power2Heat (eta→cop, P_el→power_flow), HeatPump (COP→cop), CoolingTower, CHP, and HeatPumpWithSource with deprecation handling via _handle_deprecated_kwarg and _validate_kwargs; updated type annotations to Numeric_TPS and added **kwargs for backward compatibility.

Sequence Diagram

sequenceDiagram
    autonumber
    actor User
    participant LegacyCode as Legacy Parameter<br/>(e.g., Q_fu, COP)
    participant Converter as LinearConverter<br/>Constructor
    participant DepHandler as Deprecation<br/>Handler
    participant NewField as New Field<br/>(e.g., fuel_flow, cop)

    User->>Converter: __init__(..., Q_fu=value, COP=123, **kwargs)
    Converter->>DepHandler: _handle_deprecated_kwarg('Q_fu', Q_fu)
    DepHandler-->>Converter: mapped_value for fuel_flow
    Converter->>DepHandler: _validate_kwargs(**kwargs)
    alt kwargs contains legacy names
        DepHandler-->>Converter: log deprecation warning
    end
    Converter->>NewField: Initialize fuel_flow, cop<br/>with mapped/new values
    Converter-->>User: Instance created (working)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring extra attention:

  • flixopt/linear_converters.py: Deprecation pathway implementation across six converter classes; verify _handle_deprecated_kwarg and _validate_kwargs logic correctly maps legacy parameters to new attributes and preserves backward compatibility.
  • flixopt/components.py: Comprehensive type updates to Storage charge-state and LinearConverter parameters; ensure Numeric_PS/Numeric_TPS distinctions (period vs. temporal) are correctly applied.
  • flixopt/interface.py: InvestParameters and OnOffParameters internal field initialization (effects stored as {} by default); verify type consistency with new union signatures and deprecation property logic.
  • flixopt/effects.py: Replacement of legacy effect-domain aliases with new Effect_TPS/Effect_PS/Effect_S; cross-reference with create_effect_values_dict signature changes to ensure effect value mapping logic is preserved.
  • flixopt/modeling.py: Systematic replacement of TemporalData with xr.DataArray in bounds and duration-tracking function signatures; confirm no type-narrowing side effects on downstream modeling logic.

Possibly related PRs

  • PR #348: Directly related — both introduce and switch to dimension-aware type aliases (Numeric_*, Effect_*, Scalar, NumericOrBool) and update public signatures across many overlapping modules (effects, components, core, interface).
  • PR #370: Both refactor public typing and API names across the same modules (effects, core, flow_system, calculation, components), touching identical symbols and class signatures.
  • PR #356: Related at the DataConverter level — both modify to_dataarray API and typing; the main PR introduces NumericOrBool while retrieved PR adds bool support to the converter.

Poem

🐰 A rabbit hops through types so bright,
From Temporal to Numeric light,
With Numeric_TPS now in place,
Dimensions dance with data's grace—
Old names retire with gentle cheer,
As cleaner types make goals appear! 🎯

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description provides minimal detail about the changes. While it mentions parameter renaming in linear_converters.py, it lacks specifics about which parameters changed, why the changes matter, and doesn't adequately address the extensive type system changes across multiple files. Expand the description to detail specific parameter renamings, explain the rationale for the new type system (Bool_PS, Numeric_TPS, etc.), and summarize changes across all modified files like init.py, core.py, effects.py, and components.py.
Docstring Coverage ⚠️ Warning Docstring coverage is 41.51% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Feature/parameter renames' is vague and generic, using non-descriptive phrasing that doesn't clarify which parameters are being renamed or why. Consider using a more specific title like 'Rename linear converter parameters (eta→cop, Q_fu→fuel_flow)' to clearly convey the main changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/parameter-renames

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
flixopt/interface.py (1)

1-1344: PR description doesn't match the actual changes.

The PR title mentions "parameter renames" and the description says "Renaming some parameters in linear_converters.py", but the actual changes in this file (and modeling.py) constitute a comprehensive type system refactoring across the codebase. The changes involve:

  1. Introducing new type aliases (Numeric_TPS, Numeric_PS, Effect_TPS, Effect_PS)
  2. Updating type annotations across multiple public APIs
  3. Changing default values from None to {} for several parameters
  4. No changes to linear_converters.py are visible in the provided files

This is much more significant than "renaming some parameters" and represents a breaking change to the public API. Please update the PR description to accurately reflect the scope of changes.

🧹 Nitpick comments (11)
flixopt/features.py (2)

151-158: previous_states type hint is broader than what get_previous actually supports*

previous_states is now annotated as Numeric_TPS | None, but _get_previous_on_duration and _get_previous_off_duration assume an xr.DataArray-like object (they call .isel and rely on array arithmetic). Passing other Numeric_TPS-compatible types (e.g. np.ndarray, pd.Series, pd.DataFrame) would not satisfy those assumptions.

Consider either:

  • Narrowing the annotation to xr.DataArray | None (under TYPE_CHECKING), or
  • Converting previous_states to a DataArray in __init__ (e.g. via your existing conversion utilities), so the broader Numeric_TPS type remains correct.

This keeps the public type surface honest about what is actually supported at runtime.

Also applies to: 307-321


515-542: Align ShareAllocationModel Numeric_ hints with supported runtime containers*

The constructor now types total_max/total_min as Numeric_PS | None and max_per_hour/min_per_hour as Numeric_TPS | None, which (per flixopt.types) includes scalars, np.ndarray, pd.Series, pd.DataFrame, and xr.DataArray. In _do_modeling these are then used directly in arithmetic with np.inf and self._model.hours_per_step (an xr.DataArray) and passed as bounds into add_variables.

To avoid surprising behavior for callers passing, say, pd.Series/pd.DataFrame, it may be worth either:

  • Narrowing these annotations to the containers you know behave correctly here (e.g. Scalar | xr.DataArray-like), or
  • Normalizing them up front (e.g. via your central converter) so _total_* and _max/_min_per_hour are guaranteed to be xr.DataArray or scalars when used in the arithmetic.

That would keep the new Numeric_* aliases consistent with the actual expectations of this feature model.

Also applies to: 558-570

flixopt/types.py (1)

1-112: Type alias design is coherent; consider clarifying NumericOrBool’s public/internal status

The _Numeric / _Bool / _Effect bases and the _TPS / _PS / _S suffixed aliases are well structured and align with how other modules use them. The docstring also sets clear expectations about “max dimensions” vs. actual FlowSystem dims.

One small polish point: NumericOrBool is exported via __all__ but the docstring calls it “for internal utilities”. If you intend it to be internal-only, consider omitting it from __all__; if it should be public, rephrase the docstring to avoid implying it’s internal-only.

flixopt/effects.py (1)

489-524: Slight type-hint mismatch in create_effect_values_dict helper

The runtime behavior is fine—get_effect_label correctly handles Effect instances, None (mapping to standard_effect), and strings—but the signature def get_effect_label(eff: Effect | str) -> str: doesn’t include None even though it’s supported. Consider widening it to Effect | str | None (and, if you care about static checking, reflecting the same in the Effect_TPS key type) to keep the annotations aligned with the actual behavior.

flixopt/linear_converters.py (6)

24-113: Boiler: parameter renames and efficiency encoding are correct, but flows could be validated

The mapping from eta, fuel_flow, and thermal_flow into conversion_factors = [{fuel: eta, thermal: 1}] is consistent with the intended thermal_flow = fuel_flow × eta relation and with LinearConverterModel’s constraint construction. Deprecation handling for Q_fu/Q_th via _handle_deprecated_kwarg is also in line with the shared pattern and will catch conflicting usage.

You might want to add an explicit check that fuel_flow and thermal_flow are not None after deprecation handling so users who forget to pass them get a clear ValueError instead of later attribute errors in Component._connect_flows.


115-209: Power2Heat: renamed flows and eta handling align with existing semantics

eta is correctly bounded via check_bounds and encoded as conversion_factors = [{power: eta, thermal: 1}], matching the documented thermal_flow = power_flow × eta relationship. Backward compatibility for P_el and Q_th is handled cleanly through _handle_deprecated_kwarg + _validate_kwargs. As with Boiler, a shallow post-init check that power_flow and thermal_flow are non-None would improve error messages for misconfigured instances.


211-306: HeatPump: COP mapping and deprecation handling are sound

The cop property correctly drives conversion_factors = [{power: cop, thermal: 1}], giving thermal_flow = power_flow × cop as intended. The deprecation mapping for COP, P_el, and Q_th is handled via _handle_deprecated_kwarg, and _validate_kwargs will reject unexpected kwargs.

Semantically this matches the linear-converter model; no functional issues spotted. Same minor suggestion as above: reject missing power_flow/thermal_flow early with a targeted exception instead of relying on later attribute errors.


308-403: CoolingTower: conversion factor sign convention matches the documented relation

Encoding specific_electricity_demand as conversion_factors = [{power: -1, thermal: value}] yields the constraint -power + value×thermal = 0, i.e. power_flow = thermal_flow × specific_electricity_demand, which matches the docstring. specific_electricity_demand is checked with check_bounds(..., 0, 1), which is appropriate for a fractional auxiliary demand.

Same as for other converters, consider validating that both power_flow and thermal_flow are non-None right in __init__ for better error messages.


405-533: CHP: dual-efficiency setup and degrees of freedom are encoded correctly

The two conversion-factor entries

  • [{fuel: eta_th, thermal: 1}, ...]
  • [..., {fuel: eta_el, power: 1}]

produce thermal_flow = fuel_flow × eta_th and power_flow = fuel_flow × eta_el under LinearConverterModel, matching the documented relationships. The guards in the setters plus check_bounds(eta_th), check_bounds(eta_el), and the aggregate check on eta_th + eta_el are consistent with the “total efficiency ≤ 1” requirement (albeit enforced via warnings for boundary violations).

No correctness issues seen; flows are again effectively required in practice, so adding explicit None checks after deprecation handling would improve robustness and diagnostics.


535-648: HeatPumpWithSource: COP > 1 enforcement and conversion factors look correct

The cop setter:

  • Uses check_bounds(value, 'cop', ..., 1, 20) to warn about out-of-range values.
  • Explicitly raises a ValueError when any entry is <= 1, ensuring you don’t hit the singularity in value / (value - 1).
  • Encodes conversion factors as:
    • {power: cop, thermal: 1}thermal_flow = power_flow × cop
    • {heat_source: cop/(cop-1), thermal: 1}thermal_flow = heat_source_flow × cop/(cop-1), equivalent to the documented heat_source_flow = thermal_flow × (COP-1)/COP.

This aligns with the energy-balance relationships described in the docstring. Again, checking for None flows (power_flow, heat_source_flow, thermal_flow) early would make misconfigurations fail fast with clearer messages.

flixopt/elements.py (1)

730-757: absolute_flow_rate_bounds type hint is stricter than its actual return type

The property is annotated as tuple[xr.DataArray, xr.DataArray], but for flows with on/off behavior and no mandatory investment the lower bound remains the scalar 0 (it’s never multiplied by a size), while the upper bound is an xr.DataArray. This is fine for linopy (scalar bounds are broadcast), but it contradicts the annotation and may confuse type checkers.

Consider normalizing lb to a DataArray in those cases, e.g.:

-        lb = 0
+        lb: xr.DataArray | int = 0
         if not self.with_on_off:
             ...
-        if self.with_investment:
-            ub = ub_relative * self.element.size.maximum_or_fixed_size
-        else:
-            ub = ub_relative * self.element.size
-
-        return lb, ub
+        if self.with_investment:
+            ub = ub_relative * self.element.size.maximum_or_fixed_size
+        else:
+            ub = ub_relative * self.element.size
+
+        if not isinstance(lb, xr.DataArray):
+            lb = xr.zeros_like(ub)
+        return lb, ub

This keeps behavior the same while making the type hint accurate.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1eaef1f and bddce4f.

📒 Files selected for processing (13)
  • flixopt/__init__.py (1 hunks)
  • flixopt/calculation.py (2 hunks)
  • flixopt/components.py (8 hunks)
  • flixopt/core.py (2 hunks)
  • flixopt/effects.py (4 hunks)
  • flixopt/elements.py (6 hunks)
  • flixopt/features.py (3 hunks)
  • flixopt/flow_system.py (5 hunks)
  • flixopt/interface.py (9 hunks)
  • flixopt/io.py (2 hunks)
  • flixopt/linear_converters.py (29 hunks)
  • flixopt/modeling.py (7 hunks)
  • flixopt/types.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
flixopt/calculation.py (1)
flixopt/core.py (3)
  • DataConverter (146-554)
  • TimeSeriesData (35-143)
  • drop_constant_arrays (584-614)
flixopt/flow_system.py (2)
flixopt/effects.py (2)
  • Effect (32-399)
  • EffectCollection (451-633)
flixopt/structure.py (1)
  • weights (224-234)
flixopt/elements.py (2)
flixopt/core.py (1)
  • PlausibilityError (23-26)
flixopt/interface.py (2)
  • InvestParameters (671-1079)
  • OnOffParameters (1083-1344)
flixopt/components.py (2)
flixopt/core.py (1)
  • PlausibilityError (23-26)
flixopt/interface.py (1)
  • InvestParameters (671-1079)
flixopt/features.py (2)
flixopt/interface.py (3)
  • InvestParameters (671-1079)
  • OnOffParameters (1083-1344)
  • Piecewise (87-228)
flixopt/elements.py (2)
  • previous_states (779-792)
  • previous_states (907-924)
flixopt/linear_converters.py (3)
flixopt/core.py (1)
  • TimeSeriesData (35-143)
flixopt/structure.py (4)
  • _handle_deprecated_kwarg (420-479)
  • _validate_kwargs (481-509)
  • label_full (874-875)
  • label_full (1366-1367)
flixopt/elements.py (2)
  • Flow (296-562)
  • label_full (552-553)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.10)
🔇 Additional comments (21)
flixopt/calculation.py (1)

29-29: LGTM: Import cleanup aligns with type system refactoring.

The removal of Scalar from imports is consistent with the repository-wide shift to using primitive numeric types (int | float) instead of custom type aliases, as mentioned in the AI summary.

flixopt/__init__.py (1)

44-56: Top-level export of dimension-aware types looks good

Re-exporting the Bool_, Effect_, Numeric_* and Scalar aliases at the package level is consistent with the new type system and keeps the runtime surface unchanged.

flixopt/io.py (1)

19-23: numeric_to_str_for_repr annotation correctly aligned with new Numeric_TPS alias

Using Numeric_TPS in the TYPE_CHECKING import and as the parameter type matches the function’s actual supported inputs (scalars, ndarray, Series, DataFrame, DataArray); no behavior change, just clearer typing.

Also applies to: 655-659

flixopt/features.py (1)

17-21: Updated TYPE_CHECKING imports are consistent with new type system

Importing FlowSystemDimensions, Numeric_PS, and Numeric_TPS under TYPE_CHECKING cleanly supports the annotations in this module without affecting runtime.

flixopt/core.py (1)

15-18: DataConverter.to_dataarray correctly updated to use NumericOrBool

Importing NumericOrBool and using it for the data parameter brings the signature in line with both the docstring and the isinstance checks (scalars, np.ndarray, pd.Series, pd.DataFrame, xr.DataArray). No behavioral change, just clearer typing and a single source of truth for supported input types.

Also applies to: 390-505

flixopt/flow_system.py (2)

25-36: Type imports and weights typing look consistent with the new type system

Importing Effect/EffectCollection and the TYPE_CHECKING-only aliases (Numeric_PS, Numeric_TPS, NumericOrBool, etc.) aligns with how these types are used throughout the file and the rest of the codebase. Narrowing weights to Numeric_PS | None in FlowSystem.__init__ matches its actual usage (passed into fit_to_model_coords and later consumed by FlowSystemModel.weights) without changing behavior.

Also applies to: 155-165


523-587: fit_to_model_coords / fit_effects_to_model_coords remain behaviorally compatible

The updated signatures (data: NumericOrBool | None, effect_values: Effect_TPS | Numeric_TPS | None) and the use of coords filtering by dims keep the old behavior while making type usage explicit. Delegating effect handling to EffectCollection.create_effect_values_dict is consistent with the new Effect_TPS/Numeric_TPS aliases, and returning {} instead of None for empty mappings is compatible with downstream truthiness checks (if effect.share_from_*:). No functional issues spotted.

Also applies to: 588-599

flixopt/effects.py (1)

172-201: Effect bound/share typing and defaults are consistent

Switching the constructor parameters and attributes to Effect_TPS/Effect_PS and Numeric_PS/Numeric_TPS matches how these fields are consumed in transform_data and in EffectCollection.calculate_effect_share_factors. Initializing share_from_temporal/share_from_periodic to {} when None keeps existing behavior with the if effect.share_from_*: checks while simplifying downstream handling.

flixopt/linear_converters.py (1)

651-683: check_bounds helper behaves as a soft guard (warnings only)

The updated check_bounds correctly:

  • Handles TimeSeriesData by unwrapping .data.
  • Supports array-like Numeric_TPS values via np.all(value > lower_bound) / < upper_bound.
  • Logs warnings (without raising) when values touch or exceed the exclusive bounds.

This is fine as long as you intend it as a diagnostic tool rather than a hard validator; for parameters that must obey strict constraints (like COP in HeatPumpWithSource), the additional explicit ValueError you added is the right way to enforce that.

flixopt/elements.py (2)

16-37: PlausibilityError and new numeric/effect types integrate cleanly into Flow

Importing PlausibilityError from .core and switching Flow’s constructor signature to Numeric_PS/Numeric_TPS/Effect_TPS matches the rest of the refactor (InvestParameters, OnOffParameters, FlowSystem). _plausibility_checks raising PlausibilityError for inconsistent relative bounds is appropriate and keeps error semantics aligned with other modeling plausibility checks. No behavioral issues spotted here.

Also applies to: 429-459


779-792: previous_states return type aligns with OnOff usage

The updated annotation xr.DataArray | None matches the actual result from ModelingUtilitiesAbstract.to_binary and how previous_states is consumed in OnOffModel. The scalar/1D handling of previous_flow_rate is unchanged; no issues detected.

flixopt/components.py (3)

31-37: LinearConverter: conversion_factors typing and transformation are coherent

Typing conversion_factors as list[dict[str, Numeric_TPS]] | None matches how _transform_conversion_factors feeds values into fit_to_model_coords, and the method correctly returns a list of dict[str, xr.DataArray] used by LinearConverterModel. The PlausibilityError checks (degrees_of_freedom, flows present in self.flows) remain valid under the new types.

Also applies to: 167-237


383-433: Storage: new numeric type aliases and charge-state bounds stay consistent

Switching capacity_in_flow_hours, relative charge-state parameters, efficiencies, and losses to Numeric_PS/Numeric_TPS while transforming everything through fit_to_model_coords keeps the existing behavior and plays nicely with InvestParameters. _absolute_charge_state_bounds now explicitly returns tuple[xr.DataArray, xr.DataArray] by multiplying relative bounds with either scalar/DataArray capacity or InvestParameters’ min/max, which matches how StorageModel uses these bounds when creating charge_state variables.

Also applies to: 438-481, 919-961


547-573: Transmission: loss parameters now aligned with the shared numeric types

Typing relative_losses and absolute_losses as Numeric_TPS | None and converting them via fit_to_model_coords in transform_data is consistent with the rest of the modeling layer. create_transmission_equation still encodes

  • out = in × (1 - relative_losses)
  • plus on * absolute_losses when present,

which matches the documented behavior. The guard in TransmissionModel.__init__ that auto-attaches OnOffParameters whenever non-zero absolute_losses are present is still valid under the new types.

Also applies to: 660-773

flixopt/modeling.py (2)

205-569: Consistent type system refactoring looks good.

The systematic replacement of TemporalData with xr.DataArray throughout the module is consistent and aligns with the broader type system changes described in the PR summary. The changes maintain parameter names and logic while only updating type annotations.


120-142: No backward compatibility issue found. TemporalData does not exist in the codebase.

The review comment references a type change from TemporalData to xr.DataArray, but TemporalData does not appear anywhere in the codebase. The actual parameter accepts Numeric_TPS | None, which is a type alias that already includes xr.DataArray in its union of accepted types. All existing call sites pass either xr.DataArray objects or values derived from arithmetic operations on xr.DataArray, making them fully compatible with the annotated type. The type annotation change is correct and poses no backward compatibility concerns.

Likely an incorrect or invalid review comment.

flixopt/interface.py (5)

1001-1047: Deprecated property return types correctly updated.

The return type annotations for deprecated properties have been updated to align with the new type system. This maintains consistency between the deprecated interface and the new attribute types.


19-23: All type aliases are properly defined and exported.

Verification confirms that flixopt/types.py exists, contains all four type aliases (Effect_PS, Effect_TPS, Numeric_PS, Numeric_TPS) as properly structured TypeAlias definitions, and exports them in __all__. The base types (_Numeric, _Effect) are well-defined, and the module includes clear documentation on dimension semantics. The imports in interface.py are correct and complete.


1264-1286: No backward compatibility issues found.

Verification confirms the default value changes are safe:

  1. Truthiness checks: Code uses if self.parameters.effects_per_running_hour: (features.py lines 251, 261). Since {} and None are both falsy in Python, behavior is identical.

  2. Dictionary operations: The .items() calls on these attributes (features.py lines 256, 265) work correctly with {} and produce the same empty iterator result as a None case would.

  3. No explicit None checks: Searching the codebase found no patterns like is None or == None on these attributes, confirming the code treats them as dictionaries from the start.

The change from None to {} defaults is semantically equivalent and maintains full backward compatibility.


874-924: Review comment is incorrect. No breaking change to None handling.

The codebase search found no production code that checks for None on these effect parameters—only one test validates the new empty-dict default is correct. The function signature still accepts None as input; the internal conversion from None to {} is transparent to callers and cannot break downstream code. Test suite confirms this behavior is intentional.

Likely an incorrect or invalid review comment.


1-1344: Testing verification cannot be completed in sandbox environment.

The sandbox lacks necessary dependencies (linopy, mypy) and git history to verify the testing request. Additionally:

  • No test files related to interface.py were located in the repository
  • The repository is not a git repository in this environment, so the actual PR diff cannot be retrieved
  • The provided code snippet shows only the final state, not what changed

To properly verify this review comment, please manually confirm:

  1. What changed in this PR? The review assumes "type system changes" but only the final code state is visible. Provide the git diff or describe specific breaking changes introduced.

  2. Do existing tests pass? Can you run pytest tests/ -v locally and confirm all tests pass with these changes?

  3. Are there type errors? Run mypy flixopt/interface.py --strict locally to confirm type checking passes.

  4. PR objectives status? The review references unchecked testing boxes—verify whether testing was actually performed before this review.

Without this information, I cannot confirm whether the testing request addresses real issues or is a procedural precaution.


@property
def main_results(self) -> dict[str, Scalar | dict]:
def main_results(self) -> dict[str, int | float | dict]:
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incomplete return type annotation: missing list type.

The return type annotation dict[str, int | float | dict] doesn't account for the 'Buses with excess' key at lines 134-146, which returns a list of dicts. Type checkers will flag this inconsistency.

Apply this diff to fix the type annotation:

-    def main_results(self) -> dict[str, int | float | dict]:
+    def main_results(self) -> dict[str, int | float | dict | list]:
🤖 Prompt for AI Agents
In flixopt/calculation.py around line 106, the return type annotation def
main_results(self) -> dict[str, int | float | dict] is missing the case where a
value is a list of dicts (the 'Buses with excess' key); update the annotation to
include list[dict[str, int | float | dict]] (e.g. def main_results(self) ->
dict[str, int | float | dict | list[dict[str, int | float | dict]]]) so type
checkers accept the list-of-dicts return value.

@FBumann FBumann changed the base branch from main to feature/simplify-data-converter November 15, 2025 13:12
@FBumann
Copy link
Member Author

FBumann commented Nov 15, 2025

Continue in #468

@FBumann FBumann closed this Nov 15, 2025
@FBumann FBumann deleted the feature/parameter-renames branch November 19, 2025 13:41
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.

2 participants