55from dataclasses import InitVar , dataclass , field
66from itertools import chain , product , repeat
77from types import SimpleNamespace
8- from typing import TYPE_CHECKING , Any , Optional , Union , cast
8+ from typing import TYPE_CHECKING , Any , cast
99from warnings import warn
1010
1111import numpy as np
3434 class ToDatetimeKeywords (TypedDict , total = False ):
3535 format : str
3636
37- KeyOrAttributeValue = Union [ " common.KeyValue" , " common.AttributeValue" ]
37+ KeyOrAttributeValue = common .KeyValue | common .AttributeValue
3838
3939
4040_HAS_PANDAS_2 = pd .__version__ .split ("." )[0 ] >= "2"
@@ -150,8 +150,8 @@ class ColumnSpec:
150150
151151 def __init__ (
152152 self ,
153- pc : Optional [ "PandasConverter" ] = None ,
154- ds : Optional [ "common.BaseDataSet" ] = None ,
153+ pc : "PandasConverter | None" = None ,
154+ ds : "common.BaseDataSet | None" = None ,
155155 ) -> None :
156156 if pc is None or ds is None :
157157 return # Empty/placeholder
@@ -227,9 +227,9 @@ def __init__(
227227
228228 @staticmethod
229229 def _maybe_construct_dsd (
230- dsd : Optional [ "common.BaseDataStructureDefinition" ] ,
230+ dsd : v21 . DataStructureDefinition | v30 . DataStructureDefinition | None ,
231231 obs : "common.BaseObservation" ,
232- ) -> Union [ " v21.DataStructureDefinition" , " v30.DataStructure" ] :
232+ ) -> v21 .DataStructureDefinition | v30 .DataStructureDefinition :
233233 """If `dsd` is None, construct a DSD by inspection of `obs`."""
234234 if dsd is not None :
235235 return dsd
@@ -275,7 +275,7 @@ def convert_obs(self, obs: "common.BaseObservation") -> list:
275275 key = obs .key
276276 if self .constraint and key not in self .constraint :
277277 # Emit an empty row to be dropped
278- result : Iterable [Union [ str , None ] ] = repeat (None , len (self .obs ))
278+ result : Iterable [str | None ] = repeat (None , len (self .obs ))
279279 else :
280280 # Observation values
281281 # FIXME Handled CodedObservationValue, similar to AttributeValue
@@ -288,7 +288,7 @@ def convert_obs(self, obs: "common.BaseObservation") -> list:
288288 self .add_obs_attrib (avs )
289289
290290 # - Convert the observation Key using key Columns.
291- # - Convert the value to Optional[ str] .
291+ # - Convert the value to str | None .
292292 # - Convert the attribute values using attribute Columns.
293293 result = chain (
294294 [c (key .values ) for c in self .key ],
@@ -314,26 +314,26 @@ class PandasConverter(DispatchConverter):
314314 attributes : Attributes = Attributes .none
315315
316316 #: If given, only Observations included by the *constraint* are returned.
317- constraint : Optional [ "ContentConstraint" ] = None
317+ constraint : "ContentConstraint | None" = None
318318
319319 #: Datatype for observation values. If :any:`None`, data values remain
320320 #: :class:`object`/:class:`str`.
321- dtype : Union [ type ["np.generic" ], type ["ExtensionDtype" ], str , None ] = np .float64
321+ dtype : type ["np.generic" ] | type ["ExtensionDtype" ] | str | None = np .float64
322322
323323 #: Axis on which to place a time dimension. One of:
324324 #:
325325 #: - :py:`-1`: disabled.
326326 #: - :py:`0, "index"`: first/index axis.
327327 #: - :py:`1, "columns"`: second/columns axis.
328- datetime_axis : Union [ int , str ] = - 1
328+ datetime_axis : int | str = - 1
329329
330330 #: Dimension to convert to :class:`pandas.DatetimeIndex`. A :class:`str` value is
331331 #: interpreted as a dimension ID.
332- datetime_dimension : Optional [ "common.DimensionComponent" ] = None
332+ datetime_dimension : "common.DimensionComponent | None" = None
333333
334334 #: Frequency for conversion to :class:`pandas.PeriodIndex`. A :class:`str` value is
335335 #: interpreted as one of the :ref:`pd:timeseries.period_aliases`.
336- datetime_freq : Optional [ "DateOffset" ] = None
336+ datetime_freq : "DateOffset | None" = None
337337
338338 #: include : iterable of str or str, optional
339339 #: One or more of the attributes of the StructureMessage ('category_scheme',
@@ -367,9 +367,7 @@ class PandasConverter(DispatchConverter):
367367 # Columns to be set as index levels, then unstacked.
368368 _unstack : list [str ] = field (default_factory = list )
369369
370- _context : dict [Union [str , type ], Any ] = field (
371- default_factory = lambda : dict (compat = False )
372- )
370+ _context : dict [str | type , Any ] = field (default_factory = lambda : dict (compat = False ))
373371
374372 def get_components (self , kind ) -> list ["common.Component" ]:
375373 """Return an appropriate list of dimensions or attributes."""
@@ -434,21 +432,22 @@ def handle_datetime(self, value: Any) -> None:
434432 stacklevel = 2 ,
435433 )
436434
437- if isinstance (value , (str , common .DimensionComponent )):
438- self .datetime_dimension = value # type: ignore [assignment]
439- elif isinstance (value , dict ):
440- # Unpack a dict of 'advanced' arguments
441- self .datetime_axis = value .pop ("axis" , self .datetime_axis )
442- self .datetime_dimension = value .pop ("dim" , self .datetime_dimension )
443- self .datetime_freq = value .pop ("freq" , self .datetime_freq )
444- if len (value ):
445- raise ValueError (f"Unexpected datetime={ tuple (sorted (value ))!r} " )
446- elif isinstance (value , bool ):
447- self .datetime_axis = 0 if value else - 1
448- else :
449- raise TypeError (f"PandasConverter(…, datetime={ type (value )} )" )
450-
451- def __post_init__ (self , datetime : Any , rtype : Optional [str ]) -> None :
435+ match value :
436+ case str () | common .DimensionComponent ():
437+ self .datetime_dimension = value # type: ignore [assignment]
438+ case dict ():
439+ # Unpack a dict of 'advanced' arguments
440+ self .datetime_axis = value .pop ("axis" , self .datetime_axis )
441+ self .datetime_dimension = value .pop ("dim" , self .datetime_dimension )
442+ self .datetime_freq = value .pop ("freq" , self .datetime_freq )
443+ if len (value ):
444+ raise ValueError (f"Unexpected datetime={ tuple (sorted (value ))!r} " )
445+ case bool ():
446+ self .datetime_axis = 0 if value else - 1
447+ case _:
448+ raise TypeError (f"PandasConverter(…, datetime={ type (value )} )" )
449+
450+ def __post_init__ (self , datetime : Any , rtype : str | None ) -> None :
452451 """Transform and validate arguments."""
453452 # Raise on unsupported arguments
454453 if isinstance (
@@ -626,7 +625,7 @@ def convert_structuremessage(c: "PandasConverter", obj: message.StructureMessage
626625 Keys are StructureMessage attributes; values are pandas objects.
627626 """
628627 attrs = sorted (c .include )
629- result : DictLike [str , Union [ pd .Series , pd .DataFrame ] ] = DictLike ()
628+ result : DictLike [str , pd .Series | pd .DataFrame ] = DictLike ()
630629 for a in attrs :
631630 dl = c .convert (getattr (obj , a ))
632631 if len (dl ):
@@ -755,17 +754,15 @@ def _convert_datetime(df: "pd.DataFrame", c: "PandasConverter") -> "pd.DataFrame
755754 return df .assign (** {dim .id : pd .to_datetime (df [dim .id ], ** dt_kw )})
756755
757756
758- def _ensure_multiindex (obj : Union [ pd .Series , pd .DataFrame ] ):
757+ def _ensure_multiindex (obj : pd .Series | pd .DataFrame ):
759758 if not isinstance (obj .index , pd .MultiIndex ):
760759 obj .index = pd .MultiIndex .from_product (
761760 [obj .index .to_list ()], names = [obj .index .name ]
762761 )
763762 return obj
764763
765764
766- def _reshape (
767- df : "pd.DataFrame" , c : "PandasConverter"
768- ) -> Union [pd .Series , pd .DataFrame ]:
765+ def _reshape (df : "pd.DataFrame" , c : "PandasConverter" ) -> pd .Series | pd .DataFrame :
769766 """Reshape `df` to provide expected return types."""
770767
771768 if c ._strict :
@@ -790,7 +787,7 @@ def _reshape(
790787 return result
791788
792789
793- def _to_periodindex (obj : Union [ "pd.Series" , " pd.DataFrame"] , c : "PandasConverter" ):
790+ def _to_periodindex (obj : "pd.Series | pd.DataFrame" , c : "PandasConverter" ):
794791 """Convert a 1-D datetime index on `obj` to a PeriodIndex."""
795792 result = obj
796793
@@ -887,7 +884,7 @@ def add_item(item):
887884 add_item (item )
888885
889886 # Convert to DataFrame
890- result : Union [ pd .DataFrame , pd .Series ] = pd .DataFrame .from_dict (
887+ result : pd .DataFrame | pd .Series = pd .DataFrame .from_dict (
891888 items ,
892889 orient = "index" ,
893890 dtype = object , # type: ignore [arg-type]
0 commit comments