tagreader 6.2.0__tar.gz → 6.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tagreader
3
- Version: 6.2.0
3
+ Version: 6.2.1
4
4
  Summary: Tagreader is a Python package for reading trend data from the OSIsoft PI and Aspen Infoplus.21 IMS systems.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -37,6 +37,10 @@ Project-URL: Homepage, https://github.com/equinor/tagreader-python
37
37
  Project-URL: Repository, https://github.com/equinor/tagreader-python
38
38
  Description-Content-Type: text/markdown
39
39
 
40
+ ⚠️ **Important:** **We are phasing out TagReader, and the code will no longer be maintained.**
41
+
42
+ For employees in Equinor we recommend using Omnia Timeseries
43
+
40
44
  # tagreader-python <!-- omit in toc -->
41
45
 
42
46
  ![GitHub Build Status](https://github.com/equinor/tagreader-python/workflows/Test/badge.svg)
@@ -86,6 +90,3 @@ For more details, see the [Tagreader Docs](https://equinor.github.io/tagreader-p
86
90
  ## Documentation
87
91
  The full documentation can be found in [Tagreader Docs](https://equinor.github.io/tagreader-python/)
88
92
 
89
- ## Contribute
90
- To starting contributing, please see [Tagreader Docs - Contribute](https://equinor.github.io/tagreader-python/docs/contribute/overview)
91
-
@@ -1,3 +1,7 @@
1
+ ⚠️ **Important:** **We are phasing out TagReader, and the code will no longer be maintained.**
2
+
3
+ For employees in Equinor we recommend using Omnia Timeseries
4
+
1
5
  # tagreader-python <!-- omit in toc -->
2
6
 
3
7
  ![GitHub Build Status](https://github.com/equinor/tagreader-python/workflows/Test/badge.svg)
@@ -46,6 +50,3 @@ For more details, see the [Tagreader Docs](https://equinor.github.io/tagreader-p
46
50
 
47
51
  ## Documentation
48
52
  The full documentation can be found in [Tagreader Docs](https://equinor.github.io/tagreader-python/)
49
-
50
- ## Contribute
51
- To starting contributing, please see [Tagreader Docs - Contribute](https://equinor.github.io/tagreader-python/docs/contribute/overview)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tagreader"
3
- version = "6.2.0"
3
+ version = "6.2.1"
4
4
  description = "Tagreader is a Python package for reading trend data from the OSIsoft PI and Aspen Infoplus.21 IMS systems."
5
5
  authors = [
6
6
  { name = "Einar S. Idsø", email = "eiids@equinor.com" },
@@ -1,9 +1,8 @@
1
- from datetime import datetime, timedelta
1
+ from datetime import datetime, timedelta, timezone
2
2
  from pathlib import Path
3
3
  from typing import Dict, List, Optional, Tuple, Union, cast
4
4
 
5
5
  import pandas as pd
6
- import pytz
7
6
  from diskcache import Cache
8
7
 
9
8
  from tagreader.logger import logger
@@ -21,7 +20,7 @@ def safe_tagname(tagname: str) -> str:
21
20
  def timestamp_to_epoch(timestamp: datetime) -> int:
22
21
  origin = datetime(1970, 1, 1)
23
22
  if timestamp.tzinfo is not None:
24
- timestamp = timestamp.astimezone(pytz.utc).replace(tzinfo=None)
23
+ timestamp = timestamp.astimezone(timezone.utc).replace(tzinfo=None)
25
24
  return (timestamp - origin) // timedelta(seconds=1)
26
25
 
27
26
 
@@ -2,11 +2,11 @@ from datetime import datetime, timedelta, timezone, tzinfo
2
2
  from itertools import groupby
3
3
  from operator import itemgetter
4
4
  from typing import Any, Dict, List, Optional, Tuple, Union
5
- from urllib.error import HTTPError
5
+ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
6
6
 
7
7
  import numpy as np
8
8
  import pandas as pd
9
- import pytz
9
+ import requests
10
10
 
11
11
  from tagreader.cache import BucketCache, SmartCache
12
12
  from tagreader.logger import logger
@@ -21,11 +21,12 @@ from tagreader.web_handlers import (
21
21
  PIHandlerWeb,
22
22
  get_auth_aspen,
23
23
  get_auth_pi,
24
+ get_url_aspen,
24
25
  list_aspenone_sources,
25
26
  list_piwebapi_sources,
26
27
  )
27
28
 
28
- NONE_START_TIME = datetime(1970, 1, 1, tzinfo=pytz.UTC)
29
+ NONE_START_TIME = datetime(1970, 1, 1, tzinfo=timezone.utc)
29
30
 
30
31
 
31
32
  def list_sources(
@@ -49,8 +50,6 @@ def list_sources(
49
50
  auth = get_auth_pi()
50
51
  return list_piwebapi_sources(url=url, auth=auth, verify_ssl=verify_ssl)
51
52
  elif imstype == IMSType.ASPENONE:
52
- if auth is None:
53
- auth = get_auth_aspen()
54
53
  return list_aspenone_sources(url=url, auth=auth, verify_ssl=verify_ssl)
55
54
  elif imstype in [IMSType.PI, IMSType.ASPEN, IMSType.IP21]:
56
55
  raise ValueError(
@@ -121,24 +120,41 @@ def get_handler(
121
120
  url: Optional[str],
122
121
  options: Dict[str, Union[int, float, str]],
123
122
  verify_ssl: Optional[Union[bool, str]],
124
- auth: Optional[Any],
123
+ auth: Optional[Any] = None,
125
124
  cache: Optional[Union[SmartCache, BucketCache]] = None,
126
125
  ):
127
126
  if imstype is None:
127
+ orig_auth = auth
128
+ orig_url = url
128
129
  try:
129
- if datasource in list_aspenone_sources(
130
+ aspen_source = list_aspenone_sources(
130
131
  url=None, auth=None, verify_ssl=verify_ssl
131
- ):
132
- imstype = IMSType.ASPENONE
133
- except HTTPError as e:
134
- logger.debug(f"Could not list Aspenone sources: {e}")
132
+ )
133
+ except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError):
134
+ # Try again using app registration auth
135
+ try:
136
+ auth = get_auth_aspen(False)
137
+ url = get_url_aspen(False)
138
+ aspen_source = list_aspenone_sources(
139
+ auth=auth, url=url, verify_ssl=verify_ssl
140
+ )
141
+ except requests.exceptions.HTTPError as e:
142
+ logger.debug(f"Could not list Aspenone sources: {e}")
143
+ aspen_source = []
144
+
145
+ if datasource in aspen_source:
146
+ imstype = IMSType.ASPENONE
147
+ else:
148
+ auth = orig_auth
149
+ url = orig_url
150
+
135
151
  if imstype is None:
136
152
  try:
137
153
  if datasource in list_piwebapi_sources(
138
154
  url=None, auth=None, verify_ssl=verify_ssl
139
155
  ):
140
156
  imstype = IMSType.PIWEBAPI
141
- except HTTPError as e:
157
+ except requests.exceptions.HTTPError as e:
142
158
  logger.debug(f"Could not list PI sources: {e}")
143
159
 
144
160
  if imstype == IMSType.PIWEBAPI:
@@ -175,7 +191,7 @@ class IMSClient:
175
191
  self,
176
192
  datasource: str,
177
193
  imstype: Optional[Union[str, IMSType]] = None,
178
- tz: Union[tzinfo, str] = pytz.timezone("Europe/Oslo"),
194
+ tz: Optional[Union[tzinfo, str]] = None,
179
195
  url: Optional[str] = None,
180
196
  handler_options: Dict[str, Union[int, float, str]] = {}, # noqa:
181
197
  verify_ssl: Optional[Union[bool, str]] = True,
@@ -191,11 +207,15 @@ class IMSClient:
191
207
  f" We suggest to use the tagreader.IMSType enumerator when initiating a client."
192
208
  )
193
209
 
210
+ if tz is None or tz == "":
211
+ tz = ZoneInfo("Europe/Oslo")
194
212
  if isinstance(tz, str):
195
- if tz in pytz.all_timezones:
196
- self.tz = pytz.timezone(tz)
197
- else:
198
- raise ValueError(f"Invalid timezone string Given type was {type(tz)}")
213
+ try:
214
+ self.tz = ZoneInfo(tz)
215
+ except ZoneInfoNotFoundError:
216
+ raise ValueError(
217
+ f"Invalid timezone string. Given tz was {tz}"
218
+ ) from None
199
219
  elif isinstance(tz, tzinfo):
200
220
  self.tz = tz
201
221
  else:
@@ -3,14 +3,14 @@ import hashlib
3
3
  import platform
4
4
  import socket
5
5
  import ssl
6
- from datetime import datetime, tzinfo
6
+ from datetime import datetime, timezone, tzinfo
7
7
  from enum import Enum
8
8
  from pathlib import Path
9
- from typing import Union
9
+ from typing import Optional, Union
10
+ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
10
11
 
11
12
  import certifi
12
13
  import pandas as pd
13
- import pytz
14
14
  import requests
15
15
  from platformdirs import user_data_dir
16
16
 
@@ -50,12 +50,24 @@ def convert_to_pydatetime(date_stamp: Union[datetime, str, pd.Timestamp]) -> dat
50
50
 
51
51
  def ensure_datetime_with_tz(
52
52
  date_stamp: Union[datetime, str, pd.Timestamp],
53
- tz: tzinfo = pytz.timezone("Europe/Oslo"),
53
+ tz: Optional[tzinfo] = None,
54
54
  ) -> datetime:
55
+ if tz is None:
56
+ try:
57
+ tz = ZoneInfo("Europe/Oslo")
58
+ except ZoneInfoNotFoundError:
59
+ logger.warning(
60
+ "Unable to load timezone 'Europe/Oslo'. Falling back to UTC."
61
+ )
62
+ tz = timezone.utc
55
63
  date_stamp = convert_to_pydatetime(date_stamp)
56
64
 
57
65
  if not date_stamp.tzinfo:
58
- date_stamp = tz.localize(date_stamp)
66
+ localize = getattr(tz, "localize", None)
67
+ if callable(localize):
68
+ date_stamp = localize(date_stamp)
69
+ else:
70
+ date_stamp = date_stamp.replace(tzinfo=tz)
59
71
 
60
72
  return date_stamp
61
73
 
@@ -3,14 +3,13 @@ import json
3
3
  import re
4
4
  import urllib.parse
5
5
  from abc import ABC, abstractmethod
6
- from datetime import datetime, timedelta
6
+ from datetime import datetime, timedelta, timezone
7
7
  from hashlib import new as hashlib_new_method
8
8
  from json.decoder import JSONDecodeError
9
9
  from typing import Any, Dict, List, Optional, Tuple, Union
10
10
 
11
11
  import numpy as np
12
12
  import pandas as pd
13
- import pytz
14
13
  import requests
15
14
  import urllib3
16
15
  from Crypto.Hash import MD4 as _MD4
@@ -115,6 +114,8 @@ def list_aspenone_sources(
115
114
  except JSONDecodeError as e:
116
115
  logger.error(f"Could not decode JSON response: {e}")
117
116
 
117
+ return []
118
+
118
119
 
119
120
  def list_piwebapi_sources(
120
121
  url: Optional[str] = None,
@@ -143,6 +144,8 @@ def list_piwebapi_sources(
143
144
  except JSONDecodeError as e:
144
145
  logger.error(f"Could not decode JSON response: {e}")
145
146
 
147
+ return []
148
+
146
149
 
147
150
  def get_piwebapi_source_to_webid_dict(
148
151
  url: Optional[str] = None,
@@ -170,6 +173,8 @@ def get_piwebapi_source_to_webid_dict(
170
173
  except JSONDecodeError as e:
171
174
  logger.error(f"Could not decode JSON response: {e}")
172
175
 
176
+ return []
177
+
173
178
 
174
179
  class BaseHandlerWeb(ABC):
175
180
  def __init__(
@@ -437,7 +442,7 @@ class AspenHandlerWeb(BaseHandlerWeb):
437
442
  return ret
438
443
 
439
444
  def _get_default_mapname(self, tagname: str):
440
- (tagname, _) = self.split_tagmap(tagname)
445
+ tagname, _ = self.split_tagmap(tagname)
441
446
  all_maps = self._get_maps(tagname)
442
447
  for k, v in all_maps.items():
443
448
  if v:
@@ -729,7 +734,7 @@ class PIHandlerWeb(BaseHandlerWeb):
729
734
 
730
735
  @staticmethod
731
736
  def _time_to_UTC_string(time: datetime) -> str:
732
- return time.astimezone(pytz.UTC).strftime("%d-%b-%y %H:%M:%S")
737
+ return time.astimezone(timezone.utc).strftime("%d-%b-%y %H:%M:%S")
733
738
 
734
739
  @staticmethod
735
740
  def escape(s: str) -> str:
@@ -994,7 +999,7 @@ class PIHandlerWeb(BaseHandlerWeb):
994
999
  if not web_id:
995
1000
  return pd.DataFrame()
996
1001
 
997
- (url, params) = self.generate_read_query(
1002
+ url, params = self.generate_read_query(
998
1003
  tag=web_id,
999
1004
  start=start,
1000
1005
  end=end,
File without changes
File without changes