dcicutils 8.8.3.1b12__py3-none-any.whl → 8.8.3.1b14__py3-none-any.whl
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.
- dcicutils/data_readers.py +11 -0
- dcicutils/datetime_utils.py +116 -1
- dcicutils/progress_bar.py +3 -1
- {dcicutils-8.8.3.1b12.dist-info → dcicutils-8.8.3.1b14.dist-info}/METADATA +1 -1
- {dcicutils-8.8.3.1b12.dist-info → dcicutils-8.8.3.1b14.dist-info}/RECORD +8 -8
- {dcicutils-8.8.3.1b12.dist-info → dcicutils-8.8.3.1b14.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.8.3.1b12.dist-info → dcicutils-8.8.3.1b14.dist-info}/WHEEL +0 -0
- {dcicutils-8.8.3.1b12.dist-info → dcicutils-8.8.3.1b14.dist-info}/entry_points.txt +0 -0
dcicutils/data_readers.py
CHANGED
@@ -66,6 +66,13 @@ class RowReader(abc.ABC):
|
|
66
66
|
else:
|
67
67
|
return value
|
68
68
|
|
69
|
+
@property
|
70
|
+
def nrows(self) -> int:
|
71
|
+
nrows = 0
|
72
|
+
for row in self:
|
73
|
+
nrows += 1
|
74
|
+
return nrows
|
75
|
+
|
69
76
|
def open(self) -> None:
|
70
77
|
pass
|
71
78
|
|
@@ -192,6 +199,10 @@ class Excel:
|
|
192
199
|
return True
|
193
200
|
return False
|
194
201
|
|
202
|
+
@property
|
203
|
+
def nsheets(self) -> int:
|
204
|
+
return len(self.sheet_names)
|
205
|
+
|
195
206
|
def __del__(self) -> None:
|
196
207
|
if (workbook := self._workbook) is not None:
|
197
208
|
self._workbook = None
|
dcicutils/datetime_utils.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from dcicutils.misc_utils import normalize_spaces
|
2
2
|
from datetime import datetime, timedelta, timezone
|
3
|
-
from
|
3
|
+
from dateutil import parser as datetime_parser
|
4
|
+
from typing import Optional, Tuple, Union
|
4
5
|
|
5
6
|
|
6
7
|
def parse_datetime_string(value: str) -> Optional[datetime]:
|
@@ -82,6 +83,32 @@ def normalize_date_string(value: str) -> Optional[str]:
|
|
82
83
|
return d.strftime("%Y-%m-%d") if d else None
|
83
84
|
|
84
85
|
|
86
|
+
def get_timezone(hours: int, minutes: Optional[int] = None) -> timezone:
|
87
|
+
try:
|
88
|
+
return timezone(timedelta(hours=hours, minutes=minutes or 0))
|
89
|
+
except Exception:
|
90
|
+
return timezone.utc
|
91
|
+
|
92
|
+
|
93
|
+
def get_timezone_hours_minutes(tz: timezone) -> Tuple[int, int]:
|
94
|
+
"""
|
95
|
+
Returns a tuple with the integer hours and minutes offset for the given timezone.
|
96
|
+
"""
|
97
|
+
tz_minutes = datetime.now(tz).utcoffset().total_seconds() / 60
|
98
|
+
return int(tz_minutes // 60), int(abs(tz_minutes % 60))
|
99
|
+
|
100
|
+
|
101
|
+
def get_utc_timezone() -> timezone:
|
102
|
+
return timezone.utc
|
103
|
+
|
104
|
+
|
105
|
+
def get_local_timezone() -> timezone:
|
106
|
+
"""
|
107
|
+
Returns current/local timezone as a datetime.timezone object.
|
108
|
+
"""
|
109
|
+
return datetime.now().astimezone().tzinfo
|
110
|
+
|
111
|
+
|
85
112
|
def get_local_timezone_string() -> str:
|
86
113
|
"""
|
87
114
|
Returns current/local timezone in format like: "-05:00".
|
@@ -96,3 +123,91 @@ def get_local_timezone_hours_minutes() -> Tuple[int, int]:
|
|
96
123
|
"""
|
97
124
|
tz_minutes = datetime.now(timezone.utc).astimezone().utcoffset().total_seconds() / 60
|
98
125
|
return int(tz_minutes // 60), int(abs(tz_minutes % 60))
|
126
|
+
|
127
|
+
|
128
|
+
def parse_datetime(value: str, utc: bool = False, tz: Optional[timezone] = None) -> Optional[datetime]:
|
129
|
+
"""
|
130
|
+
Parses the given string into a datetime, if possible, and returns that value,
|
131
|
+
or None if not able to parse. The timezone of the returned datetime will be the
|
132
|
+
local timezone; or if the given utc argument is True then it will be UTC; or if the
|
133
|
+
given tz argument is a datetime.timezone then return datetime will be in that timezone.
|
134
|
+
"""
|
135
|
+
if isinstance(value, datetime):
|
136
|
+
return value
|
137
|
+
elif not isinstance(value, str):
|
138
|
+
return None
|
139
|
+
try:
|
140
|
+
# This dateutil.parser handles quite a wide variety of formats and suits our needs.
|
141
|
+
value = datetime_parser.parse(value)
|
142
|
+
if utc is True:
|
143
|
+
# If the given utc argument is True then it trumps any tz argument if given.
|
144
|
+
tz = timezone.utc
|
145
|
+
if value.tzinfo is not None:
|
146
|
+
# The given value had an explicit timezone specified.
|
147
|
+
if isinstance(tz, timezone):
|
148
|
+
return value.astimezone(tz)
|
149
|
+
return value
|
150
|
+
return value.replace(tzinfo=tz if isinstance(tz, timezone) else get_local_timezone())
|
151
|
+
except Exception:
|
152
|
+
return None
|
153
|
+
|
154
|
+
|
155
|
+
def format_datetime(value: datetime,
|
156
|
+
utc: bool = False,
|
157
|
+
iso: bool = False,
|
158
|
+
ms: bool = False,
|
159
|
+
tz: Optional[Union[timezone, bool]] = None,
|
160
|
+
notz: bool = False,
|
161
|
+
noseconds: bool = False,
|
162
|
+
verbose: bool = False,
|
163
|
+
noseparator: bool = False,
|
164
|
+
noday: bool = False) -> Optional[str]:
|
165
|
+
"""
|
166
|
+
Returns the given datetime as a string in "YYYY:MM:DD hh:mm:ss tz" format, for
|
167
|
+
example "2024-04-17 15:42:26 EDT". If the given notz argument is True then omits
|
168
|
+
the timezone; if the noseconds argument is given the omits the seconds. If the given
|
169
|
+
verbose argument is True then returns a really verbose version of the datetime, for
|
170
|
+
example "Wednesday, April 17, 2024 | 15:42:26 EDT"; if the noseparator argument is
|
171
|
+
True then omits the "|" separator; if the noday argument is True then omits the day
|
172
|
+
of week part. The timezone of the returned datetime string will default to the local
|
173
|
+
one; if the given utc argument is True then it will be UTC; or if the given tz
|
174
|
+
argument is a datetime.timezone it will be in that timezone.
|
175
|
+
"""
|
176
|
+
if not isinstance(value, datetime):
|
177
|
+
if not isinstance(value, str) or not (value := parse_datetime(value)):
|
178
|
+
return None
|
179
|
+
try:
|
180
|
+
if utc is True:
|
181
|
+
tz = timezone.utc
|
182
|
+
elif not isinstance(tz, timezone):
|
183
|
+
tz = get_local_timezone()
|
184
|
+
if tz is True:
|
185
|
+
notz = False
|
186
|
+
elif tz is False:
|
187
|
+
notz = True
|
188
|
+
if noseconds is True:
|
189
|
+
ms = False
|
190
|
+
value = value.astimezone(tz)
|
191
|
+
if iso:
|
192
|
+
if notz is True:
|
193
|
+
value = value.replace(tzinfo=None)
|
194
|
+
if not (ms is True):
|
195
|
+
value = value.replace(microsecond=0)
|
196
|
+
if noseconds is True:
|
197
|
+
if notz is True:
|
198
|
+
return value.strftime(f"%Y-%m-%dT%H:%M")
|
199
|
+
tz = value.strftime("%z")
|
200
|
+
tz = tz[:3] + ":" + tz[3:]
|
201
|
+
return value.strftime(f"%Y-%m-%dT%H:%M") + tz
|
202
|
+
return value.isoformat()
|
203
|
+
if verbose:
|
204
|
+
return value.strftime(
|
205
|
+
f"{'' if noday is True else '%A, '}%B %-d, %Y{'' if noseparator is True else ' |'}"
|
206
|
+
f" %-I:%M{'' if noseconds is True else ':%S'}"
|
207
|
+
f"{f'.%f' if ms is True else ''} %p{'' if notz is True else ' %Z'}")
|
208
|
+
else:
|
209
|
+
return value.strftime(
|
210
|
+
f"%Y-%m-%d %H:%M{'' if noseconds is True else ':%S'}"
|
211
|
+
f"{f'.%f' if ms is True else ''}{'' if notz is True else ' %Z'}")
|
212
|
+
except Exception:
|
213
|
+
return None
|
dcicutils/progress_bar.py
CHANGED
@@ -50,6 +50,7 @@ class ProgressBar:
|
|
50
50
|
def __init__(self, total: Optional[int] = None,
|
51
51
|
description: Optional[str] = None,
|
52
52
|
use_byte_size_for_rate: bool = False,
|
53
|
+
use_ascii: bool = False,
|
53
54
|
catch_interrupt: bool = True,
|
54
55
|
interrupt: Optional[Callable] = None,
|
55
56
|
interrupt_continue: Optional[Callable] = None,
|
@@ -66,6 +67,7 @@ class ProgressBar:
|
|
66
67
|
self._tidy_output_hack = (tidy_output_hack is True)
|
67
68
|
self._stop_requested = False
|
68
69
|
self._use_byte_size_for_rate = (use_byte_size_for_rate is True and self._tidy_output_hack)
|
70
|
+
self._use_ascii = (use_ascii is True)
|
69
71
|
# Interrupt handling. We do not do the actual (signal) interrupt setup
|
70
72
|
# in self._initialize as that could be called from a (sub) thread; and in
|
71
73
|
# Python we can only set a signal (SIGINT in our case) on the main thread.
|
@@ -103,7 +105,7 @@ class ProgressBar:
|
|
103
105
|
else:
|
104
106
|
bar_format = "{l_bar}{bar}| {n_fmt}/{total_fmt} | {rate_fmt} | {elapsed}{postfix} | ETA: {remaining} "
|
105
107
|
self._bar = TQDM(total=self._total, desc=self._description,
|
106
|
-
dynamic_ncols=True, bar_format=bar_format, unit="", file=sys.stdout)
|
108
|
+
dynamic_ncols=True, bar_format=bar_format, unit="", file=sys.stdout, ascii=self._use_ascii)
|
107
109
|
self._started = time.time()
|
108
110
|
if self._disabled:
|
109
111
|
self._bar.disable = True
|
@@ -10,9 +10,9 @@ dcicutils/common.py,sha256=YE8Mt5-vaZWWz4uaChSVhqGFbFtW5QKtnIyOr4zG4vM,3955
|
|
10
10
|
dcicutils/contribution_scripts.py,sha256=0k5Gw1TumcD5SAcXVkDd6-yvuMEw-jUp5Kfb7FJH6XQ,2015
|
11
11
|
dcicutils/contribution_utils.py,sha256=vYLS1JUB3sKd24BUxZ29qUBqYeQBLK9cwo8x3k64uPg,25653
|
12
12
|
dcicutils/creds_utils.py,sha256=xrLekD49Ex0GOpL9n7LlJA4gvNcY7txTVFOSYD7LvEU,11113
|
13
|
-
dcicutils/data_readers.py,sha256=
|
13
|
+
dcicutils/data_readers.py,sha256=6EMrY7TjDE8H7bA_TCWtpLQP7slJ0YTL77_dNh6e7sg,7626
|
14
14
|
dcicutils/data_utils.py,sha256=k2OxOlsx7AJ6jF-YNlMyGus_JqSUBe4_n1s65Mv1gQQ,3098
|
15
|
-
dcicutils/datetime_utils.py,sha256=
|
15
|
+
dcicutils/datetime_utils.py,sha256=S3SCmpqv_Z0CS8_yqZsoN4aL1Epu8jwKs6DDYs96OdM,9427
|
16
16
|
dcicutils/deployment_utils.py,sha256=sKv8Jb-_Zw2aH3OAywRlsre-Cqm3a7fEGG3_1PT-r-s,69908
|
17
17
|
dcicutils/diff_utils.py,sha256=sQx-yz56DHAcQWOChYbAG3clXu7TbiZKlw-GggeveO0,8118
|
18
18
|
dcicutils/docker_utils.py,sha256=30gUiqz7X9rJwSPXTPn4ewjQibUgoSJqhP9o9vn5X-A,1747
|
@@ -48,7 +48,7 @@ dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmj
|
|
48
48
|
dcicutils/opensearch_utils.py,sha256=V2exmFYW8Xl2_pGFixF4I2Cc549Opwe4PhFi5twC0M8,1017
|
49
49
|
dcicutils/portal_object_utils.py,sha256=gDXRgPsRvqCFwbC8WatsuflAxNiigOnqr0Hi93k3AgE,15422
|
50
50
|
dcicutils/portal_utils.py,sha256=DYyE5o15GekDgzpJWas9iS7klAYbjJZUPW0G42McArk,30779
|
51
|
-
dcicutils/progress_bar.py,sha256=
|
51
|
+
dcicutils/progress_bar.py,sha256=th-M7Q1UfkmQWc8M36lfVoRhFAQVRT9fSpdHi5RHqNY,17389
|
52
52
|
dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
|
53
53
|
dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
|
54
54
|
dcicutils/qa_utils.py,sha256=TT0SiJWiuxYvbsIyhK9VO4uV_suxhB6CpuC4qPacCzQ,160208
|
@@ -72,8 +72,8 @@ dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
|
|
72
72
|
dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
|
73
73
|
dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
|
74
74
|
dcicutils/zip_utils.py,sha256=rnjNv_k6L9jT2SjDSgVXp4BEJYLtz9XN6Cl2Fy-tqnM,2027
|
75
|
-
dcicutils-8.8.3.
|
76
|
-
dcicutils-8.8.3.
|
77
|
-
dcicutils-8.8.3.
|
78
|
-
dcicutils-8.8.3.
|
79
|
-
dcicutils-8.8.3.
|
75
|
+
dcicutils-8.8.3.1b14.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
76
|
+
dcicutils-8.8.3.1b14.dist-info/METADATA,sha256=Od4jg67J1tt_7cxv1n04p8PGmpjbnlfi9-EKsMS-GKk,3357
|
77
|
+
dcicutils-8.8.3.1b14.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
78
|
+
dcicutils-8.8.3.1b14.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
79
|
+
dcicutils-8.8.3.1b14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|