everysk-lib 1.10.2__cp312-cp312-win_amd64.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.
Files changed (137) hide show
  1. everysk/__init__.py +30 -0
  2. everysk/_version.py +683 -0
  3. everysk/api/__init__.py +61 -0
  4. everysk/api/api_requestor.py +167 -0
  5. everysk/api/api_resources/__init__.py +23 -0
  6. everysk/api/api_resources/api_resource.py +371 -0
  7. everysk/api/api_resources/calculation.py +779 -0
  8. everysk/api/api_resources/custom_index.py +42 -0
  9. everysk/api/api_resources/datastore.py +81 -0
  10. everysk/api/api_resources/file.py +42 -0
  11. everysk/api/api_resources/market_data.py +223 -0
  12. everysk/api/api_resources/parser.py +66 -0
  13. everysk/api/api_resources/portfolio.py +43 -0
  14. everysk/api/api_resources/private_security.py +42 -0
  15. everysk/api/api_resources/report.py +65 -0
  16. everysk/api/api_resources/report_template.py +39 -0
  17. everysk/api/api_resources/tests.py +115 -0
  18. everysk/api/api_resources/worker_execution.py +64 -0
  19. everysk/api/api_resources/workflow.py +65 -0
  20. everysk/api/api_resources/workflow_execution.py +93 -0
  21. everysk/api/api_resources/workspace.py +42 -0
  22. everysk/api/http_client.py +63 -0
  23. everysk/api/tests.py +32 -0
  24. everysk/api/utils.py +262 -0
  25. everysk/config.py +451 -0
  26. everysk/core/_tests/serialize/test_json.py +336 -0
  27. everysk/core/_tests/serialize/test_orjson.py +295 -0
  28. everysk/core/_tests/serialize/test_pickle.py +48 -0
  29. everysk/core/cloud_function/main.py +78 -0
  30. everysk/core/cloud_function/tests.py +86 -0
  31. everysk/core/compress.py +245 -0
  32. everysk/core/datetime/__init__.py +12 -0
  33. everysk/core/datetime/calendar.py +144 -0
  34. everysk/core/datetime/date.py +424 -0
  35. everysk/core/datetime/date_expression.py +299 -0
  36. everysk/core/datetime/date_mixin.py +1475 -0
  37. everysk/core/datetime/date_settings.py +30 -0
  38. everysk/core/datetime/datetime.py +713 -0
  39. everysk/core/exceptions.py +435 -0
  40. everysk/core/fields.py +1176 -0
  41. everysk/core/firestore.py +555 -0
  42. everysk/core/fixtures/_settings.py +29 -0
  43. everysk/core/fixtures/other/_settings.py +18 -0
  44. everysk/core/fixtures/user_agents.json +88 -0
  45. everysk/core/http.py +691 -0
  46. everysk/core/lists.py +92 -0
  47. everysk/core/log.py +709 -0
  48. everysk/core/number.py +37 -0
  49. everysk/core/object.py +1469 -0
  50. everysk/core/redis.py +1021 -0
  51. everysk/core/retry.py +51 -0
  52. everysk/core/serialize.py +674 -0
  53. everysk/core/sftp.py +414 -0
  54. everysk/core/signing.py +53 -0
  55. everysk/core/slack.py +127 -0
  56. everysk/core/string.py +199 -0
  57. everysk/core/tests.py +240 -0
  58. everysk/core/threads.py +199 -0
  59. everysk/core/undefined.py +70 -0
  60. everysk/core/unittests.py +73 -0
  61. everysk/core/workers.py +241 -0
  62. everysk/sdk/__init__.py +23 -0
  63. everysk/sdk/base.py +98 -0
  64. everysk/sdk/brutils/cnpj.py +391 -0
  65. everysk/sdk/brutils/cnpj_pd.py +129 -0
  66. everysk/sdk/engines/__init__.py +26 -0
  67. everysk/sdk/engines/cache.py +185 -0
  68. everysk/sdk/engines/compliance.py +37 -0
  69. everysk/sdk/engines/cryptography.py +69 -0
  70. everysk/sdk/engines/expression.cp312-win_amd64.pyd +0 -0
  71. everysk/sdk/engines/expression.pyi +55 -0
  72. everysk/sdk/engines/helpers.cp312-win_amd64.pyd +0 -0
  73. everysk/sdk/engines/helpers.pyi +26 -0
  74. everysk/sdk/engines/lock.py +120 -0
  75. everysk/sdk/engines/market_data.py +244 -0
  76. everysk/sdk/engines/settings.py +19 -0
  77. everysk/sdk/entities/__init__.py +23 -0
  78. everysk/sdk/entities/base.py +784 -0
  79. everysk/sdk/entities/base_list.py +131 -0
  80. everysk/sdk/entities/custom_index/base.py +209 -0
  81. everysk/sdk/entities/custom_index/settings.py +29 -0
  82. everysk/sdk/entities/datastore/base.py +160 -0
  83. everysk/sdk/entities/datastore/settings.py +17 -0
  84. everysk/sdk/entities/fields.py +375 -0
  85. everysk/sdk/entities/file/base.py +215 -0
  86. everysk/sdk/entities/file/settings.py +63 -0
  87. everysk/sdk/entities/portfolio/base.py +248 -0
  88. everysk/sdk/entities/portfolio/securities.py +241 -0
  89. everysk/sdk/entities/portfolio/security.py +580 -0
  90. everysk/sdk/entities/portfolio/settings.py +97 -0
  91. everysk/sdk/entities/private_security/base.py +226 -0
  92. everysk/sdk/entities/private_security/settings.py +17 -0
  93. everysk/sdk/entities/query.py +603 -0
  94. everysk/sdk/entities/report/base.py +214 -0
  95. everysk/sdk/entities/report/settings.py +23 -0
  96. everysk/sdk/entities/script.py +310 -0
  97. everysk/sdk/entities/secrets/base.py +128 -0
  98. everysk/sdk/entities/secrets/script.py +119 -0
  99. everysk/sdk/entities/secrets/settings.py +17 -0
  100. everysk/sdk/entities/settings.py +48 -0
  101. everysk/sdk/entities/tags.py +174 -0
  102. everysk/sdk/entities/worker_execution/base.py +307 -0
  103. everysk/sdk/entities/worker_execution/settings.py +63 -0
  104. everysk/sdk/entities/workflow_execution/base.py +113 -0
  105. everysk/sdk/entities/workflow_execution/settings.py +32 -0
  106. everysk/sdk/entities/workspace/base.py +99 -0
  107. everysk/sdk/entities/workspace/settings.py +27 -0
  108. everysk/sdk/settings.py +67 -0
  109. everysk/sdk/tests.py +105 -0
  110. everysk/sdk/worker_base.py +47 -0
  111. everysk/server/__init__.py +9 -0
  112. everysk/server/applications.py +63 -0
  113. everysk/server/endpoints.py +516 -0
  114. everysk/server/example_api.py +69 -0
  115. everysk/server/middlewares.py +80 -0
  116. everysk/server/requests.py +62 -0
  117. everysk/server/responses.py +119 -0
  118. everysk/server/routing.py +64 -0
  119. everysk/server/settings.py +36 -0
  120. everysk/server/tests.py +36 -0
  121. everysk/settings.py +98 -0
  122. everysk/sql/__init__.py +9 -0
  123. everysk/sql/connection.py +232 -0
  124. everysk/sql/model.py +376 -0
  125. everysk/sql/query.py +417 -0
  126. everysk/sql/row_factory.py +63 -0
  127. everysk/sql/settings.py +49 -0
  128. everysk/sql/utils.py +129 -0
  129. everysk/tests.py +23 -0
  130. everysk/utils.py +81 -0
  131. everysk/version.py +15 -0
  132. everysk_lib-1.10.2.dist-info/.gitignore +5 -0
  133. everysk_lib-1.10.2.dist-info/METADATA +326 -0
  134. everysk_lib-1.10.2.dist-info/RECORD +137 -0
  135. everysk_lib-1.10.2.dist-info/WHEEL +5 -0
  136. everysk_lib-1.10.2.dist-info/licenses/LICENSE.txt +9 -0
  137. everysk_lib-1.10.2.dist-info/top_level.txt +2 -0
@@ -0,0 +1,713 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2023 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ from datetime import datetime, timezone # pylint: disable=import-self
11
+ from typing import Any, Self
12
+ from zoneinfo import ZoneInfo
13
+
14
+ from everysk.core.datetime import date_settings
15
+ from everysk.core.datetime.date_mixin import DateMixin
16
+
17
+
18
+ class DateTime(DateMixin, datetime): # pylint: disable=inherit-non-class
19
+ def __new__(
20
+ cls,
21
+ year: int,
22
+ month: int = None,
23
+ day: int = None,
24
+ hour: int = 0,
25
+ minute: int = 0,
26
+ second: int = 0,
27
+ microsecond: int = 0,
28
+ tzinfo: ZoneInfo = None,
29
+ fold: int = 0,
30
+ ) -> Self:
31
+ """
32
+ Create a new DateTime object.
33
+
34
+ Args:
35
+ year (int): The year.
36
+ month (int, optional): The month. Defaults to None.
37
+ day (int, optional): The day. Defaults to None.
38
+ hour (int, optional): The hour. Defaults to 0.
39
+ minute (int, optional): The minute. Defaults to 0.
40
+ second (int, optional): The second. Defaults to 0.
41
+ microsecond (int, optional): The microsecond. Defaults to 0.
42
+ tzinfo (ZoneInfo, optional): The time zone information. Defaults to None (UTC).
43
+ fold (int, optional): Fold value (0 or 1). Defaults to 0.
44
+
45
+ Raises:
46
+ ValueError: If the input values are not valid for creating a DateTime object.
47
+
48
+ Returns:
49
+ DateTime: A new DateTime object.
50
+
51
+ Example:
52
+ Create a DateTime object:
53
+ >>> DateTime(2023, 9, 15, tzinfo=ZoneInfo('US/Eastern'))
54
+ DateTime(2023, 9, 15, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='US/Eastern'))
55
+
56
+ See Also:
57
+ [Python Documentation](https://docs.python.org/3/library/datetime.html#datetime.datetime.fold)
58
+ """
59
+ # We check for tzinfo to enforce the UTC if it is not provided
60
+ # This is useful for all methods that do not provide tzinfo except replace - see below
61
+ if tzinfo is None:
62
+ tzinfo = ZoneInfo('UTC')
63
+
64
+ # https://everysk.atlassian.net/browse/COD-13539
65
+ # None is a valid tzinfo used to remove it, only use the replace method so we exchange it for Undefined.
66
+ # See replace method at the bottom of this file.
67
+ if tzinfo is Undefined:
68
+ tzinfo = None
69
+
70
+ args = (year, month, day, hour, minute, second, microsecond)
71
+ kwargs = {'tzinfo': tzinfo, 'fold': fold}
72
+ # To keep the pickle support we need to check the year param
73
+ # and we must keep month and day optional on the class initialization.
74
+ if isinstance(year, (bytes, str)):
75
+ # When we not provide the tzinfo, month will be empty
76
+ if not month:
77
+ month = tzinfo
78
+ args = (year, month)
79
+ kwargs = {}
80
+
81
+ return super().__new__(cls, *args, **kwargs)
82
+
83
+ @classmethod
84
+ def ensure(cls, value: 'DateTime') -> Self:
85
+ """
86
+ Ensure that the provided value is an instance of DateTime.
87
+
88
+ Args:
89
+ value (DateTime): The value to ensure as a DateTime object.
90
+
91
+ Raises:
92
+ ValueError: If the provided value cannot be converted to a DateTime object.
93
+
94
+ Returns:
95
+ DateTime: A DateTime object.
96
+
97
+ Example:
98
+ Ensure a value is a DateTime object:
99
+ >>> DateTime.ensure(datetime(2023, 9, 15))
100
+ DateTime(2023, 9, 15, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
101
+ >>> DateTime.ensure(DateTime(2023, 9, 15))
102
+ DateTime(2023, 9, 15, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
103
+ >>> DateTime.ensure(DatetimeWithNanoseconds(2023, 9, 15))
104
+ DateTime(2023, 9, 15, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
105
+ """
106
+ try:
107
+ value = cls(
108
+ value.year,
109
+ value.month,
110
+ value.day,
111
+ value.hour,
112
+ value.minute,
113
+ value.second,
114
+ value.microsecond,
115
+ value.tzinfo,
116
+ )
117
+ except AttributeError as error:
118
+ raise ValueError(
119
+ f"Invalid instantiation of class '{cls.__name__}' from '{value.__class__.__name__}'"
120
+ ) from error
121
+
122
+ return value
123
+
124
+ @classmethod
125
+ def fromtimestamp(cls, timestamp: float, tz: ZoneInfo = None) -> Self:
126
+ """
127
+ Create a DateTime object from a timestamp number.
128
+
129
+ Args:
130
+ timestamp (float): A number representing a DateTime object in float format.
131
+ tz (ZoneInfo, optional): The time zone information. Defaults to None (UTC).
132
+
133
+ Raises:
134
+ ValueError: If the timestamp is not a valid number.
135
+
136
+ Returns:
137
+ DateTime: A DateTime object created from the timestamp.
138
+
139
+ Example:
140
+ Create a DateTime object from a timestamp:
141
+ >>> DateTime.fromtimestamp(1631702400.0, ZoneInfo('US/Eastern'))
142
+ DateTime(2021, 9, 15, 6, 40, tzinfo=zoneinfo.ZoneInfo(key='US/Eastern'))
143
+ """
144
+ if tz is None:
145
+ tz = ZoneInfo('UTC')
146
+ return super().fromtimestamp(timestamp, tz)
147
+
148
+ # OLD date_time_adjust_time_zone
149
+ def adjust_time_zone(self, time_zone: str = date_settings.DEFAULT_TIME_ZONE) -> Self:
150
+ """
151
+ Adjust the time zone of a DateTime object by replacing its timezone information.
152
+
153
+ Args:
154
+ time_zone (str, optional): The time zone string to set for the date and time object.
155
+ Should be a valid time zone string recognized by `zoneinfo.ZoneInfo`.
156
+ Defaults to the value of `date_settings.DEFAULT_TIME_ZONE`.
157
+
158
+ Raises:
159
+ ValueError: If the provided `time_zone` string is not a valid time zone.
160
+
161
+ Returns:
162
+ DateTime: A new DateTime object with the replaced timezone information.
163
+
164
+ Example:
165
+ To adjust the time zone of a DateTime object:
166
+ >>> date_time_obj = DateTime(2023, 7, 31, 12, 34, 56)
167
+ >>> date_time_obj.adjust_time_zone(time_zone='America/New_York')
168
+ DateTime(2023, 7, 31, 12, 34, 56, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))
169
+ """
170
+ tz = ZoneInfo(time_zone)
171
+ return self.replace(tzinfo=tz)
172
+
173
+ def astimezone(self, tz: str = date_settings.DEFAULT_TIME_ZONE) -> Self:
174
+ """
175
+ Adjust the time zone of a DateTime object using the underlying superclass method.
176
+
177
+ Args:
178
+ tz (str, optional): The time zone string to use for adjusting the date and time.
179
+ Should be a valid time zone string recognized by `zoneinfo.ZoneInfo`.
180
+ Defaults to the value of `date_settings.DEFAULT_TIME_ZONE`.
181
+
182
+ Returns:
183
+ DateTime: A new DateTime object representing the adjusted date and time in the specified time zone.
184
+
185
+ Example:
186
+ >>> date_time_obj = DateTime(2023, 7, 31, 12, 34, 56)
187
+ >>> date_time_obj.astimezone(tz='America/New_York')
188
+ DateTime(2023, 7, 31, 8, 34, 56, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))
189
+ """
190
+ if isinstance(tz, str):
191
+ tz = ZoneInfo(tz)
192
+ return super().astimezone(tz)
193
+
194
+ @classmethod
195
+ def now(cls, tzinfo: timezone = None) -> Self:
196
+ """
197
+ Get the current DateTime object for a specified time zone.
198
+
199
+ Args:
200
+ tzinfo (timezone, str, optional): The time zone information.
201
+ - If not provided, it defaults to 'UTC'.
202
+ - If a string is provided, it's used to create a `zoneinfo.ZoneInfo` object.
203
+
204
+ Raises:
205
+ ValueError: If the provided `tzinfo` is not a valid time zone.
206
+
207
+ Returns:
208
+ DateTime: A DateTime object representing the current date and time in the specified time zone.
209
+
210
+ Example:
211
+ Get the current DateTime object in a specific time zone:
212
+ >>> DateTime.now(tzinfo='America/New_York')
213
+ DateTime(2023, 9, 15, 10, 30, 0, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))
214
+ """
215
+ if tzinfo is None:
216
+ tzinfo = ZoneInfo('UTC')
217
+ elif isinstance(tzinfo, str):
218
+ tzinfo = ZoneInfo(tzinfo)
219
+ return super().now(tzinfo)
220
+
221
+ @classmethod
222
+ def fromisoformat(cls, date_string: str) -> Self:
223
+ """
224
+ Convert ISO formatted date and datetime strings to a `DateTime` object.
225
+
226
+ Args:
227
+ date_string (str):
228
+ The ISO formatted date or datetime string to convert to a `DateTime` object.
229
+
230
+ Raises:
231
+ ValueError: If the input date_string is not in a valid ISO format.
232
+
233
+ Returns:
234
+ DateTime: A `DateTime` object representing the date and time extracted from the input ISO formatted string.
235
+
236
+ Examples:
237
+ Convert ISO formatted date or datetime strings to `DateTime` objects:
238
+ >>> DateTime.fromisoformat('20230101')
239
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
240
+
241
+ >>> DateTime.fromisoformat('2023-01-01')
242
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
243
+
244
+ >>> DateTime.fromisoformat('2023-01-01T00:00:00')
245
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
246
+
247
+ >>> DateTime.fromisoformat('20230101 00:00:00')
248
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
249
+
250
+ >>> DateTime.fromisoformat('2023-01-01T00:00:00+00:00')
251
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
252
+
253
+ >>> DateTime.fromisoformat('2023-01-01 00:00:00+00:00')
254
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
255
+
256
+ >>> DateTime.fromisoformat('2023-01-01T00:00:00.000000Z')
257
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
258
+
259
+ >>> DateTime.fromisoformat('2023-01-01 00:00:00.000000Z')
260
+ DateTime(2023, 1, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
261
+ """
262
+ if date_string:
263
+ # This Z format is not native, we need to implement.
264
+ if date_string[-1] == 'Z':
265
+ # 2023-08-08T21:29:54.5713046Z -> This is from Refinitiv
266
+ if '.' in date_string:
267
+ # We need to get all numbers after the '.'
268
+ milliseconds = date_string[date_string.index('.') + 1 : -1]
269
+
270
+ # Then we need to transform to be 6 length exact
271
+ # rjust will put 0 to the right until reach 6 in size
272
+ correct_milliseconds = milliseconds.rjust(6, '0')[:6]
273
+
274
+ # Then we generate the correct new __date_string
275
+ date_string = date_string.replace(milliseconds, correct_milliseconds)
276
+
277
+ # Z is used to represent UTC
278
+ date_string = date_string.replace('Z', '+00:00')
279
+ elif len(date_string) == 8:
280
+ return cls.strptime(date_string, '%Y%m%d')
281
+ elif len(date_string) == 10:
282
+ return cls.strptime(date_string, '%Y-%m-%d')
283
+ elif len(date_string) == 17 and ' ' in date_string:
284
+ return cls.strptime(date_string)
285
+
286
+ return super().fromisoformat(date_string).astimezone('UTC')
287
+
288
+ # OLD date_time_to_timestamp
289
+ def timestamp(self) -> int:
290
+ """
291
+ Get the timestamp of the DateTime object.
292
+
293
+ Returns:
294
+ int: The timestamp as an integer representing the number of seconds since the Unix epoch.
295
+
296
+ Example:
297
+ Get the timestamp of a DateTime object:
298
+ >>> dt = DateTime(2023, 9, 15, 12, 0)
299
+ >>> dt.timestamp()
300
+ 1694779200
301
+ """
302
+ return int(super().timestamp())
303
+
304
+ def force_time(self, force_time: str = date_settings.DEFAULT_FORCE_TIME) -> Self:
305
+ """
306
+ Force a specific time on the DateTime object.
307
+
308
+ This method allows you to force a specific time on the DateTime object based on the provided `force_time` parameter.
309
+
310
+ Args:
311
+ force_time (str, optional): The time to be forced on the DateTime object.
312
+ - 'MIDDAY': Sets the time to 12:00:00.
313
+ - 'NOW': Sets the time to the current time.
314
+ - 'FIRST_MINUTE': Sets the time to 00:00:00.
315
+ - 'LAST_MINUTE': Sets the time to 23:59:59.
316
+ - Defaults to 'MIDDAY'.
317
+
318
+ Raises:
319
+ ValueError: If an invalid `force_time` is provided.
320
+
321
+ Returns:
322
+ DateTime: A new DateTime object with the forced time.
323
+
324
+ Example:
325
+ Force a specific time on a DateTime object:
326
+ >>> dt = DateTime(2023, 9, 15, 0, 0)
327
+ >>> dt.force_time('MIDDAY')
328
+ DateTime(2023, 9, 15, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
329
+ """
330
+ hour, minute, second, microsecond = None, None, None, None
331
+
332
+ if force_time == 'MIDDAY':
333
+ hour, minute, second, microsecond = 12, 0, 0, 0
334
+ elif force_time == 'NOW':
335
+ dt_now = super().utcnow()
336
+ hour, minute, second, microsecond = dt_now.hour, dt_now.minute, dt_now.second, dt_now.microsecond
337
+ elif force_time == 'FIRST_MINUTE':
338
+ hour, minute, second, microsecond = 0, 0, 0, 0
339
+ elif force_time == 'LAST_MINUTE':
340
+ hour, minute, second, microsecond = 23, 59, 59, 999999
341
+ else:
342
+ raise ValueError(
343
+ 'Invalid force_time. Please choose one of the following: NOW, MIDDAY, FIRST_MINUTE, LAST_MINUTE.'
344
+ )
345
+
346
+ return self.replace(hour=hour, minute=minute, second=second, microsecond=microsecond)
347
+
348
+ # OLD string_to_date_time
349
+ @classmethod
350
+ def strptime(cls, date_string: str, format: str = date_settings.DEFAULT_DATE_TIME_FORMAT) -> Self: # pylint: disable=redefined-builtin
351
+ """
352
+ Parse a string representing a date and time into a DateTime object.
353
+
354
+ This class method parses a string `date_string` representing a date and time according to the provided
355
+ format string `format` and returns a DateTime object.
356
+
357
+ Args:
358
+ date_string (str): The input date and time string to parse.
359
+ format (str, optional): The format string specifying the expected format of `date_string`.
360
+ - Defaults to the format '%Y%m%d %H:%M:%S'.
361
+
362
+ Raises:
363
+ ValueError: If the input `date_string` does not match the provided `format` format.
364
+
365
+ Returns:
366
+ DateTime: A DateTime object representing the parsed date and time.
367
+
368
+ Example:
369
+ Parse a date and time string into a DateTime object:
370
+ >>> date_string = '2023-09-15 12:00:00'
371
+ >>> DateTime.strptime(date_string, format='%Y-%m-%d %H:%M:%S')
372
+ DateTime(2023, 9, 15, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
373
+ """
374
+ return super().strptime(date_string, format)
375
+
376
+ @classmethod
377
+ def strptime_or_null(cls, date_string: str, format: str = date_settings.DEFAULT_DATE_TIME_FORMAT) -> Self | None: # pylint: disable=redefined-builtin
378
+ """
379
+ Parse a string representing a date and time into a DateTime object, or return None if parsing fails.
380
+
381
+ This class method attempts to parse a string `date_string` representing a date and time according to
382
+ the provided format string `format` and returns a DateTime object. If parsing fails, it returns None.
383
+
384
+ Args:
385
+ date_string (str): The input date and time string to parse.
386
+ format (str, optional): The format string specifying the expected format of `date_string`.
387
+ - Defaults to the format specified in `date_settings.DEFAULT_DATE_TIME_FORMAT`.
388
+
389
+ Returns:
390
+ DateTime or None: A DateTime object representing the parsed date and time, or None if parsing fails.
391
+
392
+ Example:
393
+ Parse a date and time string into a DateTime object or return None if parsing fails:
394
+ >>> date_string = '2023-09-15 12:00:00'
395
+ >>> DateTime.strptime_or_null(date_string, format='%Y-%m-%d %H:%M:%S')
396
+ DateTime(2023, 9, 15, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
397
+
398
+ >>> invalid_date_string = '2023-09-15T12:00:00Z'
399
+ >>> DateTime.strptime_or_null(invalid_date_string)
400
+ None
401
+ """
402
+ date_time = None
403
+
404
+ try:
405
+ date_time = cls.strptime(date_string, format=format)
406
+ except Exception: # pylint: disable=broad-exception-caught
407
+ pass
408
+
409
+ return date_time
410
+
411
+ # OLD string_date_to_date_time
412
+ @classmethod
413
+ def string_date_to_date_time(cls, date_string: str, force_time: str = date_settings.DEFAULT_FORCE_TIME) -> Self:
414
+ """
415
+ Convert a string date to a DateTime object with a specified time.
416
+
417
+ This class method converts a given string date to a DateTime object
418
+ by combining the provided date string with a specified time. The `force_time`
419
+ parameter allows you to set the time component of the resulting datetime object.
420
+ If no `force_time` is provided, the default time is used.
421
+
422
+ Args:
423
+ date_string (str): A string representing a date.
424
+ force_time (str, optional): A string indicating the desired time for the datetime object.
425
+ Valid values are 'MIDDAY', 'NOW', 'FIRST_MINUTE', 'LAST_MINUTE', or a custom time in the format 'HH:MM:SS'. Defaults to 'MIDDAY'.
426
+
427
+ Raises:
428
+ ValueError: If an invalid `force_time` value is provided.
429
+
430
+ Returns:
431
+ DateTime: A DateTime object representing the combination of the input string date and the specified or default time.
432
+
433
+ Example:
434
+ Convert a string date to a datetime object with a specified time:
435
+ >>> DateTime.string_date_to_date_time('20230815', force_time='MIDDAY')
436
+ DateTime(2023, 8, 15, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
437
+
438
+ >>> DateTime.string_date_to_date_time('20230815', force_time='FIRST_MINUTE')
439
+ DateTime(2023, 8, 15, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
440
+
441
+ >>> DateTime.string_date_to_date_time('20230815')
442
+ DateTime(2023, 8, 15, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC')) # Assuming DEFAULT_FORCE_TIME is 'MIDDAY'
443
+ """
444
+ if force_time == 'MIDDAY':
445
+ force_time = '12:00:00'
446
+ elif force_time == 'NOW':
447
+ force_time = super().utcnow().strftime('%H:%M:%S')
448
+ elif force_time == 'FIRST_MINUTE':
449
+ force_time = '00:00:00'
450
+ elif force_time == 'LAST_MINUTE':
451
+ force_time = '23:59:59'
452
+ return super().strptime(f'{date_string} {force_time}', date_settings.DEFAULT_DATE_TIME_FORMAT)
453
+
454
+ def strftime(self, format: str = date_settings.DEFAULT_DATE_TIME_FORMAT) -> str: # pylint: disable=redefined-builtin, useless-parent-delegation
455
+ """
456
+ Convert a DateTime object to a date string.
457
+
458
+ This method takes a DateTime object and converts it to a date string using the specified date format.
459
+ If no format is provided, the method will use the default date format specified in `date_settings.DEFAULT_DATE_TIME_FORMAT`.
460
+
461
+ Args:
462
+ format (str, optional): The desired date format. This should be a string representing the desired format using the appropriate format codes. Defaults to '%Y%m%d %H:%M:%S'.
463
+
464
+ Raises:
465
+ ValueError: If the provided `format` format string is invalid.
466
+
467
+ Returns:
468
+ str: The date string representation of the DateTime object in the specified date format.
469
+
470
+ Example:
471
+ Convert a DateTime object to a date string:
472
+ >>> dt = DateTime(2023, 9, 15, 12, 0)
473
+ >>> dt.strftime('%Y-%m-%d %H:%M:%S')
474
+ '2023-09-15 12:00:00'
475
+
476
+ >>> dt.strftime('%d/%m/%Y %H:%M:%S')
477
+ '15/09/2023 12:00:00'
478
+ """
479
+ return super().strftime(format)
480
+
481
+ @classmethod
482
+ def strftime_or_null(cls, datetime_: Any, format: str = date_settings.DEFAULT_DATE_TIME_FORMAT) -> str | None: # pylint: disable=redefined-builtin
483
+ """
484
+ Convert a `DateTime` object to a string representation or return None if the input is not a Date.
485
+
486
+ This class method takes a `DateTime` object and converts it to a string representation
487
+ using the specified date format. If the input date is None, the method returns None.
488
+
489
+ Args:
490
+ datetime_ (DateTime or None): The `DateTime` object to convert to a string representation, or None.
491
+ format (str, optional): The desired date format. This should be a string representing the desired format using the appropriate format codes. Defaults to `date_settings.DEFAULT_DATE_TIME_FORMAT`.
492
+
493
+ Raises:
494
+ ValueError: If the provided `format` format string is invalid.
495
+
496
+ Returns:
497
+ str or None: A string representation of the input date in the specified date format, or None if the input date is None.
498
+
499
+ Example:
500
+ Convert a `DateTime` object to a string representation or return None:
501
+ >>> date_obj = DateTime(2023, 7, 31, 12, 0)
502
+ >>> DateTime.strftime_or_null(date_obj)
503
+ '20230731 12:00:00'
504
+
505
+ >>> DateTime.strftime_or_null(None)
506
+ None
507
+ """
508
+ if datetime_ is not None:
509
+ try:
510
+ datetime_ = datetime_.strftime(format=format)
511
+ except Exception: # pylint: disable=broad-exception-caught
512
+ datetime_ = None
513
+
514
+ return datetime_
515
+
516
+ # OLD date_time_to_pretty
517
+ def strftime_pretty(self, just_date: bool = False, just_time: bool = False) -> str:
518
+ """
519
+ Convert a DateTime object to a pretty date string representation.
520
+
521
+ This method takes a DateTime object and converts it to a pretty date string
522
+ representation with an optional time zone adjustment. The date string representation follows
523
+ the format 'Month day, Year' if `just_time` is False, and 'Month day, Year, Hour:Minute:Second AM/PM'
524
+ if `just_time` is True.
525
+
526
+ Args:
527
+ just_date (bool, optional):
528
+ If True, the hour information is omitted and only the date is shown.
529
+ If False, the full date and time are shown.
530
+ - Defaults to False.
531
+ just_time (bool, optional):
532
+ If True, the date information is omitted and only the time is shown.
533
+ If False, the full date and time are shown.
534
+ - Defaults to False.
535
+
536
+ Raises:
537
+ ValueError: If an invalid value is provided for the `just_time` or `just_date` parameter.
538
+
539
+ Returns:
540
+ str:
541
+ A pretty date or time string representation of the input DateTime object.
542
+
543
+ Criteria:
544
+ - The method accepts an input `just_date` and `just_time` parameter to control the display of date and time.
545
+ - It raises a ValueError if an invalid value is provided for the `just_time` or `just_date`parameter.
546
+ - It returns a string representing the DateTime object in a pretty format.
547
+
548
+ Example:
549
+ Convert a DateTime object to a pretty date string representation:
550
+ >>> date_time_obj = DateTime(2023, 7, 31, 12, 34, 56)
551
+ >>> DateTime.strftime_pretty(date_time_obj)
552
+ 'Jul. 31, 2023, 12:34:56 p.m.'
553
+
554
+ >>> DateTime.strftime_pretty(date_time_obj, just_time=True)
555
+ '12:34 p.m.'
556
+
557
+ >>> DateTime.strftime_pretty(date_time_obj, just_date=True)
558
+ 'Jul. 31, 2023'
559
+ """
560
+ if just_date and just_time:
561
+ raise ValueError('Both "just_date" and "just_time" flags cannot be true')
562
+
563
+ out = None
564
+ if just_date:
565
+ out = self.strftime('%b. %d, %Y')
566
+ elif just_time:
567
+ out = self.strftime('%I:%M %p')
568
+ else:
569
+ out = self.strftime('%b. %d, %Y, %I:%M:%S %p')
570
+ out = out.replace('PM', 'p.m.')
571
+ out = out.replace('AM', 'a.m.')
572
+ return out
573
+
574
+ @classmethod
575
+ def date_to_date_time(cls, date_: 'Date', frc_time: str = date_settings.DEFAULT_FORCE_TIME) -> Self: # type: ignore
576
+ """
577
+ Convert a Date object to a DateTime object.
578
+
579
+ This class method takes a Date object and converts it to a DateTime
580
+ object by combining the specified `date` with the provided `frc_time`, creating a combined
581
+ date and time representation.
582
+
583
+ Args:
584
+ date_ (Date): The Date object to convert to a DateTime object.
585
+ frc_time (str, optional):
586
+ The time to append to the date. This should be a valid time representation
587
+ compatible with the DateTime.strptime function.
588
+ - Defaults to DEFAULT_FORCE_TIME = 'MIDDAY', which sets the time to 12:00:00.
589
+
590
+ Raises:
591
+ ValueError: If an invalid value is provided for the `frc_time` parameter.
592
+
593
+ Returns:
594
+ DateTime:
595
+ A DateTime object representing the date and time
596
+ obtained by combining the input date with the specified `frc_time`.
597
+
598
+ Criteria:
599
+ - The method accepts a `Date` object as input and converts it to a `DateTime` object.
600
+ - It raises a ValueError if an invalid value is provided for the `frc_time` parameter.
601
+ - It returns a `DateTime` object representing the combined date and time.
602
+
603
+ Examples:
604
+ >>> date_obj = Date(2023, 7, 31)
605
+ >>> DateTime.date_to_date_time(date_obj)
606
+ DateTime(2023, 7, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
607
+
608
+ >>> date_obj = Date(2023, 1, 1)
609
+ >>> DateTime.date_to_date_time(date_obj, frc_time='MIDDAY')
610
+ DateTime(2023, 1, 1, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
611
+ """
612
+ # string_date = date_.strftime('%Y-%m-%d')
613
+ # date_time_str = f'{string_date} {frc_time}'
614
+ return DateTime(date_.year, date_.month, date_.day).force_time(force_time=frc_time)
615
+
616
+ @staticmethod
617
+ def is_datetime(value: Any) -> bool:
618
+ """
619
+ Check if a value is a DateTime object.
620
+
621
+ This static method checks whether a given value is an instance of the `DateTime` class or the built-in `datetime.datetime` class.
622
+ It's necessary to use this custom check because `isinstance(value, date)` will return True for both `datetime` and `date` objects
623
+ due to their shared base class.
624
+
625
+ Args:
626
+ value (Any): The value to be checked.
627
+
628
+ Returns:
629
+ bool: True if the value is a DateTime object, False otherwise.
630
+
631
+ Criteria:
632
+ - The method checks if the value is an instance of the `DateTime` class or `datetime.datetime` class.
633
+ - It returns True if the value is a DateTime object, otherwise False.
634
+
635
+ Example:
636
+ Check if a value is a DateTime object:
637
+ >>> value = DateTime(2023, 7, 31, 12, 34, 56)
638
+ >>> DateTime.is_datetime(value)
639
+ True
640
+
641
+ >>> value = datetime.datetime(2023, 7, 31, 12, 34, 56)
642
+ >>> DateTime.is_datetime(value)
643
+ True
644
+
645
+ >>> value = Date(2023, 7, 31)
646
+ >>> DateTime.is_datetime(value)
647
+ False
648
+ """
649
+ if value is not None:
650
+ if value.__class__ in (DateTime, datetime):
651
+ return True
652
+
653
+ return False
654
+
655
+ # OLD is_realtime_portfolio_date
656
+ def is_today(self) -> bool:
657
+ """
658
+ Check if the DateTime object corresponds to the current date.
659
+
660
+ This method compares the DateTime object with the current date and returns True if they represent the same date.
661
+
662
+ Returns:
663
+ bool: True if the DateTime object represents the current date, False otherwise.
664
+
665
+ Criteria:
666
+ - The method compares the DateTime object with the current date.
667
+ - It returns True if they represent the same date, otherwise False.
668
+
669
+ Example:
670
+ Check if a DateTime object corresponds to the current date:
671
+ >>> date_time_obj = DateTime(2023, 1, 1)
672
+ >>> date_time_obj.is_today()
673
+ False
674
+
675
+ >>> current_date_time = DateTime.now()
676
+ >>> current_date_time.is_today()
677
+ True
678
+ """
679
+ return DateTime.now().date() == self.date()
680
+
681
+ def replace(self, **kwargs: Any) -> Self:
682
+ """
683
+ Return a new DateTime object with specified attributes replaced.
684
+
685
+ This method creates a new DateTime object by replacing specified attributes
686
+ of the current DateTime object with new values provided as keyword arguments.
687
+
688
+ We need to use kwargs to not put required parameters and allow only the ones that are passed to be replaced.
689
+
690
+
691
+ Args:
692
+ **kwargs: Keyword arguments representing the attributes to be replaced.
693
+ Valid attributes include 'year', 'month', 'day', 'hour', 'minute',
694
+ 'second', 'microsecond', 'tzinfo', and 'fold'.
695
+
696
+ Example:
697
+ Replace attributes of a DateTime object:
698
+ >>> dt = DateTime(2023, 9, 15, 12, 0)
699
+ >>> new_dt = dt.replace(hour=15, minute=30)
700
+ >>> new_dt
701
+ DateTime(2023, 9, 15, 15, 30, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
702
+ """
703
+ import sys # noqa: PLC0415
704
+
705
+ # On Python 3.12.11 and below, the replace method validate tzinfo, so we can't pass Undefined
706
+ # but the tzinfo=None works as expected.
707
+ if sys.version_info[:3] >= (3, 12, 12):
708
+ # https://everysk.atlassian.net/browse/COD-13539
709
+ # We use Undefined to identify when we want to remove the tzinfo
710
+ if 'tzinfo' in kwargs and kwargs['tzinfo'] is None:
711
+ kwargs['tzinfo'] = Undefined
712
+
713
+ return super().replace(**kwargs)