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,424 @@
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 date, datetime # pylint: disable=import-self
11
+ from typing import Any, Union, Self
12
+
13
+ from everysk.core.datetime import date_settings
14
+ from everysk.core.datetime.date_expression import DateExpressionMixin
15
+ from everysk.core.datetime.date_mixin import DateMixin
16
+
17
+
18
+ class Date(DateMixin, DateExpressionMixin, date): #pylint: disable=inherit-non-class
19
+
20
+ @classmethod
21
+ def ensure(cls, value: Any) -> Self:
22
+ """
23
+ Ensure that a value is a Date object or convert it to one.
24
+
25
+ This class method takes a value and ensures that it is a Date object. If the value is a datetime.date object, it will be
26
+ converted to a Date object by extracting the year, month, and day components. If the value is already a Date object, it
27
+ will be returned as is. If the value is neither a Date object nor a datetime.date object, a ValueError is raised.
28
+
29
+ Args:
30
+ value (Any): The value to ensure as a Date object.
31
+
32
+ Raises:
33
+ ValueError: If the value cannot be converted to a Date object.
34
+
35
+ Returns:
36
+ Date: A Date object representing the same date as the input value.
37
+
38
+ Example:
39
+ Ensure a value is a Date object:
40
+ >>> date_value = Date(2023, 7, 31)
41
+ >>> Date.ensure(date_value)
42
+ Date(2023, 7, 31)
43
+
44
+ >>> datetime_date = datetime.date(2023, 7, 31)
45
+ >>> Date.ensure(datetime_date)
46
+ Date(2023, 7, 31)
47
+
48
+ """
49
+ if value.__class__ != cls:
50
+ try:
51
+ value = cls(value.year, value.month, value.day)
52
+ except Exception:
53
+ raise ValueError(f"Invalid instantiation of class '{cls.__name__}' from '{value.__class__.__name__}'") # pylint: disable=raise-missing-from
54
+
55
+ return value
56
+
57
+ @classmethod
58
+ def fromisoformat(cls, date_string: str) -> Self:
59
+ """
60
+ Convert an ISO formatted date string to a Date object.
61
+
62
+ This class method takes an ISO formatted date string and converts it to a Date object.
63
+
64
+ Args:
65
+ date_string (str): The ISO formatted date string to convert to a Date object.
66
+
67
+ Raises:
68
+ ValueError: If the input date string does not have the expected format.
69
+
70
+ Returns:
71
+ Date: A Date object representing the date extracted from the input ISO formatted date string.
72
+
73
+ Example:
74
+ Convert an ISO formatted date string to a Date object:
75
+ >>> input_string = '20230101'
76
+ >>> Date.fromisoformat(input_string)
77
+ Date(2023, 1, 1)
78
+
79
+ >>> input_string = '2023-01-01'
80
+ >>> Date.fromisoformat(input_string)
81
+ Date(2023, 1, 1)
82
+
83
+ """
84
+ if date_string and len(date_string) == 8:
85
+ return cls.strptime(date_string)
86
+
87
+ return super().fromisoformat(date_string)
88
+
89
+ # antes retornava string, agora retorna self date
90
+ # agora start_date é date
91
+ @classmethod
92
+ def fromordinal(cls, date_ordinal: int, start_date: 'Date' = None) -> Self:
93
+ """
94
+ Convert the ordinal day count since a base date to a Date object.
95
+
96
+ This static method takes an `date_ordinal`, which is the number of days since a specified `start_date`,
97
+ and converts it into a Date object.
98
+
99
+ Args:
100
+ date_ordinal (int): The ordinal day count since the base date specified by `start_date`.
101
+ start_date (Date, optional): The base date to start counting from. Defaults to January 1, 1 AD (00010101).
102
+
103
+ Raises:
104
+ TypeError: If the input date_ordinal is not an integer.
105
+ AttributeError: If the start date is not a Date object or None.
106
+
107
+ Returns:
108
+ Date: A Date object representing the date calculated from the ordinal day count and start_date.
109
+
110
+ Example:
111
+ Convert an ordinal day count to a Date object:
112
+ >>> Date.fromordinal(1)
113
+ Date(1, 1, 1)
114
+
115
+ >>> Date.fromordinal(365)
116
+ Date(1, 12, 31)
117
+
118
+ """
119
+ if start_date:
120
+ date_ordinal += start_date.toordinal() - 1
121
+
122
+ return super().fromordinal(date_ordinal)
123
+
124
+ @classmethod
125
+ def strptime(cls, date_string: str, format: str = date_settings.DEFAULT_DATE_FORMAT) -> Self: # pylint: disable=redefined-builtin
126
+ """
127
+ Convert a string to a Date object using the specified format.
128
+
129
+ This static method takes a string and attempts to convert it into a Date object using the provided
130
+ format. If the conversion is successful, the resulting Date object is returned. If the input string is
131
+ empty or cannot be converted, a ValueError is raised.
132
+
133
+ Args:
134
+ date_string (str): The input string to be converted to a Date object.
135
+ format (str, optional): The format string used to interpret the input string. Defaults to DEFAULT_DATE_FORMAT ('%Y%m%d').
136
+
137
+ Raises:
138
+ ValueError: If the input string is empty or cannot be converted to a Date object using the specified format.
139
+
140
+ Returns:
141
+ Date: A Date object representing the converted date if successful.
142
+
143
+ Example:
144
+ >>> date_str = '20230731'
145
+ >>> Date.string_to_date(date_str)
146
+ Date(2023, 7, 31)
147
+
148
+ """
149
+ datetime_ = datetime.strptime(date_string, format) # pylint: disable=no-member
150
+ return cls(datetime_.year, datetime_.month, datetime_.day)
151
+
152
+ @classmethod
153
+ def strptime_or_null(cls, date_string: str, format: str = date_settings.DEFAULT_DATE_FORMAT) -> Union[Self, None]: # pylint: disable=redefined-builtin
154
+ """
155
+ Convert a string to a Date object using the specified format or return None.
156
+
157
+ This class method takes a string and attempts to convert it into a Date object using the provided
158
+ format. If the conversion is successful, the resulting Date object is returned. If the input string is
159
+ empty or cannot be converted, the method returns None.
160
+
161
+ Args:
162
+ date_string (str): The input string to be converted to a Date object.
163
+ format (str, optional): The format string used to interpret the input string. Defaults to DEFAULT_DATE_FORMAT ('%Y%m%d').
164
+
165
+ Returns:
166
+ Date or None: A Date object representing the converted date if successful, or None if the input string is empty or cannot be converted.
167
+
168
+ Example:
169
+ To convert a string to a Date object:
170
+ >>> date_string = '20230731'
171
+ >>> date_obj = Date.strptime_or_null(date_string)
172
+ """
173
+ date_ = None
174
+
175
+ try:
176
+ date_ = Date.strptime(date_string, format=format)
177
+ except Exception: # pylint: disable=broad-exception-caught
178
+ pass
179
+
180
+ return date_
181
+
182
+ @classmethod
183
+ def is_string_date(cls, date_string: str, format: str = date_settings.DEFAULT_DATE_FORMAT) -> bool: # pylint: disable=redefined-builtin
184
+ """
185
+ Check if a string is a valid representation of a date.
186
+
187
+ This class method checks if the input string is a valid representation of a date
188
+ using the specified date format. If the input string can be successfully converted to a
189
+ Date object using the provided format, the method returns True. Otherwise, it returns False.
190
+
191
+ Args:
192
+ date_string (str): The string to check for validity as a date representation.
193
+ format (str, optional): The format string used to interpret the input string. Defaults to DEFAULT_DATE_FORMAT ('%Y%m%d').
194
+
195
+ Returns:
196
+ bool: True if the input string is a valid date representation, False otherwise.
197
+
198
+ Example:
199
+ To check if a string is a valid date representation:
200
+ >>> date_string = '20230731'
201
+ Date.is_string_date(date_string)
202
+ True
203
+
204
+ >>> date_string = '2023-05-01'
205
+ Date.is_string_date(date_string)
206
+ False
207
+
208
+ >>> date_string = '2023-05-01'
209
+ Date.is_string_date(date_string, format='%Y-%m-%d')
210
+ True
211
+ """
212
+ return bool(cls.strptime_or_null(date_string, format=format))
213
+
214
+ def strftime(self, format: str = date_settings.DEFAULT_DATE_FORMAT) -> str: # pylint: disable=redefined-builtin, useless-parent-delegation
215
+ """
216
+ Convert a `Date` object to a date string representation.
217
+
218
+ This instance method takes a `Date` object and converts it to a date string representation
219
+ using the specified date `format`. If no `format` is provided, the method will use the Everysk's default date
220
+ format `DEFAULT_DATE_FORMAT`.
221
+
222
+ Args:
223
+ format (str, optional): The desired date format. This should be a string representing the desired format using the appropriate format codes. (default is `DEFAULT_DATE_FORMAT`)
224
+
225
+ Raises:
226
+ TypeError: If a invalid argument is provided.
227
+
228
+ Returns:
229
+ str: The date string representation of the input `Date` object in the specified date format.
230
+
231
+ Example:
232
+ To convert a `Date` object to a date string:
233
+ >>> date_obj = Date(2023, 7, 31)
234
+ >>> date_obj.strftime(format='%d/%m/%Y')
235
+ '31/07/2023'
236
+
237
+ """
238
+ return super().strftime(format)
239
+
240
+ @classmethod
241
+ def strftime_or_null(cls, date_: Any, format: str = date_settings.DEFAULT_DATE_FORMAT) -> Union[str, None]: # pylint: disable=redefined-builtin
242
+ """
243
+ Convert a Date object to a string representation or return None.
244
+
245
+ This class method takes a Date object and converts it to a string representation
246
+ using the default date format ('%Y%m%d'), which represents dates in the format 'YYYYMMDD'.
247
+ If the input date is None, the method returns None.
248
+
249
+ Args:
250
+ date_ (Date or None): The Date object to convert to a string representation, or None.
251
+ format (str, optional): The desired date format. This should be a string representing the desired format using the appropriate format codes. (default is `DEFAULT_DATE_FORMAT`)
252
+
253
+ Returns:
254
+ str or None: A string representation of the input date in the specified date format, or None if the input date is None.
255
+
256
+ Example:
257
+ To convert a Date object to a date string or return None:
258
+ >>> import datetime
259
+ >>> date_obj = Date(2023, 7, 31)
260
+ >>> Date.strftime_or_null(date_obj)
261
+ '20230731'
262
+
263
+ >>> Date.strftime_or_null(None)
264
+ None
265
+ """
266
+ if date_ is not None:
267
+ try:
268
+ date_ = date_.strftime(format=format)
269
+ except Exception: # pylint: disable=broad-exception-caught
270
+ date_ = None
271
+
272
+ return date_
273
+
274
+ @classmethod
275
+ def is_date(cls, value: Any) -> bool:
276
+ """
277
+ Check if a value is a Date object.
278
+
279
+ This class method checks if the input value is an instance of the `Date` class.
280
+
281
+ Args:
282
+ value (Any): The value to be checked.
283
+
284
+ Returns:
285
+ bool: True if the input value is a Date object, False otherwise.
286
+
287
+ Example:
288
+ >>> date_obj = Date(2023, 7, 31)
289
+ >>> Date.is_date(date_obj)
290
+ True
291
+
292
+ >>> date_time_obj = DateTime(2023, 7, 31, 12, 0)
293
+ >>> Date.is_date(date_time_obj)
294
+ False
295
+ """
296
+ if value is not None:
297
+ if value.__class__ in (Date, date):
298
+ return True
299
+
300
+ return False
301
+
302
+ def is_today(self) -> bool:
303
+ """
304
+ Check if the current date corresponds to the date represented by this Date object.
305
+
306
+ This method compares the date represented by this Date object with the current date and returns True if they are the same.
307
+
308
+ Returns:
309
+ bool: True if this Date object represents the current date, False otherwise.
310
+
311
+ Example:
312
+ >>> today = Date.today()
313
+ >>> today.is_today()
314
+ True
315
+
316
+ >>> future_date = Date(2023, 12, 31)
317
+ >>> future_date.is_today()
318
+ False
319
+ """
320
+ return self == Date.today()
321
+
322
+ def date(self) -> Self:
323
+ """
324
+ Return Date object with same year, month and day. Used to maintain consistency between DateTime and Date instances
325
+
326
+ Returns:
327
+ Date: A Date object representing the same date as the input value.
328
+
329
+ Example:
330
+ >>> today = Date(2023, 12, 31)
331
+ >>> today.date()
332
+ Date(2023, 12, 31)
333
+ """
334
+ return self
335
+
336
+ ####################################
337
+ ### DATE RANGE
338
+ ####################################
339
+
340
+ @classmethod
341
+ def date_range(cls, range_type: str, period: str, n_period: int, start_date: 'Date', end_date: 'Date') -> tuple[str, str]:
342
+ """
343
+ Get the start date and end date based on specified parameters.
344
+
345
+ This method returns a tuple of two dates (start_date and end_date) based on the provided parameters. It is useful for generating date ranges based on different requirements.
346
+
347
+ Args:
348
+ range_type (str): Specifies the type of range needed. Possible values: 'single_date', 'custom_range', 'n_period', 'period_to_date', 'end_period_to_date'.
349
+ period (str): Specifies the type of period in case `range_type` is 'n_period' or 'period_to_date'. Possible values: 'days', 'weeks', 'months', 'years', 'mtd', 'qtd', 'ytd'.
350
+ n_period (int): Specifies the number of periods to be considered in case `range_type` is 'n_period'.
351
+ start_date (Date): The start date of the custom range in case `range_type` is 'custom_range'.
352
+ end_date (Date): The end date of the custom range in case `range_type` is 'custom_range' or 'single_date'.
353
+
354
+ Returns:
355
+ tuple[str, str]: A tuple of start date and end date in string format ('YYYYMMDD').
356
+
357
+ Raises:
358
+ ValueError: If an invalid `endDate`, `startDate`, `nPeriod`, `period`, or `range_type` is provided.
359
+
360
+ Example:
361
+ >>> Date.date_range('single_date', None, None, None, Date(2023, 1, 10))
362
+ ('20230110', '20230110')
363
+
364
+ >>> Date.date_range('custom_range', None, None, Date(2023, 1, 1), Date(2023, 1, 10))
365
+ ('20230101', '20230110')
366
+
367
+ >>> Date.date_range('n_period', 'months', 3, None, Date(2023, 1, 10))
368
+ ('20231010', '20230110')
369
+
370
+ >>> Date.date_range('period_to_date', 'ytd', None, None, Date(2023, 12, 31))
371
+ ('20230101', '20231231')
372
+ """
373
+ if start_date and start_date.__class__ != Date:
374
+ raise ValueError('Invalid start_date type')
375
+
376
+ if end_date and end_date.__class__ != Date:
377
+ raise ValueError('Invalid end_date type')
378
+
379
+ if not end_date:
380
+ end_date = Date.today()
381
+
382
+ date_ = end_date
383
+
384
+ if range_type == 'single_date':
385
+ start_date = end_date
386
+
387
+ elif range_type == 'custom_range':
388
+ if not start_date:
389
+ start_date = cls.ensure(date_settings.MARKET_START_DATE)
390
+
391
+ elif range_type == 'n_period':
392
+ delta = -int(n_period)
393
+
394
+ if period == 'days':
395
+ start_date = date_.delta(period=delta, periodicity='D')
396
+ elif period == 'weeks':
397
+ start_date = date_.delta(period=delta, periodicity='W')
398
+ elif period == 'months':
399
+ start_date = date_.delta(period=delta, periodicity='M')
400
+ elif period == 'years':
401
+ start_date = date_.delta(period=delta, periodicity='Y')
402
+ else:
403
+ raise ValueError('invalid n period')
404
+
405
+ elif range_type in ('period_to_date', 'end_period_to_date'):
406
+ if period == 'mtd':
407
+ start_date = end_date
408
+ start_date = start_date.replace(day=1)
409
+ elif period == 'qtd':
410
+ start_date = Date(date_.year, 3 * date_.quarter - 2, 1)
411
+ elif period == 'ytd':
412
+ start_date = end_date
413
+ start_date = start_date.replace(month=1, day=1)
414
+ else:
415
+ raise ValueError('invalid period to date')
416
+
417
+ if range_type == 'end_period_to_date':
418
+ start_date = start_date.delta(period=-1, periodicity='B')
419
+ else:
420
+ raise ValueError('invalid range type')
421
+
422
+ assert (start_date and end_date)
423
+
424
+ return (start_date, end_date)