diff --git a/PIconnect/PI.py b/PIconnect/PI.py index 9a4f5788..a8895ec3 100644 --- a/PIconnect/PI.py +++ b/PIconnect/PI.py @@ -1,7 +1,7 @@ """PI - Core containers for connections to PI databases.""" import warnings -from typing import Any, Dict, List, Optional, Union, cast +from typing import Any, cast import PIconnect.PIPoint as PIPoint_ from PIconnect import AF, PIConsts @@ -14,8 +14,8 @@ _DEFAULT_AUTH_MODE = PIConsts.AuthenticationMode.PI_USER_AUTHENTICATION -def _lookup_servers() -> Dict[str, AF.PI.PIServer]: - servers: Dict[str, AF.PI.PIServer] = {} +def _lookup_servers() -> dict[str, AF.PI.PIServer]: + servers: dict[str, AF.PI.PIServer] = {} for server in AF.PI.PIServers(): try: @@ -30,7 +30,7 @@ def _lookup_servers() -> Dict[str, AF.PI.PIServer]: return servers -def _lookup_default_server() -> Optional[AF.PI.PIServer]: +def _lookup_default_server() -> AF.PI.PIServer | None: default_server = None try: default_server = AF.PI.PIServers().DefaultPIServer @@ -65,12 +65,12 @@ class PIServer(object): # pylint: disable=useless-object-inheritance def __init__( self, - server: Optional[str] = None, - username: Optional[str] = None, - password: Optional[str] = None, - domain: Optional[str] = None, + server: str | None = None, + username: str | None = None, + password: str | None = None, + domain: str | None = None, authentication_mode: PIConsts.AuthenticationMode = _DEFAULT_AUTH_MODE, - timeout: Optional[int] = None, + timeout: int | None = None, ) -> None: if server is None: if self.default_server is None: @@ -138,8 +138,8 @@ def server_name(self): return self.connection.Name def search( - self, query: Union[str, List[str]], source: Optional[str] = None - ) -> List[PIPoint_.PIPoint]: + self, query: str | list[str], source: str | None = None + ) -> list[PIPoint_.PIPoint]: """Search PIPoints on the PIServer. Parameters diff --git a/PIconnect/PIAF.py b/PIconnect/PIAF.py index 0dc48640..7466bb1c 100644 --- a/PIconnect/PIAF.py +++ b/PIconnect/PIAF.py @@ -2,7 +2,7 @@ import dataclasses import warnings -from typing import Any, Optional, Union, cast +from typing import Any, cast import pandas as pd @@ -20,12 +20,12 @@ class PIAFServer: server: AF.PISystem databases: dict[str, AF.AFDatabase] = dataclasses.field(default_factory=dict) - def __getitem__(self, attr: str) -> Union[AF.PISystem, dict[str, AF.AFDatabase]]: + def __getitem__(self, attr: str) -> AF.PISystem | dict[str, AF.AFDatabase]: """Allow access to attributes as if they were dictionary items.""" return getattr(self, attr) -ServerSpec = dict[str, Union[AF.PISystem, dict[str, AF.AFDatabase]]] +ServerSpec = dict[str, AF.PISystem | dict[str, AF.AFDatabase]] def _lookup_servers() -> dict[str, ServerSpec]: @@ -59,7 +59,7 @@ def _lookup_servers() -> dict[str, ServerSpec]: } -def _lookup_default_server() -> Optional[ServerSpec]: +def _lookup_default_server() -> ServerSpec | None: servers = _lookup_servers() if AF.PISystems().DefaultPISystem: return servers[AF.PISystems().DefaultPISystem.Name] @@ -75,14 +75,14 @@ class PIAFDatabase(object): version = "0.3.0" servers: dict[str, ServerSpec] = _lookup_servers() - default_server: Optional[ServerSpec] = _lookup_default_server() + default_server: ServerSpec | None = _lookup_default_server() - def __init__(self, server: Optional[str] = None, database: Optional[str] = None) -> None: + def __init__(self, server: str | None = None, database: str | None = None) -> None: server_spec = self._initialise_server(server) self.server: AF.PISystem = server_spec["server"] # type: ignore self.database: AF.AFDatabase = self._initialise_database(server_spec, database) - def _initialise_server(self, server: Optional[str]) -> ServerSpec: + def _initialise_server(self, server: str | None) -> ServerSpec: if server is None: if self.default_server is None: raise ValueError("No server specified and no default server found.") @@ -99,9 +99,7 @@ def _initialise_server(self, server: Optional[str]) -> ServerSpec: return self.servers[server] - def _initialise_database( - self, server: ServerSpec, database: Optional[str] - ) -> AF.AFDatabase: + def _initialise_database(self, server: ServerSpec, database: str | None) -> AF.AFDatabase: def default_db(): default = self.server.Databases.DefaultDatabase if default is None: @@ -161,7 +159,7 @@ def descendant(self, path: str) -> "PIAFElement": """Return a descendant of the database from an exact path.""" return PIAFElement(self.database.Elements.get_Item(path)) - def search(self, query: Union[str, list[str]]) -> list[PIAFAttribute.PIAFAttribute]: + def search(self, query: str | list[str]) -> list[PIAFAttribute.PIAFAttribute]: """Search PIAFAttributes by element|attribute path strings. Return a list of PIAFAttributes directly from a list of element|attribute path strings @@ -220,7 +218,7 @@ class PIAFElement(PIAFBase.PIAFBaseElement[AF.Asset.AFElement]): version = "0.1.0" @property - def parent(self) -> Optional["PIAFElement"]: + def parent(self) -> "PIAFElement | None": """Return the parent element of the current element, or None if it has none.""" if not self.element.Parent: return None @@ -247,7 +245,7 @@ def event_frame(self) -> AF.EventFrame.AFEventFrame: return self.element @property - def parent(self) -> Optional["PIAFEventFrame"]: + def parent(self) -> "PIAFEventFrame | None": """Return the parent element of the current event frame, or None if it has none.""" if not self.element.Parent: return None diff --git a/PIconnect/PIAFAttribute.py b/PIconnect/PIAFAttribute.py index 38692d8a..11cf6f41 100644 --- a/PIconnect/PIAFAttribute.py +++ b/PIconnect/PIAFAttribute.py @@ -2,7 +2,7 @@ import dataclasses import datetime -from typing import Any, Dict, Optional +from typing import Any from PIconnect import AF, PIData, PIPoint, _time @@ -21,7 +21,7 @@ def name(self) -> str: return self.data_reference.Name @property - def pi_point(self) -> Optional[PIPoint.PIPoint]: + def pi_point(self) -> PIPoint.PIPoint | None: if self.data_reference.PIPoint is not None: return PIPoint.PIPoint(self.data_reference.PIPoint) @@ -56,14 +56,14 @@ def name(self) -> str: return self.attribute.Name @property - def parent(self) -> Optional["PIAFAttribute"]: + def parent(self) -> "PIAFAttribute | None": """Return the parent attribute of the current attribute, or None if it has none.""" if not self.attribute.Parent: return None return self.__class__(self.element, self.attribute.Parent) @property - def children(self) -> Dict[str, "PIAFAttribute"]: + def children(self) -> dict[str, "PIAFAttribute"]: """Return a dictionary of the direct child attributes of the current attribute.""" return {a.Name: self.__class__(self.element, a) for a in self.attribute.Attributes} diff --git a/PIconnect/PIAFBase.py b/PIconnect/PIAFBase.py index 31df979e..87a2ece3 100644 --- a/PIconnect/PIAFBase.py +++ b/PIconnect/PIAFBase.py @@ -1,6 +1,6 @@ """Base element class for PI AF elements.""" -from typing import Dict, Generic, TypeVar +from typing import Generic, TypeVar import PIconnect.PIAFAttribute as PIattr from PIconnect import AF @@ -26,7 +26,7 @@ def name(self) -> str: return self.element.Name @property - def attributes(self) -> Dict[str, PIattr.PIAFAttribute]: + def attributes(self) -> dict[str, PIattr.PIAFAttribute]: """Return a dictionary of the attributes of the current element.""" return {a.Name: PIattr.PIAFAttribute(self.element, a) for a in self.element.Attributes} diff --git a/PIconnect/PIData.py b/PIconnect/PIData.py index 3f79cfc0..02b78f71 100644 --- a/PIconnect/PIData.py +++ b/PIconnect/PIData.py @@ -2,7 +2,7 @@ import abc import datetime -from typing import Any, List, Optional +from typing import Any import pandas as pd @@ -24,9 +24,9 @@ class PISeries(pd.Series): # type: ignore Parameters ---------- tag (str): Name of the new series - timestamp (List[datetime]): List of datetime objects to + timestamp (list[datetime]): List of datetime objects to create the new index - value (List): List of values for the timeseries, should be equally long + value (list): List of values for the timeseries, should be equally long as the `timestamp` argument uom (str, optional): Defaults to None. Unit of measurement for the series @@ -42,9 +42,9 @@ class PISeries(pd.Series): # type: ignore def __init__( self, tag: str, - timestamp: List[datetime.datetime], - value: List[Any], - uom: Optional[str] = None, + timestamp: list[datetime.datetime], + value: list[Any], + uom: str | None = None, *args: Any, **kwargs: Any, ) -> None: @@ -87,7 +87,7 @@ def filtered_summaries( summary_types: PIConsts.SummaryType, calculation_basis: PIConsts.CalculationBasis = _DEFAULT_CALCULATION_BASIS, filter_evaluation: PIConsts.ExpressionSampleType = _DEFAULT_FILTER_EVALUATION, - filter_interval: Optional[str] = None, + filter_interval: str | None = None, time_type: PIConsts.TimestampCalculation = PIConsts.TimestampCalculation.AUTO, ) -> pd.DataFrame: """Return one or more summary values for each interval within a time range. @@ -259,8 +259,8 @@ def interpolated_values( _filter_expression = self._normalize_filter_expression(filter_expression) pivalues = self._interpolated_values(time_range, _interval, _filter_expression) - timestamps: List[datetime.datetime] = [] - values: List[Any] = [] + timestamps: list[datetime.datetime] = [] + values: list[Any] = [] for value in pivalues: timestamps.append(_time.timestamp_to_index(value.Timestamp.UtcTime)) values.append(value.Value) @@ -393,8 +393,8 @@ def recorded_values( pivalues = self._recorded_values(time_range, _boundary_type, _filter_expression) - timestamps: List[datetime.datetime] = [] - values: List[Any] = [] + timestamps: list[datetime.datetime] = [] + values: list[Any] = [] for value in pivalues: timestamps.append(_time.timestamp_to_index(value.Timestamp.UtcTime)) values.append(value.Value) @@ -558,14 +558,14 @@ def _summaries( @property @abc.abstractmethod - def units_of_measurement(self) -> Optional[str]: + def units_of_measurement(self) -> str | None: """Return the units of measurment of the values in the current object.""" pass def update_value( self, value: Any, - time: Optional[_time.TimeLike] = None, + time: _time.TimeLike | None = None, update_mode: PIConsts.UpdateMode = PIConsts.UpdateMode.NO_REPLACE, buffer_mode: PIConsts.BufferMode = PIConsts.BufferMode.BUFFER_IF_POSSIBLE, ) -> None: diff --git a/PIconnect/PIPoint.py b/PIconnect/PIPoint.py index d9d597e3..2d9bf4d8 100644 --- a/PIconnect/PIPoint.py +++ b/PIconnect/PIPoint.py @@ -1,6 +1,6 @@ """PIPoint.""" -from typing import Any, Dict, Optional +from typing import Any import PIconnect._typing.AF as _AFtyping from PIconnect import AF, PIData, _time @@ -56,13 +56,13 @@ def name(self) -> str: return self.tag @property - def raw_attributes(self) -> Dict[str, Any]: + def raw_attributes(self) -> dict[str, Any]: """Return a dictionary of the raw attributes of the PI Point.""" self.__load_attributes() return self.__raw_attributes @property - def units_of_measurement(self) -> Optional[str]: + def units_of_measurement(self) -> str | None: """Return the units of measument in which values for this PI Point are reported.""" return self.raw_attributes["engunits"] diff --git a/PIconnect/_time.py b/PIconnect/_time.py index abfa39eb..6355f2d6 100644 --- a/PIconnect/_time.py +++ b/PIconnect/_time.py @@ -3,12 +3,11 @@ # pyright: strict import datetime import zoneinfo -from typing import Union from PIconnect import AF, PIConfig from PIconnect.AFSDK import System -TimeLike = Union[str, datetime.datetime] +TimeLike = str | datetime.datetime def to_af_time_range(start_time: TimeLike, end_time: TimeLike) -> AF.Time.AFTimeRange: diff --git a/PIconnect/_typing/AF.py b/PIconnect/_typing/AF.py index 671471ac..aaa89a93 100644 --- a/PIconnect/_typing/AF.py +++ b/PIconnect/_typing/AF.py @@ -1,6 +1,6 @@ """Mock classes for the AF namespace of the OSIsoft PI-AF SDK.""" -from typing import Iterator, List +from collections.abc import Iterator from . import PI, Asset, Data, EventFrame, Time, UnitsOfMeasure @@ -22,8 +22,8 @@ class AFCategory: """Mock class of the AF.AFCategory class.""" -class AFCategories(List[AFCategory]): - def __init__(self, elements: List[AFCategory]) -> None: +class AFCategories(list[AFCategory]): + def __init__(self, elements: list[AFCategory]) -> None: self.Count: int self._values = elements @@ -33,7 +33,9 @@ class AFDatabase: def __init__(self, name: str) -> None: self.Name = name - self.Elements = Asset.AFElements([Asset.AFElement("TestElement")]) + self.Elements = Asset.AFElements( + [Asset.AFElement("TestElement"), Asset.AFElement("BaseElement")] + ) self.Tables = Asset.AFTables([Asset.AFTable("TestTable")]) diff --git a/PIconnect/_typing/Asset.py b/PIconnect/_typing/Asset.py index 00e6a9a3..fb2cf445 100644 --- a/PIconnect/_typing/Asset.py +++ b/PIconnect/_typing/Asset.py @@ -1,7 +1,7 @@ """Mock classes for the AF module.""" from collections.abc import Iterator -from typing import Optional, Union, cast +from typing import cast from . import AF, Data, Generic from . import UnitsOfMeasure as UOM @@ -23,7 +23,7 @@ class AFAttribute: - def __init__(self, name: str, parent: Optional["AFAttribute"] = None) -> None: + def __init__(self, name: str, parent: "AFAttribute | None" = None) -> None: self.Attributes: AFAttributes if parent is None: self.Attributes = AFAttributes( @@ -55,7 +55,7 @@ def __iter__(self) -> Iterator[AFAttribute]: class AFBaseElement: - def __init__(self, name: str, parent: Optional["AFElement"] = None) -> None: + def __init__(self, name: str, parent: "AFElement | None" = None) -> None: self.Attributes = AFAttributes( [ AFAttribute("Attribute1"), @@ -86,7 +86,7 @@ def __init__(self, elements: list[AFElement]) -> None: self.Count: int self._values = elements - def get_Item(self, name: Union[str, int]) -> AFElement: + def get_Item(self, name: str | int) -> AFElement: """Stub for the indexer.""" if isinstance(name, int): return self._values[name] @@ -104,7 +104,7 @@ class AFDataReference: from . import PI def __init__( - self, name: str, attribute: AFAttribute, pi_point: Optional[PI.PIPoint] = None + self, name: str, attribute: AFAttribute, pi_point: PI.PIPoint | None = None ) -> None: self.Attribute = attribute self.Name = name diff --git a/PIconnect/_typing/EventFrame.py b/PIconnect/_typing/EventFrame.py index 25f1b18a..1fda7725 100644 --- a/PIconnect/_typing/EventFrame.py +++ b/PIconnect/_typing/EventFrame.py @@ -1,7 +1,7 @@ """Mock classes for the AF.EventFrame namespace of the OSIsoft PI-AF SDK.""" import enum -from typing import Iterable, List, Optional +from collections.abc import Iterable from . import AF, Asset, Time @@ -19,7 +19,7 @@ class AFEventFrameSearchMode(enum.IntEnum): class AFEventFrame(Asset.AFBaseElement): """Mock class of the AF.EventFrame.AFEventFrame class.""" - def __init__(self, name: str, parent: Optional["AFEventFrame"] = None) -> None: + def __init__(self, name: str, parent: "AFEventFrame | None" = None) -> None: self.Name = name self.Parent = parent self.EventFrames: AFEventFrames @@ -27,22 +27,22 @@ def __init__(self, name: str, parent: Optional["AFEventFrame"] = None) -> None: @staticmethod def FindEventFrames( database: "AF.AFDatabase", - search_root: Optional["AFEventFrame"], + search_root: "AFEventFrame | None", start_time: Time.AFTime, start_index: int, max_count: int, search_mode: AFEventFrameSearchMode, - name_filter: Optional[str] = None, - referenced_element_name_filter: Optional[str] = None, - element_category: Optional["AF.AFCategory"] = None, - element_template: Optional[Asset.AFElementTemplate] = None, + name_filter: str | None = None, + referenced_element_name_filter: str | None = None, + element_category: "AF.AFCategory | None" = None, + element_template: Asset.AFElementTemplate | None = None, search_full_hierarchy: bool = False, /, ) -> Iterable["AFEventFrame"]: return [] -class AFEventFrames(List[AFEventFrame]): - def __init__(self, elements: List[AFEventFrame]) -> None: +class AFEventFrames(list[AFEventFrame]): + def __init__(self, elements: list[AFEventFrame]) -> None: self.Count: int self._values = elements diff --git a/PIconnect/_typing/Generic.py b/PIconnect/_typing/Generic.py index 73f7a32d..4ff7dde6 100644 --- a/PIconnect/_typing/Generic.py +++ b/PIconnect/_typing/Generic.py @@ -3,7 +3,8 @@ TODO: Migrate to the `_typing.dotnet` module. """ -from typing import Any, Generic, Iterable, Iterator, Optional, Tuple, TypeVar +from collections.abc import Iterable, Iterator +from typing import Any, Generic, TypeVar _KT = TypeVar("_KT") _VT = TypeVar("_VT") @@ -16,7 +17,7 @@ def __init__(self, key: _KT, value: _VT) -> None: class Dictionary(Generic[_KT, _VT]): - def __init__(self, items: Iterable[Tuple[_KT, _VT]]) -> None: + def __init__(self, items: Iterable[tuple[_KT, _VT]]) -> None: self.Items = items def __iter__(self) -> Iterator[DictItem[_KT, _VT]]: @@ -41,7 +42,7 @@ def AppendChar(self, char: str) -> None: class NetworkCredential: def __init__( - self, username: str, password: SecureString, domain: Optional[str] = None + self, username: str, password: SecureString, domain: str | None = None ) -> None: self.UserName = username self.Password = password diff --git a/PIconnect/_typing/PI.py b/PIconnect/_typing/PI.py index 8cd174f0..1a5a8edf 100644 --- a/PIconnect/_typing/PI.py +++ b/PIconnect/_typing/PI.py @@ -1,7 +1,7 @@ """Mock classes of the AF.PI namespace of the OSIsoft PI-AF SDK.""" import enum -from typing import Iterable, Iterator, List, Optional, Union +from collections.abc import Iterable, Iterator from . import Data, Generic, Time, _values from . import dotnet as System @@ -33,8 +33,8 @@ def __init__(self, name: str) -> None: def Connect( self, - retry: Union[bool, System.Net.NetworkCredential], - authentication_mode: Optional[PIAuthenticationMode] = None, + retry: bool | System.Net.NetworkCredential, + authentication_mode: PIAuthenticationMode | None = None, ) -> None: """Stub for connecting to test server.""" self._connected = True @@ -82,14 +82,14 @@ def FilteredSummaries( def FindPIPoints( connection: PIServer, query: str, - source: Optional[str], - attribute_names: Optional[Iterable[str]], + source: str | None, + attribute_names: Iterable[str] | None, ) -> Iterable["PIPoint"]: """Stub to mock querying PIPoints.""" return [] @staticmethod - def GetAttributes(names: List[str], /) -> Generic.PropertyDict: + def GetAttributes(names: list[str], /) -> Generic.PropertyDict: return Generic.PropertyDict([]) @staticmethod @@ -107,7 +107,7 @@ def InterpolatedValues( return _values.AFValues() @staticmethod - def LoadAttributes(params: List[str], /) -> None: + def LoadAttributes(params: list[str], /) -> None: pass @staticmethod diff --git a/PIconnect/_typing/Time.py b/PIconnect/_typing/Time.py index 3a0ffa2d..81f6741d 100644 --- a/PIconnect/_typing/Time.py +++ b/PIconnect/_typing/Time.py @@ -1,7 +1,5 @@ """Mock classes for the AF.Time module.""" -from typing import Optional - from . import dotnet as System @@ -32,6 +30,6 @@ def __init__(self): pass @staticmethod - def Parse(interval: Optional[str], /) -> "AFTimeSpan": + def Parse(interval: str | None, /) -> "AFTimeSpan": """Stub for parsing strings that should return a AFTimeSpan.""" return AFTimeSpan() diff --git a/PIconnect/_typing/_values.py b/PIconnect/_typing/_values.py index dfb3b41d..b0cfda65 100644 --- a/PIconnect/_typing/_values.py +++ b/PIconnect/_typing/_values.py @@ -3,7 +3,7 @@ These classes are in a separate file to avoid circular imports. """ -from typing import Any, List +from typing import Any from . import Time @@ -16,7 +16,7 @@ def __init__(self, value: Any, timestamp: Time.AFTime = _DEFAULT_TIME) -> None: self.Timestamp = timestamp -class AFValues(List[AFValue]): +class AFValues(list[AFValue]): def __init__(self): self.Count: int - self.Value: List[AFValue] + self.Value: list[AFValue] diff --git a/PIconnect/_typing/dotnet/Data.py b/PIconnect/_typing/dotnet/Data.py index 9c6360f8..b10f028b 100644 --- a/PIconnect/_typing/dotnet/Data.py +++ b/PIconnect/_typing/dotnet/Data.py @@ -1,6 +1,7 @@ """Mock classes for the System.Data module.""" -from typing import Any, Dict, Iterator, List +from collections.abc import Iterator +from typing import Any __all__ = [ "DataRow", @@ -12,14 +13,14 @@ class DataRow: - __fields: Dict[str, Any] + __fields: dict[str, Any] def __getitem__(self, key: str) -> Any: return self.__fields[key] class DataRowCollection: - rows: List[DataRow] + rows: list[DataRow] def __iter__(self) -> Iterator[DataRow]: yield from self.rows @@ -31,7 +32,7 @@ def __init__(self, name: str) -> None: class DataColumnCollection: - columns: List[DataColumn] + columns: list[DataColumn] def __iter__(self) -> Iterator[DataColumn]: yield from self.columns @@ -39,5 +40,5 @@ def __iter__(self) -> Iterator[DataColumn]: class DataTable: Name: str - Rows: List[DataRow] - Columns: List[DataColumn] + Rows: list[DataRow] + Columns: list[DataColumn] diff --git a/PIconnect/_typing/dotnet/Net.py b/PIconnect/_typing/dotnet/Net.py index 7e01bf81..92315f7d 100644 --- a/PIconnect/_typing/dotnet/Net.py +++ b/PIconnect/_typing/dotnet/Net.py @@ -1,13 +1,11 @@ """Mock classes for the System.Net module.""" -from typing import Optional - from .Security import SecureString class NetworkCredential: def __init__( - self, username: str, password: SecureString, domain: Optional[str] = None + self, username: str, password: SecureString, domain: str | None = None ) -> None: self.UserName = username self.Password = password diff --git a/PIconnect/_version.py b/PIconnect/_version.py index 62d82f87..36a4bc12 100644 --- a/PIconnect/_version.py +++ b/PIconnect/_version.py @@ -16,10 +16,10 @@ import re import subprocess import sys -from typing import Any, Callable, Dict, List, Optional, Tuple +from typing import Any -def get_keywords() -> Dict[str, str]: +def get_keywords() -> dict[str, str]: """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must @@ -61,14 +61,14 @@ class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" -LONG_VERSION_PY: Dict[str, str] = {} -HANDLERS: Dict[str, Dict[str, Callable]] = {} +LONG_VERSION_PY: dict[str, str] = {} +HANDLERS: dict[str, dict[str, callable]] = {} -def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator +def register_vcs_handler(vcs: str, method: str) -> callable: # decorator """Create decorator to mark a method as the handler of a VCS.""" - def decorate(f: Callable) -> Callable: + def decorate(f: callable) -> callable: """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} @@ -79,18 +79,18 @@ def decorate(f: Callable) -> Callable: def run_command( - commands: List[str], - args: List[str], - cwd: Optional[str] = None, + commands: list[str], + args: list[str], + cwd: str | None = None, verbose: bool = False, hide_stderr: bool = False, - env: Optional[Dict[str, str]] = None, -) -> Tuple[Optional[str], Optional[int]]: + env: dict[str, str] | None = None, +) -> tuple[str | None, int | None]: """Call the given command(s).""" assert isinstance(commands, list) process = None - popen_kwargs: Dict[str, Any] = {} + popen_kwargs: dict[str, Any] = {} if sys.platform == "win32": # This hides the console window if pythonw.exe is used startupinfo = subprocess.STARTUPINFO() @@ -134,7 +134,7 @@ def versions_from_parentdir( parentdir_prefix: str, root: str, verbose: bool, -) -> Dict[str, Any]: +) -> dict[str, Any]: """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both @@ -165,13 +165,13 @@ def versions_from_parentdir( @register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: +def git_get_keywords(versionfile_abs: str) -> dict[str, str]: """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. - keywords: Dict[str, str] = {} + keywords: dict[str, str] = {} try: with open(versionfile_abs, "r") as fobj: for line in fobj: @@ -194,10 +194,10 @@ def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: @register_vcs_handler("git", "keywords") def git_versions_from_keywords( - keywords: Dict[str, str], + keywords: dict[str, str], tag_prefix: str, verbose: bool, -) -> Dict[str, Any]: +) -> dict[str, Any]: """Get version information from git keywords.""" if "refnames" not in keywords: raise NotThisMethod("Short version file found") @@ -269,8 +269,8 @@ def git_versions_from_keywords( @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs( - tag_prefix: str, root: str, verbose: bool, runner: Callable = run_command -) -> Dict[str, Any]: + tag_prefix: str, root: str, verbose: bool, runner: callable = run_command +) -> dict[str, Any]: """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* @@ -318,7 +318,7 @@ def git_pieces_from_vcs( raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() - pieces: Dict[str, Any] = {} + pieces: dict[str, Any] = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None @@ -410,14 +410,14 @@ def git_pieces_from_vcs( return pieces -def plus_or_dot(pieces: Dict[str, Any]) -> str: +def plus_or_dot(pieces: dict[str, Any]) -> str: """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" -def render_pep440(pieces: Dict[str, Any]) -> str: +def render_pep440(pieces: dict[str, Any]) -> str: """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you @@ -441,7 +441,7 @@ def render_pep440(pieces: Dict[str, Any]) -> str: return rendered -def render_pep440_branch(pieces: Dict[str, Any]) -> str: +def render_pep440_branch(pieces: dict[str, Any]) -> str: """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . The ".dev0" means not master branch. Note that .dev0 sorts backwards @@ -470,7 +470,7 @@ def render_pep440_branch(pieces: Dict[str, Any]) -> str: return rendered -def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: +def pep440_split_post(ver: str) -> tuple[str, int | None]: """Split pep440 version string at the post-release segment. Returns the release segments before the post-release and the @@ -480,7 +480,7 @@ def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: return vc[0], int(vc[1] or 0) if len(vc) == 2 else None -def render_pep440_pre(pieces: Dict[str, Any]) -> str: +def render_pep440_pre(pieces: dict[str, Any]) -> str: """TAG[.postN.devDISTANCE] -- No -dirty. Exceptions: @@ -504,7 +504,7 @@ def render_pep440_pre(pieces: Dict[str, Any]) -> str: return rendered -def render_pep440_post(pieces: Dict[str, Any]) -> str: +def render_pep440_post(pieces: dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards @@ -531,7 +531,7 @@ def render_pep440_post(pieces: Dict[str, Any]) -> str: return rendered -def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: +def render_pep440_post_branch(pieces: dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . The ".dev0" means not master branch. @@ -560,7 +560,7 @@ def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: return rendered -def render_pep440_old(pieces: Dict[str, Any]) -> str: +def render_pep440_old(pieces: dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. @@ -582,7 +582,7 @@ def render_pep440_old(pieces: Dict[str, Any]) -> str: return rendered -def render_git_describe(pieces: Dict[str, Any]) -> str: +def render_git_describe(pieces: dict[str, Any]) -> str: """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. @@ -602,7 +602,7 @@ def render_git_describe(pieces: Dict[str, Any]) -> str: return rendered -def render_git_describe_long(pieces: Dict[str, Any]) -> str: +def render_git_describe_long(pieces: dict[str, Any]) -> str: """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. @@ -622,7 +622,7 @@ def render_git_describe_long(pieces: Dict[str, Any]) -> str: return rendered -def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: +def render(pieces: dict[str, Any], style: str) -> dict[str, Any]: """Render the given version pieces into the requested style.""" if pieces["error"]: return { @@ -664,7 +664,7 @@ def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: } -def get_versions() -> Dict[str, Any]: +def get_versions() -> dict[str, Any]: """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some diff --git a/README.rst b/README.rst index 79e92400..649990bf 100644 --- a/README.rst +++ b/README.rst @@ -35,9 +35,9 @@ allow opening a connection using a with statement. :target: https://www.codacy.com/app/Hugovdberg/PIconnect?utm_source=github.com&utm_medium=referral&utm_content=Hugovdberg/PIconnect&utm_campaign=Badge_Grade :alt: Automated code review -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: black +.. image:: https://img.shields.io/badge/code%20style-ruff-000000.svg + :target: https://astral.sh/ruff + :alt: Code style: ruff Python connector to OSIsoft PI SDK diff --git a/pixi.lock b/pixi.lock index 9ff20d70..c1d4e431 100644 --- a/pixi.lock +++ b/pixi.lock @@ -2454,8 +2454,8 @@ packages: timestamp: 1726879653675 - pypi: . name: piconnect - version: 0.12.1+32.g454b892.dirty - sha256: 72d6e0a9b6f6cdf06448bd9c79f6bb9ce2dd1afe6aeec3e6fa9aa787ea9462e6 + version: 0.12.3+5.g8fa1ff4.dirty + sha256: 223321229fde6ca63b82ad450dcb1291f5603baa47a47ee1b5f9832fbce20817 requires_dist: - pandas>=2,<3 - numpy>=2,<3 diff --git a/pyproject.toml b/pyproject.toml index e86e5d89..0854c044 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "PIconnect" description = "PIconnect - Connector to the OSISoft PI and PI-AF databases." authors = [{ name = "Hugo Lapre", email = "dev@tbdwebdesign.nl" }] readme = "README.rst" -license = "MIT" +license = { text = "MIT" } keywords = ["OSIsoft", "AVEVA", "PI", "Process Information", "PIconnect"] classifiers = [ "Development Status :: 4 - Beta", @@ -28,7 +28,7 @@ Issues = "https://github.com/Hugovdberg/PIconnect/issues" Documentation = "https://piconnect.readthedocs.io/en/stable/" [build-system] -requires = ["setuptools>=77", "versioneer[toml]>=0.28"] +requires = ["setuptools>=75", "versioneer[toml]>=0.28"] build-backend = "setuptools.build_meta" [tool.pixi.project] diff --git a/pyrightconfig.json b/pyrightconfig.json index efadb91c..1247f650 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -5,9 +5,11 @@ "*.egg-info/*", "build/*", "dist/*", - ".tox/*" + ".tox/*", + "PIconnect/_versions.py" ], "ignore": [ - "PIconnect/_operators.py" - ] + ], + "pythonVersion": "3.10", + "deprecateTypingAliases": true } diff --git a/tests/fakes.py b/tests/fakes.py index 9d8fc5c1..260f4f3c 100644 --- a/tests/fakes.py +++ b/tests/fakes.py @@ -2,7 +2,8 @@ import dataclasses import datetime -from typing import Any, Dict, Generic, Iterable, List, TypeVar +from collections.abc import Iterable +from typing import Any, Generic, TypeVar import pytest import pytz @@ -73,7 +74,7 @@ def __init__( tag: str, values: Iterable[_a], timestamps: Iterable[datetime.datetime], - attributes: Dict[str, Any], + attributes: dict[str, Any], ): self.Name = tag self.values = [ @@ -100,17 +101,17 @@ def LoadAttributes(self, *args: Any, **kwargs: Any) -> None: """Load the attributes of the PI Point.""" self.call_stack.append("LoadAttributes called") - def GetAttributes(self, *args: Any, **kwargs: Any) -> List[FakeKeyValue[str, Any]]: + def GetAttributes(self, *args: Any, **kwargs: Any) -> list[FakeKeyValue[str, Any]]: """Return the attributes of the PI Point.""" self.call_stack.append("GetAttributes called") return self.pi_point.attributes - def RecordedValues(self, *args: Any, **kwargs: Any) -> List[FakeAFValue[_a]]: + def RecordedValues(self, *args: Any, **kwargs: Any) -> list[FakeAFValue[_a]]: """Return the recorded values of the PI Point.""" self.call_stack.append("RecordedValues called") return self.pi_point.values - def InterpolatedValues(self, *args: Any, **kwargs: Any) -> List[FakeAFValue[_a]]: + def InterpolatedValues(self, *args: Any, **kwargs: Any) -> list[FakeAFValue[_a]]: """Return the interpolated values of the PI Point.""" self.call_stack.append("InterpolatedValues called") return self.pi_point.values