Repository: oemof/oemof-solph

Issue:
FakeSequences Not Iterating Correctly
**Description**
With the changes in the new 0.5.4 update, I've run into a problem when trying to treat FakeSequences as an iterable. I have made the short code below to demonstrate:

```from oemof.solph import EnergySystem, create_time_index, Bus, Model
from oemof.solph.components import Sink, Source
from oemof.solph.flows import Flow
import pandas as pd

es = EnergySystem(
    timeindex=create_time_index(2022, 1, 3),
    infer_last_interval=False
)

bus = Bus(label = 'Bus')
source = Source(
    label = 'Source',
    outputs={bus: Flow(variable_costs=[0.1, 0.3, 0.2])}
)
sink = Sink(
    label='Sink',
    inputs = {bus: Flow(fix = [25, 30, 50], nominal_value=100)}
)

es.add(bus, source, sink)

model = Model(es)

df= pd.DataFrame(
    {
        k:v.variable_costs
        for k,v in model.flows.items()
        if v.variable_costs is not None
    }
)

print(df)
```

**Expected behavior**
In the previous version, this prints the following:
```
   Bus Source
  Sink    Bus
0    0    0.1
1    0    0.3
2    0    0.2
```

but now the following error is raised

```  File "c:\Examples\Bug_Ex.py", line 25, in <module>
    fixes = pd.DataFrame(
            ^^^^^^^^^^^^^
  File "C:\venv\Lib\site-packages\pandas\core\frame.py", line 778, in __init__
    mgr = dict_to_mgr(data, index, columns, dtype=dtype, copy=copy, typ=manager)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\venv\Lib\site-packages\pandas\core\internals\construction.py", line 503, in dict_to_mgr
    return arrays_to_mgr(arrays, columns, index, dtype=dtype, typ=typ, consolidate=copy)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\venv\Lib\site-packages\pandas\core\internals\construction.py", line 114, in arrays_to_mgr
    index = _extract_index(arrays)
            ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\venv\Lib\site-packages\pandas\core\internals\construction.py", line 662, in _extract_index
    raw_lengths.append(len(val))
                       ^^^^^^^^
TypeError: 'NoneType' object cannot be interpreted as an integer
```

and if you try to cast it to a list in the process: i.e. `list(v.fix)`, the following error is raised

```
  File "c:\Examples\Bug_Ex.py", line 26, in <module>
    {
  File "c:\Examples\Bug_Ex.py", line 27, in <dictcomp>
    k:list(v.fix)
      ^^^^^^^^^^^
  File "C:\venv\Lib\site-packages\oemof\solph\_plumbing.py", line 104, in __iter__
    return repeat(self._value, self._length)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object cannot be interpreted as an integer
```
I believe that this is coming from a problem with the self._length value but I am having a hard time tracing it

Thank you in advance for any help

Note: I am working with: 
oemof.solph 0.5.4
Python 3.11.9
pandas 2.2.2
and Windows 11


Discussion:

Patch:
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 63c0c035..7f0fe3d0 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -9,6 +9,7 @@ These are new features and improvements of note in each release
     :backlinks: top
 
 
+.. include::  whatsnew/v0-5-5.rst
 .. include::  whatsnew/v0-5-4.rst
 .. include::  whatsnew/v0-5-3.rst
 .. include::  whatsnew/v0-5-2.rst
diff --git a/docs/whatsnew/v0-5-5.rst b/docs/whatsnew/v0-5-5.rst
new file mode 100644
index 00000000..c8afd9a9
--- /dev/null
+++ b/docs/whatsnew/v0-5-5.rst
@@ -0,0 +1,12 @@
+v0.5.5 ()
+--------------------------
+
+Bug fixes
+#########
+
+* Fix iterating over _FakeSequence objects
+
+Contributors
+############
+
+* Patrik Schönfeldt
diff --git a/src/oemof/solph/_plumbing.py b/src/oemof/solph/_plumbing.py
index bb6ed5b8..77c8ffb0 100644
--- a/src/oemof/solph/_plumbing.py
+++ b/src/oemof/solph/_plumbing.py
@@ -10,7 +10,7 @@ SPDX-FileCopyrightText: henhuy
 SPDX-License-Identifier: MIT
 
 """
-
+import warnings
 from collections import abc
 from itertools import repeat
 
@@ -19,8 +19,8 @@ import numpy as np
 
 def sequence(iterable_or_scalar):
     """Checks if an object is iterable (except string) or scalar and returns
-    the original sequence if object is an iterable and an 'emulated'
-    sequence object of class _Sequence if object is a scalar or string.
+    the an numpy array of the sequence if object is an iterable or an
+    'emulated'  sequence object of class _FakeSequence if object is a scalar.
 
     Parameters
     ----------
@@ -56,6 +56,43 @@ def sequence(iterable_or_scalar):
         return _FakeSequence(value=iterable_or_scalar)
 
 
+def valid_sequence(sequence, length: int) -> bool:
+    """Checks if an object is a numpy array of at least the given length
+    or an 'emulated' sequence object of class _FakeSequence.
+    If unset, the latter is set to the required lenght.
+
+    """
+    if sequence[0] is None:
+        return False
+
+    if isinstance(sequence, _FakeSequence):
+        if sequence.size is None:
+            sequence.size = length
+
+        if sequence.size == length:
+            return True
+        else:
+            return False
+
+    if isinstance(sequence, np.ndarray):
+        if sequence.size == length:
+            return True
+        # --- BEGIN: To be removed for versions >= v0.6 ---
+        elif sequence.size > length:
+            warnings.warn(
+                "Sequence longer than needed"
+                f" ({sequence.size} items instead of {length})."
+                " This will be trated as an error in the future.",
+                FutureWarning,
+            )
+            return True
+        # --- END ---
+        else:
+            raise ValueError(f"Lentgh of {sequence} should be {length}.")
+
+    return False
+
+
 class _FakeSequence:
     """Emulates a list whose length is not known in advance.
 
diff --git a/src/oemof/solph/components/_extraction_turbine_chp.py b/src/oemof/solph/components/_extraction_turbine_chp.py
index cef1a615..dc8fb393 100644
--- a/src/oemof/solph/components/_extraction_turbine_chp.py
+++ b/src/oemof/solph/components/_extraction_turbine_chp.py
@@ -23,8 +23,8 @@ from pyomo.core.base.block import ScalarBlock
 from pyomo.environ import BuildAction
 from pyomo.environ import Constraint
 
-from oemof.solph._plumbing import sequence as solph_sequence
-from oemof.solph.components._converter import Converter
+from oemof.solph._plumbing import sequence
+from oemof.solph.components import Converter
 
 
 class ExtractionTurbineCHP(Converter):
@@ -87,7 +87,7 @@ class ExtractionTurbineCHP(Converter):
             custom_attributes=custom_attributes,
         )
         self.conversion_factor_full_condensation = {
-            k: solph_sequence(v)
+            k: sequence(v)
             for k, v in conversion_factor_full_condensation.items()
         }
 
diff --git a/src/oemof/solph/components/_generic_storage.py b/src/oemof/solph/components/_generic_storage.py
index a9c5e1c8..4a7b23c7 100644
--- a/src/oemof/solph/components/_generic_storage.py
+++ b/src/oemof/solph/components/_generic_storage.py
@@ -38,7 +38,8 @@ from pyomo.environ import Var
 
 from oemof.solph._helpers import check_node_object_for_missing_attribute
 from oemof.solph._options import Investment
-from oemof.solph._plumbing import sequence as solph_sequence
+from oemof.solph._plumbing import sequence
+from oemof.solph._plumbing import valid_sequence
 
 
 class GenericStorage(Node):
@@ -224,19 +225,15 @@ class GenericStorage(Node):
 
         self.initial_storage_level = initial_storage_level
         self.balanced = balanced
-        self.loss_rate = solph_sequence(loss_rate)
-        self.fixed_losses_relative = solph_sequence(fixed_losses_relative)
-        self.fixed_losses_absolute = solph_sequence(fixed_losses_absolute)
-        self.inflow_conversion_factor = solph_sequence(
-            inflow_conversion_factor
-        )
-        self.outflow_conversion_factor = solph_sequence(
-            outflow_conversion_factor
-        )
-        self.max_storage_level = solph_sequence(max_storage_level)
-        self.min_storage_level = solph_sequence(min_storage_level)
-        self.fixed_costs = solph_sequence(fixed_costs)
-        self.storage_costs = solph_sequence(storage_costs)
+        self.loss_rate = sequence(loss_rate)
+        self.fixed_losses_relative = sequence(fixed_losses_relative)
+        self.fixed_losses_absolute = sequence(fixed_losses_absolute)
+        self.inflow_conversion_factor = sequence(inflow_conversion_factor)
+        self.outflow_conversion_factor = sequence(outflow_conversion_factor)
+        self.max_storage_level = sequence(max_storage_level)
+        self.min_storage_level = sequence(min_storage_level)
+        self.fixed_costs = sequence(fixed_costs)
+        self.storage_costs = sequence(storage_costs)
         self.invest_relation_input_output = invest_relation_input_output
         self.invest_relation_input_capacity = invest_relation_input_capacity
         self.invest_relation_output_capacity = invest_relation_output_capacity
@@ -603,7 +600,7 @@ class GenericStorageBlock(ScalarBlock):
 
         if m.es.periods is not None:
             for n in self.STORAGES:
-                if n.fixed_costs[0] is not None:
+                if valid_sequence(n.fixed_costs, len(m.PERIODS)):
                     fixed_costs += sum(
                         n.nominal_storage_capacity
                         * n.fixed_costs[pp]
@@ -615,7 +612,7 @@ class GenericStorageBlock(ScalarBlock):
         storage_costs = 0
 
         for n in self.STORAGES:
-            if n.storage_costs[0] is not None:
+            if valid_sequence(n.storage_costs, len(m.TIMESTEPS)):
                 storage_costs += (
                     self.storage_content[n, 0] * n.storage_costs[0]
                 )
@@ -1861,7 +1858,7 @@ class GenericInvestmentStorageBlock(ScalarBlock):
                     period_investment_costs[p] += investment_costs_increment
 
             for n in self.INVESTSTORAGES:
-                if n.investment.fixed_costs[0] is not None:
+                if valid_sequence(n.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = n.investment.lifetime
                     for p in m.PERIODS:
                         range_limit = min(
@@ -1879,7 +1876,7 @@ class GenericInvestmentStorageBlock(ScalarBlock):
                         )
 
             for n in self.EXISTING_INVESTSTORAGES:
-                if n.investment.fixed_costs[0] is not None:
+                if valid_sequence(n.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = n.investment.lifetime
                     age = n.investment.age
                     range_limit = min(
diff --git a/src/oemof/solph/components/experimental/_sink_dsm.py b/src/oemof/solph/components/experimental/_sink_dsm.py
index 1d910f54..4645a589 100644
--- a/src/oemof/solph/components/experimental/_sink_dsm.py
+++ b/src/oemof/solph/components/experimental/_sink_dsm.py
@@ -38,6 +38,7 @@ from pyomo.environ import Var
 
 from oemof.solph._options import Investment
 from oemof.solph._plumbing import sequence
+from oemof.solph._plumbing import valid_sequence
 from oemof.solph.components._sink import Sink
 
 
@@ -703,7 +704,7 @@ class SinkDSMOemofBlock(ScalarBlock):
                         * (1 + m.discount_rate) ** (-m.es.periods_years[p])
                     )
 
-                if g.fixed_costs[0] is not None:
+                if valid_sequence(g.fixed_costs, len(m.PERIODS)):
                     fixed_costs += sum(
                         max(g.max_capacity_up, g.max_capacity_down)
                         * g.fixed_costs[pp]
@@ -1434,7 +1435,7 @@ class SinkDSMOemofInvestmentBlock(ScalarBlock):
                         * (1 + m.discount_rate) ** (-m.es.periods_years[p])
                     )
 
-                if g.investment.fixed_costs[0] is not None:
+                if valid_sequence(g.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = g.investment.lifetime
                     for p in m.PERIODS:
                         range_limit = min(
@@ -1452,7 +1453,7 @@ class SinkDSMOemofInvestmentBlock(ScalarBlock):
                         )
 
             for g in self.EXISTING_INVESTDSM:
-                if g.investment.fixed_costs[0] is not None:
+                if valid_sequence(g.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = g.investment.lifetime
                     age = g.investment.age
                     range_limit = min(
@@ -2198,7 +2199,7 @@ class SinkDSMDIWBlock(ScalarBlock):
                         * (1 + m.discount_rate) ** (-m.es.periods_years[p])
                     )
 
-                if g.fixed_costs[0] is not None:
+                if valid_sequence(g.fixed_costs, len(m.PERIODS)):
                     fixed_costs += sum(
                         max(g.max_capacity_up, g.max_capacity_down)
                         * g.fixed_costs[pp]
@@ -3290,7 +3291,7 @@ class SinkDSMDIWInvestmentBlock(ScalarBlock):
                         * (1 + m.discount_rate) ** (-m.es.periods_years[p])
                     )
 
-                if g.investment.fixed_costs[0] is not None:
+                if valid_sequence(g.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = g.investment.lifetime
                     for p in m.PERIODS:
                         range_limit = min(
@@ -3308,7 +3309,7 @@ class SinkDSMDIWInvestmentBlock(ScalarBlock):
                         )
 
             for g in self.EXISTING_INVESTDSM:
-                if g.investment.fixed_costs[0] is not None:
+                if valid_sequence(g.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = g.investment.lifetime
                     age = g.investment.age
                     range_limit = min(
@@ -4391,7 +4392,7 @@ class SinkDSMDLRBlock(ScalarBlock):
                         * (1 + m.discount_rate) ** (-m.es.periods_years[p])
                     )
 
-                if g.fixed_costs[0] is not None:
+                if valid_sequence(g.fixed_costs, len(m.PERIODS)):
                     fixed_costs += sum(
                         max(g.max_capacity_up, g.max_capacity_down)
                         * g.fixed_costs[pp]
@@ -5791,7 +5792,7 @@ class SinkDSMDLRInvestmentBlock(ScalarBlock):
                         * (1 + m.discount_rate) ** (-m.es.periods_years[p])
                     )
 
-                if g.investment.fixed_costs[0] is not None:
+                if valid_sequence(g.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = g.investment.lifetime
                     for p in m.PERIODS:
                         range_limit = min(
@@ -5809,7 +5810,7 @@ class SinkDSMDLRInvestmentBlock(ScalarBlock):
                         )
 
             for g in self.EXISTING_INVESTDSM:
-                if g.investment.fixed_costs[0] is not None:
+                if valid_sequence(g.investment.fixed_costs, len(m.PERIODS)):
                     lifetime = g.investment.lifetime
                     age = g.investment.age
                     range_limit = min(
diff --git a/src/oemof/solph/flows/_investment_flow_block.py b/src/oemof/solph/flows/_investment_flow_block.py
index 99efec0d..bb0ee5d2 100644
--- a/src/oemof/solph/flows/_investment_flow_block.py
+++ b/src/oemof/solph/flows/_investment_flow_block.py
@@ -29,6 +29,8 @@ from pyomo.core import Set
 from pyomo.core import Var
 from pyomo.core.base.block import ScalarBlock
 
+from oemof.solph._plumbing import valid_sequence
+
 
 class InvestmentFlowBlock(ScalarBlock):
     r"""Block for all flows with :attr:`Investment` being not None.
@@ -1007,7 +1009,9 @@ class InvestmentFlowBlock(ScalarBlock):
                     period_investment_costs[p] += investment_costs_increment
 
             for i, o in self.INVESTFLOWS:
-                if m.flows[i, o].investment.fixed_costs[0] is not None:
+                if valid_sequence(
+                    m.flows[i, o].investment.fixed_costs, len(m.PERIODS)
+                ):
                     lifetime = m.flows[i, o].investment.lifetime
                     for p in m.PERIODS:
                         range_limit = min(
@@ -1022,7 +1026,9 @@ class InvestmentFlowBlock(ScalarBlock):
                         )
 
             for i, o in self.EXISTING_INVESTFLOWS:
-                if m.flows[i, o].investment.fixed_costs[0] is not None:
+                if valid_sequence(
+                    m.flows[i, o].investment.fixed_costs, len(m.PERIODS)
+                ):
                     lifetime = m.flows[i, o].investment.lifetime
                     age = m.flows[i, o].investment.age
                     range_limit = min(
diff --git a/src/oemof/solph/flows/_non_convex_flow_block.py b/src/oemof/solph/flows/_non_convex_flow_block.py
index aa1cf457..31b870ca 100644
--- a/src/oemof/solph/flows/_non_convex_flow_block.py
+++ b/src/oemof/solph/flows/_non_convex_flow_block.py
@@ -25,6 +25,8 @@ from pyomo.core import Set
 from pyomo.core import Var
 from pyomo.core.base.block import ScalarBlock
 
+from oemof.solph._plumbing import valid_sequence
+
 
 class NonConvexFlowBlock(ScalarBlock):
     r"""
@@ -327,7 +329,9 @@ class NonConvexFlowBlock(ScalarBlock):
 
             if m.es.periods is None:
                 for i, o in self.STARTUPFLOWS:
-                    if m.flows[i, o].nonconvex.startup_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.startup_costs, len(m.TIMESTEPS)
+                    ):
                         startup_costs += sum(
                             self.startup[i, o, t]
                             * m.flows[i, o].nonconvex.startup_costs[t]
@@ -335,7 +339,9 @@ class NonConvexFlowBlock(ScalarBlock):
                         )
             else:
                 for i, o in self.STARTUPFLOWS:
-                    if m.flows[i, o].nonconvex.startup_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.startup_costs, len(m.TIMESTEPS)
+                    ):
                         startup_costs += sum(
                             self.startup[i, o, t]
                             * m.flows[i, o].nonconvex.startup_costs[t]
@@ -361,7 +367,10 @@ class NonConvexFlowBlock(ScalarBlock):
 
             if m.es.periods is None:
                 for i, o in self.SHUTDOWNFLOWS:
-                    if m.flows[i, o].nonconvex.shutdown_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.shutdown_costs,
+                        len(m.TIMESTEPS),
+                    ):
                         shutdown_costs += sum(
                             self.shutdown[i, o, t]
                             * m.flows[i, o].nonconvex.shutdown_costs[t]
@@ -369,7 +378,10 @@ class NonConvexFlowBlock(ScalarBlock):
                         )
             else:
                 for i, o in self.SHUTDOWNFLOWS:
-                    if m.flows[i, o].nonconvex.shutdown_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.shutdown_costs,
+                        len(m.TIMESTEPS),
+                    ):
                         shutdown_costs += sum(
                             self.shutdown[i, o, t]
                             * m.flows[i, o].nonconvex.shutdown_costs[t]
@@ -395,7 +407,10 @@ class NonConvexFlowBlock(ScalarBlock):
 
             if m.es.periods is None:
                 for i, o in self.ACTIVITYCOSTFLOWS:
-                    if m.flows[i, o].nonconvex.activity_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.activity_costs,
+                        len(m.TIMESTEPS),
+                    ):
                         activity_costs += sum(
                             self.status[i, o, t]
                             * m.flows[i, o].nonconvex.activity_costs[t]
@@ -403,7 +418,10 @@ class NonConvexFlowBlock(ScalarBlock):
                         )
             else:
                 for i, o in self.ACTIVITYCOSTFLOWS:
-                    if m.flows[i, o].nonconvex.activity_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.activity_costs,
+                        len(m.TIMESTEPS),
+                    ):
                         activity_costs += sum(
                             self.status[i, o, t]
                             * m.flows[i, o].nonconvex.activity_costs[t]
@@ -429,7 +447,10 @@ class NonConvexFlowBlock(ScalarBlock):
 
             if m.es.periods is None:
                 for i, o in self.INACTIVITYCOSTFLOWS:
-                    if m.flows[i, o].nonconvex.inactivity_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.inactivity_costs,
+                        len(m.TIMESTEPS),
+                    ):
                         inactivity_costs += sum(
                             (1 - self.status[i, o, t])
                             * m.flows[i, o].nonconvex.inactivity_costs[t]
@@ -437,7 +458,10 @@ class NonConvexFlowBlock(ScalarBlock):
                         )
             else:
                 for i, o in self.INACTIVITYCOSTFLOWS:
-                    if m.flows[i, o].nonconvex.inactivity_costs[0] is not None:
+                    if valid_sequence(
+                        m.flows[i, o].nonconvex.inactivity_costs,
+                        len(m.TIMESTEPS),
+                    ):
                         inactivity_costs += sum(
                             (1 - self.status[i, o, t])
                             * m.flows[i, o].nonconvex.inactivity_costs[t]
diff --git a/src/oemof/solph/flows/_simple_flow_block.py b/src/oemof/solph/flows/_simple_flow_block.py
index 7cf21bce..e7d8d684 100644
--- a/src/oemof/solph/flows/_simple_flow_block.py
+++ b/src/oemof/solph/flows/_simple_flow_block.py
@@ -26,6 +26,8 @@ from pyomo.core import Set
 from pyomo.core import Var
 from pyomo.core.base.block import ScalarBlock
 
+from oemof.solph._plumbing import valid_sequence
+
 
 class SimpleFlowBlock(ScalarBlock):
     r"""Flow block with definitions for standard flows.
@@ -172,12 +174,16 @@ class SimpleFlowBlock(ScalarBlock):
         )
         # set upper bound of gradient variable
         for i, o, f in group:
-            if m.flows[i, o].positive_gradient_limit[0] is not None:
+            if valid_sequence(
+                m.flows[i, o].positive_gradient_limit, len(m.TIMESTEPS)
+            ):
                 for t in m.TIMESTEPS:
                     self.positive_gradient[i, o, t].setub(
                         f.positive_gradient_limit[t] * f.nominal_value
                     )
-            if m.flows[i, o].negative_gradient_limit[0] is not None:
+            if valid_sequence(
+                m.flows[i, o].negative_gradient_limit, len(m.TIMESTEPS)
+            ):
                 for t in m.TIMESTEPS:
                     self.negative_gradient[i, o, t].setub(
                         f.negative_gradient_limit[t] * f.nominal_value
@@ -429,7 +435,9 @@ class SimpleFlowBlock(ScalarBlock):
 
         if m.es.periods is None:
             for i, o in m.FLOWS:
-                if m.flows[i, o].variable_costs[0] is not None:
+                if valid_sequence(
+                    m.flows[i, o].variable_costs, len(m.TIMESTEPS)
+                ):
                     for t in m.TIMESTEPS:
                         variable_costs += (
                             m.flow[i, o, t]
@@ -439,7 +447,9 @@ class SimpleFlowBlock(ScalarBlock):
 
         else:
             for i, o in m.FLOWS:
-                if m.flows[i, o].variable_costs[0] is not None:
+                if valid_sequence(
+                    m.flows[i, o].variable_costs, len(m.TIMESTEPS)
+                ):
                     for p, t in m.TIMEINDEX:
                         variable_costs += (
                             m.flow[i, o, t]
@@ -464,7 +474,7 @@ class SimpleFlowBlock(ScalarBlock):
 
             # Fixed costs for units with limited lifetime
             for i, o in self.LIFETIME_FLOWS:
-                if m.flows[i, o].fixed_costs[0] is not None:
+                if valid_sequence(m.flows[i, o].fixed_costs, len(m.TIMESTEPS)):
                     range_limit = min(
                         m.es.end_year_of_optimization,
                         m.flows[i, o].lifetime,
@@ -477,7 +487,7 @@ class SimpleFlowBlock(ScalarBlock):
                     )
 
             for i, o in self.LIFETIME_AGE_FLOWS:
-                if m.flows[i, o].fixed_costs[0] is not None:
+                if valid_sequence(m.flows[i, o].fixed_costs, len(m.TIMESTEPS)):
                     range_limit = min(
                         m.es.end_year_of_optimization,
                         m.flows[i, o].lifetime - m.flows[i, o].age,
diff --git a/src/oemof/solph/flows/experimental/_electrical_line.py b/src/oemof/solph/flows/experimental/_electrical_line.py
index 2b5e2eb8..ad08f99f 100644
--- a/src/oemof/solph/flows/experimental/_electrical_line.py
+++ b/src/oemof/solph/flows/experimental/_electrical_line.py
@@ -25,7 +25,7 @@ from pyomo.environ import Constraint
 from pyomo.environ import Set
 from pyomo.environ import Var
 
-from oemof.solph._plumbing import sequence as solph_sequence
+from oemof.solph._plumbing import sequence
 from oemof.solph.buses.experimental._electrical_bus import ElectricalBus
 from oemof.solph.flows._flow import Flow
 
@@ -75,7 +75,7 @@ class ElectricalLine(Flow):
             nonconvex=kwargs.get("nonconvex"),
             custom_attributes=kwargs.get("costom_attributes"),
         )
-        self.reactance = solph_sequence(kwargs.get("reactance", 0.00001))
+        self.reactance = sequence(kwargs.get("reactance", 0.00001))
 
         self.input = kwargs.get("input")
         self.output = kwargs.get("output")


Test patch:
diff --git a/tests/test_plumbing.py b/tests/test_plumbing.py
index b51187be..f97ff96c 100644
--- a/tests/test_plumbing.py
+++ b/tests/test_plumbing.py
@@ -11,6 +11,7 @@ import pytest
 
 from oemof.solph._plumbing import _FakeSequence
 from oemof.solph._plumbing import sequence
+from oemof.solph._plumbing import valid_sequence
 
 
 def test_fake_sequence():
@@ -63,3 +64,31 @@ def test_sequence():
     seq_ab = sequence("ab")
     assert isinstance(seq_ab, str)
     assert seq_ab == "ab"
+
+
+def test_valid_sequence():
+    np_array = np.array([0, 1, 2, 3, 4])
+    assert valid_sequence(np_array, 5)
+
+    with pytest.warns(FutureWarning, match="Sequence longer than needed"):
+        valid_sequence(np_array, 4)
+
+    # it's not that long
+    with pytest.raises(ValueError):
+        valid_sequence(np_array, 1337)
+
+    fake_sequence = _FakeSequence(42)
+    assert valid_sequence(fake_sequence, 5)
+    assert len(fake_sequence) == 5
+
+    # wil not automatically overwrite size
+    assert not valid_sequence(fake_sequence, 1337)
+    assert len(fake_sequence) == 5
+
+    # manually overwriting length is still possible
+    fake_sequence.size = 1337
+    assert valid_sequence(fake_sequence, 1337)
+    assert len(fake_sequence) == 1337
+
+    # strings are no valid sequences
+    assert not valid_sequence("abc", 3)
diff --git a/tests/test_scripts/test_solph/test_generic_caes/generic_caes.csv b/tests/test_scripts/test_solph/test_generic_caes/generic_caes.csv
index 0c00956b..1658a9f4 100644
--- a/tests/test_scripts/test_solph/test_generic_caes/generic_caes.csv
+++ b/tests/test_scripts/test_solph/test_generic_caes/generic_caes.csv
@@ -238,4 +238,3 @@ timestep,price_el_sink,price_el_source
 237,-33.57,33.57
 238,-30.51,30.51
 239,-30.57,30.57
-240,-29.28,29.28
diff --git a/tests/test_scripts/test_solph/test_generic_caes/test_generic_caes.py b/tests/test_scripts/test_solph/test_generic_caes/test_generic_caes.py
index dc40286c..8c9e041e 100644
--- a/tests/test_scripts/test_solph/test_generic_caes/test_generic_caes.py
+++ b/tests/test_scripts/test_solph/test_generic_caes/test_generic_caes.py
@@ -34,7 +34,7 @@ def test_gen_caes():
     data = pd.read_csv(full_filename)
 
     # select periods
-    periods = len(data) - 1
+    periods = len(data)
 
     # create an energy system
     idx = pd.date_range("1/1/2017", periods=periods, freq="h")
diff --git a/tests/test_scripts/test_solph/test_generic_chp/ccet.csv b/tests/test_scripts/test_solph/test_generic_chp/ccet.csv
index ec231419..185a1f1a 100644
--- a/tests/test_scripts/test_solph/test_generic_chp/ccet.csv
+++ b/tests/test_scripts/test_solph/test_generic_chp/ccet.csv
@@ -198,4 +198,3 @@ timestep,demand_th,price_el,Eta_el_max_woDH,P_max_woDH,Eta_el_min_woDH,P_min_woD
 197,0.97,-50,0.53,199.73,0.43,80.65,0.19,31.71,0.19
 198,0.98,-50,0.53,199.73,0.43,80.65,0.19,31.71,0.19
 199,0.99,-50,0.53,199.73,0.43,80.65,0.19,31.71,0.19
-200,1,-50,0.53,199.73,0.43,80.65,0.19,31.71,0.19
diff --git a/tests/test_scripts/test_solph/test_generic_chp/test_generic_chp.py b/tests/test_scripts/test_solph/test_generic_chp/test_generic_chp.py
index 6c9f8c42..c5770d27 100644
--- a/tests/test_scripts/test_solph/test_generic_chp/test_generic_chp.py
+++ b/tests/test_scripts/test_solph/test_generic_chp/test_generic_chp.py
@@ -28,7 +28,7 @@ def test_gen_chp():
     data = pd.read_csv(full_filename)
 
     # select periods
-    periods = len(data) - 1
+    periods = len(data)
 
     # create an energy system
     idx = pd.date_range("1/1/2017", periods=periods, freq="h")