BryanW commited on
Commit
adf4098
·
verified ·
1 Parent(s): 0d11c13

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/_yaml/__pycache__/__init__.cpython-312.pyc +0 -0
  2. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc +0 -0
  3. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc +0 -0
  4. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc +0 -0
  5. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc +0 -0
  6. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc +0 -0
  7. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc +0 -0
  8. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc +0 -0
  9. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc +0 -0
  10. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc +0 -0
  11. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc +0 -0
  12. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/__init__.cpython-312.pyc +0 -0
  13. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/_common.cpython-312.pyc +0 -0
  14. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/easter.cpython-312.pyc +0 -0
  15. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/tzwin.cpython-312.pyc +0 -0
  16. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/utils.cpython-312.pyc +0 -0
  17. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__init__.py +61 -0
  18. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__pycache__/__init__.cpython-312.pyc +0 -0
  19. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__pycache__/_parser.cpython-312.pyc +0 -0
  20. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__pycache__/isoparser.cpython-312.pyc +0 -0
  21. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/_parser.py +1613 -0
  22. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/isoparser.py +416 -0
  23. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/__init__.cpython-312.pyc +0 -0
  24. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/_common.cpython-312.pyc +0 -0
  25. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/_factories.cpython-312.pyc +0 -0
  26. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/tz.cpython-312.pyc +0 -0
  27. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/win.cpython-312.pyc +0 -0
  28. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-312.pyc +0 -0
  29. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-312.pyc +0 -0
  30. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/rebuild.py +75 -0
  31. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/__init__.cpython-312.pyc +0 -0
  32. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_api.cpython-312.pyc +0 -0
  33. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_error.cpython-312.pyc +0 -0
  34. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_soft.cpython-312.pyc +0 -0
  35. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_unix.cpython-312.pyc +0 -0
  36. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_util.cpython-312.pyc +0 -0
  37. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_windows.cpython-312.pyc +0 -0
  38. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/asyncio.cpython-312.pyc +0 -0
  39. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/version.cpython-312.pyc +0 -0
  40. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/fsspec-2024.5.0.dist-info/licenses/LICENSE +29 -0
  41. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/__init__.cpython-312.pyc +0 -0
  42. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_abnf.cpython-312.pyc +0 -0
  43. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_connection.cpython-312.pyc +0 -0
  44. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_events.cpython-312.pyc +0 -0
  45. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_headers.cpython-312.pyc +0 -0
  46. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_readers.cpython-312.pyc +0 -0
  47. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_receivebuffer.cpython-312.pyc +0 -0
  48. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_state.cpython-312.pyc +0 -0
  49. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_util.cpython-312.pyc +0 -0
  50. Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_version.cpython-312.pyc +0 -0
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/_yaml/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (893 Bytes). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (2.76 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc ADDED
Binary file (27.5 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc ADDED
Binary file (30.7 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc ADDED
Binary file (2.48 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc ADDED
Binary file (24.8 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc ADDED
Binary file (14.2 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc ADDED
Binary file (3.14 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc ADDED
Binary file (22.9 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc ADDED
Binary file (49.5 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc ADDED
Binary file (26.4 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.16 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/_common.cpython-312.pyc ADDED
Binary file (1.96 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/easter.cpython-312.pyc ADDED
Binary file (2.88 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/tzwin.cpython-312.pyc ADDED
Binary file (239 Bytes). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/utils.cpython-312.pyc ADDED
Binary file (2.59 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__init__.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ from ._parser import parse, parser, parserinfo, ParserError
3
+ from ._parser import DEFAULTPARSER, DEFAULTTZPARSER
4
+ from ._parser import UnknownTimezoneWarning
5
+
6
+ from ._parser import __doc__
7
+
8
+ from .isoparser import isoparser, isoparse
9
+
10
+ __all__ = ['parse', 'parser', 'parserinfo',
11
+ 'isoparse', 'isoparser',
12
+ 'ParserError',
13
+ 'UnknownTimezoneWarning']
14
+
15
+
16
+ ###
17
+ # Deprecate portions of the private interface so that downstream code that
18
+ # is improperly relying on it is given *some* notice.
19
+
20
+
21
+ def __deprecated_private_func(f):
22
+ from functools import wraps
23
+ import warnings
24
+
25
+ msg = ('{name} is a private function and may break without warning, '
26
+ 'it will be moved and or renamed in future versions.')
27
+ msg = msg.format(name=f.__name__)
28
+
29
+ @wraps(f)
30
+ def deprecated_func(*args, **kwargs):
31
+ warnings.warn(msg, DeprecationWarning)
32
+ return f(*args, **kwargs)
33
+
34
+ return deprecated_func
35
+
36
+ def __deprecate_private_class(c):
37
+ import warnings
38
+
39
+ msg = ('{name} is a private class and may break without warning, '
40
+ 'it will be moved and or renamed in future versions.')
41
+ msg = msg.format(name=c.__name__)
42
+
43
+ class private_class(c):
44
+ __doc__ = c.__doc__
45
+
46
+ def __init__(self, *args, **kwargs):
47
+ warnings.warn(msg, DeprecationWarning)
48
+ super(private_class, self).__init__(*args, **kwargs)
49
+
50
+ private_class.__name__ = c.__name__
51
+
52
+ return private_class
53
+
54
+
55
+ from ._parser import _timelex, _resultbase
56
+ from ._parser import _tzparser, _parsetz
57
+
58
+ _timelex = __deprecate_private_class(_timelex)
59
+ _tzparser = __deprecate_private_class(_tzparser)
60
+ _resultbase = __deprecate_private_class(_resultbase)
61
+ _parsetz = __deprecated_private_func(_parsetz)
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (2.69 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__pycache__/_parser.cpython-312.pyc ADDED
Binary file (61.9 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/__pycache__/isoparser.cpython-312.pyc ADDED
Binary file (15.6 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/_parser.py ADDED
@@ -0,0 +1,1613 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This module offers a generic date/time string parser which is able to parse
4
+ most known formats to represent a date and/or time.
5
+
6
+ This module attempts to be forgiving with regards to unlikely input formats,
7
+ returning a datetime object even for dates which are ambiguous. If an element
8
+ of a date/time stamp is omitted, the following rules are applied:
9
+
10
+ - If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour
11
+ on a 12-hour clock (``0 <= hour <= 12``) *must* be specified if AM or PM is
12
+ specified.
13
+ - If a time zone is omitted, a timezone-naive datetime is returned.
14
+
15
+ If any other elements are missing, they are taken from the
16
+ :class:`datetime.datetime` object passed to the parameter ``default``. If this
17
+ results in a day number exceeding the valid number of days per month, the
18
+ value falls back to the end of the month.
19
+
20
+ Additional resources about date/time string formats can be found below:
21
+
22
+ - `A summary of the international standard date and time notation
23
+ <https://www.cl.cam.ac.uk/~mgk25/iso-time.html>`_
24
+ - `W3C Date and Time Formats <https://www.w3.org/TR/NOTE-datetime>`_
25
+ - `Time Formats (Planetary Rings Node) <https://pds-rings.seti.org:443/tools/time_formats.html>`_
26
+ - `CPAN ParseDate module
27
+ <https://metacpan.org/pod/release/MUIR/Time-modules-2013.0912/lib/Time/ParseDate.pm>`_
28
+ - `Java SimpleDateFormat Class
29
+ <https://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>`_
30
+ """
31
+ from __future__ import unicode_literals
32
+
33
+ import datetime
34
+ import re
35
+ import string
36
+ import time
37
+ import warnings
38
+
39
+ from calendar import monthrange
40
+ from io import StringIO
41
+
42
+ import six
43
+ from six import integer_types, text_type
44
+
45
+ from decimal import Decimal
46
+
47
+ from warnings import warn
48
+
49
+ from .. import relativedelta
50
+ from .. import tz
51
+
52
+ __all__ = ["parse", "parserinfo", "ParserError"]
53
+
54
+
55
+ # TODO: pandas.core.tools.datetimes imports this explicitly. Might be worth
56
+ # making public and/or figuring out if there is something we can
57
+ # take off their plate.
58
+ class _timelex(object):
59
+ # Fractional seconds are sometimes split by a comma
60
+ _split_decimal = re.compile("([.,])")
61
+
62
+ def __init__(self, instream):
63
+ if isinstance(instream, (bytes, bytearray)):
64
+ instream = instream.decode()
65
+
66
+ if isinstance(instream, text_type):
67
+ instream = StringIO(instream)
68
+ elif getattr(instream, 'read', None) is None:
69
+ raise TypeError('Parser must be a string or character stream, not '
70
+ '{itype}'.format(itype=instream.__class__.__name__))
71
+
72
+ self.instream = instream
73
+ self.charstack = []
74
+ self.tokenstack = []
75
+ self.eof = False
76
+
77
+ def get_token(self):
78
+ """
79
+ This function breaks the time string into lexical units (tokens), which
80
+ can be parsed by the parser. Lexical units are demarcated by changes in
81
+ the character set, so any continuous string of letters is considered
82
+ one unit, any continuous string of numbers is considered one unit.
83
+
84
+ The main complication arises from the fact that dots ('.') can be used
85
+ both as separators (e.g. "Sep.20.2009") or decimal points (e.g.
86
+ "4:30:21.447"). As such, it is necessary to read the full context of
87
+ any dot-separated strings before breaking it into tokens; as such, this
88
+ function maintains a "token stack", for when the ambiguous context
89
+ demands that multiple tokens be parsed at once.
90
+ """
91
+ if self.tokenstack:
92
+ return self.tokenstack.pop(0)
93
+
94
+ seenletters = False
95
+ token = None
96
+ state = None
97
+
98
+ while not self.eof:
99
+ # We only realize that we've reached the end of a token when we
100
+ # find a character that's not part of the current token - since
101
+ # that character may be part of the next token, it's stored in the
102
+ # charstack.
103
+ if self.charstack:
104
+ nextchar = self.charstack.pop(0)
105
+ else:
106
+ nextchar = self.instream.read(1)
107
+ while nextchar == '\x00':
108
+ nextchar = self.instream.read(1)
109
+
110
+ if not nextchar:
111
+ self.eof = True
112
+ break
113
+ elif not state:
114
+ # First character of the token - determines if we're starting
115
+ # to parse a word, a number or something else.
116
+ token = nextchar
117
+ if self.isword(nextchar):
118
+ state = 'a'
119
+ elif self.isnum(nextchar):
120
+ state = '0'
121
+ elif self.isspace(nextchar):
122
+ token = ' '
123
+ break # emit token
124
+ else:
125
+ break # emit token
126
+ elif state == 'a':
127
+ # If we've already started reading a word, we keep reading
128
+ # letters until we find something that's not part of a word.
129
+ seenletters = True
130
+ if self.isword(nextchar):
131
+ token += nextchar
132
+ elif nextchar == '.':
133
+ token += nextchar
134
+ state = 'a.'
135
+ else:
136
+ self.charstack.append(nextchar)
137
+ break # emit token
138
+ elif state == '0':
139
+ # If we've already started reading a number, we keep reading
140
+ # numbers until we find something that doesn't fit.
141
+ if self.isnum(nextchar):
142
+ token += nextchar
143
+ elif nextchar == '.' or (nextchar == ',' and len(token) >= 2):
144
+ token += nextchar
145
+ state = '0.'
146
+ else:
147
+ self.charstack.append(nextchar)
148
+ break # emit token
149
+ elif state == 'a.':
150
+ # If we've seen some letters and a dot separator, continue
151
+ # parsing, and the tokens will be broken up later.
152
+ seenletters = True
153
+ if nextchar == '.' or self.isword(nextchar):
154
+ token += nextchar
155
+ elif self.isnum(nextchar) and token[-1] == '.':
156
+ token += nextchar
157
+ state = '0.'
158
+ else:
159
+ self.charstack.append(nextchar)
160
+ break # emit token
161
+ elif state == '0.':
162
+ # If we've seen at least one dot separator, keep going, we'll
163
+ # break up the tokens later.
164
+ if nextchar == '.' or self.isnum(nextchar):
165
+ token += nextchar
166
+ elif self.isword(nextchar) and token[-1] == '.':
167
+ token += nextchar
168
+ state = 'a.'
169
+ else:
170
+ self.charstack.append(nextchar)
171
+ break # emit token
172
+
173
+ if (state in ('a.', '0.') and (seenletters or token.count('.') > 1 or
174
+ token[-1] in '.,')):
175
+ l = self._split_decimal.split(token)
176
+ token = l[0]
177
+ for tok in l[1:]:
178
+ if tok:
179
+ self.tokenstack.append(tok)
180
+
181
+ if state == '0.' and token.count('.') == 0:
182
+ token = token.replace(',', '.')
183
+
184
+ return token
185
+
186
+ def __iter__(self):
187
+ return self
188
+
189
+ def __next__(self):
190
+ token = self.get_token()
191
+ if token is None:
192
+ raise StopIteration
193
+
194
+ return token
195
+
196
+ def next(self):
197
+ return self.__next__() # Python 2.x support
198
+
199
+ @classmethod
200
+ def split(cls, s):
201
+ return list(cls(s))
202
+
203
+ @classmethod
204
+ def isword(cls, nextchar):
205
+ """ Whether or not the next character is part of a word """
206
+ return nextchar.isalpha()
207
+
208
+ @classmethod
209
+ def isnum(cls, nextchar):
210
+ """ Whether the next character is part of a number """
211
+ return nextchar.isdigit()
212
+
213
+ @classmethod
214
+ def isspace(cls, nextchar):
215
+ """ Whether the next character is whitespace """
216
+ return nextchar.isspace()
217
+
218
+
219
+ class _resultbase(object):
220
+
221
+ def __init__(self):
222
+ for attr in self.__slots__:
223
+ setattr(self, attr, None)
224
+
225
+ def _repr(self, classname):
226
+ l = []
227
+ for attr in self.__slots__:
228
+ value = getattr(self, attr)
229
+ if value is not None:
230
+ l.append("%s=%s" % (attr, repr(value)))
231
+ return "%s(%s)" % (classname, ", ".join(l))
232
+
233
+ def __len__(self):
234
+ return (sum(getattr(self, attr) is not None
235
+ for attr in self.__slots__))
236
+
237
+ def __repr__(self):
238
+ return self._repr(self.__class__.__name__)
239
+
240
+
241
+ class parserinfo(object):
242
+ """
243
+ Class which handles what inputs are accepted. Subclass this to customize
244
+ the language and acceptable values for each parameter.
245
+
246
+ :param dayfirst:
247
+ Whether to interpret the first value in an ambiguous 3-integer date
248
+ (e.g. 01/05/09) as the day (``True``) or month (``False``). If
249
+ ``yearfirst`` is set to ``True``, this distinguishes between YDM
250
+ and YMD. Default is ``False``.
251
+
252
+ :param yearfirst:
253
+ Whether to interpret the first value in an ambiguous 3-integer date
254
+ (e.g. 01/05/09) as the year. If ``True``, the first number is taken
255
+ to be the year, otherwise the last number is taken to be the year.
256
+ Default is ``False``.
257
+ """
258
+
259
+ # m from a.m/p.m, t from ISO T separator
260
+ JUMP = [" ", ".", ",", ";", "-", "/", "'",
261
+ "at", "on", "and", "ad", "m", "t", "of",
262
+ "st", "nd", "rd", "th"]
263
+
264
+ WEEKDAYS = [("Mon", "Monday"),
265
+ ("Tue", "Tuesday"), # TODO: "Tues"
266
+ ("Wed", "Wednesday"),
267
+ ("Thu", "Thursday"), # TODO: "Thurs"
268
+ ("Fri", "Friday"),
269
+ ("Sat", "Saturday"),
270
+ ("Sun", "Sunday")]
271
+ MONTHS = [("Jan", "January"),
272
+ ("Feb", "February"), # TODO: "Febr"
273
+ ("Mar", "March"),
274
+ ("Apr", "April"),
275
+ ("May", "May"),
276
+ ("Jun", "June"),
277
+ ("Jul", "July"),
278
+ ("Aug", "August"),
279
+ ("Sep", "Sept", "September"),
280
+ ("Oct", "October"),
281
+ ("Nov", "November"),
282
+ ("Dec", "December")]
283
+ HMS = [("h", "hour", "hours"),
284
+ ("m", "minute", "minutes"),
285
+ ("s", "second", "seconds")]
286
+ AMPM = [("am", "a"),
287
+ ("pm", "p")]
288
+ UTCZONE = ["UTC", "GMT", "Z", "z"]
289
+ PERTAIN = ["of"]
290
+ TZOFFSET = {}
291
+ # TODO: ERA = ["AD", "BC", "CE", "BCE", "Stardate",
292
+ # "Anno Domini", "Year of Our Lord"]
293
+
294
+ def __init__(self, dayfirst=False, yearfirst=False):
295
+ self._jump = self._convert(self.JUMP)
296
+ self._weekdays = self._convert(self.WEEKDAYS)
297
+ self._months = self._convert(self.MONTHS)
298
+ self._hms = self._convert(self.HMS)
299
+ self._ampm = self._convert(self.AMPM)
300
+ self._utczone = self._convert(self.UTCZONE)
301
+ self._pertain = self._convert(self.PERTAIN)
302
+
303
+ self.dayfirst = dayfirst
304
+ self.yearfirst = yearfirst
305
+
306
+ self._year = time.localtime().tm_year
307
+ self._century = self._year // 100 * 100
308
+
309
+ def _convert(self, lst):
310
+ dct = {}
311
+ for i, v in enumerate(lst):
312
+ if isinstance(v, tuple):
313
+ for v in v:
314
+ dct[v.lower()] = i
315
+ else:
316
+ dct[v.lower()] = i
317
+ return dct
318
+
319
+ def jump(self, name):
320
+ return name.lower() in self._jump
321
+
322
+ def weekday(self, name):
323
+ try:
324
+ return self._weekdays[name.lower()]
325
+ except KeyError:
326
+ pass
327
+ return None
328
+
329
+ def month(self, name):
330
+ try:
331
+ return self._months[name.lower()] + 1
332
+ except KeyError:
333
+ pass
334
+ return None
335
+
336
+ def hms(self, name):
337
+ try:
338
+ return self._hms[name.lower()]
339
+ except KeyError:
340
+ return None
341
+
342
+ def ampm(self, name):
343
+ try:
344
+ return self._ampm[name.lower()]
345
+ except KeyError:
346
+ return None
347
+
348
+ def pertain(self, name):
349
+ return name.lower() in self._pertain
350
+
351
+ def utczone(self, name):
352
+ return name.lower() in self._utczone
353
+
354
+ def tzoffset(self, name):
355
+ if name in self._utczone:
356
+ return 0
357
+
358
+ return self.TZOFFSET.get(name)
359
+
360
+ def convertyear(self, year, century_specified=False):
361
+ """
362
+ Converts two-digit years to year within [-50, 49]
363
+ range of self._year (current local time)
364
+ """
365
+
366
+ # Function contract is that the year is always positive
367
+ assert year >= 0
368
+
369
+ if year < 100 and not century_specified:
370
+ # assume current century to start
371
+ year += self._century
372
+
373
+ if year >= self._year + 50: # if too far in future
374
+ year -= 100
375
+ elif year < self._year - 50: # if too far in past
376
+ year += 100
377
+
378
+ return year
379
+
380
+ def validate(self, res):
381
+ # move to info
382
+ if res.year is not None:
383
+ res.year = self.convertyear(res.year, res.century_specified)
384
+
385
+ if ((res.tzoffset == 0 and not res.tzname) or
386
+ (res.tzname == 'Z' or res.tzname == 'z')):
387
+ res.tzname = "UTC"
388
+ res.tzoffset = 0
389
+ elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname):
390
+ res.tzoffset = 0
391
+ return True
392
+
393
+
394
+ class _ymd(list):
395
+ def __init__(self, *args, **kwargs):
396
+ super(self.__class__, self).__init__(*args, **kwargs)
397
+ self.century_specified = False
398
+ self.dstridx = None
399
+ self.mstridx = None
400
+ self.ystridx = None
401
+
402
+ @property
403
+ def has_year(self):
404
+ return self.ystridx is not None
405
+
406
+ @property
407
+ def has_month(self):
408
+ return self.mstridx is not None
409
+
410
+ @property
411
+ def has_day(self):
412
+ return self.dstridx is not None
413
+
414
+ def could_be_day(self, value):
415
+ if self.has_day:
416
+ return False
417
+ elif not self.has_month:
418
+ return 1 <= value <= 31
419
+ elif not self.has_year:
420
+ # Be permissive, assume leap year
421
+ month = self[self.mstridx]
422
+ return 1 <= value <= monthrange(2000, month)[1]
423
+ else:
424
+ month = self[self.mstridx]
425
+ year = self[self.ystridx]
426
+ return 1 <= value <= monthrange(year, month)[1]
427
+
428
+ def append(self, val, label=None):
429
+ if hasattr(val, '__len__'):
430
+ if val.isdigit() and len(val) > 2:
431
+ self.century_specified = True
432
+ if label not in [None, 'Y']: # pragma: no cover
433
+ raise ValueError(label)
434
+ label = 'Y'
435
+ elif val > 100:
436
+ self.century_specified = True
437
+ if label not in [None, 'Y']: # pragma: no cover
438
+ raise ValueError(label)
439
+ label = 'Y'
440
+
441
+ super(self.__class__, self).append(int(val))
442
+
443
+ if label == 'M':
444
+ if self.has_month:
445
+ raise ValueError('Month is already set')
446
+ self.mstridx = len(self) - 1
447
+ elif label == 'D':
448
+ if self.has_day:
449
+ raise ValueError('Day is already set')
450
+ self.dstridx = len(self) - 1
451
+ elif label == 'Y':
452
+ if self.has_year:
453
+ raise ValueError('Year is already set')
454
+ self.ystridx = len(self) - 1
455
+
456
+ def _resolve_from_stridxs(self, strids):
457
+ """
458
+ Try to resolve the identities of year/month/day elements using
459
+ ystridx, mstridx, and dstridx, if enough of these are specified.
460
+ """
461
+ if len(self) == 3 and len(strids) == 2:
462
+ # we can back out the remaining stridx value
463
+ missing = [x for x in range(3) if x not in strids.values()]
464
+ key = [x for x in ['y', 'm', 'd'] if x not in strids]
465
+ assert len(missing) == len(key) == 1
466
+ key = key[0]
467
+ val = missing[0]
468
+ strids[key] = val
469
+
470
+ assert len(self) == len(strids) # otherwise this should not be called
471
+ out = {key: self[strids[key]] for key in strids}
472
+ return (out.get('y'), out.get('m'), out.get('d'))
473
+
474
+ def resolve_ymd(self, yearfirst, dayfirst):
475
+ len_ymd = len(self)
476
+ year, month, day = (None, None, None)
477
+
478
+ strids = (('y', self.ystridx),
479
+ ('m', self.mstridx),
480
+ ('d', self.dstridx))
481
+
482
+ strids = {key: val for key, val in strids if val is not None}
483
+ if (len(self) == len(strids) > 0 or
484
+ (len(self) == 3 and len(strids) == 2)):
485
+ return self._resolve_from_stridxs(strids)
486
+
487
+ mstridx = self.mstridx
488
+
489
+ if len_ymd > 3:
490
+ raise ValueError("More than three YMD values")
491
+ elif len_ymd == 1 or (mstridx is not None and len_ymd == 2):
492
+ # One member, or two members with a month string
493
+ if mstridx is not None:
494
+ month = self[mstridx]
495
+ # since mstridx is 0 or 1, self[mstridx-1] always
496
+ # looks up the other element
497
+ other = self[mstridx - 1]
498
+ else:
499
+ other = self[0]
500
+
501
+ if len_ymd > 1 or mstridx is None:
502
+ if other > 31:
503
+ year = other
504
+ else:
505
+ day = other
506
+
507
+ elif len_ymd == 2:
508
+ # Two members with numbers
509
+ if self[0] > 31:
510
+ # 99-01
511
+ year, month = self
512
+ elif self[1] > 31:
513
+ # 01-99
514
+ month, year = self
515
+ elif dayfirst and self[1] <= 12:
516
+ # 13-01
517
+ day, month = self
518
+ else:
519
+ # 01-13
520
+ month, day = self
521
+
522
+ elif len_ymd == 3:
523
+ # Three members
524
+ if mstridx == 0:
525
+ if self[1] > 31:
526
+ # Apr-2003-25
527
+ month, year, day = self
528
+ else:
529
+ month, day, year = self
530
+ elif mstridx == 1:
531
+ if self[0] > 31 or (yearfirst and self[2] <= 31):
532
+ # 99-Jan-01
533
+ year, month, day = self
534
+ else:
535
+ # 01-Jan-01
536
+ # Give precedence to day-first, since
537
+ # two-digit years is usually hand-written.
538
+ day, month, year = self
539
+
540
+ elif mstridx == 2:
541
+ # WTF!?
542
+ if self[1] > 31:
543
+ # 01-99-Jan
544
+ day, year, month = self
545
+ else:
546
+ # 99-01-Jan
547
+ year, day, month = self
548
+
549
+ else:
550
+ if (self[0] > 31 or
551
+ self.ystridx == 0 or
552
+ (yearfirst and self[1] <= 12 and self[2] <= 31)):
553
+ # 99-01-01
554
+ if dayfirst and self[2] <= 12:
555
+ year, day, month = self
556
+ else:
557
+ year, month, day = self
558
+ elif self[0] > 12 or (dayfirst and self[1] <= 12):
559
+ # 13-01-01
560
+ day, month, year = self
561
+ else:
562
+ # 01-13-01
563
+ month, day, year = self
564
+
565
+ return year, month, day
566
+
567
+
568
+ class parser(object):
569
+ def __init__(self, info=None):
570
+ self.info = info or parserinfo()
571
+
572
+ def parse(self, timestr, default=None,
573
+ ignoretz=False, tzinfos=None, **kwargs):
574
+ """
575
+ Parse the date/time string into a :class:`datetime.datetime` object.
576
+
577
+ :param timestr:
578
+ Any date/time string using the supported formats.
579
+
580
+ :param default:
581
+ The default datetime object, if this is a datetime object and not
582
+ ``None``, elements specified in ``timestr`` replace elements in the
583
+ default object.
584
+
585
+ :param ignoretz:
586
+ If set ``True``, time zones in parsed strings are ignored and a
587
+ naive :class:`datetime.datetime` object is returned.
588
+
589
+ :param tzinfos:
590
+ Additional time zone names / aliases which may be present in the
591
+ string. This argument maps time zone names (and optionally offsets
592
+ from those time zones) to time zones. This parameter can be a
593
+ dictionary with timezone aliases mapping time zone names to time
594
+ zones or a function taking two parameters (``tzname`` and
595
+ ``tzoffset``) and returning a time zone.
596
+
597
+ The timezones to which the names are mapped can be an integer
598
+ offset from UTC in seconds or a :class:`tzinfo` object.
599
+
600
+ .. doctest::
601
+ :options: +NORMALIZE_WHITESPACE
602
+
603
+ >>> from dateutil.parser import parse
604
+ >>> from dateutil.tz import gettz
605
+ >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
606
+ >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
607
+ datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
608
+ >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
609
+ datetime.datetime(2012, 1, 19, 17, 21,
610
+ tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
611
+
612
+ This parameter is ignored if ``ignoretz`` is set.
613
+
614
+ :param \\*\\*kwargs:
615
+ Keyword arguments as passed to ``_parse()``.
616
+
617
+ :return:
618
+ Returns a :class:`datetime.datetime` object or, if the
619
+ ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
620
+ first element being a :class:`datetime.datetime` object, the second
621
+ a tuple containing the fuzzy tokens.
622
+
623
+ :raises ParserError:
624
+ Raised for invalid or unknown string format, if the provided
625
+ :class:`tzinfo` is not in a valid format, or if an invalid date
626
+ would be created.
627
+
628
+ :raises TypeError:
629
+ Raised for non-string or character stream input.
630
+
631
+ :raises OverflowError:
632
+ Raised if the parsed date exceeds the largest valid C integer on
633
+ your system.
634
+ """
635
+
636
+ if default is None:
637
+ default = datetime.datetime.now().replace(hour=0, minute=0,
638
+ second=0, microsecond=0)
639
+
640
+ res, skipped_tokens = self._parse(timestr, **kwargs)
641
+
642
+ if res is None:
643
+ raise ParserError("Unknown string format: %s", timestr)
644
+
645
+ if len(res) == 0:
646
+ raise ParserError("String does not contain a date: %s", timestr)
647
+
648
+ try:
649
+ ret = self._build_naive(res, default)
650
+ except ValueError as e:
651
+ six.raise_from(ParserError(str(e) + ": %s", timestr), e)
652
+
653
+ if not ignoretz:
654
+ ret = self._build_tzaware(ret, res, tzinfos)
655
+
656
+ if kwargs.get('fuzzy_with_tokens', False):
657
+ return ret, skipped_tokens
658
+ else:
659
+ return ret
660
+
661
+ class _result(_resultbase):
662
+ __slots__ = ["year", "month", "day", "weekday",
663
+ "hour", "minute", "second", "microsecond",
664
+ "tzname", "tzoffset", "ampm","any_unused_tokens"]
665
+
666
+ def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,
667
+ fuzzy_with_tokens=False):
668
+ """
669
+ Private method which performs the heavy lifting of parsing, called from
670
+ ``parse()``, which passes on its ``kwargs`` to this function.
671
+
672
+ :param timestr:
673
+ The string to parse.
674
+
675
+ :param dayfirst:
676
+ Whether to interpret the first value in an ambiguous 3-integer date
677
+ (e.g. 01/05/09) as the day (``True``) or month (``False``). If
678
+ ``yearfirst`` is set to ``True``, this distinguishes between YDM
679
+ and YMD. If set to ``None``, this value is retrieved from the
680
+ current :class:`parserinfo` object (which itself defaults to
681
+ ``False``).
682
+
683
+ :param yearfirst:
684
+ Whether to interpret the first value in an ambiguous 3-integer date
685
+ (e.g. 01/05/09) as the year. If ``True``, the first number is taken
686
+ to be the year, otherwise the last number is taken to be the year.
687
+ If this is set to ``None``, the value is retrieved from the current
688
+ :class:`parserinfo` object (which itself defaults to ``False``).
689
+
690
+ :param fuzzy:
691
+ Whether to allow fuzzy parsing, allowing for string like "Today is
692
+ January 1, 2047 at 8:21:00AM".
693
+
694
+ :param fuzzy_with_tokens:
695
+ If ``True``, ``fuzzy`` is automatically set to True, and the parser
696
+ will return a tuple where the first element is the parsed
697
+ :class:`datetime.datetime` datetimestamp and the second element is
698
+ a tuple containing the portions of the string which were ignored:
699
+
700
+ .. doctest::
701
+
702
+ >>> from dateutil.parser import parse
703
+ >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
704
+ (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
705
+
706
+ """
707
+ if fuzzy_with_tokens:
708
+ fuzzy = True
709
+
710
+ info = self.info
711
+
712
+ if dayfirst is None:
713
+ dayfirst = info.dayfirst
714
+
715
+ if yearfirst is None:
716
+ yearfirst = info.yearfirst
717
+
718
+ res = self._result()
719
+ l = _timelex.split(timestr) # Splits the timestr into tokens
720
+
721
+ skipped_idxs = []
722
+
723
+ # year/month/day list
724
+ ymd = _ymd()
725
+
726
+ len_l = len(l)
727
+ i = 0
728
+ try:
729
+ while i < len_l:
730
+
731
+ # Check if it's a number
732
+ value_repr = l[i]
733
+ try:
734
+ value = float(value_repr)
735
+ except ValueError:
736
+ value = None
737
+
738
+ if value is not None:
739
+ # Numeric token
740
+ i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy)
741
+
742
+ # Check weekday
743
+ elif info.weekday(l[i]) is not None:
744
+ value = info.weekday(l[i])
745
+ res.weekday = value
746
+
747
+ # Check month name
748
+ elif info.month(l[i]) is not None:
749
+ value = info.month(l[i])
750
+ ymd.append(value, 'M')
751
+
752
+ if i + 1 < len_l:
753
+ if l[i + 1] in ('-', '/'):
754
+ # Jan-01[-99]
755
+ sep = l[i + 1]
756
+ ymd.append(l[i + 2])
757
+
758
+ if i + 3 < len_l and l[i + 3] == sep:
759
+ # Jan-01-99
760
+ ymd.append(l[i + 4])
761
+ i += 2
762
+
763
+ i += 2
764
+
765
+ elif (i + 4 < len_l and l[i + 1] == l[i + 3] == ' ' and
766
+ info.pertain(l[i + 2])):
767
+ # Jan of 01
768
+ # In this case, 01 is clearly year
769
+ if l[i + 4].isdigit():
770
+ # Convert it here to become unambiguous
771
+ value = int(l[i + 4])
772
+ year = str(info.convertyear(value))
773
+ ymd.append(year, 'Y')
774
+ else:
775
+ # Wrong guess
776
+ pass
777
+ # TODO: not hit in tests
778
+ i += 4
779
+
780
+ # Check am/pm
781
+ elif info.ampm(l[i]) is not None:
782
+ value = info.ampm(l[i])
783
+ val_is_ampm = self._ampm_valid(res.hour, res.ampm, fuzzy)
784
+
785
+ if val_is_ampm:
786
+ res.hour = self._adjust_ampm(res.hour, value)
787
+ res.ampm = value
788
+
789
+ elif fuzzy:
790
+ skipped_idxs.append(i)
791
+
792
+ # Check for a timezone name
793
+ elif self._could_be_tzname(res.hour, res.tzname, res.tzoffset, l[i]):
794
+ res.tzname = l[i]
795
+ res.tzoffset = info.tzoffset(res.tzname)
796
+
797
+ # Check for something like GMT+3, or BRST+3. Notice
798
+ # that it doesn't mean "I am 3 hours after GMT", but
799
+ # "my time +3 is GMT". If found, we reverse the
800
+ # logic so that timezone parsing code will get it
801
+ # right.
802
+ if i + 1 < len_l and l[i + 1] in ('+', '-'):
803
+ l[i + 1] = ('+', '-')[l[i + 1] == '+']
804
+ res.tzoffset = None
805
+ if info.utczone(res.tzname):
806
+ # With something like GMT+3, the timezone
807
+ # is *not* GMT.
808
+ res.tzname = None
809
+
810
+ # Check for a numbered timezone
811
+ elif res.hour is not None and l[i] in ('+', '-'):
812
+ signal = (-1, 1)[l[i] == '+']
813
+ len_li = len(l[i + 1])
814
+
815
+ # TODO: check that l[i + 1] is integer?
816
+ if len_li == 4:
817
+ # -0300
818
+ hour_offset = int(l[i + 1][:2])
819
+ min_offset = int(l[i + 1][2:])
820
+ elif i + 2 < len_l and l[i + 2] == ':':
821
+ # -03:00
822
+ hour_offset = int(l[i + 1])
823
+ min_offset = int(l[i + 3]) # TODO: Check that l[i+3] is minute-like?
824
+ i += 2
825
+ elif len_li <= 2:
826
+ # -[0]3
827
+ hour_offset = int(l[i + 1][:2])
828
+ min_offset = 0
829
+ else:
830
+ raise ValueError(timestr)
831
+
832
+ res.tzoffset = signal * (hour_offset * 3600 + min_offset * 60)
833
+
834
+ # Look for a timezone name between parenthesis
835
+ if (i + 5 < len_l and
836
+ info.jump(l[i + 2]) and l[i + 3] == '(' and
837
+ l[i + 5] == ')' and
838
+ 3 <= len(l[i + 4]) and
839
+ self._could_be_tzname(res.hour, res.tzname,
840
+ None, l[i + 4])):
841
+ # -0300 (BRST)
842
+ res.tzname = l[i + 4]
843
+ i += 4
844
+
845
+ i += 1
846
+
847
+ # Check jumps
848
+ elif not (info.jump(l[i]) or fuzzy):
849
+ raise ValueError(timestr)
850
+
851
+ else:
852
+ skipped_idxs.append(i)
853
+ i += 1
854
+
855
+ # Process year/month/day
856
+ year, month, day = ymd.resolve_ymd(yearfirst, dayfirst)
857
+
858
+ res.century_specified = ymd.century_specified
859
+ res.year = year
860
+ res.month = month
861
+ res.day = day
862
+
863
+ except (IndexError, ValueError):
864
+ return None, None
865
+
866
+ if not info.validate(res):
867
+ return None, None
868
+
869
+ if fuzzy_with_tokens:
870
+ skipped_tokens = self._recombine_skipped(l, skipped_idxs)
871
+ return res, tuple(skipped_tokens)
872
+ else:
873
+ return res, None
874
+
875
+ def _parse_numeric_token(self, tokens, idx, info, ymd, res, fuzzy):
876
+ # Token is a number
877
+ value_repr = tokens[idx]
878
+ try:
879
+ value = self._to_decimal(value_repr)
880
+ except Exception as e:
881
+ six.raise_from(ValueError('Unknown numeric token'), e)
882
+
883
+ len_li = len(value_repr)
884
+
885
+ len_l = len(tokens)
886
+
887
+ if (len(ymd) == 3 and len_li in (2, 4) and
888
+ res.hour is None and
889
+ (idx + 1 >= len_l or
890
+ (tokens[idx + 1] != ':' and
891
+ info.hms(tokens[idx + 1]) is None))):
892
+ # 19990101T23[59]
893
+ s = tokens[idx]
894
+ res.hour = int(s[:2])
895
+
896
+ if len_li == 4:
897
+ res.minute = int(s[2:])
898
+
899
+ elif len_li == 6 or (len_li > 6 and tokens[idx].find('.') == 6):
900
+ # YYMMDD or HHMMSS[.ss]
901
+ s = tokens[idx]
902
+
903
+ if not ymd and '.' not in tokens[idx]:
904
+ ymd.append(s[:2])
905
+ ymd.append(s[2:4])
906
+ ymd.append(s[4:])
907
+ else:
908
+ # 19990101T235959[.59]
909
+
910
+ # TODO: Check if res attributes already set.
911
+ res.hour = int(s[:2])
912
+ res.minute = int(s[2:4])
913
+ res.second, res.microsecond = self._parsems(s[4:])
914
+
915
+ elif len_li in (8, 12, 14):
916
+ # YYYYMMDD
917
+ s = tokens[idx]
918
+ ymd.append(s[:4], 'Y')
919
+ ymd.append(s[4:6])
920
+ ymd.append(s[6:8])
921
+
922
+ if len_li > 8:
923
+ res.hour = int(s[8:10])
924
+ res.minute = int(s[10:12])
925
+
926
+ if len_li > 12:
927
+ res.second = int(s[12:])
928
+
929
+ elif self._find_hms_idx(idx, tokens, info, allow_jump=True) is not None:
930
+ # HH[ ]h or MM[ ]m or SS[.ss][ ]s
931
+ hms_idx = self._find_hms_idx(idx, tokens, info, allow_jump=True)
932
+ (idx, hms) = self._parse_hms(idx, tokens, info, hms_idx)
933
+ if hms is not None:
934
+ # TODO: checking that hour/minute/second are not
935
+ # already set?
936
+ self._assign_hms(res, value_repr, hms)
937
+
938
+ elif idx + 2 < len_l and tokens[idx + 1] == ':':
939
+ # HH:MM[:SS[.ss]]
940
+ res.hour = int(value)
941
+ value = self._to_decimal(tokens[idx + 2]) # TODO: try/except for this?
942
+ (res.minute, res.second) = self._parse_min_sec(value)
943
+
944
+ if idx + 4 < len_l and tokens[idx + 3] == ':':
945
+ res.second, res.microsecond = self._parsems(tokens[idx + 4])
946
+
947
+ idx += 2
948
+
949
+ idx += 2
950
+
951
+ elif idx + 1 < len_l and tokens[idx + 1] in ('-', '/', '.'):
952
+ sep = tokens[idx + 1]
953
+ ymd.append(value_repr)
954
+
955
+ if idx + 2 < len_l and not info.jump(tokens[idx + 2]):
956
+ if tokens[idx + 2].isdigit():
957
+ # 01-01[-01]
958
+ ymd.append(tokens[idx + 2])
959
+ else:
960
+ # 01-Jan[-01]
961
+ value = info.month(tokens[idx + 2])
962
+
963
+ if value is not None:
964
+ ymd.append(value, 'M')
965
+ else:
966
+ raise ValueError()
967
+
968
+ if idx + 3 < len_l and tokens[idx + 3] == sep:
969
+ # We have three members
970
+ value = info.month(tokens[idx + 4])
971
+
972
+ if value is not None:
973
+ ymd.append(value, 'M')
974
+ else:
975
+ ymd.append(tokens[idx + 4])
976
+ idx += 2
977
+
978
+ idx += 1
979
+ idx += 1
980
+
981
+ elif idx + 1 >= len_l or info.jump(tokens[idx + 1]):
982
+ if idx + 2 < len_l and info.ampm(tokens[idx + 2]) is not None:
983
+ # 12 am
984
+ hour = int(value)
985
+ res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 2]))
986
+ idx += 1
987
+ else:
988
+ # Year, month or day
989
+ ymd.append(value)
990
+ idx += 1
991
+
992
+ elif info.ampm(tokens[idx + 1]) is not None and (0 <= value < 24):
993
+ # 12am
994
+ hour = int(value)
995
+ res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 1]))
996
+ idx += 1
997
+
998
+ elif ymd.could_be_day(value):
999
+ ymd.append(value)
1000
+
1001
+ elif not fuzzy:
1002
+ raise ValueError()
1003
+
1004
+ return idx
1005
+
1006
+ def _find_hms_idx(self, idx, tokens, info, allow_jump):
1007
+ len_l = len(tokens)
1008
+
1009
+ if idx+1 < len_l and info.hms(tokens[idx+1]) is not None:
1010
+ # There is an "h", "m", or "s" label following this token. We take
1011
+ # assign the upcoming label to the current token.
1012
+ # e.g. the "12" in 12h"
1013
+ hms_idx = idx + 1
1014
+
1015
+ elif (allow_jump and idx+2 < len_l and tokens[idx+1] == ' ' and
1016
+ info.hms(tokens[idx+2]) is not None):
1017
+ # There is a space and then an "h", "m", or "s" label.
1018
+ # e.g. the "12" in "12 h"
1019
+ hms_idx = idx + 2
1020
+
1021
+ elif idx > 0 and info.hms(tokens[idx-1]) is not None:
1022
+ # There is a "h", "m", or "s" preceding this token. Since neither
1023
+ # of the previous cases was hit, there is no label following this
1024
+ # token, so we use the previous label.
1025
+ # e.g. the "04" in "12h04"
1026
+ hms_idx = idx-1
1027
+
1028
+ elif (1 < idx == len_l-1 and tokens[idx-1] == ' ' and
1029
+ info.hms(tokens[idx-2]) is not None):
1030
+ # If we are looking at the final token, we allow for a
1031
+ # backward-looking check to skip over a space.
1032
+ # TODO: Are we sure this is the right condition here?
1033
+ hms_idx = idx - 2
1034
+
1035
+ else:
1036
+ hms_idx = None
1037
+
1038
+ return hms_idx
1039
+
1040
+ def _assign_hms(self, res, value_repr, hms):
1041
+ # See GH issue #427, fixing float rounding
1042
+ value = self._to_decimal(value_repr)
1043
+
1044
+ if hms == 0:
1045
+ # Hour
1046
+ res.hour = int(value)
1047
+ if value % 1:
1048
+ res.minute = int(60*(value % 1))
1049
+
1050
+ elif hms == 1:
1051
+ (res.minute, res.second) = self._parse_min_sec(value)
1052
+
1053
+ elif hms == 2:
1054
+ (res.second, res.microsecond) = self._parsems(value_repr)
1055
+
1056
+ def _could_be_tzname(self, hour, tzname, tzoffset, token):
1057
+ return (hour is not None and
1058
+ tzname is None and
1059
+ tzoffset is None and
1060
+ len(token) <= 5 and
1061
+ (all(x in string.ascii_uppercase for x in token)
1062
+ or token in self.info.UTCZONE))
1063
+
1064
+ def _ampm_valid(self, hour, ampm, fuzzy):
1065
+ """
1066
+ For fuzzy parsing, 'a' or 'am' (both valid English words)
1067
+ may erroneously trigger the AM/PM flag. Deal with that
1068
+ here.
1069
+ """
1070
+ val_is_ampm = True
1071
+
1072
+ # If there's already an AM/PM flag, this one isn't one.
1073
+ if fuzzy and ampm is not None:
1074
+ val_is_ampm = False
1075
+
1076
+ # If AM/PM is found and hour is not, raise a ValueError
1077
+ if hour is None:
1078
+ if fuzzy:
1079
+ val_is_ampm = False
1080
+ else:
1081
+ raise ValueError('No hour specified with AM or PM flag.')
1082
+ elif not 0 <= hour <= 12:
1083
+ # If AM/PM is found, it's a 12 hour clock, so raise
1084
+ # an error for invalid range
1085
+ if fuzzy:
1086
+ val_is_ampm = False
1087
+ else:
1088
+ raise ValueError('Invalid hour specified for 12-hour clock.')
1089
+
1090
+ return val_is_ampm
1091
+
1092
+ def _adjust_ampm(self, hour, ampm):
1093
+ if hour < 12 and ampm == 1:
1094
+ hour += 12
1095
+ elif hour == 12 and ampm == 0:
1096
+ hour = 0
1097
+ return hour
1098
+
1099
+ def _parse_min_sec(self, value):
1100
+ # TODO: Every usage of this function sets res.second to the return
1101
+ # value. Are there any cases where second will be returned as None and
1102
+ # we *don't* want to set res.second = None?
1103
+ minute = int(value)
1104
+ second = None
1105
+
1106
+ sec_remainder = value % 1
1107
+ if sec_remainder:
1108
+ second = int(60 * sec_remainder)
1109
+ return (minute, second)
1110
+
1111
+ def _parse_hms(self, idx, tokens, info, hms_idx):
1112
+ # TODO: Is this going to admit a lot of false-positives for when we
1113
+ # just happen to have digits and "h", "m" or "s" characters in non-date
1114
+ # text? I guess hex hashes won't have that problem, but there's plenty
1115
+ # of random junk out there.
1116
+ if hms_idx is None:
1117
+ hms = None
1118
+ new_idx = idx
1119
+ elif hms_idx > idx:
1120
+ hms = info.hms(tokens[hms_idx])
1121
+ new_idx = hms_idx
1122
+ else:
1123
+ # Looking backwards, increment one.
1124
+ hms = info.hms(tokens[hms_idx]) + 1
1125
+ new_idx = idx
1126
+
1127
+ return (new_idx, hms)
1128
+
1129
+ # ------------------------------------------------------------------
1130
+ # Handling for individual tokens. These are kept as methods instead
1131
+ # of functions for the sake of customizability via subclassing.
1132
+
1133
+ def _parsems(self, value):
1134
+ """Parse a I[.F] seconds value into (seconds, microseconds)."""
1135
+ if "." not in value:
1136
+ return int(value), 0
1137
+ else:
1138
+ i, f = value.split(".")
1139
+ return int(i), int(f.ljust(6, "0")[:6])
1140
+
1141
+ def _to_decimal(self, val):
1142
+ try:
1143
+ decimal_value = Decimal(val)
1144
+ # See GH 662, edge case, infinite value should not be converted
1145
+ # via `_to_decimal`
1146
+ if not decimal_value.is_finite():
1147
+ raise ValueError("Converted decimal value is infinite or NaN")
1148
+ except Exception as e:
1149
+ msg = "Could not convert %s to decimal" % val
1150
+ six.raise_from(ValueError(msg), e)
1151
+ else:
1152
+ return decimal_value
1153
+
1154
+ # ------------------------------------------------------------------
1155
+ # Post-Parsing construction of datetime output. These are kept as
1156
+ # methods instead of functions for the sake of customizability via
1157
+ # subclassing.
1158
+
1159
+ def _build_tzinfo(self, tzinfos, tzname, tzoffset):
1160
+ if callable(tzinfos):
1161
+ tzdata = tzinfos(tzname, tzoffset)
1162
+ else:
1163
+ tzdata = tzinfos.get(tzname)
1164
+ # handle case where tzinfo is paased an options that returns None
1165
+ # eg tzinfos = {'BRST' : None}
1166
+ if isinstance(tzdata, datetime.tzinfo) or tzdata is None:
1167
+ tzinfo = tzdata
1168
+ elif isinstance(tzdata, text_type):
1169
+ tzinfo = tz.tzstr(tzdata)
1170
+ elif isinstance(tzdata, integer_types):
1171
+ tzinfo = tz.tzoffset(tzname, tzdata)
1172
+ else:
1173
+ raise TypeError("Offset must be tzinfo subclass, tz string, "
1174
+ "or int offset.")
1175
+ return tzinfo
1176
+
1177
+ def _build_tzaware(self, naive, res, tzinfos):
1178
+ if (callable(tzinfos) or (tzinfos and res.tzname in tzinfos)):
1179
+ tzinfo = self._build_tzinfo(tzinfos, res.tzname, res.tzoffset)
1180
+ aware = naive.replace(tzinfo=tzinfo)
1181
+ aware = self._assign_tzname(aware, res.tzname)
1182
+
1183
+ elif res.tzname and res.tzname in time.tzname:
1184
+ aware = naive.replace(tzinfo=tz.tzlocal())
1185
+
1186
+ # Handle ambiguous local datetime
1187
+ aware = self._assign_tzname(aware, res.tzname)
1188
+
1189
+ # This is mostly relevant for winter GMT zones parsed in the UK
1190
+ if (aware.tzname() != res.tzname and
1191
+ res.tzname in self.info.UTCZONE):
1192
+ aware = aware.replace(tzinfo=tz.UTC)
1193
+
1194
+ elif res.tzoffset == 0:
1195
+ aware = naive.replace(tzinfo=tz.UTC)
1196
+
1197
+ elif res.tzoffset:
1198
+ aware = naive.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
1199
+
1200
+ elif not res.tzname and not res.tzoffset:
1201
+ # i.e. no timezone information was found.
1202
+ aware = naive
1203
+
1204
+ elif res.tzname:
1205
+ # tz-like string was parsed but we don't know what to do
1206
+ # with it
1207
+ warnings.warn("tzname {tzname} identified but not understood. "
1208
+ "Pass `tzinfos` argument in order to correctly "
1209
+ "return a timezone-aware datetime. In a future "
1210
+ "version, this will raise an "
1211
+ "exception.".format(tzname=res.tzname),
1212
+ category=UnknownTimezoneWarning)
1213
+ aware = naive
1214
+
1215
+ return aware
1216
+
1217
+ def _build_naive(self, res, default):
1218
+ repl = {}
1219
+ for attr in ("year", "month", "day", "hour",
1220
+ "minute", "second", "microsecond"):
1221
+ value = getattr(res, attr)
1222
+ if value is not None:
1223
+ repl[attr] = value
1224
+
1225
+ if 'day' not in repl:
1226
+ # If the default day exceeds the last day of the month, fall back
1227
+ # to the end of the month.
1228
+ cyear = default.year if res.year is None else res.year
1229
+ cmonth = default.month if res.month is None else res.month
1230
+ cday = default.day if res.day is None else res.day
1231
+
1232
+ if cday > monthrange(cyear, cmonth)[1]:
1233
+ repl['day'] = monthrange(cyear, cmonth)[1]
1234
+
1235
+ naive = default.replace(**repl)
1236
+
1237
+ if res.weekday is not None and not res.day:
1238
+ naive = naive + relativedelta.relativedelta(weekday=res.weekday)
1239
+
1240
+ return naive
1241
+
1242
+ def _assign_tzname(self, dt, tzname):
1243
+ if dt.tzname() != tzname:
1244
+ new_dt = tz.enfold(dt, fold=1)
1245
+ if new_dt.tzname() == tzname:
1246
+ return new_dt
1247
+
1248
+ return dt
1249
+
1250
+ def _recombine_skipped(self, tokens, skipped_idxs):
1251
+ """
1252
+ >>> tokens = ["foo", " ", "bar", " ", "19June2000", "baz"]
1253
+ >>> skipped_idxs = [0, 1, 2, 5]
1254
+ >>> _recombine_skipped(tokens, skipped_idxs)
1255
+ ["foo bar", "baz"]
1256
+ """
1257
+ skipped_tokens = []
1258
+ for i, idx in enumerate(sorted(skipped_idxs)):
1259
+ if i > 0 and idx - 1 == skipped_idxs[i - 1]:
1260
+ skipped_tokens[-1] = skipped_tokens[-1] + tokens[idx]
1261
+ else:
1262
+ skipped_tokens.append(tokens[idx])
1263
+
1264
+ return skipped_tokens
1265
+
1266
+
1267
+ DEFAULTPARSER = parser()
1268
+
1269
+
1270
+ def parse(timestr, parserinfo=None, **kwargs):
1271
+ """
1272
+
1273
+ Parse a string in one of the supported formats, using the
1274
+ ``parserinfo`` parameters.
1275
+
1276
+ :param timestr:
1277
+ A string containing a date/time stamp.
1278
+
1279
+ :param parserinfo:
1280
+ A :class:`parserinfo` object containing parameters for the parser.
1281
+ If ``None``, the default arguments to the :class:`parserinfo`
1282
+ constructor are used.
1283
+
1284
+ The ``**kwargs`` parameter takes the following keyword arguments:
1285
+
1286
+ :param default:
1287
+ The default datetime object, if this is a datetime object and not
1288
+ ``None``, elements specified in ``timestr`` replace elements in the
1289
+ default object.
1290
+
1291
+ :param ignoretz:
1292
+ If set ``True``, time zones in parsed strings are ignored and a naive
1293
+ :class:`datetime` object is returned.
1294
+
1295
+ :param tzinfos:
1296
+ Additional time zone names / aliases which may be present in the
1297
+ string. This argument maps time zone names (and optionally offsets
1298
+ from those time zones) to time zones. This parameter can be a
1299
+ dictionary with timezone aliases mapping time zone names to time
1300
+ zones or a function taking two parameters (``tzname`` and
1301
+ ``tzoffset``) and returning a time zone.
1302
+
1303
+ The timezones to which the names are mapped can be an integer
1304
+ offset from UTC in seconds or a :class:`tzinfo` object.
1305
+
1306
+ .. doctest::
1307
+ :options: +NORMALIZE_WHITESPACE
1308
+
1309
+ >>> from dateutil.parser import parse
1310
+ >>> from dateutil.tz import gettz
1311
+ >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
1312
+ >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
1313
+ datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
1314
+ >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
1315
+ datetime.datetime(2012, 1, 19, 17, 21,
1316
+ tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
1317
+
1318
+ This parameter is ignored if ``ignoretz`` is set.
1319
+
1320
+ :param dayfirst:
1321
+ Whether to interpret the first value in an ambiguous 3-integer date
1322
+ (e.g. 01/05/09) as the day (``True``) or month (``False``). If
1323
+ ``yearfirst`` is set to ``True``, this distinguishes between YDM and
1324
+ YMD. If set to ``None``, this value is retrieved from the current
1325
+ :class:`parserinfo` object (which itself defaults to ``False``).
1326
+
1327
+ :param yearfirst:
1328
+ Whether to interpret the first value in an ambiguous 3-integer date
1329
+ (e.g. 01/05/09) as the year. If ``True``, the first number is taken to
1330
+ be the year, otherwise the last number is taken to be the year. If
1331
+ this is set to ``None``, the value is retrieved from the current
1332
+ :class:`parserinfo` object (which itself defaults to ``False``).
1333
+
1334
+ :param fuzzy:
1335
+ Whether to allow fuzzy parsing, allowing for string like "Today is
1336
+ January 1, 2047 at 8:21:00AM".
1337
+
1338
+ :param fuzzy_with_tokens:
1339
+ If ``True``, ``fuzzy`` is automatically set to True, and the parser
1340
+ will return a tuple where the first element is the parsed
1341
+ :class:`datetime.datetime` datetimestamp and the second element is
1342
+ a tuple containing the portions of the string which were ignored:
1343
+
1344
+ .. doctest::
1345
+
1346
+ >>> from dateutil.parser import parse
1347
+ >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
1348
+ (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
1349
+
1350
+ :return:
1351
+ Returns a :class:`datetime.datetime` object or, if the
1352
+ ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
1353
+ first element being a :class:`datetime.datetime` object, the second
1354
+ a tuple containing the fuzzy tokens.
1355
+
1356
+ :raises ParserError:
1357
+ Raised for invalid or unknown string formats, if the provided
1358
+ :class:`tzinfo` is not in a valid format, or if an invalid date would
1359
+ be created.
1360
+
1361
+ :raises OverflowError:
1362
+ Raised if the parsed date exceeds the largest valid C integer on
1363
+ your system.
1364
+ """
1365
+ if parserinfo:
1366
+ return parser(parserinfo).parse(timestr, **kwargs)
1367
+ else:
1368
+ return DEFAULTPARSER.parse(timestr, **kwargs)
1369
+
1370
+
1371
+ class _tzparser(object):
1372
+
1373
+ class _result(_resultbase):
1374
+
1375
+ __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset",
1376
+ "start", "end"]
1377
+
1378
+ class _attr(_resultbase):
1379
+ __slots__ = ["month", "week", "weekday",
1380
+ "yday", "jyday", "day", "time"]
1381
+
1382
+ def __repr__(self):
1383
+ return self._repr("")
1384
+
1385
+ def __init__(self):
1386
+ _resultbase.__init__(self)
1387
+ self.start = self._attr()
1388
+ self.end = self._attr()
1389
+
1390
+ def parse(self, tzstr):
1391
+ res = self._result()
1392
+ l = [x for x in re.split(r'([,:.]|[a-zA-Z]+|[0-9]+)',tzstr) if x]
1393
+ used_idxs = list()
1394
+ try:
1395
+
1396
+ len_l = len(l)
1397
+
1398
+ i = 0
1399
+ while i < len_l:
1400
+ # BRST+3[BRDT[+2]]
1401
+ j = i
1402
+ while j < len_l and not [x for x in l[j]
1403
+ if x in "0123456789:,-+"]:
1404
+ j += 1
1405
+ if j != i:
1406
+ if not res.stdabbr:
1407
+ offattr = "stdoffset"
1408
+ res.stdabbr = "".join(l[i:j])
1409
+ else:
1410
+ offattr = "dstoffset"
1411
+ res.dstabbr = "".join(l[i:j])
1412
+
1413
+ for ii in range(j):
1414
+ used_idxs.append(ii)
1415
+ i = j
1416
+ if (i < len_l and (l[i] in ('+', '-') or l[i][0] in
1417
+ "0123456789")):
1418
+ if l[i] in ('+', '-'):
1419
+ # Yes, that's right. See the TZ variable
1420
+ # documentation.
1421
+ signal = (1, -1)[l[i] == '+']
1422
+ used_idxs.append(i)
1423
+ i += 1
1424
+ else:
1425
+ signal = -1
1426
+ len_li = len(l[i])
1427
+ if len_li == 4:
1428
+ # -0300
1429
+ setattr(res, offattr, (int(l[i][:2]) * 3600 +
1430
+ int(l[i][2:]) * 60) * signal)
1431
+ elif i + 1 < len_l and l[i + 1] == ':':
1432
+ # -03:00
1433
+ setattr(res, offattr,
1434
+ (int(l[i]) * 3600 +
1435
+ int(l[i + 2]) * 60) * signal)
1436
+ used_idxs.append(i)
1437
+ i += 2
1438
+ elif len_li <= 2:
1439
+ # -[0]3
1440
+ setattr(res, offattr,
1441
+ int(l[i][:2]) * 3600 * signal)
1442
+ else:
1443
+ return None
1444
+ used_idxs.append(i)
1445
+ i += 1
1446
+ if res.dstabbr:
1447
+ break
1448
+ else:
1449
+ break
1450
+
1451
+
1452
+ if i < len_l:
1453
+ for j in range(i, len_l):
1454
+ if l[j] == ';':
1455
+ l[j] = ','
1456
+
1457
+ assert l[i] == ','
1458
+
1459
+ i += 1
1460
+
1461
+ if i >= len_l:
1462
+ pass
1463
+ elif (8 <= l.count(',') <= 9 and
1464
+ not [y for x in l[i:] if x != ','
1465
+ for y in x if y not in "0123456789+-"]):
1466
+ # GMT0BST,3,0,30,3600,10,0,26,7200[,3600]
1467
+ for x in (res.start, res.end):
1468
+ x.month = int(l[i])
1469
+ used_idxs.append(i)
1470
+ i += 2
1471
+ if l[i] == '-':
1472
+ value = int(l[i + 1]) * -1
1473
+ used_idxs.append(i)
1474
+ i += 1
1475
+ else:
1476
+ value = int(l[i])
1477
+ used_idxs.append(i)
1478
+ i += 2
1479
+ if value:
1480
+ x.week = value
1481
+ x.weekday = (int(l[i]) - 1) % 7
1482
+ else:
1483
+ x.day = int(l[i])
1484
+ used_idxs.append(i)
1485
+ i += 2
1486
+ x.time = int(l[i])
1487
+ used_idxs.append(i)
1488
+ i += 2
1489
+ if i < len_l:
1490
+ if l[i] in ('-', '+'):
1491
+ signal = (-1, 1)[l[i] == "+"]
1492
+ used_idxs.append(i)
1493
+ i += 1
1494
+ else:
1495
+ signal = 1
1496
+ used_idxs.append(i)
1497
+ res.dstoffset = (res.stdoffset + int(l[i]) * signal)
1498
+
1499
+ # This was a made-up format that is not in normal use
1500
+ warn(('Parsed time zone "%s"' % tzstr) +
1501
+ 'is in a non-standard dateutil-specific format, which ' +
1502
+ 'is now deprecated; support for parsing this format ' +
1503
+ 'will be removed in future versions. It is recommended ' +
1504
+ 'that you switch to a standard format like the GNU ' +
1505
+ 'TZ variable format.', tz.DeprecatedTzFormatWarning)
1506
+ elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
1507
+ not [y for x in l[i:] if x not in (',', '/', 'J', 'M',
1508
+ '.', '-', ':')
1509
+ for y in x if y not in "0123456789"]):
1510
+ for x in (res.start, res.end):
1511
+ if l[i] == 'J':
1512
+ # non-leap year day (1 based)
1513
+ used_idxs.append(i)
1514
+ i += 1
1515
+ x.jyday = int(l[i])
1516
+ elif l[i] == 'M':
1517
+ # month[-.]week[-.]weekday
1518
+ used_idxs.append(i)
1519
+ i += 1
1520
+ x.month = int(l[i])
1521
+ used_idxs.append(i)
1522
+ i += 1
1523
+ assert l[i] in ('-', '.')
1524
+ used_idxs.append(i)
1525
+ i += 1
1526
+ x.week = int(l[i])
1527
+ if x.week == 5:
1528
+ x.week = -1
1529
+ used_idxs.append(i)
1530
+ i += 1
1531
+ assert l[i] in ('-', '.')
1532
+ used_idxs.append(i)
1533
+ i += 1
1534
+ x.weekday = (int(l[i]) - 1) % 7
1535
+ else:
1536
+ # year day (zero based)
1537
+ x.yday = int(l[i]) + 1
1538
+
1539
+ used_idxs.append(i)
1540
+ i += 1
1541
+
1542
+ if i < len_l and l[i] == '/':
1543
+ used_idxs.append(i)
1544
+ i += 1
1545
+ # start time
1546
+ len_li = len(l[i])
1547
+ if len_li == 4:
1548
+ # -0300
1549
+ x.time = (int(l[i][:2]) * 3600 +
1550
+ int(l[i][2:]) * 60)
1551
+ elif i + 1 < len_l and l[i + 1] == ':':
1552
+ # -03:00
1553
+ x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60
1554
+ used_idxs.append(i)
1555
+ i += 2
1556
+ if i + 1 < len_l and l[i + 1] == ':':
1557
+ used_idxs.append(i)
1558
+ i += 2
1559
+ x.time += int(l[i])
1560
+ elif len_li <= 2:
1561
+ # -[0]3
1562
+ x.time = (int(l[i][:2]) * 3600)
1563
+ else:
1564
+ return None
1565
+ used_idxs.append(i)
1566
+ i += 1
1567
+
1568
+ assert i == len_l or l[i] == ','
1569
+
1570
+ i += 1
1571
+
1572
+ assert i >= len_l
1573
+
1574
+ except (IndexError, ValueError, AssertionError):
1575
+ return None
1576
+
1577
+ unused_idxs = set(range(len_l)).difference(used_idxs)
1578
+ res.any_unused_tokens = not {l[n] for n in unused_idxs}.issubset({",",":"})
1579
+ return res
1580
+
1581
+
1582
+ DEFAULTTZPARSER = _tzparser()
1583
+
1584
+
1585
+ def _parsetz(tzstr):
1586
+ return DEFAULTTZPARSER.parse(tzstr)
1587
+
1588
+
1589
+ class ParserError(ValueError):
1590
+ """Exception subclass used for any failure to parse a datetime string.
1591
+
1592
+ This is a subclass of :py:exc:`ValueError`, and should be raised any time
1593
+ earlier versions of ``dateutil`` would have raised ``ValueError``.
1594
+
1595
+ .. versionadded:: 2.8.1
1596
+ """
1597
+ def __str__(self):
1598
+ try:
1599
+ return self.args[0] % self.args[1:]
1600
+ except (TypeError, IndexError):
1601
+ return super(ParserError, self).__str__()
1602
+
1603
+ def __repr__(self):
1604
+ args = ", ".join("'%s'" % arg for arg in self.args)
1605
+ return "%s(%s)" % (self.__class__.__name__, args)
1606
+
1607
+
1608
+ class UnknownTimezoneWarning(RuntimeWarning):
1609
+ """Raised when the parser finds a timezone it cannot parse into a tzinfo.
1610
+
1611
+ .. versionadded:: 2.7.0
1612
+ """
1613
+ # vim:ts=4:sw=4:et
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/parser/isoparser.py ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This module offers a parser for ISO-8601 strings
4
+
5
+ It is intended to support all valid date, time and datetime formats per the
6
+ ISO-8601 specification.
7
+
8
+ ..versionadded:: 2.7.0
9
+ """
10
+ from datetime import datetime, timedelta, time, date
11
+ import calendar
12
+ from dateutil import tz
13
+
14
+ from functools import wraps
15
+
16
+ import re
17
+ import six
18
+
19
+ __all__ = ["isoparse", "isoparser"]
20
+
21
+
22
+ def _takes_ascii(f):
23
+ @wraps(f)
24
+ def func(self, str_in, *args, **kwargs):
25
+ # If it's a stream, read the whole thing
26
+ str_in = getattr(str_in, 'read', lambda: str_in)()
27
+
28
+ # If it's unicode, turn it into bytes, since ISO-8601 only covers ASCII
29
+ if isinstance(str_in, six.text_type):
30
+ # ASCII is the same in UTF-8
31
+ try:
32
+ str_in = str_in.encode('ascii')
33
+ except UnicodeEncodeError as e:
34
+ msg = 'ISO-8601 strings should contain only ASCII characters'
35
+ six.raise_from(ValueError(msg), e)
36
+
37
+ return f(self, str_in, *args, **kwargs)
38
+
39
+ return func
40
+
41
+
42
+ class isoparser(object):
43
+ def __init__(self, sep=None):
44
+ """
45
+ :param sep:
46
+ A single character that separates date and time portions. If
47
+ ``None``, the parser will accept any single character.
48
+ For strict ISO-8601 adherence, pass ``'T'``.
49
+ """
50
+ if sep is not None:
51
+ if (len(sep) != 1 or ord(sep) >= 128 or sep in '0123456789'):
52
+ raise ValueError('Separator must be a single, non-numeric ' +
53
+ 'ASCII character')
54
+
55
+ sep = sep.encode('ascii')
56
+
57
+ self._sep = sep
58
+
59
+ @_takes_ascii
60
+ def isoparse(self, dt_str):
61
+ """
62
+ Parse an ISO-8601 datetime string into a :class:`datetime.datetime`.
63
+
64
+ An ISO-8601 datetime string consists of a date portion, followed
65
+ optionally by a time portion - the date and time portions are separated
66
+ by a single character separator, which is ``T`` in the official
67
+ standard. Incomplete date formats (such as ``YYYY-MM``) may *not* be
68
+ combined with a time portion.
69
+
70
+ Supported date formats are:
71
+
72
+ Common:
73
+
74
+ - ``YYYY``
75
+ - ``YYYY-MM``
76
+ - ``YYYY-MM-DD`` or ``YYYYMMDD``
77
+
78
+ Uncommon:
79
+
80
+ - ``YYYY-Www`` or ``YYYYWww`` - ISO week (day defaults to 0)
81
+ - ``YYYY-Www-D`` or ``YYYYWwwD`` - ISO week and day
82
+
83
+ The ISO week and day numbering follows the same logic as
84
+ :func:`datetime.date.isocalendar`.
85
+
86
+ Supported time formats are:
87
+
88
+ - ``hh``
89
+ - ``hh:mm`` or ``hhmm``
90
+ - ``hh:mm:ss`` or ``hhmmss``
91
+ - ``hh:mm:ss.ssssss`` (Up to 6 sub-second digits)
92
+
93
+ Midnight is a special case for `hh`, as the standard supports both
94
+ 00:00 and 24:00 as a representation. The decimal separator can be
95
+ either a dot or a comma.
96
+
97
+
98
+ .. caution::
99
+
100
+ Support for fractional components other than seconds is part of the
101
+ ISO-8601 standard, but is not currently implemented in this parser.
102
+
103
+ Supported time zone offset formats are:
104
+
105
+ - `Z` (UTC)
106
+ - `±HH:MM`
107
+ - `±HHMM`
108
+ - `±HH`
109
+
110
+ Offsets will be represented as :class:`dateutil.tz.tzoffset` objects,
111
+ with the exception of UTC, which will be represented as
112
+ :class:`dateutil.tz.tzutc`. Time zone offsets equivalent to UTC (such
113
+ as `+00:00`) will also be represented as :class:`dateutil.tz.tzutc`.
114
+
115
+ :param dt_str:
116
+ A string or stream containing only an ISO-8601 datetime string
117
+
118
+ :return:
119
+ Returns a :class:`datetime.datetime` representing the string.
120
+ Unspecified components default to their lowest value.
121
+
122
+ .. warning::
123
+
124
+ As of version 2.7.0, the strictness of the parser should not be
125
+ considered a stable part of the contract. Any valid ISO-8601 string
126
+ that parses correctly with the default settings will continue to
127
+ parse correctly in future versions, but invalid strings that
128
+ currently fail (e.g. ``2017-01-01T00:00+00:00:00``) are not
129
+ guaranteed to continue failing in future versions if they encode
130
+ a valid date.
131
+
132
+ .. versionadded:: 2.7.0
133
+ """
134
+ components, pos = self._parse_isodate(dt_str)
135
+
136
+ if len(dt_str) > pos:
137
+ if self._sep is None or dt_str[pos:pos + 1] == self._sep:
138
+ components += self._parse_isotime(dt_str[pos + 1:])
139
+ else:
140
+ raise ValueError('String contains unknown ISO components')
141
+
142
+ if len(components) > 3 and components[3] == 24:
143
+ components[3] = 0
144
+ return datetime(*components) + timedelta(days=1)
145
+
146
+ return datetime(*components)
147
+
148
+ @_takes_ascii
149
+ def parse_isodate(self, datestr):
150
+ """
151
+ Parse the date portion of an ISO string.
152
+
153
+ :param datestr:
154
+ The string portion of an ISO string, without a separator
155
+
156
+ :return:
157
+ Returns a :class:`datetime.date` object
158
+ """
159
+ components, pos = self._parse_isodate(datestr)
160
+ if pos < len(datestr):
161
+ raise ValueError('String contains unknown ISO ' +
162
+ 'components: {!r}'.format(datestr.decode('ascii')))
163
+ return date(*components)
164
+
165
+ @_takes_ascii
166
+ def parse_isotime(self, timestr):
167
+ """
168
+ Parse the time portion of an ISO string.
169
+
170
+ :param timestr:
171
+ The time portion of an ISO string, without a separator
172
+
173
+ :return:
174
+ Returns a :class:`datetime.time` object
175
+ """
176
+ components = self._parse_isotime(timestr)
177
+ if components[0] == 24:
178
+ components[0] = 0
179
+ return time(*components)
180
+
181
+ @_takes_ascii
182
+ def parse_tzstr(self, tzstr, zero_as_utc=True):
183
+ """
184
+ Parse a valid ISO time zone string.
185
+
186
+ See :func:`isoparser.isoparse` for details on supported formats.
187
+
188
+ :param tzstr:
189
+ A string representing an ISO time zone offset
190
+
191
+ :param zero_as_utc:
192
+ Whether to return :class:`dateutil.tz.tzutc` for zero-offset zones
193
+
194
+ :return:
195
+ Returns :class:`dateutil.tz.tzoffset` for offsets and
196
+ :class:`dateutil.tz.tzutc` for ``Z`` and (if ``zero_as_utc`` is
197
+ specified) offsets equivalent to UTC.
198
+ """
199
+ return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
200
+
201
+ # Constants
202
+ _DATE_SEP = b'-'
203
+ _TIME_SEP = b':'
204
+ _FRACTION_REGEX = re.compile(b'[\\.,]([0-9]+)')
205
+
206
+ def _parse_isodate(self, dt_str):
207
+ try:
208
+ return self._parse_isodate_common(dt_str)
209
+ except ValueError:
210
+ return self._parse_isodate_uncommon(dt_str)
211
+
212
+ def _parse_isodate_common(self, dt_str):
213
+ len_str = len(dt_str)
214
+ components = [1, 1, 1]
215
+
216
+ if len_str < 4:
217
+ raise ValueError('ISO string too short')
218
+
219
+ # Year
220
+ components[0] = int(dt_str[0:4])
221
+ pos = 4
222
+ if pos >= len_str:
223
+ return components, pos
224
+
225
+ has_sep = dt_str[pos:pos + 1] == self._DATE_SEP
226
+ if has_sep:
227
+ pos += 1
228
+
229
+ # Month
230
+ if len_str - pos < 2:
231
+ raise ValueError('Invalid common month')
232
+
233
+ components[1] = int(dt_str[pos:pos + 2])
234
+ pos += 2
235
+
236
+ if pos >= len_str:
237
+ if has_sep:
238
+ return components, pos
239
+ else:
240
+ raise ValueError('Invalid ISO format')
241
+
242
+ if has_sep:
243
+ if dt_str[pos:pos + 1] != self._DATE_SEP:
244
+ raise ValueError('Invalid separator in ISO string')
245
+ pos += 1
246
+
247
+ # Day
248
+ if len_str - pos < 2:
249
+ raise ValueError('Invalid common day')
250
+ components[2] = int(dt_str[pos:pos + 2])
251
+ return components, pos + 2
252
+
253
+ def _parse_isodate_uncommon(self, dt_str):
254
+ if len(dt_str) < 4:
255
+ raise ValueError('ISO string too short')
256
+
257
+ # All ISO formats start with the year
258
+ year = int(dt_str[0:4])
259
+
260
+ has_sep = dt_str[4:5] == self._DATE_SEP
261
+
262
+ pos = 4 + has_sep # Skip '-' if it's there
263
+ if dt_str[pos:pos + 1] == b'W':
264
+ # YYYY-?Www-?D?
265
+ pos += 1
266
+ weekno = int(dt_str[pos:pos + 2])
267
+ pos += 2
268
+
269
+ dayno = 1
270
+ if len(dt_str) > pos:
271
+ if (dt_str[pos:pos + 1] == self._DATE_SEP) != has_sep:
272
+ raise ValueError('Inconsistent use of dash separator')
273
+
274
+ pos += has_sep
275
+
276
+ dayno = int(dt_str[pos:pos + 1])
277
+ pos += 1
278
+
279
+ base_date = self._calculate_weekdate(year, weekno, dayno)
280
+ else:
281
+ # YYYYDDD or YYYY-DDD
282
+ if len(dt_str) - pos < 3:
283
+ raise ValueError('Invalid ordinal day')
284
+
285
+ ordinal_day = int(dt_str[pos:pos + 3])
286
+ pos += 3
287
+
288
+ if ordinal_day < 1 or ordinal_day > (365 + calendar.isleap(year)):
289
+ raise ValueError('Invalid ordinal day' +
290
+ ' {} for year {}'.format(ordinal_day, year))
291
+
292
+ base_date = date(year, 1, 1) + timedelta(days=ordinal_day - 1)
293
+
294
+ components = [base_date.year, base_date.month, base_date.day]
295
+ return components, pos
296
+
297
+ def _calculate_weekdate(self, year, week, day):
298
+ """
299
+ Calculate the day of corresponding to the ISO year-week-day calendar.
300
+
301
+ This function is effectively the inverse of
302
+ :func:`datetime.date.isocalendar`.
303
+
304
+ :param year:
305
+ The year in the ISO calendar
306
+
307
+ :param week:
308
+ The week in the ISO calendar - range is [1, 53]
309
+
310
+ :param day:
311
+ The day in the ISO calendar - range is [1 (MON), 7 (SUN)]
312
+
313
+ :return:
314
+ Returns a :class:`datetime.date`
315
+ """
316
+ if not 0 < week < 54:
317
+ raise ValueError('Invalid week: {}'.format(week))
318
+
319
+ if not 0 < day < 8: # Range is 1-7
320
+ raise ValueError('Invalid weekday: {}'.format(day))
321
+
322
+ # Get week 1 for the specific year:
323
+ jan_4 = date(year, 1, 4) # Week 1 always has January 4th in it
324
+ week_1 = jan_4 - timedelta(days=jan_4.isocalendar()[2] - 1)
325
+
326
+ # Now add the specific number of weeks and days to get what we want
327
+ week_offset = (week - 1) * 7 + (day - 1)
328
+ return week_1 + timedelta(days=week_offset)
329
+
330
+ def _parse_isotime(self, timestr):
331
+ len_str = len(timestr)
332
+ components = [0, 0, 0, 0, None]
333
+ pos = 0
334
+ comp = -1
335
+
336
+ if len_str < 2:
337
+ raise ValueError('ISO time too short')
338
+
339
+ has_sep = False
340
+
341
+ while pos < len_str and comp < 5:
342
+ comp += 1
343
+
344
+ if timestr[pos:pos + 1] in b'-+Zz':
345
+ # Detect time zone boundary
346
+ components[-1] = self._parse_tzstr(timestr[pos:])
347
+ pos = len_str
348
+ break
349
+
350
+ if comp == 1 and timestr[pos:pos+1] == self._TIME_SEP:
351
+ has_sep = True
352
+ pos += 1
353
+ elif comp == 2 and has_sep:
354
+ if timestr[pos:pos+1] != self._TIME_SEP:
355
+ raise ValueError('Inconsistent use of colon separator')
356
+ pos += 1
357
+
358
+ if comp < 3:
359
+ # Hour, minute, second
360
+ components[comp] = int(timestr[pos:pos + 2])
361
+ pos += 2
362
+
363
+ if comp == 3:
364
+ # Fraction of a second
365
+ frac = self._FRACTION_REGEX.match(timestr[pos:])
366
+ if not frac:
367
+ continue
368
+
369
+ us_str = frac.group(1)[:6] # Truncate to microseconds
370
+ components[comp] = int(us_str) * 10**(6 - len(us_str))
371
+ pos += len(frac.group())
372
+
373
+ if pos < len_str:
374
+ raise ValueError('Unused components in ISO string')
375
+
376
+ if components[0] == 24:
377
+ # Standard supports 00:00 and 24:00 as representations of midnight
378
+ if any(component != 0 for component in components[1:4]):
379
+ raise ValueError('Hour may only be 24 at 24:00:00.000')
380
+
381
+ return components
382
+
383
+ def _parse_tzstr(self, tzstr, zero_as_utc=True):
384
+ if tzstr == b'Z' or tzstr == b'z':
385
+ return tz.UTC
386
+
387
+ if len(tzstr) not in {3, 5, 6}:
388
+ raise ValueError('Time zone offset must be 1, 3, 5 or 6 characters')
389
+
390
+ if tzstr[0:1] == b'-':
391
+ mult = -1
392
+ elif tzstr[0:1] == b'+':
393
+ mult = 1
394
+ else:
395
+ raise ValueError('Time zone offset requires sign')
396
+
397
+ hours = int(tzstr[1:3])
398
+ if len(tzstr) == 3:
399
+ minutes = 0
400
+ else:
401
+ minutes = int(tzstr[(4 if tzstr[3:4] == self._TIME_SEP else 3):])
402
+
403
+ if zero_as_utc and hours == 0 and minutes == 0:
404
+ return tz.UTC
405
+ else:
406
+ if minutes > 59:
407
+ raise ValueError('Invalid minutes in time zone offset')
408
+
409
+ if hours > 23:
410
+ raise ValueError('Invalid hours in time zone offset')
411
+
412
+ return tz.tzoffset(None, mult * (hours * 60 + minutes) * 60)
413
+
414
+
415
+ DEFAULT_ISOPARSER = isoparser()
416
+ isoparse = DEFAULT_ISOPARSER.isoparse
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (739 Bytes). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/_common.cpython-312.pyc ADDED
Binary file (14.2 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/_factories.cpython-312.pyc ADDED
Binary file (4.63 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/tz.cpython-312.pyc ADDED
Binary file (66 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__pycache__/win.cpython-312.pyc ADDED
Binary file (17.3 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (7.46 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-312.pyc ADDED
Binary file (3.99 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/rebuild.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ import tempfile
4
+ import shutil
5
+ import json
6
+ from subprocess import check_call, check_output
7
+ from tarfile import TarFile
8
+
9
+ from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
10
+
11
+
12
+ def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
13
+ """Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
14
+
15
+ filename is the timezone tarball from ``ftp.iana.org/tz``.
16
+
17
+ """
18
+ tmpdir = tempfile.mkdtemp()
19
+ zonedir = os.path.join(tmpdir, "zoneinfo")
20
+ moduledir = os.path.dirname(__file__)
21
+ try:
22
+ with TarFile.open(filename) as tf:
23
+ for name in zonegroups:
24
+ tf.extract(name, tmpdir)
25
+ filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
26
+
27
+ _run_zic(zonedir, filepaths)
28
+
29
+ # write metadata file
30
+ with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
31
+ json.dump(metadata, f, indent=4, sort_keys=True)
32
+ target = os.path.join(moduledir, ZONEFILENAME)
33
+ with TarFile.open(target, "w:%s" % format) as tf:
34
+ for entry in os.listdir(zonedir):
35
+ entrypath = os.path.join(zonedir, entry)
36
+ tf.add(entrypath, entry)
37
+ finally:
38
+ shutil.rmtree(tmpdir)
39
+
40
+
41
+ def _run_zic(zonedir, filepaths):
42
+ """Calls the ``zic`` compiler in a compatible way to get a "fat" binary.
43
+
44
+ Recent versions of ``zic`` default to ``-b slim``, while older versions
45
+ don't even have the ``-b`` option (but default to "fat" binaries). The
46
+ current version of dateutil does not support Version 2+ TZif files, which
47
+ causes problems when used in conjunction with "slim" binaries, so this
48
+ function is used to ensure that we always get a "fat" binary.
49
+ """
50
+
51
+ try:
52
+ help_text = check_output(["zic", "--help"])
53
+ except OSError as e:
54
+ _print_on_nosuchfile(e)
55
+ raise
56
+
57
+ if b"-b " in help_text:
58
+ bloat_args = ["-b", "fat"]
59
+ else:
60
+ bloat_args = []
61
+
62
+ check_call(["zic"] + bloat_args + ["-d", zonedir] + filepaths)
63
+
64
+
65
+ def _print_on_nosuchfile(e):
66
+ """Print helpful troubleshooting message
67
+
68
+ e is an exception raised by subprocess.check_call()
69
+
70
+ """
71
+ if e.errno == 2:
72
+ logging.error(
73
+ "Could not find zic. Perhaps you need to install "
74
+ "libc-bin or some other package that provides it, "
75
+ "or it's not in your PATH?")
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.6 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_api.cpython-312.pyc ADDED
Binary file (16.7 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_error.cpython-312.pyc ADDED
Binary file (1.79 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_soft.cpython-312.pyc ADDED
Binary file (2.49 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_unix.cpython-312.pyc ADDED
Binary file (3.41 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_util.cpython-312.pyc ADDED
Binary file (2.04 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/_windows.cpython-312.pyc ADDED
Binary file (3.3 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/asyncio.cpython-312.pyc ADDED
Binary file (15.6 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/filelock/__pycache__/version.cpython-312.pyc ADDED
Binary file (616 Bytes). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/fsspec-2024.5.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2018, Martin Durant
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.1 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_abnf.cpython-312.pyc ADDED
Binary file (1.81 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_connection.cpython-312.pyc ADDED
Binary file (22.6 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_events.cpython-312.pyc ADDED
Binary file (13.3 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_headers.cpython-312.pyc ADDED
Binary file (7.89 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_readers.cpython-312.pyc ADDED
Binary file (9.45 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_receivebuffer.cpython-312.pyc ADDED
Binary file (4.73 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_state.cpython-312.pyc ADDED
Binary file (8.56 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_util.cpython-312.pyc ADDED
Binary file (4.74 kB). View file
 
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/h11/__pycache__/_version.cpython-312.pyc ADDED
Binary file (238 Bytes). View file