diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50dff03f..237348e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,16 +13,16 @@ on: - cron: "27 19 * * 3" jobs: - build: + run_tests: runs-on: windows-latest strategy: fail-fast: false matrix: python-version: [ - '3.8' - , '3.9' + '3.9' , '3.10' - # , '3.11' + , '3.11' + , '3.12' ] steps: @@ -36,23 +36,16 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 pytest wheel + python -m pip install pytest wheel python -m pip install pytest-cov python -m pip install --exists-action=w --no-cache-dir -r requirements_dev.txt python -m pip install . - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest run: | pytest - check_format: + lint_and_check_format: runs-on: windows-latest steps: @@ -66,12 +59,15 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install black + python -m pip install ruff + + - name: Lint with ruff + run: | + ruff check . - - name: Check formatting with black + - name: Check formatting with ruff run: | - # stop the build if there are Python syntax errors or undefined names - black --check --diff PIconnect + ruff format --check # codacy-security-scan: # name: Codacy Security Scan diff --git a/PIconnect/AFSDK.py b/PIconnect/AFSDK.py index 4301ada9..37bfa9a5 100644 --- a/PIconnect/AFSDK.py +++ b/PIconnect/AFSDK.py @@ -1,6 +1,5 @@ -""" AFSDK - Loads the .NET libraries from the OSIsoft AF SDK -""" +"""AFSDK - Loads the .NET libraries from the OSIsoft AF SDK.""" + import logging import os import sys @@ -16,7 +15,11 @@ def __fallback(): import warnings - warnings.warn("Can't import the PI AF SDK, running in test mode", ImportWarning) + warnings.warn( + "Can't import the PI AF SDK, running in test mode", + ImportWarning, + stacklevel=2, + ) from ._typing import AF as _af from ._typing import AF_SDK_VERSION as _AF_SDK_version @@ -32,7 +35,7 @@ def __fallback(): ): _af, _System, _AF_SDK_version = __fallback() else: - import clr + import clr # type: ignore # Get the installation directory from the environment variable or fall back # to the Windows default installation path @@ -60,7 +63,7 @@ def __fallback(): import System as _System # type: ignore from OSIsoft import AF as _af # type: ignore - _AF_SDK_version: str = _af.PISystems().Version # type: ignore ; pylint: disable=no-member + _AF_SDK_version = typing.cast(str, _af.PISystems().Version) # type: ignore ; pylint: disable=no-member print("OSIsoft(r) AF SDK Version: {}".format(_AF_SDK_version)) diff --git a/PIconnect/PI.py b/PIconnect/PI.py index 1fe18739..9a4f5788 100644 --- a/PIconnect/PI.py +++ b/PIconnect/PI.py @@ -1,6 +1,5 @@ -""" PI - Core containers for connections to PI databases -""" +"""PI - Core containers for connections to PI databases.""" + import warnings from typing import Any, Dict, List, Optional, Union, cast @@ -12,6 +11,7 @@ __all__ = ["PIServer", "PIPoint"] PIPoint = PIPoint_.PIPoint +_DEFAULT_AUTH_MODE = PIConsts.AuthenticationMode.PI_USER_AUTHENTICATION def _lookup_servers() -> Dict[str, AF.PI.PIServer]: @@ -25,6 +25,7 @@ def _lookup_servers() -> Dict[str, AF.PI.PIServer]: f"Failed loading server data for {server.Name} " f"with error {type(cast(Exception, e)).__qualname__}", InitialisationWarning, + stacklevel=2, ) return servers @@ -34,14 +35,15 @@ def _lookup_default_server() -> Optional[AF.PI.PIServer]: try: default_server = AF.PI.PIServers().DefaultPIServer except Exception: - warnings.warn("Could not load the default PI Server", ResourceWarning) + warnings.warn("Could not load the default PI Server", ResourceWarning, stacklevel=2) return default_server class PIServer(object): # pylint: disable=useless-object-inheritance - """PIServer is a connection to an OSIsoft PI Server + """PIServer is a connection to an OSIsoft PI Server. - Args: + Parameters + ---------- server (str, optional): Name of the server to connect to, defaults to None username (str, optional): can be used only with password as well password (str, optional): -//- @@ -67,14 +69,12 @@ def __init__( username: Optional[str] = None, password: Optional[str] = None, domain: Optional[str] = None, - authentication_mode: PIConsts.AuthenticationMode = PIConsts.AuthenticationMode.PI_USER_AUTHENTICATION, + authentication_mode: PIConsts.AuthenticationMode = _DEFAULT_AUTH_MODE, timeout: Optional[int] = None, ) -> None: if server is None: if self.default_server is None: - raise ValueError( - "No server was specified and no default server was found." - ) + raise ValueError("No server was specified and no default server was found.") self.connection = self.default_server elif server not in self.servers: if self.default_server is None: @@ -82,7 +82,9 @@ def __init__( f"Server '{server}' not found and no default server was found." ) message = 'Server "{server}" not found, using the default server.' - warnings.warn(message=message.format(server=server), category=UserWarning) + warnings.warn( + message=message.format(server=server), category=UserWarning, stacklevel=1 + ) self.connection = self.default_server else: self.connection = self.servers[server] @@ -110,11 +112,10 @@ def __init__( if timeout: # System.TimeSpan(hours, minutes, seconds) - self.connection.ConnectionInfo.OperationTimeOut = System.TimeSpan( - 0, 0, timeout - ) + self.connection.ConnectionInfo.OperationTimeOut = System.TimeSpan(0, 0, timeout) def __enter__(self): + """Open connection context with the PI Server.""" if self._credentials: self.connection.Connect(*self._credentials) else: @@ -124,31 +125,30 @@ def __enter__(self): return self def __exit__(self, *args: Any): + """Close connection context with the PI Server.""" self.connection.Disconnect() def __repr__(self) -> str: - return "%s(\\\\%s)" % (self.__class__.__name__, self.server_name) + """Representation of the PIServer object.""" + return f"{self.__class__.__qualname__}(\\\\{self.server_name})" @property def server_name(self): - """server_name - - Name of the connected server - """ + """Name of the connected server.""" return self.connection.Name def search( self, query: Union[str, List[str]], source: Optional[str] = None ) -> List[PIPoint_.PIPoint]: - """search - - Search PIPoints on the PIServer + """Search PIPoints on the PIServer. - Args: + Parameters + ---------- query (str or [str]): String or list of strings with queries source (str, optional): Defaults to None. Point source to limit the results - Returns: + Returns + ------- list: A list of :class:`PIPoint` objects as a result of the query .. todo:: diff --git a/PIconnect/PIAF.py b/PIconnect/PIAF.py index 0e5fb721..f20bb437 100644 --- a/PIconnect/PIAF.py +++ b/PIconnect/PIAF.py @@ -1,22 +1,25 @@ -""" PIAF - Core containers for connections to the PI Asset Framework. -""" +"""PIAF - Core containers for connections to the PI Asset Framework.""" + import dataclasses import warnings -from typing import Any, Dict, Optional, Union, cast, List +from typing import Any, Dict, List, Optional, Union, cast -from PIconnect import AF, PIAFBase, PIConsts, _time -from PIconnect.AFSDK import System +from PIconnect import AF, PIAFAttribute, PIAFBase, PIConsts, _time from PIconnect._utils import InitialisationWarning -from PIconnect import PIAFAttribute +from PIconnect.AFSDK import System + +_DEFAULT_EVENTFRAME_SEARCH_MODE = PIConsts.EventFrameSearchMode.STARTING_AFTER @dataclasses.dataclass(frozen=True) class PIAFServer: + """Reference to a PI AF server and its databases.""" + 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]]: + """Allow access to attributes as if they were dictionary items.""" return getattr(self, attr) @@ -36,17 +39,19 @@ def _lookup_servers() -> Dict[str, ServerSpec]: f"Failed loading database data for {d.Name} on {s.Name} " f"with error {type(cast(Exception, e)).__qualname__}", InitialisationWarning, + stacklevel=2, ) except (Exception, System.Exception) as e: # type: ignore warnings.warn( f"Failed loading server data for {s.Name} " f"with error {type(cast(Exception, e)).__qualname__}", InitialisationWarning, + stacklevel=2, ) return { server_name: { "server": server.server, - "databases": {db_name: db for db_name, db in server.databases.items()}, + "databases": dict(server.databases.items()), } for server_name, server in servers.items() } @@ -63,19 +68,14 @@ def _lookup_default_server() -> Optional[ServerSpec]: class PIAFDatabase(object): - """PIAFDatabase - - Context manager for connections to the PI Asset Framework database. - """ + """Context manager for connections to the PI Asset Framework database.""" version = "0.2.0" servers: Dict[str, ServerSpec] = _lookup_servers() default_server: Optional[ServerSpec] = _lookup_default_server() - def __init__( - self, server: Optional[str] = None, database: Optional[str] = None - ) -> None: + def __init__(self, server: Optional[str] = None, database: Optional[str] = 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) @@ -88,11 +88,11 @@ def _initialise_server(self, server: Optional[str]) -> ServerSpec: if server not in self.servers: if self.default_server is None: - raise ValueError( - f'Server "{server}" not found and no default server found.' - ) + raise ValueError(f'Server "{server}" not found and no default server found.') message = 'Server "{server}" not found, using the default server.' - warnings.warn(message=message.format(server=server), category=UserWarning) + warnings.warn( + message=message.format(server=server), category=UserWarning, stacklevel=2 + ) return self.default_server return self.servers[server] @@ -108,28 +108,27 @@ def _initialise_database( if database not in databases: message = 'Database "{database}" not found, using the default database.' warnings.warn( - message=message.format(database=database), category=UserWarning + message=message.format(database=database), category=UserWarning, stacklevel=2 ) return default_db return databases[database] def __enter__(self) -> "PIAFDatabase": + """Open the PI AF server connection context.""" self.server.Connect() return self def __exit__(self, *args: Any) -> None: + """Close the PI AF server connection context.""" pass # Disabled disconnecting because garbage collection sometimes impedes # connecting to another server later # self.server.Disconnect() def __repr__(self) -> str: - return "%s(\\\\%s\\%s)" % ( - self.__class__.__name__, - self.server_name, - self.database_name, - ) + """Return a representation of the PI AF database connection.""" + return f"{self.__class__.__qualname__}(\\\\{self.server_name}\\{self.database_name})" @property def server_name(self) -> str: @@ -151,7 +150,9 @@ def descendant(self, path: str) -> "PIAFElement": return PIAFElement(self.database.Elements.get_Item(path)) def search(self, query: Union[str, List[str]]) -> List[PIAFAttribute.PIAFAttribute]: - """return a list of PIAFAttributes directly from a list of element|attribute path strings + """Search PIAFAttributes by element|attribute path strings. + + Return a list of PIAFAttributes directly from a list of element|attribute path strings like this: @@ -177,9 +178,10 @@ def event_frames( start_time: _time.TimeLike = "", start_index: int = 0, max_count: int = 1000, - search_mode: PIConsts.EventFrameSearchMode = PIConsts.EventFrameSearchMode.STARTING_AFTER, + search_mode: PIConsts.EventFrameSearchMode = _DEFAULT_EVENTFRAME_SEARCH_MODE, search_full_hierarchy: bool = False, ) -> Dict[str, "PIAFEventFrame"]: + """Search for event frames in the database.""" _start_time = _time.to_af_time(start_time) _search_mode = AF.EventFrame.AFEventFrameSearchMode(int(search_mode)) return { @@ -229,6 +231,7 @@ class PIAFEventFrame(PIAFBase.PIAFBaseElement[AF.EventFrame.AFEventFrame]): @property def event_frame(self) -> AF.EventFrame.AFEventFrame: + """Return the underlying AF Event Frame object.""" return self.element @property diff --git a/PIconnect/PIAFAttribute.py b/PIconnect/PIAFAttribute.py index 13486c47..38692d8a 100644 --- a/PIconnect/PIAFAttribute.py +++ b/PIconnect/PIAFAttribute.py @@ -1,10 +1,11 @@ +"""Module for the PIAFAttribute class.""" + import dataclasses import datetime from typing import Any, Dict, Optional -from PIconnect import AF, PIPoint, PIData, _time +from PIconnect import AF, PIData, PIPoint, _time -from ._operators import OPERATORS, add_operators # type: ignore from ._typing import AF as _AFtyping __all__ = ["PIAFAttribute"] @@ -25,12 +26,6 @@ def pi_point(self) -> Optional[PIPoint.PIPoint]: return PIPoint.PIPoint(self.data_reference.PIPoint) -@add_operators( - operators=OPERATORS, - members=["_current_value", "interpolated_values"], - newclassname="VirtualPIAFAttribute", - attributes=["element", "attribute"], -) class PIAFAttribute(PIData.PISeriesContainer): """Container for attributes of PI AF elements in the database.""" @@ -44,12 +39,10 @@ def __init__( self.attribute = attribute def __repr__(self): - return "%s(%s, %s; Current Value: %s %s)" % ( - self.__class__.__name__, - self.name, - self.description, - self.current_value, - self.units_of_measurement, + """Return the string representation of the current attribute.""" + return ( + f"{self.__class__.__qualname__}({self.name}, {self.description}; " + f"Current Value: {self.current_value} {self.units_of_measurement}" ) @property @@ -72,9 +65,7 @@ def parent(self) -> Optional["PIAFAttribute"]: @property 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 - } + return {a.Name: self.__class__(self.element, a) for a in self.attribute.Attributes} @property def description(self) -> str: @@ -117,13 +108,13 @@ def _filtered_summaries( ) def _interpolated_value(self, time: AF.Time.AFTime): - """Return a single value for this PI Point""" + """Return a single value for this PI Point.""" return self.attribute.Data.InterpolatedValue(time, self.attribute.DefaultUOM) def _recorded_value( self, time: AF.Time.AFTime, retrieval_mode: AF.Data.AFRetrievalMode ) -> AF.Asset.AFValue: - """Return a single value for this PI Point""" + """Return a single value for this PI Point.""" return self.attribute.Data.RecordedValue( time, retrieval_mode, self.attribute.DefaultUOM ) @@ -149,7 +140,7 @@ def _interpolated_values( interval: AF.Time.AFTimeSpan, filter_expression: str, ) -> AF.Asset.AFValues: - """Internal function to actually query the pi point""" + """Query the pi af attribute, internal implementation.""" include_filtered_values = False return self.attribute.Data.InterpolatedValues( time_range, diff --git a/PIconnect/PIAFBase.py b/PIconnect/PIAFBase.py index 170254cd..31df979e 100644 --- a/PIconnect/PIAFBase.py +++ b/PIconnect/PIAFBase.py @@ -1,3 +1,5 @@ +"""Base element class for PI AF elements.""" + from typing import Dict, Generic, TypeVar import PIconnect.PIAFAttribute as PIattr @@ -15,7 +17,8 @@ def __init__(self, element: ElementType) -> None: self.element = element def __repr__(self) -> str: - return "%s(%s)" % (self.__class__.__name__, self.name) + """Return the string representation of the element.""" + return f"{self.__class__.__qualname__}({self.name})" @property def name(self) -> str: @@ -25,15 +28,14 @@ def name(self) -> str: @property 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 - } + return {a.Name: PIattr.PIAFAttribute(self.element, a) for a in self.element.Attributes} @property def categories(self) -> AF.AFCategories: + """Return the categories of the current element.""" return self.element.Categories @property def description(self) -> str: + """Return the description of the current element.""" return self.element.Description diff --git a/PIconnect/PIConsts.py b/PIconnect/PIConsts.py index 05b1f101..1ebfd88a 100644 --- a/PIconnect/PIConsts.py +++ b/PIconnect/PIConsts.py @@ -1,14 +1,20 @@ +"""Enumerations for PI options.""" + import enum class UpdateMode(enum.IntEnum): - """Indicates how to treat duplicate values in the archive, when supported by the Data Reference. + """Indicates how to treat duplicate values in the archive. + + Only used when supported by the Data Reference. - Detailed information is available at :afsdk:`AF.Data.AFUpdateOption ` + Detailed information is available at + :afsdk:`AF.Data.AFUpdateOption ` """ #: Add the value to the archive. - #: If any values exist at the same time, will overwrite one of them and set its Substituted flag. + #: If any values exist at the same time, will overwrite one of them and set its + #: Substituted flag. REPLACE = 0 #: Add the value to the archive. Any existing values at the same time are not overwritten. INSERT = 1 @@ -19,9 +25,11 @@ class UpdateMode(enum.IntEnum): #: If no existing value is found, the passed value is ignored. REPLACE_ONLY = 3 #: Add the value to the archive without compression. - #: If this value is written to the snapshot, the previous snapshot value will be written to the archive, + #: If this value is written to the snapshot, the previous snapshot value will be written to + #: the archive, #: without regard to compression settings. - #: Note that if a subsequent snapshot value is written without the InsertNoCompression option, + #: Note that if a subsequent snapshot value is written without the InsertNoCompression + #: option, #: the value added with the InsertNoCompression option is still subject to compression. INSERT_NO_COMPRESSION = 5 #: Remove the value from the archive if a value exists at the passed time. @@ -31,13 +39,15 @@ class UpdateMode(enum.IntEnum): class BufferMode(enum.IntEnum): """Indicates buffering option in updating values, when supported by the Data Reference. - Detailed information is available at :afsdk:`AF.Data.AFBufferOption ` + Detailed information is available at + :afsdk:`AF.Data.AFBufferOption ` """ #: Updating data reference values without buffer. DO_NOT_BUFFER = 0 #: Try updating data reference values with buffer. - #: If fails (e.g. data reference AFDataMethods does not support Buffering, or its Buffering system is not available), + #: If fails (e.g. data reference AFDataMethods does not support Buffering, + #: or its Buffering system is not available), #: then try updating directly without buffer. BUFFER_IF_POSSIBLE = 1 # Updating data reference values with buffer. @@ -45,9 +55,10 @@ class BufferMode(enum.IntEnum): class AuthenticationMode(enum.IntEnum): - """AuthenticationMode indicates how a user authenticates to a PI Server + """AuthenticationMode indicates how a user authenticates to a PI Server. - Detailed information is available at :afsdk:`AF.PI.PIAuthenticationMode `. + Detailed information is available at + :afsdk:`AF.PI.PIAuthenticationMode `. """ #: Use Windows authentication when making a connection @@ -57,31 +68,38 @@ class AuthenticationMode(enum.IntEnum): class CalculationBasis(enum.IntEnum): - """CalculationBasis indicates how values should be weighted over a time range + """CalculationBasis indicates how values should be weighted over a time range. - Detailed information is available at :afsdk:`AF.Data.AFCalculationBasis `. + Detailed information is available at + :afsdk:`AF.Data.AFCalculationBasis `. """ #: Each event is weighted according to the time over which it applies. TIME_WEIGHTED = 0 #: Each event is weighted equally. EVENT_WEIGHTED = 1 - #: Each event is time weighted, but interpolation is always done as if it is continous data. + #: Each event is time weighted, but interpolation is always done as if it is + #: continous data. TIME_WEIGHTED_CONTINUOUS = 2 - #: Each event is time weighted, but interpolation is always done as if it is discrete, stepped, data. + #: Each event is time weighted, but interpolation is always done as if it is + #: discrete, stepped, data. TIME_WEIGHTED_DISCRETE = 3 - #: Each event is weighted equally, except data at the end of the interval is excluded. + #: Each event is weighted equally, except data at the end of the interval is + #: excluded. EVENT_WEIGHTED_EXCLUDE_MOST_RECENT = 4 - #: Each event is weighted equally, except data at the beginning of the interval is excluded. + #: Each event is weighted equally, except data at the beginning of the interval + #: is excluded. EVENT_WEIGHTED_EXCLUDE_EARLIEST = 5 - #: Each event is weighted equally, data at both boundaries of the interval are explicitly included. + #: Each event is weighted equally, data at both boundaries of the interval are + #: explicitly included. EVENT_WEIGHTED_INCLUDE_BOTH_ENDS = 6 class ExpressionSampleType(enum.IntEnum): """ExpressionSampleType indicates how expressions are evaluated over a time range. - Detailed information is available at :afsdk:`AF.Data.AFSampleType `. + Detailed information is available at + :afsdk:`AF.Data.AFSampleType `. """ #: The expression is evaluated at each archive event. @@ -91,9 +109,10 @@ class ExpressionSampleType(enum.IntEnum): class RetrievalMode(enum.IntEnum): - """RetrievalMode indicates which recorded value should be returned + """RetrievalMode indicates which recorded value should be returned. - Detailed information is available at :afsdk:`AF.Data.AFRetrievalMode `. + Detailed information is available at + :afsdk:`AF.Data.AFRetrievalMode `. """ #: Autmatic detection @@ -121,7 +140,8 @@ class SummaryType(enum.IntFlag): # On Python 3.6+ 12 # On previous versions - Detailed information is available at :afsdk:`AF.Data.AFSummaryTypes `. + Detailed information is available at + :afsdk:`AF.Data.AFSummaryTypes `. """ #: No summary data @@ -140,11 +160,16 @@ class SummaryType(enum.IntFlag): STD_DEV = 32 #: The population standard deviation of the values over the time span POP_STD_DEV = 64 - #: The sum of the event count (when the calculation is event weighted). The sum of the event time duration (when the calculation is time weighted.) + #: The sum of the event count (when the calculation is event weighted). + #: The sum of the event time duration (when the calculation is time weighted.) COUNT = 128 - #: The percentage of the data with a good value over the time range. Based on time for time weighted calculations, based on event count for event weigthed calculations. + #: The percentage of the data with a good value over the time range. + #: Based on time for time weighted calculations, + #: based on event count for event weigthed calculations. PERCENT_GOOD = 8192 - #: The total over the time span, with the unit of measurement that's associated with the input (or no units if not defined for the input). + #: The total over the time span, + #: with the unit of measurement that's associated with the input + #: (or no units if not defined for the input). TOTAL_WITH_UOM = 16384 #: A convenience to retrieve all summary types ALL = 24831 @@ -154,12 +179,14 @@ class SummaryType(enum.IntFlag): class TimestampCalculation(enum.IntEnum): """ - TimestampCalculation defines the timestamp returned for a given summary calculation + TimestampCalculation defines the timestamp returned for a given summary calculation. - Detailed information is available at :afsdk:`AF.Data.AFTimeStampCalculation `. + Detailed information is available at + :afsdk:`AF.Data.AFTimeStampCalculation `. """ - #: The timestamp is the event time of the minimum or maximum for those summaries or the beginning of the interval otherwise. + #: The timestamp is the event time of the minimum or maximum for those summaries + #: or the beginning of the interval otherwise. AUTO = 0 #: The timestamp is always the beginning of the interval. EARLIEST_TIME = 1 @@ -168,15 +195,16 @@ class TimestampCalculation(enum.IntEnum): class EventFrameSearchMode(enum.IntEnum): - """EventFrameSearchMode + """EventFrameSearchMode. EventFrameSearchMode defines the interpretation and direction from the start time when searching for event frames. - Detailed information is available at https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/T_OSIsoft_AF_EventFrame_AFEventFrameSearchMode.htm, + Detailed information is available at + :afsdk:`AF.EventFrame.AFEventFrameSearchMode `. including a graphical display of event frames that are returned for a given search mode. - """ + """ # noqa: E501 #: Uninitialized NONE = 0 diff --git a/PIconnect/PIData.py b/PIconnect/PIData.py index bf94965a..af57bb71 100644 --- a/PIconnect/PIData.py +++ b/PIconnect/PIData.py @@ -1,7 +1,5 @@ -""" -PIData contains a number of auxiliary classes that define common functionality -among :class:`PIPoint` and :class:`PIAFAttribute` objects. -""" +"""Auxiliary classes for PI Point and PIAFAttribute objects.""" + import abc import datetime from typing import Any, List, Optional @@ -16,13 +14,15 @@ "PISeriesContainer", ] +_DEFAULT_CALCULATION_BASIS = PIConsts.CalculationBasis.TIME_WEIGHTED +_DEFAULT_FILTER_EVALUATION = PIConsts.ExpressionSampleType.EXPRESSION_RECORDED_VALUES -class PISeries(pd.Series): # type: ignore - """PISeries - Create a timeseries, derived from :class:`pandas.Series` +class PISeries(pd.Series): # type: ignore + """Create a timeseries, derived from :class:`pandas.Series`. - Args: + Parameters + ---------- tag (str): Name of the new series timestamp (List[datetime]): List of datetime objects to create the new index @@ -48,16 +48,13 @@ def __init__( *args: Any, **kwargs: Any, ) -> None: - pd.Series.__init__(self, data=value, index=timestamp, name=tag, *args, **kwargs) # type: ignore + pd.Series.__init__(self, *args, data=value, index=timestamp, name=tag, **kwargs) # type: ignore self.tag = tag self.uom = uom class PISeriesContainer(abc.ABC): - """PISeriesContainer - - With the ABC class we represent a general behaviour with PI Point object - (General class for objects that return :class:`PISeries` objects). + """Generic behaviour for PI Series returning objects. .. todo:: @@ -74,9 +71,7 @@ class PISeriesContainer(abc.ABC): @property def current_value(self) -> Any: - """current_value - - Return the current value of the attribute.""" + """Return the current value of the attribute.""" return self._current_value() @abc.abstractmethod @@ -90,16 +85,15 @@ def filtered_summaries( interval: str, filter_expression: str, summary_types: PIConsts.SummaryType, - calculation_basis: PIConsts.CalculationBasis = PIConsts.CalculationBasis.TIME_WEIGHTED, - filter_evaluation: PIConsts.ExpressionSampleType = PIConsts.ExpressionSampleType.EXPRESSION_RECORDED_VALUES, + calculation_basis: PIConsts.CalculationBasis = _DEFAULT_CALCULATION_BASIS, + filter_evaluation: PIConsts.ExpressionSampleType = _DEFAULT_FILTER_EVALUATION, filter_interval: Optional[str] = None, time_type: PIConsts.TimestampCalculation = PIConsts.TimestampCalculation.AUTO, ) -> pd.DataFrame: - """filtered_summaries - - Return one or more summary values for each interval within a time range + """Return one or more summary values for each interval within a time range. - Args: + Parameters + ---------- start_time (str or datetime): String containing the date, and possibly time, from which to retrieve the values. This is parsed, together with `end_time`, using @@ -133,7 +127,8 @@ def filtered_summaries( :ref:`summary_timestamps` and :any:`TimestampCalculation` for more information. Defaults to TimestampCalculation.AUTO. - Returns: + Returns + ------- pandas.DataFrame: Dataframe with the unique timestamps as row index and the summary name as column name. """ @@ -184,16 +179,20 @@ def _filtered_summaries( pass def interpolated_value(self, time: _time.TimeLike) -> PISeries: - """interpolated_value - - Return a PISeries with an interpolated value at the given time - - Args: + """Return a PISeries with an interpolated value at the given time. + + Parameters + ---------- + ----------eters + ---------- + ----------eters + ---------- time (str, datetime): String containing the date, and possibly time, for which to retrieve the value. This is parsed, using :afsdk:`AF.Time.AFTime `. - Returns: + Returns + ------- PISeries: A PISeries with a single row, with the corresponding time as the index """ @@ -219,9 +218,7 @@ def interpolated_values( interval: str, filter_expression: str = "", ) -> PISeries: - """interpolated_values - - Return a PISeries of interpolated data. + """Return a PISeries of interpolated data. Data is returned between *start_time* and *end_time* at a fixed *interval*. All three values are parsed by AF.Time and the first two @@ -235,7 +232,8 @@ def interpolated_values( values marked as such. At this point PIconnect does not support this and filtered values are always left out entirely. - Args: + Parameters + ---------- start_time (str or datetime): Containing the date, and possibly time, from which to retrieve the values. This is parsed, together with `end_time`, using @@ -251,7 +249,8 @@ def interpolated_values( data to include in the results. See :ref:`filtering_values` for more information on filter queries. - Returns: + Returns + ------- PISeries: Timeseries of the values returned by the SDK """ time_range = _time.to_af_time_range(start_time, end_time) @@ -283,6 +282,7 @@ def _interpolated_values( @property @abc.abstractmethod def name(self) -> str: + """Return the name of the current object.""" pass def _normalize_filter_expression(self, filter_expression: str) -> str: @@ -293,11 +293,10 @@ def recorded_value( time: _time.TimeLike, retrieval_mode: PIConsts.RetrievalMode = PIConsts.RetrievalMode.AUTO, ) -> PISeries: - """recorded_value + """Return a PISeries with the recorded value at or close to the given time. - Return a PISeries with the recorded value at or close to the given time - - Args: + Parameters + ---------- time (str): String containing the date, and possibly time, for which to retrieve the value. This is parsed, using :afsdk:`AF.Time.AFTime `. @@ -305,7 +304,8 @@ def recorded_value( which value to return if no value available at the exact requested time. - Returns: + Returns + ------- PISeries: A PISeries with a single row, with the corresponding time as the index """ @@ -334,9 +334,7 @@ def recorded_values( boundary_type: str = "inside", filter_expression: str = "", ): - """recorded_values - - Return a PISeries of recorded data. + """Return a PISeries of recorded data. Data is returned between the given *start_time* and *end_time*, inclusion of the boundaries is determined by the *boundary_type* @@ -357,7 +355,8 @@ def recorded_values( marked as such. At this point PIconnect does not support this and filtered values are always left out entirely. - Args: + Parameters + ---------- start_time (str or datetime): Containing the date, and possibly time, from which to retrieve the values. This is parsed, together with `end_time`, using @@ -373,14 +372,15 @@ def recorded_values( data to include in the results. See :ref:`filtering_values` for more information on filter queries. - Returns: + Returns + ------- PISeries: Timeseries of the values returned by the SDK - Raises: + Raises + ------ ValueError: If the provided `boundary_type` is not a valid key a `ValueError` is raised. """ - time_range = _time.to_af_time_range(start_time, end_time) _boundary_type = self.__boundary_types.get(boundary_type.lower()) if _boundary_type is None: @@ -411,7 +411,7 @@ def _recorded_values( boundary_type: AF.Data.AFBoundaryType, filter_expression: str, ) -> AF.Asset.AFValues: - """Abstract implementation for recorded values + """Abstract implementation for recorded values. The internals for retrieving recorded values from PI and PI-AF are different and should therefore be implemented by the respective data @@ -427,17 +427,18 @@ def summary( calculation_basis: PIConsts.CalculationBasis = PIConsts.CalculationBasis.TIME_WEIGHTED, time_type: PIConsts.TimestampCalculation = PIConsts.TimestampCalculation.AUTO, ) -> pd.DataFrame: - """summary + """Return one or more summary values over a single time range. - Return one or more summary values over a single time range. - - Args: + Parameters + ---------- start_time (str or datetime): Containing the date, and possibly time, from which to retrieve the values. This is parsed, together - with `end_time`, using :afsdk:`AF.Time.AFTimeRange `. + with `end_time`, using + :afsdk:`AF.Time.AFTimeRange `. end_time (str or datetime): Containing the date, and possibly time, until which to retrieve values. This is parsed, together - with `start_time`, using :afsdk:`AF.Time.AFTimeRange `. + with `start_time`, using + :afsdk:`AF.Time.AFTimeRange `. summary_types (int or PIConsts.SummaryType): Type(s) of summaries of the data within the requested time range. calculation_basis (int or PIConsts.CalculationBasis, optional): @@ -449,7 +450,8 @@ def summary( :ref:`summary_timestamps` and :any:`TimestampCalculation` for more information. Defaults to TimestampCalculation.AUTO. - Returns: + Returns + ------- pandas.DataFrame: Dataframe with the unique timestamps as row index and the summary name as column name. """ @@ -457,9 +459,7 @@ def summary( _summary_types = AF.Data.AFSummaryTypes(int(summary_types)) _calculation_basis = AF.Data.AFCalculationBasis(int(calculation_basis)) _time_type = AF.Data.AFTimestampCalculation(int(time_type)) - pivalues = self._summary( - time_range, _summary_types, _calculation_basis, _time_type - ) + pivalues = self._summary(time_range, _summary_types, _calculation_basis, _time_type) df = pd.DataFrame() for summary in pivalues: key = PIConsts.SummaryType(int(summary.Key)).name @@ -490,11 +490,10 @@ def summaries( calculation_basis: PIConsts.CalculationBasis = PIConsts.CalculationBasis.TIME_WEIGHTED, time_type: PIConsts.TimestampCalculation = PIConsts.TimestampCalculation.AUTO, ) -> pd.DataFrame: - """summaries - - Return one or more summary values for each interval within a time range + """Return one or more summary values for each interval within a time range. - Args: + Parameters + ---------- start_time (str or datetime): Containing the date, and possibly time, from which to retrieve the values. This is parsed, together with `end_time`, using @@ -517,7 +516,8 @@ def summaries( :ref:`summary_timestamps` and :any:`TimestampCalculation` for more information. Defaults to TimestampCalculation.AUTO. - Returns: + Returns + ------- pandas.DataFrame: Dataframe with the unique timestamps as row index and the summary name as column name. """ @@ -557,6 +557,7 @@ def _summaries( @property @abc.abstractmethod def units_of_measurement(self) -> Optional[str]: + """Return the units of measurment of the values in the current object.""" pass def update_value( @@ -568,7 +569,8 @@ def update_value( ) -> None: """Update value for existing PI object. - Args: + Parameters + ---------- value: value type should be in cohesion with PI object or it will raise PIException: [-10702] STATE Not Found time (datetime, optional): it is not possible to set future value, diff --git a/PIconnect/PIPoint.py b/PIconnect/PIPoint.py index 601f4833..d9d597e3 100644 --- a/PIconnect/PIPoint.py +++ b/PIconnect/PIPoint.py @@ -1,22 +1,16 @@ -from typing import Any, Dict, List, Optional, Union, cast +"""PIPoint.""" + +from typing import Any, Dict, Optional import PIconnect._typing.AF as _AFtyping -from PIconnect import AF, PIConsts, PIData, _time -from PIconnect._operators import OPERATORS, add_operators # type: ignore +from PIconnect import AF, PIData, _time -@add_operators( - operators=OPERATORS, - members=["_current_value", "interpolated_values"], - newclassname="VirtualPIPoint", - attributes=["pi_point"], -) class PIPoint(PIData.PISeriesContainer): - """PIPoint - - Reference to a PI Point to get data and corresponding metadata from the server. + """Reference to a PI Point to get data and corresponding metadata from the server. - Args: + Parameters + ---------- pi_point (AF.PI.PIPoint): Reference to a PIPoint as returned by the SDK """ @@ -30,12 +24,10 @@ def __init__(self, pi_point: AF.PI.PIPoint) -> None: self.__raw_attributes = {} def __repr__(self): - return "%s(%s, %s; Current Value: %s %s)" % ( - self.__class__.__name__, - self.tag, - self.description, - self.current_value, - self.units_of_measurement, + """Return the string representation of the PI Point.""" + return ( + f"{self.__class__.__qualname__}({self.tag}, {self.description}; " + f"Current Value: {self.current_value} {self.units_of_measurement})" ) @property @@ -60,6 +52,7 @@ def last_update(self): @property def name(self) -> str: + """Return the name of the PI Point.""" return self.tag @property @@ -74,13 +67,11 @@ def units_of_measurement(self) -> Optional[str]: return self.raw_attributes["engunits"] def __load_attributes(self) -> None: - """Load the raw attributes of the PI Point from the server""" + """Load the raw attributes of the PI Point from the server.""" if not self.__attributes_loaded: self.pi_point.LoadAttributes([]) self.__attributes_loaded = True - self.__raw_attributes = { - att.Key: att.Value for att in self.pi_point.GetAttributes([]) - } + self.__raw_attributes = {att.Key: att.Value for att in self.pi_point.GetAttributes([])} def _current_value(self) -> Any: """Return the last recorded value for this PI Point (internal use only).""" @@ -109,7 +100,7 @@ def _filtered_summaries( ) def _interpolated_value(self, time: AF.Time.AFTime) -> AF.Asset.AFValue: - """Return a single value for this PI Point""" + """Return a single value for this PI Point.""" return self.pi_point.InterpolatedValue(time) def _interpolated_values( @@ -118,7 +109,6 @@ def _interpolated_values( interval: AF.Time.AFTimeSpan, filter_expression: str, ) -> AF.Asset.AFValues: - """Internal function to actually query the pi point""" include_filtered_values = False return self.pi_point.InterpolatedValues( time_range, interval, filter_expression, include_filtered_values @@ -130,10 +120,8 @@ def _normalize_filter_expression(self, filter_expression: str) -> str: def _recorded_value( self, time: AF.Time.AFTime, retrieval_mode: AF.Data.AFRetrievalMode ) -> AF.Asset.AFValue: - """Return a single value for this PI Point""" - return self.pi_point.RecordedValue( - time, AF.Data.AFRetrievalMode(int(retrieval_mode)) - ) + """Return a single recorded value for this PI Point.""" + return self.pi_point.RecordedValue(time, AF.Data.AFRetrievalMode(int(retrieval_mode))) def _recorded_values( self, @@ -153,9 +141,7 @@ def _summary( calculation_basis: AF.Data.AFCalculationBasis, time_type: AF.Data.AFTimestampCalculation, ) -> _AFtyping.Data.SummaryDict: - return self.pi_point.Summary( - time_range, summary_types, calculation_basis, time_type - ) + return self.pi_point.Summary(time_range, summary_types, calculation_basis, time_type) def _summaries( self, diff --git a/PIconnect/__init__.py b/PIconnect/__init__.py index 1c98f6cc..80f6f8f7 100644 --- a/PIconnect/__init__.py +++ b/PIconnect/__init__.py @@ -1,6 +1,5 @@ -""" PIconnect - Connector to the OSISoft PI and PI-AF databases. -""" +"""PIconnect - Connector to the OSISoft PI and PI-AF databases.""" + # pragma pylint: disable=unused-import from PIconnect.AFSDK import AF, AF_SDK_VERSION from PIconnect.config import PIConfig diff --git a/PIconnect/_operators.py b/PIconnect/_operators.py deleted file mode 100644 index e85c93db..00000000 --- a/PIconnect/_operators.py +++ /dev/null @@ -1,163 +0,0 @@ -"""helpers to define numeric operators in batch on classes""" -from collections import namedtuple - -import wrapt - - -def operate(operator, operand): - """Create a decorator to apply an operator to the function and a given operand. - - Operand can be either a constant or a function which accepts the same arguments - as the base function to which the decorator is applied. Operator must be a - function of two arguments. - """ - - @wrapt.decorator - def operate_(func, instance, args, kwargs): # pylint: disable=unused-argument - """Decorate function to apply an operator to the function and a given operand.""" - if hasattr(operand, func.__name__): - func2 = getattr(operand, func.__name__) - return operator(func(*args, **kwargs), func2(*args, **kwargs)) - return operator(func(*args, **kwargs), operand) - - return operate_ - - -def decorate(decorator, base, *args, **kwargs): - """Return function decorated with the operate decorator. - - Inline replacement for @*decorator(*args, **kwargs)* - """ - return decorator(*args, **kwargs)(base) - - -def add_operators(operators, members, newclassname, attributes): - """Return a class decorator to add operators which patch each of a list of members. - - Keyword arguments: - operators -- a list of tuples containing the function name to be added to the class, - a definition of the operator (as a function of two arguments), and a - docstring for the new function. - members -- a list of strings with the names of the class members that must be - decorated. - newclassname -- the name of the new class that will be returned by the patched - versions of *members*. - attributes -- a list of attributes that are extracted from the original object and - passed as arguments to .__init__. - """ - - def build_operator_method(method, operator, docstring, cls): - """Return a method definition for a numerical operator. - - Keyword arguments: - method -- name of the operator method of a subclass of *cls*, will used for - .__name__ for clean output in the class documentation. - operator -- function of two arguments that is applied to the original function - result and a given operand. - docstring -- docstring for the new operator method. - cls -- class of which the new dynamic class will be subclassed. - """ - - def patch_members(self, other): - """Return new object of class *newclassname* with patched members. - - Creates a new virtual class with the members in *members* patched to apply - the given *operator* to the original function definition. - """ - newmembers = { - member: decorate( - decorator=operate, - base=getattr(self, member), - operator=operator, - operand=other, - ) - for member in members - } - newclass = type(str(newclassname), (cls,), newmembers) - return newclass(*[getattr(self, attr) for attr in attributes]) - - patch_members.__name__ = str(method) - patch_members.__doc__ = docstring - return patch_members - - def add_numops_(cls): - """Decorate a class to add a function for each operator in a list of operators.""" - for operator in operators: - setattr( - cls, - operator.method, - build_operator_method( - method=operator.method, - operator=operator.operator, - docstring=operator.docstring, - cls=cls, - ), - ) - return cls - - return add_numops_ - - -Operator = namedtuple("Operator", ["method", "operator", "docstring"]) -OPERATORS = [ - Operator("__add__", lambda x, y: x + y, """Add value(s) to PIPoint"""), - Operator( - "__radd__", lambda x, y: y + x, """Add PIPoint to value(s) (reverse order)""" - ), - Operator("__sub__", lambda x, y: x - y, """Subtract value(s) from PIPoint"""), - Operator( - "__rsub__", - lambda x, y: y - x, - """Subtract PIPoint from value(s) (reverse order)""", - ), - Operator("__mul__", lambda x, y: x * y, """Multiply PIPoint by value(s)"""), - Operator( - "__rmul__", - lambda x, y: y * x, - """Multiply value(s) by PIPoint (reverse order)""", - ), - Operator("__matmul__", lambda x, y: x @ y, """Matrix multiply"""), - Operator("__rmatmul__", lambda x, y: y @ x, """Matrix multiply (reverse order)"""), - Operator("__div__", lambda x, y: x / y, """Divide PIPoint by value(s)"""), - Operator( - "__rdiv__", lambda x, y: y / x, """Divide value(s) by PIPoint (reverse order)""" - ), - Operator("__truediv__", lambda x, y: x / y, """Divide PIPoint by value(s)"""), - Operator( - "__rtruediv__", - lambda x, y: y / x, - """Divide value(s) by PIPoint (reverse order)""", - ), - Operator( - "__floordiv__", lambda x, y: x // y, """Floordivide PIPoint by value(s)""" - ), - Operator( - "__rfloordiv__", - lambda x, y: y // x, - """Floordivide value(s) by PIPoint (reverse order)""", - ), - Operator("__mod__", lambda x, y: x % y, """Modulo PIPoint by value(s)"""), - Operator( - "__rmod__", lambda x, y: y % x, """Modulo value(s) by PIPoint (reverse order)""" - ), - Operator( - "__divmod__", - divmod, # This is already a function of x and y - """Return divmod of PIPoint by value(s). - - divmod(a, b) returns a tuple of the floordivision of a and b, a // b, and the - modulo of a and b, a % b. For integers this is faster than when the operations - are performed separately. - """, - ), - Operator( - "__rdivmod__", - lambda x, y: divmod(y, x), - """Return divmod of value(s) by PIPoint (reverse order). - - divmod(a, b) returns a tuple of the floordivision of a and b, a // b, and the - modulo of a and b, a % b. For integers this is faster than when the operations - are performed separately. - """, - ), -] diff --git a/PIconnect/_time.py b/PIconnect/_time.py index 0eeae2c0..132bd659 100644 --- a/PIconnect/_time.py +++ b/PIconnect/_time.py @@ -1,4 +1,5 @@ """Time related functions and classes.""" + # pyright: strict import datetime from typing import Union @@ -8,25 +9,28 @@ from PIconnect import AF, PIConfig from PIconnect.AFSDK import System - TimeLike = Union[str, datetime.datetime] def to_af_time_range(start_time: TimeLike, end_time: TimeLike) -> AF.Time.AFTimeRange: """Convert a combination of start and end time to a time range. - Both `start_time` and `end_time` can be either a :any:`datetime.datetime` object or a string. + Both `start_time` and `end_time` can be either a :any:`datetime.datetime` object or + a string. `datetime` objects are first converted to a string, before being passed to - :afsdk:`AF.Time.AFTimeRange `. It is also - possible to specify either end as a `datetime` object, and then specify the other - boundary as a relative string. + :afsdk:`AF.Time.AFTimeRange `. + It is also possible to specify either end as a `datetime` object, + and then specify the other boundary as a relative string. - Args: + Parameters + ---------- start_time (str | datetime): Start time of the time range. end_time (str | datetime): End time of the time range. - Returns: - :afsdk:`AF.Time.AFTimeRange `: Time range covered by the start and end time. + Returns + ------- + :afsdk:`AF.Time.AFTimeRange `: + Time range covered by the start and end time. """ if isinstance(start_time, datetime.datetime): start_time = start_time.isoformat() @@ -39,11 +43,14 @@ def to_af_time_range(start_time: TimeLike, end_time: TimeLike) -> AF.Time.AFTime def to_af_time(time: TimeLike) -> AF.Time.AFTime: """Convert a time to a AFTime value. - Args: + Parameters + ---------- time (str | datetime): Time to convert to AFTime. - Returns: - :afsdk:`AF.Time.AFTime `: Time range covered by the start and end time. + Returns + ------- + :afsdk:`AF.Time.AFTime `: + AFTime version of time. """ if isinstance(time, datetime.datetime): time = time.isoformat() @@ -54,12 +61,14 @@ def to_af_time(time: TimeLike) -> AF.Time.AFTime: def timestamp_to_index(timestamp: System.DateTime) -> datetime.datetime: """Convert AFTime object to datetime in local timezone. - Args: + Parameters + ---------- timestamp (`System.DateTime`): Timestamp in .NET format to convert to `datetime`. - Returns: + Returns + ------- `datetime`: Datetime with the timezone info from :data:`PIConfig.DEFAULT_TIMEZONE `. - """ + """ # noqa: E501 local_tz = pytz.timezone(PIConfig.DEFAULT_TIMEZONE) return ( datetime.datetime( diff --git a/PIconnect/_typing/AF.py b/PIconnect/_typing/AF.py index 9601e884..2e968551 100644 --- a/PIconnect/_typing/AF.py +++ b/PIconnect/_typing/AF.py @@ -1,4 +1,5 @@ -"""Mock classes for the AF namespace of the OSIsoft PI-AF SDK""" +"""Mock classes for the AF namespace of the OSIsoft PI-AF SDK.""" + from typing import Iterator, List from . import PI, Asset, Data, EventFrame, Time, UnitsOfMeasure @@ -18,7 +19,7 @@ class AFCategory: - """Mock class of the AF.AFCategory class""" + """Mock class of the AF.AFCategory class.""" class AFCategories(List[AFCategory]): @@ -28,7 +29,7 @@ def __init__(self, elements: List[AFCategory]) -> None: class AFDatabase: - """Mock class of the AF.AFDatabase class""" + """Mock class of the AF.AFDatabase class.""" def __init__(self, name: str) -> None: self.Name = name @@ -36,10 +37,10 @@ def __init__(self, name: str) -> None: class PISystem: - """Mock class of the AF.PISystem class""" + """Mock class of the AF.PISystem class.""" class InternalDatabases: - """Mock class for the AF.PISystem.Databases property""" + """Mock class for the AF.PISystem.Databases property.""" def __init__(self) -> None: self.DefaultDatabase = AFDatabase("TestDatabase") @@ -53,16 +54,16 @@ def __init__(self, name: str) -> None: self._connected = False def Connect(self) -> None: - """Stub to connect to the testing system""" + """Stub to connect to the testing system.""" self._connected = True def Disconnect(self) -> None: - """Stub to disconnect from the testing system""" + """Stub to disconnect from the testing system.""" self._connected = False class PISystems: - """Mock class of the AF.PISystems class""" + """Mock class of the AF.PISystems class.""" Version = "0.0.0.0" diff --git a/PIconnect/_typing/Asset.py b/PIconnect/_typing/Asset.py index ba8c6325..ca783300 100644 --- a/PIconnect/_typing/Asset.py +++ b/PIconnect/_typing/Asset.py @@ -1,3 +1,5 @@ +"""Mock classes for the AF module.""" + from typing import List, Optional, Union from . import AF, Data, Generic @@ -28,7 +30,7 @@ def __init__(self, name: str) -> None: @staticmethod def GetValue() -> AFValue: - """Stub for getting a value""" + """Stub for getting a value.""" return AFValue(0) @@ -49,7 +51,7 @@ def __init__(self, name: str, parent: Optional["AFElement"] = None) -> None: class AFElement(AFBaseElement): - """Mock class of the AF.AFElement class""" + """Mock class of the AF.AFElement class.""" class AFElements(List[AFElement]): @@ -58,14 +60,14 @@ def __init__(self, elements: List[AFElement]) -> None: self._values = elements def get_Item(self, name: Union[str, int]) -> AFElement: - """Stub for the indexer""" + """Stub for the indexer.""" if isinstance(name, int): return self._values[name] return AFElement(name) class AFElementTemplate: - """Mock class of the AF.Asset.AFElementTemplate class""" + """Mock class of the AF.Asset.AFElementTemplate class.""" class AFDataReference: diff --git a/PIconnect/_typing/Data.py b/PIconnect/_typing/Data.py index 83c25510..fe8954c0 100644 --- a/PIconnect/_typing/Data.py +++ b/PIconnect/_typing/Data.py @@ -1,12 +1,17 @@ +"""Type hints for the AF.Data module. + +Contains various enumerations and classes for data retrieval. +""" + import enum -from . import Time, Generic +from . import Generic, Time from . import UnitsOfMeasure as UOM from ._values import AFValue, AFValues class AFBoundaryType(enum.IntEnum): - """Mock class of the AF.Data.AFBoundaryType enumeration""" + """Mock class of the AF.Data.AFBoundaryType enumeration.""" Inside = 0 Outside = 1 @@ -14,7 +19,7 @@ class AFBoundaryType(enum.IntEnum): class AFBufferOption(enum.IntEnum): - """Mock class of the AF.Data.AFBufferOption enumeration""" + """Mock class of the AF.Data.AFBufferOption enumeration.""" DoNotBuffer = 0 BufferIfPossible = 1 @@ -22,7 +27,7 @@ class AFBufferOption(enum.IntEnum): class AFCalculationBasis(enum.IntEnum): - """Mock class of the AF.Data.AFCalculationBasis enumeration""" + """Mock class of the AF.Data.AFCalculationBasis enumeration.""" TimeWeighted = 0 EventWeighted = 1 @@ -43,14 +48,14 @@ class AFRetrievalMode(enum.IntEnum): class AFSampleType(enum.IntEnum): - """Mock class of the AF.Data.AFSampleType enumeration""" + """Mock class of the AF.Data.AFSampleType enumeration.""" ExpressionRecordedValues = 0 Interval = 1 class AFSummaryTypes(enum.IntEnum): - """Mock class of the AF.Data.AFSummaryTypes enumeration""" + """Mock class of the AF.Data.AFSummaryTypes enumeration.""" None_ = 0 Total = 1 @@ -68,7 +73,7 @@ class AFSummaryTypes(enum.IntEnum): class AFTimestampCalculation(enum.IntEnum): - """Mock class of the AF.Data.AFTimestampCalculation enumeration""" + """Mock class of the AF.Data.AFTimestampCalculation enumeration.""" Auto = 0 EarliestTime = 1 @@ -76,7 +81,7 @@ class AFTimestampCalculation(enum.IntEnum): class AFUpdateOption(enum.IntEnum): - """Mock class of the AF.Data.AFUpdateOption enumeration""" + """Mock class of the AF.Data.AFUpdateOption enumeration.""" Replace = 0 Insert = 4 @@ -91,7 +96,7 @@ class AFUpdateOption(enum.IntEnum): class AFData: - """Mock class of the AF.Data.AFData class""" + """Mock class of the AF.Data.AFData class.""" @staticmethod def FilteredSummaries( diff --git a/PIconnect/_typing/EventFrame.py b/PIconnect/_typing/EventFrame.py index 5fdc86ac..25f1b18a 100644 --- a/PIconnect/_typing/EventFrame.py +++ b/PIconnect/_typing/EventFrame.py @@ -1,10 +1,9 @@ -"""Mock classes for the AF.EventFrame namespace of the OSIsoft PI-AF SDK""" - +"""Mock classes for the AF.EventFrame namespace of the OSIsoft PI-AF SDK.""" import enum from typing import Iterable, List, Optional -from . import AF, Asset, Time # pylint: disable=unused-import +from . import AF, Asset, Time class AFEventFrameSearchMode(enum.IntEnum): @@ -18,7 +17,7 @@ class AFEventFrameSearchMode(enum.IntEnum): class AFEventFrame(Asset.AFBaseElement): - """Mock class of the AF.EventFrame.AFEventFrame class""" + """Mock class of the AF.EventFrame.AFEventFrame class.""" def __init__(self, name: str, parent: Optional["AFEventFrame"] = None) -> None: self.Name = name diff --git a/PIconnect/_typing/Generic.py b/PIconnect/_typing/Generic.py index a3177621..73f7a32d 100644 --- a/PIconnect/_typing/Generic.py +++ b/PIconnect/_typing/Generic.py @@ -1,3 +1,8 @@ +"""Mocking the Generic types from System.Collections.Generic namespace. + +TODO: Migrate to the `_typing.dotnet` module. +""" + from typing import Any, Generic, Iterable, Iterator, Optional, Tuple, TypeVar _KT = TypeVar("_KT") diff --git a/PIconnect/_typing/PI.py b/PIconnect/_typing/PI.py index 53f3781a..8cd174f0 100644 --- a/PIconnect/_typing/PI.py +++ b/PIconnect/_typing/PI.py @@ -1,28 +1,30 @@ -"""Mock classes of the AF.PI namespace of the OSIsoft PI-AF SDK""" +"""Mock classes of the AF.PI namespace of the OSIsoft PI-AF SDK.""" + import enum from typing import Iterable, Iterator, List, Optional, Union -from . import Data, Generic, Time, _values, dotnet as System +from . import Data, Generic, Time, _values +from . import dotnet as System __all__ = ["PIPoint", "PIServer", "PIServers"] class PIConnectionInfo: - """Mock class of the AF.PI.PIConnectionInfo class""" + """Mock class of the AF.PI.PIConnectionInfo class.""" def __init__(self) -> None: self.OperationTimeOut: System.TimeSpan class PIAuthenticationMode(enum.IntEnum): - """Mock class of the AF.PI.PIAuthenticationMode class""" + """Mock class of the AF.PI.PIAuthenticationMode class.""" WindowsAuthentication = 0 PIUserAuthentication = 1 class PIServer: - """Mock class of the AF.PI.PIServer class""" + """Mock class of the AF.PI.PIServer class.""" def __init__(self, name: str) -> None: self.ConnectionInfo = PIConnectionInfo() @@ -34,16 +36,16 @@ def Connect( retry: Union[bool, System.Net.NetworkCredential], authentication_mode: Optional[PIAuthenticationMode] = None, ) -> None: - """Stub for connecting to test server""" + """Stub for connecting to test server.""" self._connected = True def Disconnect(self) -> None: - """Stub for disconnecting from test server""" + """Stub for disconnecting from test server.""" self._connected = False class PIServers: - """Mock class of the AF.PI.PIServers class""" + """Mock class of the AF.PI.PIServers class.""" def __init__(self) -> None: self.DefaultPIServer = PIServer("Testing") @@ -53,7 +55,7 @@ def __iter__(self) -> Iterator[PIServer]: class PIPoint: - """Mock class of the AF.PI.PIPoint class""" + """Mock class of the AF.PI.PIPoint class.""" Name: str = "TestPIPoint" """This property identifies the name of the PIPoint""" @@ -83,7 +85,7 @@ def FindPIPoints( source: Optional[str], attribute_names: Optional[Iterable[str]], ) -> Iterable["PIPoint"]: - """Stub to mock querying PIPoints""" + """Stub to mock querying PIPoints.""" return [] @staticmethod diff --git a/PIconnect/_typing/Time.py b/PIconnect/_typing/Time.py index f1280d1c..3a0ffa2d 100644 --- a/PIconnect/_typing/Time.py +++ b/PIconnect/_typing/Time.py @@ -1,9 +1,12 @@ +"""Mock classes for the AF.Time module.""" + from typing import Optional + from . import dotnet as System class AFTime: - """Mock class of the AF.Time.AFTime class""" + """Mock class of the AF.Time.AFTime class.""" def __init__(self, time: str) -> None: self.UtcTime: System.DateTime @@ -12,7 +15,7 @@ def __init__(self, time: str) -> None: class AFTimeRange: - """Mock class of the AF.Time.AFTimeRange class""" + """Mock class of the AF.Time.AFTimeRange class.""" def __init__(self, start_time: str, end_time: str): pass @@ -23,12 +26,12 @@ def Parse(start_time: str, end_time: str) -> "AFTimeRange": class AFTimeSpan: - """Mock class of the AF.Time.AFTimeSpan class""" + """Mock class of the AF.Time.AFTimeSpan class.""" def __init__(self): pass @staticmethod def Parse(interval: Optional[str], /) -> "AFTimeSpan": - """Stub for parsing strings that should return a AFTimeSpan""" + """Stub for parsing strings that should return a AFTimeSpan.""" return AFTimeSpan() diff --git a/PIconnect/_typing/UnitsOfMeasure.py b/PIconnect/_typing/UnitsOfMeasure.py index c8e832d3..8b3881dc 100644 --- a/PIconnect/_typing/UnitsOfMeasure.py +++ b/PIconnect/_typing/UnitsOfMeasure.py @@ -1,2 +1,5 @@ +"""Mock class for Units of Measure.""" + + class UOM: - """Mock class for Units of Measure""" + """Mock class for Units of Measure.""" diff --git a/PIconnect/_typing/__init__.py b/PIconnect/_typing/__init__.py index fb2721fe..c2dbe72a 100644 --- a/PIconnect/_typing/__init__.py +++ b/PIconnect/_typing/__init__.py @@ -1,3 +1,5 @@ +"""Type stubs for the AF SDK and dotnet libraries.""" + from . import AF AF_SDK_VERSION = "2.7_compatible" diff --git a/PIconnect/_typing/_values.py b/PIconnect/_typing/_values.py index 69f87e6c..dfb3b41d 100644 --- a/PIconnect/_typing/_values.py +++ b/PIconnect/_typing/_values.py @@ -1,12 +1,17 @@ +"""Typing for AFValues and AFValue classes. + +These classes are in a separate file to avoid circular imports. +""" + from typing import Any, List from . import Time +_DEFAULT_TIME = Time.AFTime("MinValue") + class AFValue: - def __init__( - self, value: Any, timestamp: Time.AFTime = Time.AFTime("MinValue") - ) -> None: + def __init__(self, value: Any, timestamp: Time.AFTime = _DEFAULT_TIME) -> None: self.Value = value self.Timestamp = timestamp @@ -14,4 +19,4 @@ def __init__( class AFValues(List[AFValue]): def __init__(self): self.Count: int - self.Value: AFValue + self.Value: List[AFValue] diff --git a/PIconnect/_typing/dotnet/Data.py b/PIconnect/_typing/dotnet/Data.py new file mode 100644 index 00000000..9c6360f8 --- /dev/null +++ b/PIconnect/_typing/dotnet/Data.py @@ -0,0 +1,43 @@ +"""Mock classes for the System.Data module.""" + +from typing import Any, Dict, Iterator, List + +__all__ = [ + "DataRow", + "DataRowCollection", + "DataColumn", + "DataColumnCollection", + "DataTable", +] + + +class DataRow: + __fields: Dict[str, Any] + + def __getitem__(self, key: str) -> Any: + return self.__fields[key] + + +class DataRowCollection: + rows: List[DataRow] + + def __iter__(self) -> Iterator[DataRow]: + yield from self.rows + + +class DataColumn: + def __init__(self, name: str) -> None: + self.ColumnName = name + + +class DataColumnCollection: + columns: List[DataColumn] + + def __iter__(self) -> Iterator[DataColumn]: + yield from self.columns + + +class DataTable: + Name: str + Rows: List[DataRow] + Columns: List[DataColumn] diff --git a/PIconnect/_typing/dotnet/Net.py b/PIconnect/_typing/dotnet/Net.py index ad004885..7e01bf81 100644 --- a/PIconnect/_typing/dotnet/Net.py +++ b/PIconnect/_typing/dotnet/Net.py @@ -1,3 +1,5 @@ +"""Mock classes for the System.Net module.""" + from typing import Optional from .Security import SecureString diff --git a/PIconnect/_typing/dotnet/Security.py b/PIconnect/_typing/dotnet/Security.py index 6adfb0d6..f1c501ed 100644 --- a/PIconnect/_typing/dotnet/Security.py +++ b/PIconnect/_typing/dotnet/Security.py @@ -1,3 +1,6 @@ +"""Mock classes for the System.Security module.""" + + class SecureString: def __init__(self) -> None: self.Value = "" diff --git a/PIconnect/_typing/dotnet/__init__.py b/PIconnect/_typing/dotnet/__init__.py index b6046af1..84374712 100644 --- a/PIconnect/_typing/dotnet/__init__.py +++ b/PIconnect/_typing/dotnet/__init__.py @@ -1,4 +1,7 @@ +"""Mock for System.* classes.""" + from typing import Protocol + from . import Net, Security __all__ = ["Net", "Security", "Exception", "TimeSpan"] @@ -16,7 +19,7 @@ def __init__(self, /, hours: int, minutes: int, seconds: int) -> None: class DateTime(Protocol): - """Mock for System.DateTime""" + """Mock for System.DateTime.""" Year: int Month: int diff --git a/PIconnect/config.py b/PIconnect/config.py index ae77ea73..202155b4 100644 --- a/PIconnect/config.py +++ b/PIconnect/config.py @@ -2,10 +2,16 @@ class PIConfigContainer: + """Configuration for PIconnect package. + + This should not be instantiated directly, but accessed through the `PIConfig` object. + """ + _default_timezone: str = "UTC" @property def DEFAULT_TIMEZONE(self) -> str: + """Timezone in which values are returned.""" return self._default_timezone @DEFAULT_TIMEZONE.setter diff --git a/Pipfile b/Pipfile index 94ebe5bb..74e4ecbc 100644 --- a/Pipfile +++ b/Pipfile @@ -4,6 +4,7 @@ verify_ssl = true name = "pypi" [packages] +numpy = "<2" pandas = "*" pytz = "*" wrapt = "*" @@ -11,7 +12,7 @@ pythonnet = "*" piconnect = {editable = true, path = "."} [dev-packages] -black = "*" +ruff = "*" # coverage = "*" # mypy = "*" codecov = "*" @@ -21,8 +22,8 @@ pytest = "*" pytest-cov = "*" Sphinx = "*" PyYAML = "*" -"doc8" = "*" -"flake8" = "*" +# "doc8" = "*" +# "flake8" = "*" twine = "*" coverage = ">=6.0b1" diff --git a/Pipfile.lock b/Pipfile.lock index 68f425d8..6a565fc7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "67d40742eaa6c8e921f91fe8dc47e665ee28806ba5c4dd7bb0ee311350222dfb" + "sha256": "380e7590e0293edb34ebcecec5411a9762df482c9b6c491c0406035e76605633" }, "pipfile-spec": 6, "requires": { @@ -18,182 +18,201 @@ "default": { "cffi": { "hashes": [ - "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", - "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", - "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", - "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", - "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", - "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", - "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", - "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", - "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", - "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", - "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", - "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", - "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", - "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", - "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", - "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", - "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", - "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", - "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", - "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", - "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", - "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", - "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", - "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", - "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", - "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", - "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", - "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", - "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", - "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", - "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", - "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", - "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", - "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", - "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", - "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", - "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", - "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", - "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", - "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", - "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", - "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", - "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", - "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", - "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", - "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", - "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", - "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", - "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", - "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", - "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", - "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", - "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", - "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", - "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", - "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", - "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", - "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", - "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", - "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", - "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", - "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", - "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", - "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" - ], - "version": "==1.15.1" + "sha256:157cfe06e48356a7552e68cb73976a710f2620a5f9eb25a5fe7066cf71601b68", + "sha256:1c9f4df436f3780f2dbea2ff066cea0bb2f74425883bc5b098812768da2b34f7", + "sha256:1da24a9bf6fd9ab987a915887f0d3577d0a0b3946d582b776b380294dc5fce18", + "sha256:1db9f6fcf79e92ee2d193cd989dde4e1419193ff11eef4bcc00cb06293e22f4b", + "sha256:1fee79745f50734490d3358f9cb6578f57850bb61287256115dda2a513abe3c6", + "sha256:205051765f126c1480d1eaf6268c644262bae3ed610423f0783349f04e7f5a6b", + "sha256:22eac8f9c77df0899a6cd373d6a62da40644573a5e27982f7713bd2a9f0b0edf", + "sha256:2e5562c744d495f838dc0fbe9cd76cff27ebea0a2e747dd84dd8a7e47bcd3c8f", + "sha256:3113951a250b021d2092e870fe86cd4292a633a786f7ece67200663406409659", + "sha256:319ec248b55d34a49d7a43c48f2cf922b526e5ad2a3988887cc822a0c226b983", + "sha256:35bd512b1a16723b8c50665c3fe83c80789f7e5599c8f0721ef145552b6853e7", + "sha256:3745df375d5e66261295840fa219797251ff6a30afedfae650576ab2b10f43db", + "sha256:39b9131ed6c28f63132dee75d1fa5653436cb46fc7e6a097af29f32c7f5f8eca", + "sha256:3c4b0e03d0d9f3a31110994bf657076f3821ad1a88e2cdb7c3e43b4e4f96e7b0", + "sha256:3ea7190f834a5979e30bc4af334c031303a4f16f38216599645034751d683171", + "sha256:3f60cc0a65ac412887ba284c946242ed4e07065003b358a4d288334f6c2a54ed", + "sha256:475d2832950f9a65740aeb20d5baf6d84cf0d08a7063c8c6c407ec24cac41881", + "sha256:494abc4dc78792d210249127a75021049c7832468f9daa6e81ec0dfc1f55d9d0", + "sha256:4f17c3cfc4a7a53693bda38ac1631f30ceb2430f4a038550f5515728592ccd6f", + "sha256:58463f9a28f4357f4a07a94fbb0dca91486f6948f19a4971e0bedd6292ef0394", + "sha256:614afb2f32d5ea64a946643d798f3391d53bba868290e7433f4eaae7d1692e06", + "sha256:625eb8d8d377438cfbf64899e09969d20cd139019838a60644f05216f7c7767d", + "sha256:6a891c9e564527b4e65d65f87e3e989c3369329d04b39c49f279a91266287b85", + "sha256:6aff0256e080afb8964e091f94222c2808cdf7c5f13d58f88e799e2fbde53a9d", + "sha256:6bce1aa64c52c3cb0c7326dd81d1dc5a4831946b29721592983eb4ae80beb2ac", + "sha256:6df680dccdb5fcd257343532d5354c0059a6e5e4bc27b24a6a310cc51ba35a31", + "sha256:7249add87681d15f1a291e096f49350b28c44be958c5ca650d8c4dfbce3a458f", + "sha256:730a92dd144eb89f69c7b61ba4e6ac48ee6a01ba92f70c17e277c3e2c49b253d", + "sha256:752c6a06036a24b54936f488ad13b0a83b7d1e0f9fefbe3a4fc237676b1091cf", + "sha256:7953cd1968a8ea99482d7bfcf5bb9c56d56e91660b97ee940923394c8194d921", + "sha256:7e12962a21ba417611c7f9ae3e7f42d5354b68bf3c894af7796c171f6a965acf", + "sha256:84269088c987aa34045ee808b8a3c5f44397403f1afeff65429cd7c9e123dc01", + "sha256:85b997ce260a93010a72767c0f2f7c405524cada076792a9baad75cef435f293", + "sha256:8b77f45d5b938f8fa6d3087892458c57458f55a90410ce15c61585627930838b", + "sha256:8e7b261c3ea000b9a7c4fd40dd54ec3749d4592808025261d82e82f6457e8b7f", + "sha256:8fe736c2666e20090ae52af3b0297fb9273830f9d31f6041d7a8c7172fb6a566", + "sha256:94af5cfe8eb0d2742435458b8c8708aeb88f17fb48372bc4dacb87671e1ba867", + "sha256:98c7f31f55c4d0f9dba7da07bab8cd822cff6ac8dbea28ea8385e3a1e7074ac6", + "sha256:98e89b4eabb3f98c7882016cb4c498bded7882ad655f80d7a9d23043a1d12d43", + "sha256:98eaba1ed99a0a219cabe7d8bb716d9d87aeeb1b6f33792bcf84cc222c1a37b1", + "sha256:9b5cb07680e7d3c522733d14fbc0cac0660b597a2e33d8bbd305537b65eb6a51", + "sha256:9e39b8008534eedae1bde35d7cd5b71069f8aa7e6c079ae549a0de68299af43c", + "sha256:a23431415147e0c711742b4e273b362758e632bd11a1e676c58011f0ed96da42", + "sha256:a33648455eefb348b265bd10764833ab7d5f3811912a90dcefc00328d548da0d", + "sha256:a4b7e94db6e6bc2582fa540175384070edbd63c61103b182f57be3a958c0b7ad", + "sha256:a72748e56cd5edfc808c508da6e4b903225d1ed4c45463c28edf188ffea6d442", + "sha256:b3245d8073632f958cf239a198c0c3bed112a59d6ee2202e85367955b92794c6", + "sha256:b57fa5d8a1a2cc960613e0e578867d21a018f4405e9bad31c7b0af2b14004f2b", + "sha256:b6f35a638639298d4f9dca59db1f7568860ea179ace42318d658698850f2f540", + "sha256:b7cb4755dc605ac5f2cf0b00e4063fdc2ca474da7bdc473877f8b5cba133b43e", + "sha256:ba993bea9f3195dc2f8dd9e3739f97f41eac5d71f5804d1ef87ee1283a13a280", + "sha256:bf62263af2a3fadaf992775e0e555d657546dee30d3ca8a2ed1559c90006d46e", + "sha256:c207ccc9f2e459eab7952401dc9237e36d6b630b5020890736e6b18002a750f3", + "sha256:c82e1f580f3dd473a9d8b213071dfd8da07f7a433b04ba6be4773ada211d3fdb", + "sha256:ca0dd9cfb6a3fd91d6f1de5a2e2ee7a0f4b5b753309ec4edce32d5505dbc9149", + "sha256:cfc1d8a64c44544a01b06b1688dca70433dc47e2d46f462c9ee6dc02ab233ba8", + "sha256:d1089e9654cbbeb4e3ba84caa5eb0a92371fcac6ba43b14514680d339068abed", + "sha256:d50cef1600b59ec5669a28050286a456682443f20be9b0226c0fe5502860216e", + "sha256:e27ceb498d5a93f7fe833c5a3a85f8b9f0a4f1a182f1d37936e9ed31dda6926b", + "sha256:e3ae055e90ea13480185a1ef5325ebd9ac092e03f5f473be3e93eac62bfd43df", + "sha256:e547a347a983bda467ae8d8b607d278cdf8a37bea735399d655c82cba3f5d725", + "sha256:e6c686d93378b18a7b26bbb376dab75716a72bd95c04b7f2cff9094ac66a4582", + "sha256:ec95c379f5ebd92cd09e3e8183da9afee8c2da2544593fe091421ed2d757f3c1", + "sha256:f6e933e0118a97df454139ca84a28473a024429c7c1eb82619a56ef886b07583", + "sha256:f9155a5b35097cbe7a2e31611daf681b7119d895090bb101bf94805fb6bc7834", + "sha256:fa76f23281fd49c305002f510c773ecf6216118f2e7083b34ffa06983d6db96a", + "sha256:ffe885231b8b58f18149e9eaece2d556602aeb233161c069618bda31f3a30d04" + ], + "markers": "python_version >= '3.8'", + "version": "==1.17.0rc1" }, "clr-loader": { "hashes": [ - "sha256:82ed5fb654729d14fd88296e74bb6b84eb2cfb976ff4b7d49d4e449fd78a226b", - "sha256:9951413acfe56a82e8cb49413f3703ed88e7f7afc4447c6e993d6b34a2b3249c" + "sha256:019348ae6b6a83c7a406d14537c277cecf7a3a53b263ec342c81ded5845a67ee", + "sha256:79bbfee4bf6ac2f4836d89af2c39e0c32dce5d0c062596185aef380f317507a6" ], "markers": "python_version >= '3.7'", - "version": "==0.2.5" + "version": "==0.2.6" }, "numpy": { "hashes": [ - "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22", - "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f", - "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9", - "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96", - "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0", - "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a", - "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281", - "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04", - "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468", - "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253", - "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756", - "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a", - "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb", - "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d", - "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0", - "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910", - "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978", - "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5", - "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f", - "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a", - "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5", - "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2", - "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d", - "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95", - "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5", - "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d", - "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780", - "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa" - ], - "markers": "python_version >= '3.10'", - "version": "==1.24.2" + "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", + "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", + "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", + "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", + "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", + "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", + "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", + "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", + "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", + "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", + "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", + "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", + "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", + "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", + "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", + "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", + "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", + "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", + "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", + "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", + "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", + "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", + "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", + "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", + "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", + "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", + "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", + "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", + "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", + "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", + "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", + "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", + "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", + "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", + "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", + "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==1.26.4" }, "pandas": { "hashes": [ - "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813", - "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792", - "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406", - "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373", - "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328", - "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996", - "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf", - "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6", - "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7", - "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc", - "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1", - "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23", - "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a", - "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51", - "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572", - "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31", - "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5", - "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a", - "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003", - "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d", - "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354", - "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee", - "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa", - "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0", - "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9", - "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae", - "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc" + "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", + "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", + "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", + "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", + "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", + "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", + "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", + "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", + "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", + "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", + "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", + "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", + "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", + "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", + "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", + "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", + "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", + "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", + "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", + "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", + "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", + "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", + "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", + "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", + "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", + "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", + "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", + "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", + "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" ], "index": "pypi", - "version": "==1.5.3" + "markers": "python_version >= '3.9'", + "version": "==2.2.2" }, "piconnect": { "editable": true, + "markers": "python_version >= '3.8'", "path": "." }, "pycparser": { "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" ], - "version": "==2.21" + "markers": "python_version >= '3.8'", + "version": "==2.22" }, "python-dateutil": { "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "version": "==2.9.0.post0" }, "pythonnet": { "hashes": [ - "sha256:46882dabb3532b8353f42815b21176545e1a34a5e4730b3cb04a8e430ae9f9ec", - "sha256:ed4f7f7f95515404112ddb3da1638e1a1013cb56e64c48c4fa60303f02b0a3dd" + "sha256:62486f860c7955b7dcf470e085e4d2b599512224ca24193f716e857b496c530f", + "sha256:8d4b2e97158a023875f8647458a58f38817f4fe39af60abdd6b0d8adf1d77e75" ], "index": "pypi", - "version": "==3.0.1" + "markers": "python_version < '3.13' and python_version >= '3.7'", + "version": "==3.0.3" }, "pytz": { "hashes": [ - "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0", - "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a" + "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", + "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" ], "index": "pypi", - "version": "==2022.7.1" + "version": "==2024.1" }, "six": { "hashes": [ @@ -203,269 +222,220 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "tzdata": { + "hashes": [ + "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", + "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + ], + "markers": "python_version >= '2'", + "version": "==2024.1" + }, "wrapt": { "hashes": [ - "sha256:09fbbcfb17be9464c18f3e54457e4907a3913f836a691552ae1c967df4d6e4b4", - "sha256:0d47527c5c8f9fa6d20fd72e87c39c1cad627f8c7f11b62af05e27ddcd443ba3", - "sha256:107415c7367bf5489ab7b16f5348216a1a1c4ff8d5ec08612cf6f64321f9ad3c", - "sha256:123de234ee3f528ae817a4be29f811b9ce25f9f48ed446fbd5adcf68b7abb869", - "sha256:1b2975c345967fbbff2fa9ffc45c60c30de005e753b6c01135ba4fbb788d3f38", - "sha256:21c1487e21979ba8a6a1d6e2e2d026bfeb57aebec0e25da2f7960938e99a9e8c", - "sha256:25be3596f51338a6043c6679870d95eb0636e02bb1e6ccf63da61e8021e533d0", - "sha256:26bc4fe48eb78cc6a1328b70fe720555b4d31321b060b69fc03a1f8296ee40de", - "sha256:30201cbcfea303e345b3c83fb7217e34c46c87df897d3a6f9e0cb840cc0f81c9", - "sha256:32960f2f9e5f53ff8c75ef9704d03114fc14c8f604a75323aa7b907f65bfcb6b", - "sha256:338dd5c161be7c981f8afb597dac0f5d26e9310d66bbf612209fa29c21a7da33", - "sha256:3a8981cbf86e0a004160cbd299af99cb251f93a49d58032bd7400b23f40839e5", - "sha256:3cdfb26e3e9fec79e04af3e37b0576c12ee3cd5aa7ba3f041b92aa323fb7f997", - "sha256:401a64a7cdfe4d00edcd6a36666e6fba0f61291f6bacf686baf918182f02cf2d", - "sha256:42a271aac91a2c74ea6a6b869219cff14404e9362de05c4b83f65dfed7e9b12c", - "sha256:44bd131dab4ed4d6221fa78277b6ccbcfa9b439629ffa930b1d1ddc38a88a224", - "sha256:45d9589ff8649934c2106d57b85405777e9ce1278eaf0f0fec70f5e037d82c48", - "sha256:485cdea587ccc1e8d483855e4e26ab4397b6455e2b416c1f8034ac0acd820da8", - "sha256:49e9cb44795b512097f09d9df29e0d83d5f2a517a00eec47d886c0ded5be4496", - "sha256:4c08d4c4698e3119408acfa48871ed210a9c40d566b0426eee0b2bd0bc638c0e", - "sha256:4c74bf0a62faed5e40431fa846f278420d2356fe2a781b5f601946749f9ac914", - "sha256:5053e18f970b38e2e8cb4f635bba79ef1a22d236795af73017b415e9a9aeba48", - "sha256:50bfbb843e37e767634102eaf284def65a381061ca762f536c6b5a40e4aed4f4", - "sha256:515ab064a2163a05a3b6460137dc4c28c091a58853ed4a0b48b100089a29cb55", - "sha256:57ec643799932381502c3f0db4ef5de25bc10b0adc02b0de5fb2a61f23ca7562", - "sha256:5951d10d4cac32454c0a65e83330f832db7c4208eee82a69cd7e9be06bbecb70", - "sha256:59caed62ad5f7ce1a917e758e15bd2f0bfe2fd6817d0cf8c5e1a713203481669", - "sha256:5ac1a93b98c131aabc145a8712e01ed0241c66cb5940fe69ba34c61d59d8b31a", - "sha256:5cc4a8d20edb25b395c62e6932e5a1c8afe1aaf45bf2acd876ba683306f9dfa0", - "sha256:5d972d3a48c199564e0659d62de4a39d123a547dc25eba548e97b42e4733c0a8", - "sha256:5f3a8c55f27524c0426b07232dbfb7f2e0ba414dcb57ebc66054f0a170a0fc49", - "sha256:62324e76ea16e5b0339de237edfc1df338442308c599ad3ca02a22e5b3d847db", - "sha256:654160de93ee85253d426d9390a649bf2b91e3f79560410644664fd284bc2be8", - "sha256:66938fd0469076f8fb1064b24778756b47d71348e5ca7bde5f3cec303ed90676", - "sha256:67cad5aae1d0934b02f6a15fa6f181ef83e86d5d8dee2b26873ff57cdd4c0f4f", - "sha256:698e03c02d501681939f8a4376afb5521ec04dcca9bfdc023cc968e457e50410", - "sha256:6d03a9c18017976265d07e40236dd09278a387cdf3870487060ecf4f48ea5252", - "sha256:72d9f2ff2fb3e5c2bfcf891152995b8589c5e735045fbbaae00bd776a6dc9a6b", - "sha256:73942a75f7d8b78630076075848d303be3d68798f0462073639583616f0f65a0", - "sha256:77cb6f9eae637b1d19b78738602317f788df1896b79f8d81b829d186ff8154c3", - "sha256:7963d8049c452e9462e9ea9bc1a20aa31bda4ce667a39b38013e84ae1e6185b0", - "sha256:79662ce899950115f33f657b1558a83f631b2a2f91d6fcfdd09a6cbe378cbd2f", - "sha256:798bb2eb07988514ee3d213d8ab35e6677c86215190896970b1c407b84ce791a", - "sha256:7afabb46692c9dc3053a526915a05ddbc41266082ee505c64fc5aa1fd8ccfdd9", - "sha256:7bf51f7815f15d6655c67d32ceedc97787e88c41d1c9cfab19c5f54982d09c41", - "sha256:81cf008c5ef139b63dac5df0035eb597bc0b5818d321219d41da2c1aa2fa8ce3", - "sha256:88b8bfb2ce44d91789a566cd2be7083e0520208977322bf84ddd215fbee81b58", - "sha256:8ee0105bca55eb430ef949eadea557915a183810f25f396e91b5587b7aff3348", - "sha256:8f0a1f9d970d4af52c4b696022268b710e19f446423a59cf1d9c393b98c0d985", - "sha256:93d95f9007cdcd2ab1c31761840434aff21bc75859110b28dd77a1016fa39202", - "sha256:94f9d8cd233b0654c3c38b0855e872716a5b358203a42d41275acb09f3526f0a", - "sha256:99011767b4b383706ac749d52b6e2b1f7335e45a72ba604465aa097cca61da3d", - "sha256:9c025bbc3b29ca7d56cdbe8dd88e7c90a4caea59af1a236cc17222b114047342", - "sha256:9da305a413ac7be48dbcc2eda0a6376235a9cd437a3eb106e67cca36f50f9c12", - "sha256:9f74533bf0490662451e520450111548cd669440bb30f0400abe9e778789f5b9", - "sha256:a7f4fbef92c3b507232c65b9504c1f23dd5faede097b55ac5ffa599ae775c6e8", - "sha256:b51f96d1cd7a88baa373bbb39433d09326fd204c8bf95c2f53b81c530df688ef", - "sha256:b53b375ef6028136856aca7c22126de55343035d60198d32d32a90e156be857a", - "sha256:b86269bf2657876413a34c84fe205e853aa28ea84d7d044b6a58fd59f6c84e7c", - "sha256:bb6182ff6760da884274150af7b7dd3b1a71b49e7c2daa1398e48929b453022a", - "sha256:c47994d3ac60e235614235aef76fae1d41a2f882f5fbd62b6fde92f29d84d785", - "sha256:c4e87511f8b06cfdf8555701abe64bd2bd0951d1c2a5e66f9ee652ea38edeb5c", - "sha256:c588d8e582f07ae24133a4e12ff10e09789763a55acc2317760507492d0d482e", - "sha256:c9239fef921d5503c1b4489861ecabe246f56791c0804b1afb6917ba0f328002", - "sha256:d46da7b89f9b09c232528b395e9e27be7a73a2b70745eca2e4580f06fe622be4", - "sha256:d79b8d62443414fd8790e5b3f89365161957b40e1275888f8e9390a778553bb9", - "sha256:ddf53a1f0184a9d9bd72af31cbd639e48e5affc8cc473246a5fe2f89e7b01741", - "sha256:e3855ef2ffebca0fb8a1e80bfde292bcb19cdd43c73b94b2b91c874cca1116b9", - "sha256:e494137d27700a3a3b020c903d511f1f9fc7ecec406991266a023a756e61db2e", - "sha256:e7e3ba93fdec4e044a98c955641dd4e978513854d4a9425fd19f15143bc6af02", - "sha256:e8666f3b83285e84a081fc4260fd044f7ef06843691a3fa5e87432152ceeb7c3", - "sha256:e999014967cf06782702c7308c3e7977035f548217743eba752b2f8e0b576ee9", - "sha256:f50f3bb2ba9d914830ac351a6fce9fd3a5b8ff28124966941f0ea1a4789339a4", - "sha256:f6c7af527e9757af49b0de3f9447a61ad3ebc0cedb8e2ecd900265f715944a16", - "sha256:f6d36e191323cef8143915e0acc708fd222179311daec90a677f06270367fe8b" + "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc", + "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", + "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09", + "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e", + "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca", + "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0", + "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb", + "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487", + "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40", + "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", + "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060", + "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202", + "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41", + "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", + "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", + "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664", + "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", + "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362", + "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00", + "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", + "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", + "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267", + "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956", + "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966", + "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1", + "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228", + "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72", + "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d", + "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292", + "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0", + "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0", + "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", + "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c", + "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5", + "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f", + "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", + "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", + "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2", + "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593", + "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39", + "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389", + "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf", + "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf", + "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89", + "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c", + "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c", + "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f", + "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440", + "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465", + "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136", + "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b", + "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8", + "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3", + "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8", + "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6", + "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e", + "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f", + "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c", + "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e", + "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", + "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2", + "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020", + "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35", + "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d", + "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3", + "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537", + "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", + "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d", + "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a", + "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4" ], "index": "pypi", - "version": "==1.15.0rc1" + "markers": "python_version >= '3.6'", + "version": "==1.16.0" } }, "develop": { "alabaster": { "hashes": [ - "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3", - "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2" + "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", + "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92" ], - "markers": "python_version >= '3.6'", - "version": "==0.7.13" + "markers": "python_version >= '3.9'", + "version": "==0.7.16" }, "astroid": { "hashes": [ - "sha256:86b0a340a512c65abf4368b80252754cda17c02cdbbd3f587dddf98112233e7b", - "sha256:bb24615c77f4837c707669d16907331374ae8a964650a66999da3f5ca68dc946" - ], - "markers": "python_full_version >= '3.6.2'", - "version": "==2.11.7" - }, - "attrs": { - "hashes": [ - "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836", - "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99" + "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94", + "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0" ], - "markers": "python_version >= '3.6'", - "version": "==22.2.0" + "markers": "python_full_version >= '3.8.0'", + "version": "==3.2.2" }, "babel": { "hashes": [ - "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe", - "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6" - ], - "markers": "python_version >= '3.6'", - "version": "==2.11.0" - }, - "black": { - "hashes": [ - "sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd", - "sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555", - "sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481", - "sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468", - "sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9", - "sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a", - "sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958", - "sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580", - "sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26", - "sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32", - "sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8", - "sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753", - "sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b", - "sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074", - "sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651", - "sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24", - "sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6", - "sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad", - "sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac", - "sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221", - "sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06", - "sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27", - "sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648", - "sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739", - "sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104" - ], - "index": "pypi", - "version": "==23.1.0" - }, - "bleach": { - "hashes": [ - "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414", - "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4" + "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", + "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.15.0" }, "certifi": { "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2022.12.7" + "version": "==2024.6.2" }, "charset-normalizer": { "hashes": [ - "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b", - "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42", - "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d", - "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b", - "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a", - "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59", - "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154", - "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1", - "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c", - "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a", - "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d", - "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6", - "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b", - "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b", - "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783", - "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5", - "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918", - "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555", - "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639", - "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786", - "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e", - "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed", - "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820", - "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8", - "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3", - "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541", - "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14", - "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be", - "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e", - "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76", - "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b", - "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c", - "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b", - "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3", - "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc", - "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6", - "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59", - "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4", - "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d", - "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d", - "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3", - "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a", - "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea", - "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6", - "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e", - "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603", - "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24", - "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a", - "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58", - "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678", - "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a", - "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c", - "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6", - "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18", - "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174", - "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317", - "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f", - "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc", - "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837", - "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41", - "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c", - "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579", - "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753", - "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8", - "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291", - "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087", - "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866", - "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3", - "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d", - "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1", - "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca", - "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e", - "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db", - "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72", - "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d", - "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc", - "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539", - "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d", - "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af", - "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b", - "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602", - "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f", - "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478", - "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c", - "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e", - "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479", - "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7", - "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==3.0.1" - }, - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", + "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", + "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", + "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", + "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", + "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", + "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", + "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", + "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", + "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", + "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", + "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", + "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", + "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", + "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", + "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", + "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", + "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", + "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", + "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", + "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", + "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", + "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", + "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", + "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", + "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", + "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", + "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", + "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", + "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", + "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", + "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", + "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", + "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", + "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", + "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", + "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", + "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", + "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", + "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", + "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", + "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", + "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", + "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", + "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", + "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", + "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", + "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", + "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", + "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", + "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", + "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", + "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", + "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", + "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", + "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", + "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", + "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", + "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", + "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", + "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", + "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", + "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", + "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", + "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", + "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", + "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", + "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", + "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", + "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", + "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", + "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", + "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", + "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", + "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", + "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", + "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", + "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", + "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", + "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", + "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", + "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", + "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", + "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", + "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", + "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", + "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", + "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", + "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", + "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" ], - "markers": "python_version >= '3.7'", - "version": "==8.1.3" + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.2" }, "codacy-coverage": { "hashes": [ @@ -477,12 +447,13 @@ }, "codecov": { "hashes": [ - "sha256:585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47", - "sha256:782a8e5352f22593cbc5427a35320b99490eb24d9dcfa2155fd99d2b75cfb635", - "sha256:a0da46bb5025426da895af90938def8ee12d37fcbcbbbc15b6dc64cf7ebc51c1" + "sha256:2362b685633caeaf45b9951a9b76ce359cd3581dd515b430c6c3f5dfb4d92a8c", + "sha256:7d2b16c1153d01579a89a94ff14f9dbeb63634ee79e18c11036f34e7de66cbc9", + "sha256:c2ca5e51bba9ebb43644c43d0690148a55086f7f5e6fd36170858fa4206744d5" ], "index": "pypi", - "version": "==2.1.12" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.1.13" }, "colorama": { "hashes": [ @@ -493,109 +464,90 @@ "version": "==0.4.6" }, "coverage": { - "hashes": [ - "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab", - "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851", - "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265", - "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0", - "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a", - "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5", - "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6", - "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311", - "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada", - "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f", - "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8", - "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc", - "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73", - "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf", - "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e", - "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352", - "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c", - "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c", - "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c", - "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda", - "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d", - "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0", - "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3", - "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d", - "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038", - "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c", - "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8", - "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa", - "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09", - "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b", - "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c", - "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a", - "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52", - "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3", - "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146", - "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a", - "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f", - "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4", - "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c", - "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75", - "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040", - "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063", - "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050", - "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7", - "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222", - "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912", - "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801", - "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d", - "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06", - "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8", - "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2" + "extras": [ + "toml" + ], + "hashes": [ + "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", + "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", + "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", + "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", + "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", + "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", + "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", + "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", + "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", + "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", + "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", + "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", + "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", + "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", + "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", + "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", + "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", + "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", + "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", + "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", + "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", + "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", + "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", + "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", + "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", + "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", + "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", + "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", + "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", + "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", + "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", + "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", + "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", + "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", + "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", + "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", + "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", + "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", + "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", + "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", + "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", + "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", + "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", + "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", + "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", + "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", + "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", + "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", + "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", + "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", + "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", + "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" ], "index": "pypi", - "version": "==7.1.0" + "markers": "python_version >= '3.8'", + "version": "==7.5.3" }, "dill": { "hashes": [ - "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0", - "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373" + "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", + "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" ], - "markers": "python_version >= '3.7'", - "version": "==0.3.6" - }, - "doc8": { - "hashes": [ - "sha256:d97a93e8f5a2efc4713a0804657dedad83745cca4cd1d88de9186f77f9776004", - "sha256:e493aa3f36820197c49f407583521bb76a0fde4fffbcd0e092be946ff95931ac" - ], - "index": "pypi", - "version": "==1.1.1" + "markers": "python_version >= '3.11'", + "version": "==0.3.8" }, "docutils": { "hashes": [ - "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6", - "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc" - ], - "markers": "python_version >= '3.7'", - "version": "==0.19" - }, - "exceptiongroup": { - "hashes": [ - "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e", - "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23" + "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", + "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" ], - "markers": "python_version < '3.11'", - "version": "==1.1.0" - }, - "flake8": { - "hashes": [ - "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7", - "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181" - ], - "index": "pypi", - "version": "==6.0.0" + "markers": "python_version >= '3.9'", + "version": "==0.21.2" }, "idna": { "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.4" + "version": "==3.7" }, "imagesize": { "hashes": [ @@ -607,11 +559,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad", - "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d" + "sha256:04e4aad329b8b948a5711d394fa8759cb80f009225441b4f2a02bd4d8e5f426c", + "sha256:3ff4519071ed42740522d494d04819b666541b9752c43012f85afb2cc220fcc6" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.0" + "markers": "python_version >= '3.8'", + "version": "==7.2.0" }, "iniconfig": { "hashes": [ @@ -623,141 +575,125 @@ }, "isort": { "hashes": [ - "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504", - "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6" + "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", + "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6" ], "markers": "python_full_version >= '3.8.0'", - "version": "==5.12.0" + "version": "==5.13.2" }, "jaraco.classes": { "hashes": [ - "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158", - "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a" + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" ], - "markers": "python_version >= '3.7'", - "version": "==3.2.3" + "markers": "python_version >= '3.8'", + "version": "==3.4.0" + }, + "jaraco.context": { + "hashes": [ + "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266", + "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2" + ], + "markers": "python_version >= '3.8'", + "version": "==5.3.0" + }, + "jaraco.functools": { + "hashes": [ + "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664", + "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.0.1" }, "jinja2": { "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", - "version": "==3.1.2" + "version": "==3.1.4" }, "keyring": { "hashes": [ - "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd", - "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678" - ], - "markers": "python_version >= '3.7'", - "version": "==23.13.1" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382", - "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82", - "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9", - "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494", - "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46", - "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30", - "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63", - "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4", - "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae", - "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be", - "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701", - "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd", - "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006", - "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a", - "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586", - "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8", - "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821", - "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07", - "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b", - "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171", - "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b", - "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2", - "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7", - "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4", - "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8", - "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e", - "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f", - "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda", - "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4", - "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e", - "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671", - "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11", - "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455", - "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734", - "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb", - "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59" + "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50", + "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.0" + "markers": "python_version >= '3.8'", + "version": "==25.2.1" }, "markdown-it-py": { "hashes": [ - "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27", - "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da" + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.0" + "markers": "python_version >= '3.8'", + "version": "==3.0.0" }, "markupsafe": { "hashes": [ - "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed", - "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc", - "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2", - "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460", - "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7", - "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0", - "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1", - "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa", - "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03", - "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323", - "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65", - "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013", - "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036", - "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f", - "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4", - "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419", - "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2", - "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619", - "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a", - "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a", - "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd", - "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7", - "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666", - "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65", - "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859", - "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625", - "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff", - "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156", - "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd", - "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba", - "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f", - "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1", - "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094", - "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a", - "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513", - "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed", - "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d", - "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3", - "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147", - "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c", - "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603", - "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601", - "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a", - "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1", - "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d", - "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3", - "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54", - "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2", - "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6", - "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58" + "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", + "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", - "version": "==2.1.2" + "version": "==2.1.5" }, "mccabe": { "hashes": [ @@ -777,207 +713,191 @@ }, "more-itertools": { "hashes": [ - "sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41", - "sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab" - ], - "markers": "python_version >= '3.7'", - "version": "==9.0.0" - }, - "mypy-extensions": { - "hashes": [ - "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", - "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" + "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463", + "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.0" + "markers": "python_version >= '3.8'", + "version": "==10.3.0" + }, + "nh3": { + "hashes": [ + "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", + "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", + "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", + "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", + "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", + "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", + "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", + "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", + "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", + "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", + "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", + "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", + "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", + "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", + "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", + "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" + ], + "version": "==0.2.17" }, "packaging": { "hashes": [ - "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2", - "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==23.0" - }, - "pathspec": { - "hashes": [ - "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229", - "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc" - ], - "markers": "python_version >= '3.7'", - "version": "==0.11.0" - }, - "pbr": { - "hashes": [ - "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b", - "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3" - ], - "markers": "python_version >= '2.6'", - "version": "==5.11.1" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pkginfo": { "hashes": [ - "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546", - "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046" + "sha256:2e0dca1cf4c8e39644eed32408ea9966ee15e0d324c62ba899a393b3c6b467aa", + "sha256:bfa76a714fdfc18a045fcd684dbfc3816b603d9d075febef17cb6582bea29573" ], - "markers": "python_version >= '3.6'", - "version": "==1.9.6" + "markers": "python_version >= '3.8'", + "version": "==1.11.1" }, "platformdirs": { "hashes": [ - "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9", - "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], - "markers": "python_version >= '3.7'", - "version": "==3.0.0" + "markers": "python_version >= '3.8'", + "version": "==4.2.2" }, "pluggy": { "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053", - "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610" - ], - "markers": "python_version >= '3.6'", - "version": "==2.10.0" - }, - "pyflakes": { - "hashes": [ - "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf", - "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd" - ], - "markers": "python_version >= '3.6'", - "version": "==3.0.1" + "markers": "python_version >= '3.8'", + "version": "==1.5.0" }, "pygments": { "hashes": [ - "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297", - "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.6'", - "version": "==2.14.0" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pylint": { "hashes": [ - "sha256:15bc7b37f2022720765247eec24c49b93dcae6c81418adc3c36621b13d946f6d", - "sha256:add6bc6380143af0f7a1ab15b5b5f54a8d9d25afc99fc7e2d86fd66f6c3e1ad9" + "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", + "sha256:b3d7d2708a3e04b4679e02d99e72329a8b7ee8afb8d04110682278781f889fa8" ], "index": "pypi", - "version": "==3.0.0a5" + "markers": "python_full_version >= '3.8.0'", + "version": "==3.2.3" }, "pytest": { "hashes": [ - "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5", - "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42" + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", - "version": "==7.2.1" + "markers": "python_version >= '3.8'", + "version": "==8.2.2" }, "pytest-cov": { "hashes": [ - "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b", - "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470" - ], - "index": "pypi", - "version": "==4.0.0" - }, - "pytz": { - "hashes": [ - "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0", - "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a" + "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", + "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857" ], "index": "pypi", - "version": "==2022.7.1" + "markers": "python_version >= '3.8'", + "version": "==5.0.0" }, "pywin32-ctypes": { "hashes": [ - "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942", - "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98" + "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60", + "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7" ], "markers": "sys_platform == 'win32'", - "version": "==0.2.0" + "version": "==0.2.2" }, "pyyaml": { "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + "sha256:0101357af42f5c9fc7e9acc5c5ab8c3049f50db7425de175b6c7a5959cb6023d", + "sha256:0ae563b7e3ed5e918cd0184060e28b48b7e672b975bf7c6f4a892cee9d886ada", + "sha256:0fe2c1c5401a3a98f06337fed48f57340cf652a685484834b44f5ceeadb772ba", + "sha256:1eb00dd3344da80264261ab126c95481824669ed9e5ecc82fb2d88b1fce668ee", + "sha256:2086b30215c433c1e480c08c1db8b43c1edd36c59cf43d36b424e6f35fcaf1ad", + "sha256:29b4a67915232f79506211e69943e3102e211c616181ceff0adf34e21b469357", + "sha256:2e9bc8a34797f0621f56160b961d47a088644370f79d34bedc934fb89e3f47dd", + "sha256:30ec6b9afc17353a9abcff109880edf6e8d5b924eb1eeed7fe9376febc1f9800", + "sha256:31573d7e161d2f905311f036b12e65c058389b474dbd35740f4880b91e2ca2be", + "sha256:36d7bf63558843ea2a81de9d0c3e9c56c353b1df8e6c1faaec86df5adedf2e02", + "sha256:3af6b36bc195d741cd5b511810246cad143b99c953b4591e679e194a820d7b7c", + "sha256:414629800a1ddccd7303471650843fc801801cc579a195d2fe617b5b455409e3", + "sha256:459113f2b9cd68881201a3bd1a858ece3281dc0e92ece6e917d23b128f0fcb31", + "sha256:46e4fae38d00b40a62d32d60f1baa1b9ef33aff28c2aafd96b05d5cc770f1583", + "sha256:4bf821ccd51e8d5bc1a4021b8bd85a92b498832ac1cd1a53b399f0eb7c1c4258", + "sha256:50bd6560a6df3de59336b9a9086cbdea5aa9eee5361661448ee45c21eeb0da68", + "sha256:53056b51f111223e603bed1db5367f54596d44cacfa50f07e082a11929612957", + "sha256:53c5f0749a93e3296078262c9acf632de246241ff2f22bbedfe49d4b55e9bbdd", + "sha256:54c754cee6937bb9b72d6a16163160dec80b93a43020ac6fc9f13729c030c30b", + "sha256:58cc18ccbade0c48fb55102aa971a5b4e571e2b22187d083dda33f8708fa4ee7", + "sha256:5921fd128fbf27ab7c7ad1a566d2cd9557b84ade130743a7c110a55e7dec3b3c", + "sha256:5c758cc29713c9166750a30156ca3d90ac2515d5dea3c874377ae8829cf03087", + "sha256:60bf91e73354c96754220a9c04a9502c2ad063231cd754b59f8e4511157e32e2", + "sha256:6f0f728a88c6eb58a3b762726b965bb6acf12d97f8ea2cb4fecf856a727f9bdc", + "sha256:6f31c5935310da69ea0efe996a962d488f080312f0eb43beff1717acb5fe9bed", + "sha256:728b447d0cedec409ea1a3f0ad1a6cc3cec0a8d086611b45f038a9230a2242f3", + "sha256:72ffbc5c0cc71877104387548a450f2b7b7c4926b40dc9443e7598fe92aa13d9", + "sha256:73d8b233309ecd45c33c51cd55aa1be1dcab1799a9e54f6c753d8cab054b8c34", + "sha256:765029d1cf96e9e761329ee1c20f1ca2de8644e7350a151b198260698b96e30f", + "sha256:7ee3d180d886a3bc50f753b76340f1c314f9e8c507f5b107212112214c3a66fd", + "sha256:826fb4d5ac2c48b9d6e71423def2669d4646c93b6c13612a71b3ac7bb345304b", + "sha256:84c39ceec517cd8f01cb144efb08904a32050be51c55b7a59bc7958c8091568d", + "sha256:88bfe675bb19ae12a9c77c52322a28a8e2a8d3d213fbcfcded5c3f5ca3ead352", + "sha256:8e0a1ebd5c5842595365bf90db3ef7e9a8d6a79c9aedb1d05b675c81c7267fd3", + "sha256:9426067a10b369474396bf57fdf895b899045a25d1848798844693780b147436", + "sha256:9c5c0de7ec50d4df88b62f4b019ab7b3bb2883c826a1044268e9afb344c57b17", + "sha256:ad0c172fe15beffc32e3a8260f18e6708eb0e15ae82c9b3f80fbe04de0ef5729", + "sha256:ad206c7f5f08d393b872d3399f597246fdc6ebebff09c5ae5268ac45aebf4f8d", + "sha256:b0a163f4f84d1e0fe6a07ccad3b02e9b243790b8370ff0408ae5932c50c4d96d", + "sha256:b0dd9c7497d60126445e79e542ff01351c6b6dc121299d89787f5685b382c626", + "sha256:b1de10c488d6f02e498eb6956b89081bea31abf3133223c17749e7137734da75", + "sha256:b408f36eeb4e2be6f802f1be82daf1b578f3de5a51917c6e467aedb46187d827", + "sha256:bae077a01367e4bf5fddf00fd6c8b743e676385911c7c615e29e1c45ace8813b", + "sha256:bc3c3600fec6c2a719106381d6282061d8c108369cdec58b6f280610eba41e09", + "sha256:c16522bf91daa4ea9dedc1243b56b5a226357ab98b3133089ca627ef99baae6f", + "sha256:ca5136a77e2d64b4cf5106fb940376650ae232c74c09a8ff29dbb1e262495b31", + "sha256:d6e0f7ee5f8d851b1d91149a3e5074dbf5aacbb63e4b771fcce16508339a856f", + "sha256:e7930a0612e74fcca37019ca851b50d73b5f0c3dab7f3085a7c15d2026118315", + "sha256:e8e6dd230a158a836cda3cc521fcbedea16f22b16b8cfa8054d0c6cea5d0a531", + "sha256:eee36bf4bc11e39e3f17c171f25cdedff3d7c73b148aedc8820257ce2aa56d3b", + "sha256:f07adc282d51aaa528f3141ac1922d16d32fe89413ee59bfb8a73ed689ad3d23", + "sha256:f09816c047fdb588dddba53d321f1cb8081e38ad2a40ea6a7560a88b7a2f0ea8", + "sha256:fea4c4310061cd70ef73b39801231b9dc3dc638bb8858e38364b144fbd335a1a" ], "index": "pypi", - "version": "==6.0" + "markers": "python_version >= '3.6'", + "version": "==6.0.2rc1" }, "readme-renderer": { "hashes": [ - "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273", - "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343" + "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", + "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9" ], - "markers": "python_version >= '3.7'", - "version": "==37.3" + "markers": "python_version >= '3.8'", + "version": "==43.0" }, "requests": { "hashes": [ - "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa", - "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.28.2" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-toolbelt": { "hashes": [ - "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7", - "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d" + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.1" - }, - "restructuredtext-lint": { - "hashes": [ - "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45" - ], - "version": "==1.4.0" + "version": "==1.0.0" }, "rfc3986": { "hashes": [ @@ -989,27 +909,35 @@ }, "rich": { "hashes": [ - "sha256:125d96d20c92b946b983d0d392b84ff945461e5a06d3867e9f9e575f8697b67f", - "sha256:8aa57747f3fc3e977684f0176a88e789be314a99f99b43b75d1e9cb5dc6db9e9" + "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", + "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.3.1" - }, - "setuptools": { - "hashes": [ - "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c", - "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48" + "version": "==13.7.1" + }, + "ruff": { + "hashes": [ + "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6", + "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739", + "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d", + "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695", + "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804", + "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815", + "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac", + "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7", + "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631", + "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e", + "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e", + "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef", + "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6", + "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784", + "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81", + "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0", + "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca" ], + "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==67.2.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" + "version": "==0.4.10" }, "snowballstemmer": { "hashes": [ @@ -1020,35 +948,36 @@ }, "sphinx": { "hashes": [ - "sha256:0dac3b698538ffef41716cf97ba26c1c7788dba73ce6f150c1ff5b4720786dd2", - "sha256:807d1cb3d6be87eb78a381c3e70ebd8d346b9a25f3753e9947e866b2786865fc" + "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", + "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc" ], "index": "pypi", - "version": "==6.1.3" + "markers": "python_version >= '3.9'", + "version": "==7.3.7" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228", - "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e" + "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", + "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4" ], - "markers": "python_version >= '3.8'", - "version": "==1.0.4" + "markers": "python_version >= '3.9'", + "version": "==1.0.8" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", - "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" + "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", + "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" + "markers": "python_version >= '3.9'", + "version": "==1.0.6" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff", - "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903" + "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", + "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04" ], - "markers": "python_version >= '3.8'", - "version": "==2.0.1" + "markers": "python_version >= '3.9'", + "version": "==2.0.5" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -1060,155 +989,52 @@ }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", - "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" + "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", + "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.3" + "markers": "python_version >= '3.9'", + "version": "==1.0.7" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd", - "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952" + "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", + "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f" ], - "markers": "python_version >= '3.5'", - "version": "==1.1.5" - }, - "stevedore": { - "hashes": [ - "sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a", - "sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e" - ], - "markers": "python_version >= '3.8'", - "version": "==4.1.1" - }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" + "markers": "python_version >= '3.9'", + "version": "==1.1.10" }, "tomlkit": { "hashes": [ - "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b", - "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73" + "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f", + "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c" ], - "markers": "python_version >= '3.6'", - "version": "==0.11.6" + "markers": "python_version >= '3.7'", + "version": "==0.12.5" }, "twine": { "hashes": [ - "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8", - "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8" + "sha256:4d74770c88c4fcaf8134d2a6a9d863e40f08255ff7d8e2acb3cbbd57d25f6e9d", + "sha256:fe1d814395bfe50cfbe27783cb74efe93abeac3f66deaeb6c8390e4e92bacb43" ], "index": "pypi", - "version": "==4.0.2" + "markers": "python_version >= '3.8'", + "version": "==5.1.0" }, "urllib3": { "hashes": [ - "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72", - "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.14" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", - "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" - ], - "version": "==0.5.1" - }, - "wrapt": { - "hashes": [ - "sha256:09fbbcfb17be9464c18f3e54457e4907a3913f836a691552ae1c967df4d6e4b4", - "sha256:0d47527c5c8f9fa6d20fd72e87c39c1cad627f8c7f11b62af05e27ddcd443ba3", - "sha256:107415c7367bf5489ab7b16f5348216a1a1c4ff8d5ec08612cf6f64321f9ad3c", - "sha256:123de234ee3f528ae817a4be29f811b9ce25f9f48ed446fbd5adcf68b7abb869", - "sha256:1b2975c345967fbbff2fa9ffc45c60c30de005e753b6c01135ba4fbb788d3f38", - "sha256:21c1487e21979ba8a6a1d6e2e2d026bfeb57aebec0e25da2f7960938e99a9e8c", - "sha256:25be3596f51338a6043c6679870d95eb0636e02bb1e6ccf63da61e8021e533d0", - "sha256:26bc4fe48eb78cc6a1328b70fe720555b4d31321b060b69fc03a1f8296ee40de", - "sha256:30201cbcfea303e345b3c83fb7217e34c46c87df897d3a6f9e0cb840cc0f81c9", - "sha256:32960f2f9e5f53ff8c75ef9704d03114fc14c8f604a75323aa7b907f65bfcb6b", - "sha256:338dd5c161be7c981f8afb597dac0f5d26e9310d66bbf612209fa29c21a7da33", - "sha256:3a8981cbf86e0a004160cbd299af99cb251f93a49d58032bd7400b23f40839e5", - "sha256:3cdfb26e3e9fec79e04af3e37b0576c12ee3cd5aa7ba3f041b92aa323fb7f997", - "sha256:401a64a7cdfe4d00edcd6a36666e6fba0f61291f6bacf686baf918182f02cf2d", - "sha256:42a271aac91a2c74ea6a6b869219cff14404e9362de05c4b83f65dfed7e9b12c", - "sha256:44bd131dab4ed4d6221fa78277b6ccbcfa9b439629ffa930b1d1ddc38a88a224", - "sha256:45d9589ff8649934c2106d57b85405777e9ce1278eaf0f0fec70f5e037d82c48", - "sha256:485cdea587ccc1e8d483855e4e26ab4397b6455e2b416c1f8034ac0acd820da8", - "sha256:49e9cb44795b512097f09d9df29e0d83d5f2a517a00eec47d886c0ded5be4496", - "sha256:4c08d4c4698e3119408acfa48871ed210a9c40d566b0426eee0b2bd0bc638c0e", - "sha256:4c74bf0a62faed5e40431fa846f278420d2356fe2a781b5f601946749f9ac914", - "sha256:5053e18f970b38e2e8cb4f635bba79ef1a22d236795af73017b415e9a9aeba48", - "sha256:50bfbb843e37e767634102eaf284def65a381061ca762f536c6b5a40e4aed4f4", - "sha256:515ab064a2163a05a3b6460137dc4c28c091a58853ed4a0b48b100089a29cb55", - "sha256:57ec643799932381502c3f0db4ef5de25bc10b0adc02b0de5fb2a61f23ca7562", - "sha256:5951d10d4cac32454c0a65e83330f832db7c4208eee82a69cd7e9be06bbecb70", - "sha256:59caed62ad5f7ce1a917e758e15bd2f0bfe2fd6817d0cf8c5e1a713203481669", - "sha256:5ac1a93b98c131aabc145a8712e01ed0241c66cb5940fe69ba34c61d59d8b31a", - "sha256:5cc4a8d20edb25b395c62e6932e5a1c8afe1aaf45bf2acd876ba683306f9dfa0", - "sha256:5d972d3a48c199564e0659d62de4a39d123a547dc25eba548e97b42e4733c0a8", - "sha256:5f3a8c55f27524c0426b07232dbfb7f2e0ba414dcb57ebc66054f0a170a0fc49", - "sha256:62324e76ea16e5b0339de237edfc1df338442308c599ad3ca02a22e5b3d847db", - "sha256:654160de93ee85253d426d9390a649bf2b91e3f79560410644664fd284bc2be8", - "sha256:66938fd0469076f8fb1064b24778756b47d71348e5ca7bde5f3cec303ed90676", - "sha256:67cad5aae1d0934b02f6a15fa6f181ef83e86d5d8dee2b26873ff57cdd4c0f4f", - "sha256:698e03c02d501681939f8a4376afb5521ec04dcca9bfdc023cc968e457e50410", - "sha256:6d03a9c18017976265d07e40236dd09278a387cdf3870487060ecf4f48ea5252", - "sha256:72d9f2ff2fb3e5c2bfcf891152995b8589c5e735045fbbaae00bd776a6dc9a6b", - "sha256:73942a75f7d8b78630076075848d303be3d68798f0462073639583616f0f65a0", - "sha256:77cb6f9eae637b1d19b78738602317f788df1896b79f8d81b829d186ff8154c3", - "sha256:7963d8049c452e9462e9ea9bc1a20aa31bda4ce667a39b38013e84ae1e6185b0", - "sha256:79662ce899950115f33f657b1558a83f631b2a2f91d6fcfdd09a6cbe378cbd2f", - "sha256:798bb2eb07988514ee3d213d8ab35e6677c86215190896970b1c407b84ce791a", - "sha256:7afabb46692c9dc3053a526915a05ddbc41266082ee505c64fc5aa1fd8ccfdd9", - "sha256:7bf51f7815f15d6655c67d32ceedc97787e88c41d1c9cfab19c5f54982d09c41", - "sha256:81cf008c5ef139b63dac5df0035eb597bc0b5818d321219d41da2c1aa2fa8ce3", - "sha256:88b8bfb2ce44d91789a566cd2be7083e0520208977322bf84ddd215fbee81b58", - "sha256:8ee0105bca55eb430ef949eadea557915a183810f25f396e91b5587b7aff3348", - "sha256:8f0a1f9d970d4af52c4b696022268b710e19f446423a59cf1d9c393b98c0d985", - "sha256:93d95f9007cdcd2ab1c31761840434aff21bc75859110b28dd77a1016fa39202", - "sha256:94f9d8cd233b0654c3c38b0855e872716a5b358203a42d41275acb09f3526f0a", - "sha256:99011767b4b383706ac749d52b6e2b1f7335e45a72ba604465aa097cca61da3d", - "sha256:9c025bbc3b29ca7d56cdbe8dd88e7c90a4caea59af1a236cc17222b114047342", - "sha256:9da305a413ac7be48dbcc2eda0a6376235a9cd437a3eb106e67cca36f50f9c12", - "sha256:9f74533bf0490662451e520450111548cd669440bb30f0400abe9e778789f5b9", - "sha256:a7f4fbef92c3b507232c65b9504c1f23dd5faede097b55ac5ffa599ae775c6e8", - "sha256:b51f96d1cd7a88baa373bbb39433d09326fd204c8bf95c2f53b81c530df688ef", - "sha256:b53b375ef6028136856aca7c22126de55343035d60198d32d32a90e156be857a", - "sha256:b86269bf2657876413a34c84fe205e853aa28ea84d7d044b6a58fd59f6c84e7c", - "sha256:bb6182ff6760da884274150af7b7dd3b1a71b49e7c2daa1398e48929b453022a", - "sha256:c47994d3ac60e235614235aef76fae1d41a2f882f5fbd62b6fde92f29d84d785", - "sha256:c4e87511f8b06cfdf8555701abe64bd2bd0951d1c2a5e66f9ee652ea38edeb5c", - "sha256:c588d8e582f07ae24133a4e12ff10e09789763a55acc2317760507492d0d482e", - "sha256:c9239fef921d5503c1b4489861ecabe246f56791c0804b1afb6917ba0f328002", - "sha256:d46da7b89f9b09c232528b395e9e27be7a73a2b70745eca2e4580f06fe622be4", - "sha256:d79b8d62443414fd8790e5b3f89365161957b40e1275888f8e9390a778553bb9", - "sha256:ddf53a1f0184a9d9bd72af31cbd639e48e5affc8cc473246a5fe2f89e7b01741", - "sha256:e3855ef2ffebca0fb8a1e80bfde292bcb19cdd43c73b94b2b91c874cca1116b9", - "sha256:e494137d27700a3a3b020c903d511f1f9fc7ecec406991266a023a756e61db2e", - "sha256:e7e3ba93fdec4e044a98c955641dd4e978513854d4a9425fd19f15143bc6af02", - "sha256:e8666f3b83285e84a081fc4260fd044f7ef06843691a3fa5e87432152ceeb7c3", - "sha256:e999014967cf06782702c7308c3e7977035f548217743eba752b2f8e0b576ee9", - "sha256:f50f3bb2ba9d914830ac351a6fce9fd3a5b8ff28124966941f0ea1a4789339a4", - "sha256:f6c7af527e9757af49b0de3f9447a61ad3ebc0cedb8e2ecd900265f715944a16", - "sha256:f6d36e191323cef8143915e0acc708fd222179311daec90a677f06270367fe8b" + "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", + "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" ], - "index": "pypi", - "version": "==1.15.0rc1" + "markers": "python_version >= '3.8'", + "version": "==2.2.2" }, "zipp": { "hashes": [ - "sha256:6c4fe274b8f85ec73c37a8e4e3fa00df9fb9335da96fb789e3b96b318e5097b3", - "sha256:a3cac813d40993596b39ea9e93a18e8a2076d5c378b8bc88ec32ab264e04ad02" + "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19", + "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c" ], - "markers": "python_version >= '3.7'", - "version": "==3.12.1" + "markers": "python_version >= '3.8'", + "version": "==3.19.2" } } } diff --git a/pyproject.toml b/pyproject.toml index d78f1cf6..fb21025d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,11 +6,34 @@ build-backend = "setuptools.build_meta:__legacy__" minversion = "6.0" addopts = "-ra --durations=0 --cov-report xml:coverage.xml --cov PIconnect" -[tool.isort] -# make it compatible with black -profile = "black" +[tool.ruff] +line-length = 95 +exclude = ["build", "dist", "docs", "venv"] -[tool.black] -line-length = 88 -target-version = ['py38', 'py39', 'py310', 'py311'] -include = '\.pyi?$' +[tool.ruff.lint] +# See: https://docs.astral.sh/ruff/rules/ +select = [ + "C4", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "PT", # pytest-style + "D", # pydocstyle + "B", # flake8-bugbear + "NPY", # numpy +] +# ignore = [ +# "D100", # Missing docstring in public module +# "E501", # Line too long +# "D101", # Missing docstring in public class +# "D102", # Missing docstring in public method +# "D103", # Missing docstring in public function +# "D104", # Missing docstring in public package +# "D105", # Missing docstring in magic method +# "D205", # 1 blank line required between summary line and description +# "D401", # First line of docstring should be in imperative mood +# "E741", # Ambiguous variable name (such as "l") +# ] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" diff --git a/requirements.txt b/requirements.txt index 637a5fff..098b0f26 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,24 +1,13 @@ -i https://pypi.org/simple - -cffi==1.15.1 - -clr-loader==0.2.5 ; python_version >= '3.7' - -numpy==1.24.2 ; python_version >= '3.10' - -pandas==1.5.3 - --e . - -pycparser==2.21 - -python-dateutil==2.8.2 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' - -pythonnet==3.0.1 - -pytz==2022.7.1 - -six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' - -wrapt==1.15.0rc1 - +cffi==1.17.0rc1; python_version >= '3.8' +clr-loader==0.2.6; python_version >= '3.7' +numpy==1.26.4; python_version >= '3.9' +pandas==2.2.2; python_version >= '3.9' +-e . ; python_version >= '3.8' +pycparser==2.22; python_version >= '3.8' +python-dateutil==2.9.0.post0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pythonnet==3.0.3; python_version < '3.13' and python_version >= '3.7' +pytz==2024.1 +six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +tzdata==2024.1; python_version >= '2' +wrapt==1.16.0; python_version >= '3.6' diff --git a/requirements_dev.txt b/requirements_dev.txt index d9c8a7c4..372038a4 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,162 +1,78 @@ -i https://pypi.org/simple - -alabaster==0.7.13 ; python_version >= '3.6' - -astroid==2.11.7 ; python_full_version >= '3.6.2' - -attrs==22.2.0 ; python_version >= '3.6' - -babel==2.11.0 ; python_version >= '3.6' - -black==23.1.0 - -bleach==6.0.0 ; python_version >= '3.7' - -certifi==2022.12.7 ; python_version >= '3.6' - -charset-normalizer==3.0.1 ; python_full_version >= '3.6.0' - -click==8.1.3 ; python_version >= '3.7' - +alabaster==0.7.16; python_version >= '3.9' +astroid==3.2.2; python_full_version >= '3.8.0' +babel==2.15.0; python_version >= '3.8' +black==24.4.2; python_version >= '3.8' +certifi==2024.6.2; python_version >= '3.6' +charset-normalizer==3.3.2; python_full_version >= '3.7.0' +click==8.1.7; python_version >= '3.7' codacy-coverage==1.3.11 - -codecov==2.1.12 - -colorama==0.4.6 ; sys_platform == 'win32' - -coverage==7.1.0 - -dill==0.3.6 ; python_version >= '3.7' - -doc8==1.1.1 - -docutils==0.19 ; python_version >= '3.7' - -exceptiongroup==1.1.0 ; python_version < '3.11' - -flake8==6.0.0 - -idna==3.4 ; python_version >= '3.5' - -imagesize==1.4.1 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' - -importlib-metadata==6.0.0 ; python_version >= '3.7' - -iniconfig==2.0.0 ; python_version >= '3.7' - -isort==5.12.0 ; python_full_version >= '3.8.0' - -jaraco.classes==3.2.3 ; python_version >= '3.7' - -jinja2==3.1.2 ; python_version >= '3.7' - -keyring==23.13.1 ; python_version >= '3.7' - -lazy-object-proxy==1.9.0 ; python_version >= '3.7' - -markdown-it-py==2.1.0 ; python_version >= '3.7' - -markupsafe==2.1.2 ; python_version >= '3.7' - -mccabe==0.7.0 ; python_version >= '3.6' - -mdurl==0.1.2 ; python_version >= '3.7' - -more-itertools==9.0.0 ; python_version >= '3.7' - -mypy-extensions==1.0.0 ; python_version >= '3.5' - -packaging==23.0 ; python_version >= '3.7' - -pathspec==0.11.0 ; python_version >= '3.7' - -pbr==5.11.1 ; python_version >= '2.6' - -pkginfo==1.9.6 ; python_version >= '3.6' - -platformdirs==3.0.0 ; python_version >= '3.7' - -pluggy==1.0.0 ; python_version >= '3.6' - -pycodestyle==2.10.0 ; python_version >= '3.6' - -pyflakes==3.0.1 ; python_version >= '3.6' - -pygments==2.14.0 ; python_version >= '3.6' - -pylint==3.0.0a5 - -pytest==7.2.1 - -pytest-cov==4.0.0 - -pytz==2022.7.1 - -pywin32-ctypes==0.2.0 ; sys_platform == 'win32' - -pyyaml==6.0 - -readme-renderer==37.3 ; python_version >= '3.7' - -requests==2.28.2 ; python_version >= '3.7' and python_version < '4' - -requests-toolbelt==0.10.1 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' - +codecov==2.1.13; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +colorama==0.4.6; sys_platform == 'win32' +coverage[toml]==7.5.3; python_version >= '3.8' +dill==0.3.8; python_version >= '3.11' +doc8==1.1.1; python_version >= '3.8' +docutils==0.20.1; python_version >= '3.7' +flake8==7.1.0; python_full_version >= '3.8.1' +idna==3.7; python_version >= '3.5' +imagesize==1.4.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +importlib-metadata==7.2.0; python_version >= '3.8' +iniconfig==2.0.0; python_version >= '3.7' +isort==5.13.2; python_full_version >= '3.8.0' +jaraco.classes==3.4.0; python_version >= '3.8' +jaraco.context==5.3.0; python_version >= '3.8' +jaraco.functools==4.0.1; python_version >= '3.8' +jinja2==3.1.4; python_version >= '3.7' +keyring==25.2.1; python_version >= '3.8' +markdown-it-py==3.0.0; python_version >= '3.8' +markupsafe==2.1.5; python_version >= '3.7' +mccabe==0.7.0; python_version >= '3.6' +mdurl==0.1.2; python_version >= '3.7' +more-itertools==10.3.0; python_version >= '3.8' +mypy-extensions==1.0.0; python_version >= '3.5' +nh3==0.2.17 +packaging==24.1; python_version >= '3.8' +pathspec==0.12.1; python_version >= '3.8' +pbr==6.0.0; python_version >= '2.6' +pkginfo==1.11.1; python_version >= '3.8' +platformdirs==4.2.2; python_version >= '3.8' +pluggy==1.5.0; python_version >= '3.8' +pycodestyle==2.12.0; python_version >= '3.8' +pyflakes==3.2.0; python_version >= '3.8' +pygments==2.18.0; python_version >= '3.8' +pylint==3.2.3; python_full_version >= '3.8.0' +pytest==8.2.2; python_version >= '3.8' +pytest-cov==5.0.0; python_version >= '3.8' +pywin32-ctypes==0.2.2; sys_platform == 'win32' +pyyaml==6.0.2rc1; python_version >= '3.6' +readme-renderer==43.0; python_version >= '3.8' +requests==2.32.3; python_version >= '3.8' +requests-toolbelt==1.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' restructuredtext-lint==1.4.0 - -rfc3986==2.0.0 ; python_version >= '3.7' - -rich==13.3.1 ; python_full_version >= '3.7.0' - -setuptools==67.2.0 ; python_version >= '3.7' - -six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' - +rfc3986==2.0.0; python_version >= '3.7' +rich==13.7.1; python_full_version >= '3.7.0' snowballstemmer==2.2.0 - -sphinx==6.1.3 - -sphinxcontrib-applehelp==1.0.4 ; python_version >= '3.8' - -sphinxcontrib-devhelp==1.0.2 ; python_version >= '3.5' - -sphinxcontrib-htmlhelp==2.0.1 ; python_version >= '3.8' - -sphinxcontrib-jsmath==1.0.1 ; python_version >= '3.5' - -sphinxcontrib-qthelp==1.0.3 ; python_version >= '3.5' - -sphinxcontrib-serializinghtml==1.1.5 ; python_version >= '3.5' - -stevedore==4.1.1 ; python_version >= '3.8' - -tomli==2.0.1 ; python_version < '3.11' - -tomlkit==0.11.6 ; python_version >= '3.6' - -twine==4.0.2 - -urllib3==1.26.14 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' - -webencodings==0.5.1 - -wrapt==1.15.0rc1 - -zipp==3.12.1 ; python_version >= '3.7' - -cffi==1.15.1 - -clr-loader==0.2.5 ; python_version >= '3.7' - -numpy==1.24.2 ; python_version >= '3.10' - -pandas==1.5.3 - --e . - -pycparser==2.21 - -python-dateutil==2.8.2 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' - -pythonnet==3.0.1 - +sphinx==7.3.7; python_version >= '3.9' +sphinxcontrib-applehelp==1.0.8; python_version >= '3.9' +sphinxcontrib-devhelp==1.0.6; python_version >= '3.9' +sphinxcontrib-htmlhelp==2.0.5; python_version >= '3.9' +sphinxcontrib-jsmath==1.0.1; python_version >= '3.5' +sphinxcontrib-qthelp==1.0.7; python_version >= '3.9' +sphinxcontrib-serializinghtml==1.1.10; python_version >= '3.9' +stevedore==5.2.0; python_version >= '3.8' +tomlkit==0.12.5; python_version >= '3.7' +twine==5.1.0; python_version >= '3.8' +urllib3==2.2.2; python_version >= '3.8' +zipp==3.19.2; python_version >= '3.8' +cffi==1.17.0rc1; python_version >= '3.8' +clr-loader==0.2.6; python_version >= '3.7' +numpy==1.26.4; python_version >= '3.9' +pandas==2.2.2; python_version >= '3.9' +-e . ; python_version >= '3.8' +pycparser==2.22; python_version >= '3.8' +python-dateutil==2.9.0.post0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +pythonnet==3.0.3; python_version < '3.13' and python_version >= '3.7' +pytz==2024.1 +six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +tzdata==2024.1; python_version >= '2' +wrapt==1.16.0; python_version >= '3.6' diff --git a/setup.cfg b/setup.cfg index f17bb0aa..c9b714fa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,9 +18,9 @@ classifiers = Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 author = Hugo Lapré author_email = hugo.lapre@brabantwater.nl url = https://github.com/Hugovdberg/PIconnect @@ -39,7 +39,7 @@ install_requires = wrapt pytz pythonnet -python_requires = >= 3.8 +python_requires = >= 3.9 include_package_data = True zip_safe=False diff --git a/setup.py b/setup.py deleted file mode 100644 index 06293acc..00000000 --- a/setup.py +++ /dev/null @@ -1,4 +0,0 @@ -"""A setuptools based setup module.""" -import setuptools - -setuptools.setup() diff --git a/tests/fakes.py b/tests/fakes.py index ecde526a..60e34d25 100644 --- a/tests/fakes.py +++ b/tests/fakes.py @@ -1,6 +1,5 @@ -""" PIconnect.test.fakes - Fake classes to mask SDK complexity -""" +"""Fake classes to mask SDK complexity.""" + import dataclasses import datetime from typing import Any, Dict, Generic, Iterable, List, TypeVar @@ -8,9 +7,8 @@ import pytest import pytz -import PIconnect.PI as PI import PIconnect._typing.AF as AF -from PIconnect._operators import OPERATORS, add_operators +import PIconnect.PI as PI @dataclasses.dataclass @@ -44,14 +42,14 @@ def __init__(self, timestamp: datetime.datetime): class FakeKeyValue(Generic[_a, _b]): - """Container for fake Key:Value pairs""" + """Container for fake Key:Value pairs.""" def __init__(self, key: _a, value: _b) -> None: self.Key = key self.Value = value -class FakeAFValue(Generic[_a]): +class FakeAFValue(AF.Asset.AFValue, Generic[_a]): """Fake AFValue to mask away SDK complexity.""" def __init__(self, value: _a, timestamp: datetime.datetime): @@ -59,7 +57,17 @@ def __init__(self, value: _a, timestamp: datetime.datetime): self.Timestamp = FakeAFTime(timestamp) +class FakeAFValues(AF.Asset.AFValues, Generic[_a]): + """Fake AFValues to mask away SDK complexity.""" + + def __init__(self, values: Iterable[FakeAFValue[_a]]): + self.Value = list(values) + self.Count = len(self.Value) + + class FakePIPoint_(Generic[_a]): + """Fake PI Point to mask away SDK complexity.""" + def __init__( self, tag: str, @@ -69,18 +77,11 @@ def __init__( ): self.Name = tag self.values = [ - FakeAFValue(value, timestamp) - for value, timestamp in zip(values, timestamps) + FakeAFValue(value, timestamp) for value, timestamp in zip(values, timestamps) ] self.attributes = [FakeKeyValue(*att) for att in attributes.items()] -@add_operators( - operators=OPERATORS, - members=["_current_value", "sampled_data"], - newclassname="VirtualFakePIPoint", - attributes=["pi_point"], -) class FakePIPoint(AF.PI.PIPoint, Generic[_a]): """Fake PI Point to mask away SDK complexity.""" @@ -90,21 +91,26 @@ def __init__(self, pi_point: FakePIPoint_[_a]) -> None: self.Name = pi_point.Name def CurrentValue(self) -> FakeAFValue[_a]: + """Return the current value of the PI Point.""" self.call_stack.append("CurrentValue called") return self.pi_point.values[-1] 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]]: + """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]]: + """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]]: + """Return the interpolated values of the PI Point.""" self.call_stack.append("InterpolatedValues called") return self.pi_point.values @@ -128,8 +134,7 @@ def __init__(self): 1502732545.013, ] self.timestamps = [ - datetime.datetime.fromtimestamp(x, tz=pytz.utc) - for x in self.timestamp_numbers + datetime.datetime.fromtimestamp(x, tz=pytz.utc) for x in self.timestamp_numbers ] self.attributes = {"engunits": "m3/h", "descriptor": "Flow"} pi_point = FakePIPoint_( @@ -141,6 +146,7 @@ def __init__(self): self.point = PI.PIPoint(FakePIPoint(pi_point)) -@pytest.fixture -def pi_point(): +@pytest.fixture() +def pi_point() -> VirtualTestCase: + """Return a VirtualTestCase object.""" return VirtualTestCase() diff --git a/tests/test_PI.py b/tests/test_PI.py index bf73d525..4a3d22c1 100644 --- a/tests/test_PI.py +++ b/tests/test_PI.py @@ -1,39 +1,47 @@ -""" PIconnect.test.test_PI - Test communication with the PI System. -""" +"""Test communication with the PI System.""" + import datetime import pytest import pytz import PIconnect as PI +import PIconnect.PI as PI_ + +from .fakes import VirtualTestCase, pi_point -from .fakes import pi_point # pylint: disable=unused-import +__all__ = ["TestServer", "TestSearchPIPoints", "TestPIPoint", "pi_point"] class TestServer: - """Test connecting to the server""" + """Test connecting to the server.""" def test_connection(self): - """Test that creating a PI.PIServer object without arguments raises no exception""" + """Test that creating a PI.PIServer object without arguments raises no exception.""" PI.PIServer() def test_server_name(self): """Test that the server reports the same name as which was connected to.""" - servername = PI.PIServer.default_server.Name + default_server = PI.PIServer.default_server + if default_server is None: + pytest.skip("No default server found.") + servername = default_server.Name server = PI.PIServer(servername) assert server.server_name == servername def test_warn_unkown_server(self): """Test that the server reports a warning when an unknown host is specified.""" - server_names = [name for name in PI.PIServer.servers] + server_names = list(PI.PIServer.servers) server_name = "__".join(server_names + ["UnknownHostName"]) with pytest.warns(UserWarning): PI.PIServer(server_name) def test_repr(self): """Test that the server representation matches the connected server.""" - servername = PI.PIServer.default_server.Name + default_server = PI.PIServer.default_server + if default_server is None: + pytest.skip("No default server found.") + servername = default_server.Name server = PI.PIServer(servername) assert repr(server) == "PIServer(\\\\{})".format(servername) @@ -47,7 +55,7 @@ def test_search_single_string(self): points = server.search("L_140_053*") assert isinstance(points, list) for point in points: - assert isinstance(point, PI.PI.PIPoint) + assert isinstance(point, PI_.PIPoint) def test_search_multiple_strings(self): """Tests searching for PI points using a list of strings.""" @@ -55,7 +63,7 @@ def test_search_multiple_strings(self): points = server.search(["L_140_053*", "M_127*"]) assert isinstance(points, list) for point in points: - assert isinstance(point, PI.PI.PIPoint) + assert isinstance(point, PI_.PIPoint) # def test_search_integer_raises_error(self): # """Tests searching for PI points using an integer raises a TypeError.""" @@ -66,7 +74,7 @@ def test_search_multiple_strings(self): class TestPIPoint: """Test valid interface of PIPoint.""" - def test_repr(self, pi_point): + def test_repr(self, pi_point: VirtualTestCase): """Test representation of the PI Point.""" assert repr(pi_point.point) == "%s(%s, %s; Current Value: %s %s)" % ( "PIPoint", @@ -76,15 +84,15 @@ def test_repr(self, pi_point): pi_point.attributes["engunits"], ) - def test_name(self, pi_point): + def test_name(self, pi_point: VirtualTestCase): """Test retrieving the name of the PI Point.""" assert pi_point.point.tag == pi_point.tag - def test_current_value(self, pi_point): + def test_current_value(self, pi_point: VirtualTestCase): """Test retrieving the current value from a PI point.""" assert pi_point.point.current_value == pi_point.values[-1] - def test_last_update(self, pi_point): + def test_last_update(self, pi_point: VirtualTestCase): """Test retrieving the last update timestamp.""" origin = datetime.datetime(1970, 1, 1).replace(tzinfo=pytz.utc) assert ( @@ -96,34 +104,34 @@ def test_last_update(self, pi_point): == 0 ) - def test_units_of_measurement(self, pi_point): + def test_units_of_measurement(self, pi_point: VirtualTestCase): """Test retrieving the units of measurement of the returned PI point.""" assert pi_point.point.units_of_measurement == pi_point.attributes["engunits"] - def test_description(self, pi_point): + def test_description(self, pi_point: VirtualTestCase): """Test retrieving the description of the PI point.""" assert pi_point.point.description == pi_point.attributes["descriptor"] - def test_raw_attributes(self, pi_point): + def test_raw_attributes(self, pi_point: VirtualTestCase): """Test retrieving the attributes of the PI point as a dict.""" assert pi_point.point.raw_attributes == pi_point.attributes - def test_recorded_values_values(self, pi_point): + def test_recorded_values_values(self, pi_point: VirtualTestCase): """Test retrieving some recorded data from the server.""" data = pi_point.point.recorded_values("01-07-2017", "02-07-2017") assert list(data.values) == pi_point.values - def test_recorded_values_timestamps(self, pi_point): + def test_recorded_values_timestamps(self, pi_point: VirtualTestCase): """Test retrieving some recorded data from the server.""" data = pi_point.point.recorded_values("01-07-2017", "02-07-2017") assert list(data.index) == pi_point.timestamps - def test_interpolated_values_values(self, pi_point): + def test_interpolated_values_values(self, pi_point: VirtualTestCase): """Test retrieving some interpolated data from the server.""" data = pi_point.point.interpolated_values("01-07-2017", "02-07-2017", "1h") assert list(data.values) == pi_point.values - def test_interpolated_values_timestamps(self, pi_point): + def test_interpolated_values_timestamps(self, pi_point: VirtualTestCase): """Test retrieving some interpolated data from the server.""" data = pi_point.point.interpolated_values("01-07-2017", "02-07-2017", "1h") assert list(data.index) == pi_point.timestamps diff --git a/tests/test_PIAF.py b/tests/test_PIAF.py index 615fa362..c9640dbf 100644 --- a/tests/test_PIAF.py +++ b/tests/test_PIAF.py @@ -1,5 +1,7 @@ -"""Test communication with the PI AF system""" -from typing import cast, List +"""Test communication with the PI AF system.""" + +from typing import cast + import pytest import PIconnect as PI @@ -7,10 +9,10 @@ class TestAFDatabase: - """Test connecting to the AF database""" + """Test connecting to the AF database.""" def test_connection(self): - """Test that creating a PI.PIAFDatabase object without arguments raises no exception""" + """Test creating a PI.PIAFDatabase object without arguments raises no exception.""" PI.PIAFDatabase() def test_server_name(self): @@ -20,21 +22,17 @@ def test_server_name(self): server = PI.PIAFDatabase(AFserver, database) assert server.server_name == AFserver assert server.database_name == database - assert repr(server) == "PIAFDatabase(\\\\{s}\\{d})".format( - s=AFserver, d=database - ) + assert repr(server) == "PIAFDatabase(\\\\{s}\\{d})".format(s=AFserver, d=database) def test_unknown_server_name(self): """Test that the server reports a warning for an unknown server.""" - AFserver_name = "__".join( - [name for name in PI.PIAFDatabase.servers] + ["UnkownServerName"] - ) + AFserver_name = "__".join(list(PI.PIAFDatabase.servers) + ["UnkownServerName"]) with pytest.warns(UserWarning): PI.PIAFDatabase(server=AFserver_name) def test_unknown_database_name(self): """Test that the server reports a warning for an unknown database.""" - server = cast(AF.PISystem, PI.PIAFDatabase.default_server["server"]) # type: ignore + server = cast(AF.PISystem, PI.PIAFDatabase.default_server["server"]) # type: ignore databases = [db.Name for db in server.Databases] AFdatabase_name = "__".join(databases + ["UnkownDatabaseName"]) with pytest.warns(UserWarning): @@ -42,20 +40,20 @@ def test_unknown_database_name(self): class TestDatabaseDescendants: - """Test retrieving child elements""" + """Test retrieving child elements.""" def test_children(self): - """Test that calling children on the database returns a dict of child elements""" + """Test that calling children on the database returns a dict of child elements.""" with PI.PIAFDatabase() as db: children = db.children assert isinstance(children, dict) class TestDatabaseSearch: - """Test retrieving attributes""" + """Test retrieving attributes.""" def test_search(self): - """Test that calling attributes on the database returns a list of attributes""" + """Test that calling attributes on the database returns a list of attributes.""" with PI.PIAFDatabase() as db: - attributes = db.search([r'', r'']) + attributes = db.search([r"", r""]) assert isinstance(attributes, list) diff --git a/tests/test_VirtualPIPoint_calculus.py b/tests/test_VirtualPIPoint_calculus.py deleted file mode 100644 index f672a42d..00000000 --- a/tests/test_VirtualPIPoint_calculus.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Test VirtualPIPoint calculus.""" -from .fakes import pi_point, VirtualTestCase # pylint: disable=unused-import - - -class TestVirtualAddition: - """Test VirtualPIPoint addition.""" - - def test_add_integer_current_value(self, pi_point: VirtualTestCase): - """Test adding an integer to a PIPoint via the current value.""" - point2 = pi_point.point + 1 - cur_value1 = pi_point.values[-1] + 1 - try: - cur_value2 = point2.current_value - except Exception as e: - raise AttributeError( - f"Error in current_value (type {type(e)!r}, attribute: {type(point2)})" - ) from e - assert round(cur_value2 - cur_value1, ndigits=7) == 0 - - def test_add_integer_reverse_current_value(self, pi_point): - """Test adding a PIPoint to an integer via the current value.""" - point2 = 1 + pi_point.point - assert round(point2.current_value - (pi_point.values[-1] + 1), ndigits=7) == 0 - - def test_add_pipoints_current_value(self, pi_point): - """Test adding two PIPoints via the current value.""" - total = pi_point.point + pi_point.point - assert ( - round( - total.current_value - (pi_point.values[-1] + pi_point.values[-1]), - ndigits=7, - ) - == 0 - ) - - -class TestVirtualMultiplication: - """Test VirtualPIPoint addition.""" - - def test_multiply_integer_current_value(self, pi_point): - """Test adding an integer to a PIPoint via the current value.""" - point2 = pi_point.point * 1 - assert round(point2.current_value - (pi_point.values[-1] * 1), ndigits=7) == 0 - - def test_multiply_integer_reverse_current_value(self, pi_point): - """Test adding a PIPoint to an integer via the current value.""" - point2 = 1 * pi_point.point - assert round(point2.current_value - (pi_point.values[-1] * 1), ndigits=7) == 0 - - def test_multiply_pipoints_current_value(self, pi_point): - """Test adding two PIPoints via the current value.""" - total = pi_point.point * pi_point.point - assert ( - round( - total.current_value - (pi_point.values[-1] * pi_point.values[-1]), - ndigits=7, - ) - == 0 - ) - - def test_multiply_integer_two_current_value(self, pi_point): - """Test adding an integer to a PIPoint via the current value.""" - point2 = pi_point.point * 2 - assert round(point2.current_value - (pi_point.values[-1] * 2), ndigits=7) == 0 - - def test_multiply_integer_two_reverse_current_value(self, pi_point): - """Test adding a PIPoint to an integer via the current value.""" - point2 = 2 * pi_point.point - assert round(point2.current_value - (pi_point.values[-1] * 2), ndigits=7) == 0 - - def test_multiply_float_two_current_value(self, pi_point): - """Test adding an integer to a PIPoint via the current value.""" - point2 = pi_point.point * 2.0 - assert round(point2.current_value - (pi_point.values[-1] * 2.0), ndigits=7) == 0 - - def test_multiply_float_two_reverse_current_value(self, pi_point): - """Test adding a PIPoint to an integer via the current value.""" - point2 = 2.0 * pi_point.point - assert round(point2.current_value - (pi_point.values[-1] * 2.0), ndigits=7) == 0 diff --git a/tests/test_piconnect.py b/tests/test_piconnect.py index 3c658c9e..2f784e9b 100644 --- a/tests/test_piconnect.py +++ b/tests/test_piconnect.py @@ -3,11 +3,9 @@ """Tests for `PIconnect` package.""" -import pytest # from click.testing import CliRunner -import PIconnect # from PIconnect import cli