datedict 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of datedict might be problematic. Click here for more details.

datedict/DateDict.py CHANGED
@@ -1,50 +1,72 @@
1
- from datetime import date
1
+ from datetime import date, timedelta
2
2
  from decimal import Decimal
3
+ from typing import Mapping
3
4
 
4
- from datetime import timedelta
5
-
6
- from .common import ZERO
5
+ from .common import NAN, ONE, Decimable, to_decimal, ZERO
7
6
 
8
7
 
9
8
  class DateDict:
10
- def __init__(self, data=dict()):
11
- self.data: dict[str, Decimal | None] = data
12
-
13
- def create(self, start_date, end_date, value: Decimal) -> "DateDict":
9
+ def __init__(self, data: Mapping[str, Decimable], strict: bool = True):
10
+ if not data:
11
+ raise ValueError("Data cannot be empty.")
12
+ dates = sorted(data.keys())
13
+ if strict:
14
+ # enforce contiguous coverage
15
+ if dates != [
16
+ (date.fromisoformat(dates[0]) + timedelta(days=i)).strftime("%Y-%m-%d")
17
+ for i in range(
18
+ (date.fromisoformat(dates[-1]) - date.fromisoformat(dates[0])).days
19
+ + 1
20
+ )
21
+ ]:
22
+ raise ValueError(
23
+ "Data must cover all dates in the contiguous range. "
24
+ "To disable this check, set strict=False."
25
+ )
26
+ self.start_date, self.end_date = dates[0], dates[-1]
27
+ self.data: dict[str, Decimal] = {k: to_decimal(v) for k, v in data.items()}
28
+
29
+ def fill(self, start_date, end_date, value: Decimable) -> "DateDict":
14
30
  """
15
31
  Create a new graph with a specified range and value.
16
32
  The range is defined by start_date and end_date.
17
- If the value is None, it will not be included in the graph.
18
33
  """
19
- start = (
20
- date.fromisoformat(start_date)
21
- if isinstance(start_date, str)
22
- else start_date
34
+ v = to_decimal(value)
35
+ return DateDict(
36
+ {
37
+ (date.fromisoformat(start_date) + timedelta(days=i)).strftime(
38
+ "%Y-%m-%d"
39
+ ): v
40
+ for i in range(
41
+ (date.fromisoformat(end_date) - date.fromisoformat(start_date)).days
42
+ + 1
43
+ )
44
+ }
23
45
  )
24
- end = date.fromisoformat(end_date) if isinstance(end_date, str) else end_date
25
- self.data = {
26
- date.strftime("%Y-%m-%d"): (value if value is not None else None)
27
- for date in (
28
- start + timedelta(days=i) for i in range((end - start).days + 1)
29
- )
30
- }
31
- return self
32
46
 
33
- def get(self, key: str, default: Decimal) -> Decimal:
47
+ def get(self, key: str, default: Decimal = NAN) -> Decimal:
34
48
  """
35
49
  Get the value for a specific date. If the date does not exist, return the default value.
36
50
  The date should be in the format yyyy-mm-dd.
37
51
  If the value is None, return the default value.
38
52
  """
39
- return self.data.get(key) or default
53
+ temp = self.data.get(key, NAN)
54
+ if temp.is_nan():
55
+ return default
56
+ return temp
40
57
 
41
- def __getitem__(self, key) -> Decimal | None:
42
- return self.data.get(key, None)
58
+ def __getitem__(self, key) -> Decimal:
59
+ return self.data[key]
43
60
 
44
61
  def __setitem__(self, key: str, value) -> None:
45
- self.data[key] = value
46
-
47
- def crop(self, start: str | None = None, end: str | None = None) -> "DateDict":
62
+ self.data[key] = to_decimal(value)
63
+
64
+ def crop(
65
+ self,
66
+ start: str | None = None,
67
+ end: str | None = None,
68
+ initial_value: Decimable = NAN,
69
+ ) -> "DateDict":
48
70
  """
49
71
  Crop the graph data to a specific range defined by start and end.
50
72
  If any of the parameters is None, it will not filter by that parameter.
@@ -53,85 +75,140 @@ class DateDict:
53
75
  return self
54
76
  return DateDict(
55
77
  {
56
- k: v
57
- for k, v in self.data.items()
58
- if (start is None or k >= start) and (end is None or k <= end)
78
+ k: (self.get(k, to_decimal(initial_value)))
79
+ for k in map(
80
+ lambda x: x.strftime("%Y-%m-%d"),
81
+ [
82
+ (
83
+ date.fromisoformat(self.start_date)
84
+ if start is None
85
+ else date.fromisoformat(start)
86
+ )
87
+ + timedelta(days=i)
88
+ for i in range(
89
+ (
90
+ (
91
+ date.fromisoformat(self.end_date)
92
+ if end is None
93
+ else date.fromisoformat(end)
94
+ )
95
+ - (
96
+ date.fromisoformat(self.start_date)
97
+ if start is None
98
+ else date.fromisoformat(start)
99
+ )
100
+ ).days
101
+ + 1
102
+ )
103
+ ],
104
+ )
59
105
  }
60
106
  )
61
107
 
62
- def sum(self: "DateDict") -> Decimal:
108
+ def non_negative(self) -> "DateDict":
63
109
  """
64
- Calculate the sum of all values in the graph.
65
- If a value is None, it is treated as zero.
110
+ Return a new DateDict with all negative values set to zero.
66
111
  """
67
- return Decimal(
68
- sum(value if value is not None else ZERO for value in self.data.values())
112
+ return DateDict({k: (v if (not v.is_nan() and v >= ZERO) else ZERO) for k, v in self.data.items()})
113
+
114
+ def sum(
115
+ self: "DateDict", start: str | None = None, end: str | None = None
116
+ ) -> Decimal:
117
+ """
118
+ Return the sum of values in the specified range.
119
+ If a value is NaN, it is treated as zero.
120
+ """
121
+ s = self.start_date if start is None else start
122
+ e = self.end_date if end is None else end
123
+ return sum(
124
+ [
125
+ (self.get(k, ZERO))
126
+ for k in map(
127
+ lambda x: x.strftime("%Y-%m-%d"),
128
+ [
129
+ date.fromisoformat(s) + timedelta(days=i)
130
+ for i in range(
131
+ (date.fromisoformat(e) - date.fromisoformat(s)).days + 1
132
+ )
133
+ ],
134
+ )
135
+ ],
136
+ ZERO,
69
137
  )
70
138
 
71
- def __add__(self, other: "Decimal | DateDict") -> "DateDict":
72
- if isinstance(other, Decimal):
73
- return DateDict(
74
- {
75
- k: (v + other if v is not None else None)
76
- for k, v in self.data.items()
77
- }
78
- )
79
- else:
80
- return DateDict(
81
- {
82
- k: ((v + (other.data.get(k) or ZERO) if v is not None else None))
83
- for k, v in self.data.items()
84
- }
85
- )
86
-
87
- def __mul__(self, other: "Decimal | DateDict") -> "DateDict":
88
- if isinstance(other, Decimal):
89
- return DateDict(
90
- {
91
- k: (v * other if v is not None else None)
92
- for k, v in self.data.items()
93
- }
94
- )
95
- elif isinstance(other, DateDict):
96
- return DateDict(
97
- {
98
- k: ((v * (other.data.get(k) or ZERO) if v is not None else None))
99
- for k, v in self.data.items()
100
- }
101
- )
102
-
103
- def __sub__(self, other: "Decimal | DateDict") -> "DateDict":
104
- return self + (other * Decimal(-1))
105
-
106
- def __truediv__(self, other: "Decimal | DateDict") -> "DateDict":
107
- if isinstance(other, Decimal):
108
- return DateDict(
109
- {
110
- k: (v / other if v is not None else None)
111
- for k, v in self.data.items()
112
- }
113
- )
139
+ def __mul__(self, other: "Decimable | DateDict") -> "DateDict":
140
+ if isinstance(other, Decimable):
141
+ return DateDict({k: v * to_decimal(other) for k, v in self.data.items()})
114
142
  elif isinstance(other, DateDict):
115
- return DateDict(
116
- {
117
- k: ((v / (other.data.get(k) or ZERO) if v is not None else None))
118
- for k, v in self.data.items()
119
- }
120
- )
143
+ return DateDict({k: v * other.get(k, ONE) for k, v in self.data.items()})
144
+
145
+ def __rmul__(self, other: "Decimable | DateDict") -> "DateDict":
146
+ return self.__mul__(other)
121
147
 
122
- def to_dict(self) -> dict[str, Decimal | None]:
148
+ def __neg__(self) -> "DateDict":
149
+ return self * Decimal("-1")
150
+
151
+ def __add__(self, other: "Decimable | DateDict") -> "DateDict":
152
+ if isinstance(other, Decimable):
153
+ return DateDict({k: (v + to_decimal(other)) for k, v in self.data.items()})
154
+ else:
155
+ return DateDict({k: v + other.get(k, ZERO) for k, v in self.data.items()})
156
+
157
+ def __radd__(self, other: "Decimable | DateDict") -> "DateDict":
158
+ return self.__add__(other)
159
+
160
+ def __sub__(self, other: "Decimable | DateDict") -> "DateDict":
161
+ if isinstance(other, Decimable):
162
+ return self.__add__(-to_decimal(other))
163
+ else:
164
+ return self.__add__(-other)
165
+
166
+ def __rsub__(self, other: "Decimable | DateDict") -> "DateDict":
167
+ return (-self).__add__(other)
168
+
169
+ def __truediv__(self, other: "Decimable | DateDict") -> "DateDict":
170
+ if isinstance(other, Decimable):
171
+ return DateDict({k: v / to_decimal(other) for k, v in self.data.items()})
172
+ else:
173
+ return DateDict({k: v / other.get(k, ONE) for k, v in self.data.items()})
174
+
175
+ def __eq__(self, other: object) -> bool:
176
+ if not isinstance(other, DateDict):
177
+ return False
178
+ for k in set(self.data.keys()).union(other.data.keys()):
179
+ s = self.get(k)
180
+ o = other.get(k)
181
+ if s.is_nan() and o.is_nan():
182
+ continue
183
+ if s != o:
184
+ return False
185
+ return True
186
+
187
+ def __str__(self) -> str:
188
+ return "\n".join(f"{k}: {v}" for k, v in sorted(self.data.items()))
189
+
190
+ def __repr__(self) -> str:
191
+ return f"{self.data!r}"
192
+
193
+ def to_array(self) -> list[Decimal]:
194
+ """
195
+ Convert the DateDict values to a list of Decimals, ordered by date.
123
196
  """
124
- Convert the graph data to a dictionary.
125
- This is useful for serialization or returning as a response.
197
+ return [self.data[k] for k in sorted(self.data.keys())]
198
+
199
+ def to_dict(self) -> dict[str, Decimal]:
200
+ """
201
+ Convert the DateDict to a standard dictionary.
126
202
  """
127
- return self.data.copy()
203
+ return dict(self.data)
204
+
128
205
 
129
206
  def average(self) -> Decimal:
130
207
  """
131
- Calculate the average of all values in the graph.
132
- If there are no valid values, return Decimal(0).
208
+ Calculate the average of all values in the DateDict.
209
+ If there are no valid values, return ZERO.
133
210
  """
134
- valid_values = [v for v in self.data.values() if v is not None]
211
+ valid_values = [v for v in self.data.values() if not v.is_nan()]
135
212
  if not valid_values:
136
213
  return ZERO
137
214
  return Decimal(sum(valid_values)) / len(valid_values)
datedict/YearDict.py CHANGED
@@ -1,101 +1,129 @@
1
1
  from decimal import Decimal
2
+ from typing import Mapping
2
3
 
3
- from .common import to_decimal, ZERO
4
+ from .common import NAN, ONE, Decimable, to_decimal, ZERO
4
5
 
5
6
 
6
7
  class YearDict:
7
- def __init__(
8
- self,
9
- start_year=2025,
10
- end_year=2025,
11
- initial_value: Decimal | int | float = ZERO,
12
- ):
13
- self.start_year: int = start_year
14
- self.end_year: int = end_year
15
- iv: Decimal = to_decimal(initial_value)
16
- self.data: dict[int, Decimal] = {
17
- y: iv for y in range(self.start_year, self.end_year + 1)
18
- }
8
+ def __init__(self, data: Mapping[int, Decimable], strict: bool = True):
9
+ if not data:
10
+ raise ValueError("Data cannot be empty.")
11
+ years = sorted(data.keys())
12
+ if strict:
13
+ # enforce contiguous coverage
14
+ if years != list(range(years[0], years[-1] + 1)):
15
+ raise ValueError(
16
+ "Data must cover all years in the contiguous range. "
17
+ "To disable this check, set strict=False."
18
+ )
19
+ self.start_year, self.end_year = years[0], years[-1]
20
+ self.data = {k: to_decimal(v) for k, v in data.items()}
21
+
22
+ def fill(self, start_year: int, end_year: int, value: Decimable) -> "YearDict":
23
+ """
24
+ Create a new graph with a specified range and value.
25
+ The range is defined by start_year and end_year.
26
+ """
27
+ v = to_decimal(value)
28
+ return YearDict({y: v for y in range(int(start_year), int(end_year) + 1)})
29
+
30
+ def get(self, year: int, default: Decimal = NAN) -> Decimal:
31
+ """
32
+ Get the value for a specific year. If the year does not exist, return the default value.
33
+ If the value is None, return the default value.
34
+ """
35
+ temp = self.data.get(year, NAN)
36
+ if temp.is_nan():
37
+ return default
38
+ return temp
19
39
 
20
40
  def __getitem__(self, year: int) -> Decimal:
21
41
  return self.data[year]
22
42
 
23
- def __setitem__(self, year: int, value):
43
+ def __setitem__(self, year: int, value) -> None:
24
44
  self.data[int(year)] = to_decimal(value)
25
45
 
26
- def override(self, data: dict[int, Decimal | float | int | str]) -> "YearDict":
27
- if not data:
28
- raise ValueError("Data cannot be empty.")
29
- ys = sorted(data.keys())
30
- # enforce contiguous coverage
31
- if ys != list(range(ys[0], ys[-1] + 1)):
32
- raise ValueError("Data must cover all years in the contiguous range.")
33
- self.start_year, self.end_year = ys[0], ys[-1] # inclusive
34
- self.data = {
35
- y: to_decimal(data[y]) for y in range(self.start_year, self.end_year + 1)
36
- }
37
- return self
38
-
39
- def fit(self, start_year: int, end_year: int, initial_value: Decimal = ZERO):
40
- self.start_year, self.end_year = int(start_year), int(end_year)
41
- iv = to_decimal(initial_value)
42
- self.data = {
43
- y: to_decimal(self.data[y]) if y in self.data else iv
44
- for y in range(self.start_year, self.end_year + 1)
45
- }
46
- return self
46
+ def crop(
47
+ self,
48
+ start: int | None = None,
49
+ end: int | None = None,
50
+ initial_value: Decimable = NAN,
51
+ ) -> "YearDict":
52
+ if start is None and end is None:
53
+ return self
54
+ return YearDict(
55
+ {
56
+ k: (self.get(k, to_decimal(initial_value)))
57
+ for k in range(
58
+ self.start_year if start is None else int(start),
59
+ self.end_year if end is None else int(end)
60
+ +1,
61
+ )
62
+ }
63
+ )
47
64
 
48
65
  def non_negative(self) -> "YearDict":
49
- out = YearDict(self.start_year, self.end_year)
50
- out.data = {y: (v if v >= ZERO else ZERO) for y, v in self.data.items()}
51
- return out
52
-
53
- def sum(
54
- self, start_year: int | None = None, end_year: int | None = None
55
- ) -> Decimal:
56
- sy = self.start_year if start_year is None else int(start_year)
57
- ey = self.end_year if end_year is None else int(end_year)
58
- return sum((self.data[y] for y in range(sy, ey + 1) if y in self.data), ZERO)
59
-
60
- def __mul__(self, other):
61
- result = YearDict(self.start_year, self.end_year)
62
- if isinstance(other, (int, float, Decimal)):
63
- result.data = {
64
- year: Decimal(value) * Decimal(str(other))
65
- for year, value in self.data.items()
66
- }
66
+ """
67
+ Return a new YearDict with all negative values set to zero.
68
+ """
69
+ return YearDict({y: (v if (not v.is_nan() and v >= ZERO) else ZERO) for y, v in self.data.items()})
70
+
71
+ def sum(self, start: int | None = None, end: int | None = None) -> Decimal:
72
+ """
73
+ Return the sum of values in the specified range.
74
+ If a value is NaN, it is treated as zero.
75
+ """
76
+ s = self.start_year if start is None else start
77
+ e = self.end_year if end is None else end
78
+ return sum((self.get(y, ZERO) for y in range(s, e + 1) if y in self.data), ZERO)
79
+
80
+ def __mul__(self, other: "Decimable | YearDict") -> "YearDict":
81
+ if isinstance(other, Decimable):
82
+ return YearDict({k: v * to_decimal(other) for k, v in self.data.items()})
67
83
  elif isinstance(other, YearDict):
68
- result.data = {
69
- year: Decimal(self.data[year]) * Decimal(other.data[year])
70
- for year in self.data.keys() & other.data.keys()
71
- }
72
- else:
73
- return NotImplemented
74
- return result
84
+ return YearDict({k: v * other.get(k, ONE) for k, v in self.data.items()})
75
85
 
76
86
  def __rmul__(self, other):
77
87
  return self.__mul__(other)
78
88
 
79
- def __add__(self, other):
80
- result = YearDict(self.start_year, self.end_year)
81
- if isinstance(other, (int, float, Decimal)):
82
- result.data = {
83
- year: value + Decimal(str(other)) for year, value in self.data.items()
84
- }
89
+ def __neg__(self) -> "YearDict":
90
+ return self * Decimal("-1")
91
+
92
+ def __add__(self, other: "Decimable | YearDict") -> "YearDict":
93
+ if isinstance(other, Decimable):
94
+ return YearDict({k: v + to_decimal(other) for k, v in self.data.items()})
85
95
  elif isinstance(other, YearDict):
86
- result.data = {
87
- year: Decimal(self.data[year]) + Decimal(other.data[year])
88
- for year in self.data.keys() & other.data.keys()
89
- }
90
- else:
91
- return NotImplemented
92
- return result
96
+ return YearDict({k: v + other.get(k, ZERO) for k, v in self.data.items()})
93
97
 
94
- def __radd__(self, other):
98
+ def __radd__(self, other: "Decimable | YearDict") -> "YearDict":
95
99
  return self.__add__(other)
96
100
 
97
- def __sub__(self, other):
98
- return self.__add__(-1 * other)
101
+ def __sub__(self, other: "Decimable | YearDict") -> "YearDict":
102
+ if isinstance(other, Decimable):
103
+ return self.__add__(-to_decimal(other))
104
+ elif isinstance(other, YearDict):
105
+ return self.__add__(-other)
106
+
107
+ def __rsub__(self, other: "Decimable | YearDict") -> "YearDict":
108
+ return (-self).__add__(other)
109
+
110
+ def __truediv__(self, other: "Decimable | YearDict") -> "YearDict":
111
+ if isinstance(other, Decimable):
112
+ return YearDict({k: v / to_decimal(other) for k, v in self.data.items()})
113
+ elif isinstance(other, YearDict):
114
+ return YearDict({k: v / other.get(k, ONE) for k, v in self.data.items()})
115
+
116
+ def __eq__(self, other: object) -> bool:
117
+ if not isinstance(other, YearDict):
118
+ return False
119
+ for k in set(self.data.keys()).union(other.data.keys()):
120
+ s = self.get(k)
121
+ o = other.get(k)
122
+ if s.is_nan() and o.is_nan():
123
+ continue
124
+ if s != o:
125
+ return False
126
+ return True
99
127
 
100
128
  def __str__(self):
101
129
  return "\n".join(f"{y}: {v}" for y, v in sorted(self.data.items()))
@@ -104,7 +132,17 @@ class YearDict:
104
132
  return f"{self.data!r}"
105
133
 
106
134
  def to_array(self):
107
- return [self.data[y] for y in range(self.start_year, self.end_year + 1)]
135
+ return [self.data[k] for k in self.data.keys()]
108
136
 
109
137
  def to_dict(self):
110
138
  return dict(self.data)
139
+
140
+ def average(self) -> Decimal:
141
+ """
142
+ Return the average of the values in the YearDict.
143
+ If there are no years, return Zero
144
+ """
145
+ valid_values = [v for v in self.data.values() if not v.is_nan()]
146
+ if not valid_values:
147
+ return ZERO
148
+ return sum(valid_values, ZERO) / Decimal(len(valid_values))
datedict/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from .DateDict import DateDict
2
2
  from .YearDict import YearDict
3
- from .common import ZERO
3
+ from .common import ZERO, ONE, NAN, Decimable
4
4
 
5
- __all__ = ["DateDict", "YearDict", "ZERO"]
5
+ __all__ = ["DateDict", "YearDict", "ZERO", "ONE", "NAN", "Decimable"]
6
6
  __version__ = "0.1.2"
datedict/common.py CHANGED
@@ -1,14 +1,19 @@
1
1
  from decimal import Decimal
2
+ from typing import Union
2
3
 
4
+ Decimable = Union[Decimal, str, int, float, None]
3
5
 
4
6
  ZERO = Decimal("0")
7
+ ONE = Decimal("1")
8
+ NAN = Decimal("NaN")
5
9
 
6
10
 
7
- def to_decimal(x) -> Decimal:
11
+ def to_decimal(x: Decimable) -> Decimal:
12
+ if x is None:
13
+ return Decimal("NaN")
8
14
  if isinstance(x, Decimal):
9
15
  return x
10
16
  if isinstance(x, (int, str)):
11
17
  return Decimal(x)
12
18
  if isinstance(x, float):
13
19
  return Decimal(str(x))
14
- raise TypeError(f"Unsupported type for Decimal: {type(x)}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datedict
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: DateDict and YearDict: date-aware dictionary structures
5
5
  Project-URL: Homepage, https://github.com/you/datedict
6
6
  Project-URL: Issues, https://github.com/you/datedict/issues
@@ -0,0 +1,8 @@
1
+ datedict/DateDict.py,sha256=YsvCgsNGHKDaCya8KEb3KrTo98cxoiXZrr6xqsz2Mq8,7700
2
+ datedict/YearDict.py,sha256=YI6lE1SXYoK4R7LKLGLt75_ISNg0snBEJ_Uk4E-0c6c,5436
3
+ datedict/__init__.py,sha256=4QSCqCW_owSqD3k3Oz1WAsB4p_vvzUlINroAxxFCEWQ,201
4
+ datedict/common.py,sha256=aUCsMV6roKGQIQXSFIJIN0cxAXIlK_YyRDWS1EIBu8E,424
5
+ datedict-0.1.3.dist-info/METADATA,sha256=YW0NObrsMdZrHZE_plT8MEhw2lRSwzT3yontyIV8D2g,1985
6
+ datedict-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
+ datedict-0.1.3.dist-info/licenses/LICENSE,sha256=ULDgLM2c4o9DLMR-VEkeyuB-DRWBFX7VunJmlWShWxQ,1072
8
+ datedict-0.1.3.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- datedict/DateDict.py,sha256=JrqKAJIcZL4Q7JMvzKPZQCzXGQ3wZAEkpWABAfHXLr0,4658
2
- datedict/YearDict.py,sha256=P8t43vUyOtxxABtIKf1epAU7Ohqx2-V9e9t-PyqFEh0,3798
3
- datedict/__init__.py,sha256=pZv27luenqTNoEm9jdodgCu3B5vnYdDgMYllFwCA2Sc,153
4
- datedict/common.py,sha256=yW3ohkISis4FP6baN8QJFPYHCkpVyecip7AlFg49_Kw,314
5
- datedict-0.1.2.dist-info/METADATA,sha256=p8BOciltez0gbtRl-UPsG0ihMtI4cSn5w8PBm1sNlwM,1985
6
- datedict-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- datedict-0.1.2.dist-info/licenses/LICENSE,sha256=ULDgLM2c4o9DLMR-VEkeyuB-DRWBFX7VunJmlWShWxQ,1072
8
- datedict-0.1.2.dist-info/RECORD,,