resolvekit 0.0.1__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.
Files changed (70) hide show
  1. resolvekit/README.md +134 -0
  2. resolvekit/__init__.py +67 -0
  3. resolvekit/api/README.md +165 -0
  4. resolvekit/api/__init__.py +10 -0
  5. resolvekit/api/convenience.py +53 -0
  6. resolvekit/api/resolver.py +457 -0
  7. resolvekit/builders/README.md +173 -0
  8. resolvekit/builders/__init__.py +0 -0
  9. resolvekit/calibration/README.md +351 -0
  10. resolvekit/calibration/__init__.py +12 -0
  11. resolvekit/calibration/calibrator.py +184 -0
  12. resolvekit/calibration/features.py +139 -0
  13. resolvekit/calibration/models.py +78 -0
  14. resolvekit/cli/README.md +215 -0
  15. resolvekit/cli/__init__.py +0 -0
  16. resolvekit/cli/main.py +18 -0
  17. resolvekit/config.py +128 -0
  18. resolvekit/constants.py +252 -0
  19. resolvekit/constraints/README.md +102 -0
  20. resolvekit/constraints/__init__.py +17 -0
  21. resolvekit/constraints/constraint_engine.py +111 -0
  22. resolvekit/constraints/hierarchy_validator.py +148 -0
  23. resolvekit/constraints/membership_validator.py +60 -0
  24. resolvekit/constraints/protocols.py +33 -0
  25. resolvekit/constraints/temporal_validator.py +43 -0
  26. resolvekit/constraints/type_validator.py +42 -0
  27. resolvekit/data/README.md +165 -0
  28. resolvekit/data/__init__.py +14 -0
  29. resolvekit/data/alias_repository.py +206 -0
  30. resolvekit/data/code_repository.py +85 -0
  31. resolvekit/data/context_filters.py +49 -0
  32. resolvekit/data/db_manager.py +196 -0
  33. resolvekit/data/entity_repository.py +466 -0
  34. resolvekit/data/membership_repository.py +107 -0
  35. resolvekit/data/query_builder.py +177 -0
  36. resolvekit/data/schema.py +122 -0
  37. resolvekit/disambiguation/README.md +72 -0
  38. resolvekit/disambiguation/__init__.py +0 -0
  39. resolvekit/extraction/README.md +204 -0
  40. resolvekit/extraction/__init__.py +0 -0
  41. resolvekit/matchers/README.md +77 -0
  42. resolvekit/matchers/__init__.py +65 -0
  43. resolvekit/matchers/alias_exact.py +65 -0
  44. resolvekit/matchers/canonical_name.py +62 -0
  45. resolvekit/matchers/cascade.py +127 -0
  46. resolvekit/matchers/code_validators.py +250 -0
  47. resolvekit/matchers/exact_code.py +177 -0
  48. resolvekit/matchers/fts_matcher.py +106 -0
  49. resolvekit/matchers/fuzzy_matcher.py +142 -0
  50. resolvekit/matchers/priorities.py +174 -0
  51. resolvekit/matchers/protocols.py +75 -0
  52. resolvekit/normalization/README.md +192 -0
  53. resolvekit/normalization/__init__.py +8 -0
  54. resolvekit/normalization/normalizer.py +164 -0
  55. resolvekit/overlays/README.md +226 -0
  56. resolvekit/overlays/__init__.py +0 -0
  57. resolvekit/types.py +534 -0
  58. resolvekit/utils/README.md +188 -0
  59. resolvekit/utils/__init__.py +48 -0
  60. resolvekit/utils/cache.py +109 -0
  61. resolvekit/utils/dates.py +339 -0
  62. resolvekit/utils/errors.py +145 -0
  63. resolvekit/utils/files.py +366 -0
  64. resolvekit/utils/logging.py +219 -0
  65. resolvekit/utils/text.py +475 -0
  66. resolvekit/utils/validation.py +301 -0
  67. resolvekit-0.0.1.dist-info/METADATA +36 -0
  68. resolvekit-0.0.1.dist-info/RECORD +70 -0
  69. resolvekit-0.0.1.dist-info/WHEEL +4 -0
  70. resolvekit-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,301 @@
1
+ """Validation utilities for resolvekit."""
2
+
3
+ import re
4
+ from datetime import date
5
+ from typing import Any
6
+
7
+ from resolvekit.constants import CODE_SYSTEMS
8
+ from resolvekit.types import AliasType, EntityType
9
+ from resolvekit.utils.errors import CodeFormatError, ValidationError
10
+
11
+
12
+ def validate_dcid(dcid: str) -> bool:
13
+ """
14
+ Validate DCID format.
15
+
16
+ Args:
17
+ dcid: DCID to validate
18
+
19
+ Returns:
20
+ True if valid, False otherwise
21
+
22
+ Examples:
23
+ >>> validate_dcid("country/USA")
24
+ True
25
+ >>> validate_dcid("invalid")
26
+ False
27
+ """
28
+ if not dcid or not isinstance(dcid, str):
29
+ return False
30
+
31
+ pattern = CODE_SYSTEMS["dcid"]["format"]
32
+ return bool(re.match(pattern, dcid))
33
+
34
+
35
+ def validate_code_format(code: str, code_system: str, strict: bool = True) -> bool:
36
+ """
37
+ Validate code format for a given code system.
38
+
39
+ Args:
40
+ code: Code to validate
41
+ code_system: Code system (iso2, iso3, m49, etc.)
42
+ strict: If True, raise exception on invalid format
43
+
44
+ Returns:
45
+ True if valid
46
+
47
+ Raises:
48
+ CodeFormatError: If strict=True and code is invalid
49
+ """
50
+ if not code or not isinstance(code, str):
51
+ if strict:
52
+ raise CodeFormatError(str(code), code_system, "non-empty string")
53
+ return False
54
+
55
+ if code_system not in CODE_SYSTEMS:
56
+ if strict:
57
+ raise ValidationError(
58
+ f"Unknown code system: {code_system}",
59
+ details={"code_system": code_system},
60
+ )
61
+ return False
62
+
63
+ pattern = CODE_SYSTEMS[code_system]["format"]
64
+ is_valid = bool(re.match(pattern, code))
65
+
66
+ if not is_valid and strict:
67
+ example = CODE_SYSTEMS[code_system]["example"]
68
+ raise CodeFormatError(code, code_system, f"{pattern} (e.g., {example})")
69
+
70
+ return is_valid
71
+
72
+
73
+ def validate_iso2(code: str, strict: bool = True) -> bool:
74
+ """Validate ISO 3166-1 alpha-2 code."""
75
+ return validate_code_format(code, "iso2", strict=strict)
76
+
77
+
78
+ def validate_iso3(code: str, strict: bool = True) -> bool:
79
+ """Validate ISO 3166-1 alpha-3 code."""
80
+ return validate_code_format(code, "iso3", strict=strict)
81
+
82
+
83
+ def validate_iso_numeric(code: str, strict: bool = True) -> bool:
84
+ """Validate ISO 3166-1 numeric code."""
85
+ return validate_code_format(code, "iso_numeric", strict=strict)
86
+
87
+
88
+ def validate_m49(code: str, strict: bool = True) -> bool:
89
+ """Validate UN M49 code."""
90
+ return validate_code_format(code, "m49", strict=strict)
91
+
92
+
93
+ def validate_wikidata_qid(qid: str, strict: bool = True) -> bool:
94
+ """Validate Wikidata QID."""
95
+ return validate_code_format(qid, "wikidata", strict=strict)
96
+
97
+
98
+ def validate_confidence(confidence: float) -> bool:
99
+ """
100
+ Validate confidence score.
101
+
102
+ Args:
103
+ confidence: Confidence score
104
+
105
+ Returns:
106
+ True if valid (0.0 <= confidence <= 1.0)
107
+ """
108
+ if not isinstance(confidence, int | float):
109
+ return False
110
+ return 0.0 <= confidence <= 1.0
111
+
112
+
113
+ def validate_date_string(date_str: str) -> bool:
114
+ """
115
+ Validate ISO date string format.
116
+
117
+ Args:
118
+ date_str: Date string in ISO format (YYYY-MM-DD)
119
+
120
+ Returns:
121
+ True if valid
122
+
123
+ Examples:
124
+ >>> validate_date_string("2025-01-01")
125
+ True
126
+ >>> validate_date_string("2025-1-1")
127
+ False
128
+ """
129
+ if not date_str or not isinstance(date_str, str):
130
+ return False
131
+
132
+ pattern = r"^\d{4}-\d{2}-\d{2}$"
133
+ if not re.match(pattern, date_str):
134
+ return False
135
+
136
+ # Try parsing to ensure it's a valid date
137
+ try:
138
+ year, month, day = map(int, date_str.split("-"))
139
+ date(year, month, day)
140
+ return True
141
+ except ValueError:
142
+ return False
143
+
144
+
145
+ def validate_temporal_range(
146
+ valid_from: date | None,
147
+ valid_until: date | None,
148
+ strict: bool = True,
149
+ ) -> bool:
150
+ """
151
+ Validate temporal validity range.
152
+
153
+ Args:
154
+ valid_from: Start date (inclusive)
155
+ valid_until: End date (exclusive)
156
+ strict: If True, raise exception on invalid range
157
+
158
+ Returns:
159
+ True if valid
160
+
161
+ Raises:
162
+ ValidationError: If strict=True and range is invalid
163
+ """
164
+ if valid_from is None and valid_until is None:
165
+ return True
166
+
167
+ if valid_from is not None and valid_until is not None and valid_from >= valid_until:
168
+ if strict:
169
+ raise ValidationError(
170
+ f"Invalid temporal range: valid_from ({valid_from}) "
171
+ f"must be before valid_until ({valid_until})",
172
+ details={"valid_from": valid_from, "valid_until": valid_until},
173
+ )
174
+ return False
175
+
176
+ return True
177
+
178
+
179
+ def validate_entity_type(entity_type: str) -> bool:
180
+ """
181
+ Validate entity type against EntityType enum values.
182
+
183
+ Args:
184
+ entity_type: Entity type to validate
185
+
186
+ Returns:
187
+ True if valid
188
+ """
189
+ return entity_type in {t.value for t in EntityType}
190
+
191
+
192
+ def validate_alias_type(alias_type: str) -> bool:
193
+ """
194
+ Validate alias type against AliasType enum values.
195
+
196
+ Args:
197
+ alias_type: Alias type to validate
198
+
199
+ Returns:
200
+ True if valid
201
+ """
202
+ return alias_type in {t.value for t in AliasType}
203
+
204
+
205
+ def validate_language_code(lang_code: str) -> bool:
206
+ """
207
+ Validate ISO 639-1 language code (basic validation).
208
+
209
+ Args:
210
+ lang_code: Language code (e.g., "en", "fr")
211
+
212
+ Returns:
213
+ True if format is valid (2 lowercase letters)
214
+ """
215
+ if not lang_code or not isinstance(lang_code, str):
216
+ return False
217
+ return bool(re.match(r"^[a-z]{2}$", lang_code))
218
+
219
+
220
+ def validate_non_empty_string(value: Any, field_name: str = "value") -> str:
221
+ """
222
+ Validate that value is a non-empty string.
223
+
224
+ Args:
225
+ value: Value to validate
226
+ field_name: Field name for error message
227
+
228
+ Returns:
229
+ The validated string
230
+
231
+ Raises:
232
+ ValidationError: If value is not a non-empty string
233
+ """
234
+ if not isinstance(value, str):
235
+ raise ValidationError(
236
+ f"{field_name} must be a string",
237
+ details={"field": field_name, "type": type(value).__name__},
238
+ )
239
+
240
+ if not value.strip():
241
+ raise ValidationError(
242
+ f"{field_name} must not be empty",
243
+ details={"field": field_name},
244
+ )
245
+
246
+ return value
247
+
248
+
249
+ def validate_precedence(precedence: int) -> bool:
250
+ """
251
+ Validate overlay precedence value.
252
+
253
+ Args:
254
+ precedence: Precedence value (0-999)
255
+
256
+ Returns:
257
+ True if valid
258
+ """
259
+ return isinstance(precedence, int) and 0 <= precedence <= 999
260
+
261
+
262
+ def sanitize_query(query: str) -> str:
263
+ """
264
+ Sanitize query string.
265
+
266
+ Args:
267
+ query: Raw query string
268
+
269
+ Returns:
270
+ Sanitized query string
271
+ """
272
+ if not isinstance(query, str):
273
+ return ""
274
+
275
+ # Strip whitespace
276
+ query = query.strip()
277
+
278
+ # Collapse multiple spaces
279
+ query = re.sub(r"\s+", " ", query)
280
+
281
+ # Remove control characters
282
+ query = "".join(char for char in query if ord(char) >= 32 or char in "\n\t")
283
+
284
+ return query
285
+
286
+
287
+ def validate_schema_version(version: str) -> bool:
288
+ """
289
+ Validate semantic version string.
290
+
291
+ Args:
292
+ version: Version string (e.g., "1.2.3")
293
+
294
+ Returns:
295
+ True if valid semantic version
296
+ """
297
+ if not version or not isinstance(version, str):
298
+ return False
299
+
300
+ pattern = r"^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$"
301
+ return bool(re.match(pattern, version))
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.3
2
+ Name: resolvekit
3
+ Version: 0.0.1
4
+ Summary: A local, offline-first entity and place resolution system that maps messy place/entity strings and codes to canonical entities with calibrated confidence scores
5
+ Keywords: entity-resolution,geocoding,place-names,data-commons,iso-codes,offline,disambiguation,normalization
6
+ Author: Jorge Rivera
7
+ Author-email: Jorge Rivera <jorge.rivera@one.org>
8
+ License: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Topic :: Scientific/Engineering :: GIS
20
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
21
+ Classifier: Topic :: Text Processing :: Linguistic
22
+ Classifier: Typing :: Typed
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Requires-Dist: pydantic-settings>=2.0.0
25
+ Requires-Dist: rapidfuzz>=3.0.0
26
+ Requires-Dist: python-dateutil>=2.8.0
27
+ Requires-Dist: sqlalchemy>=2.0.0
28
+ Requires-Dist: sqlmodel>=0.0.24
29
+ Requires-Python: >=3.11
30
+ Project-URL: Documentation, https://github.com/jm-rivera/resolvekit
31
+ Project-URL: Homepage, https://github.com/jm-rivera/resolvekit
32
+ Project-URL: Repository, https://github.com/jm-rivera/resolvekit
33
+ Description-Content-Type: text/markdown
34
+
35
+ # resolvekit
36
+ An open offline resolver for places and entities
@@ -0,0 +1,70 @@
1
+ resolvekit/README.md,sha256=y3wwMUUhTa-74Th-9egHjLT_eU4Ezdt346N-1DniXDc,3341
2
+ resolvekit/__init__.py,sha256=P27cp_CtpQIYq-5s492dbwmoNOydR_b7D4SA2IwRXGI,1453
3
+ resolvekit/api/README.md,sha256=m9YT0X23bvnK8DfjKKJsXxLlTabqgCn31gyEfvQpKV0,4402
4
+ resolvekit/api/__init__.py,sha256=IyQGE-3MV2YHJ9_M2ALuXnHdawf5vFeWja9DKnDXYvU,200
5
+ resolvekit/api/convenience.py,sha256=k14RTIZ8ECfbl-Lw9HuJQ5VsaPIjqaoGBONabYQs2KU,1537
6
+ resolvekit/api/resolver.py,sha256=EkKRg7qPZdQnTcVThlwzKcG18FJ4-LYaxmvv7TKXqBk,16402
7
+ resolvekit/builders/README.md,sha256=Rgi5CYSjzx3HFF8BOXlwP5pwCueBO0TyZY_H3YaLAKs,4408
8
+ resolvekit/builders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ resolvekit/calibration/README.md,sha256=3AK1svhKwDl1qmuMe2UQpuWQzm5n1G2oCzL8E9DAYkU,10308
10
+ resolvekit/calibration/__init__.py,sha256=xrHDRZrX-dEoLELn-akglIQwhiZoYbXliUjc9_AbVOk,378
11
+ resolvekit/calibration/calibrator.py,sha256=S2D78NPcxtkMXg12oeWzrbpZY63mTFqYJx-h9lfq-ps,5751
12
+ resolvekit/calibration/features.py,sha256=brZW13GY8q7nvlGapBpc6t5tCJg5jwGS5c5rTdUf6z0,5057
13
+ resolvekit/calibration/models.py,sha256=OswPHOg6VibnIdlyOMcFpoPZcSDiyP0I8mjuMdTdxN4,2681
14
+ resolvekit/cli/README.md,sha256=RqMHx6sGos9lqSBQOshxNaCbDEfOL7AchbYeIl06hyo,4357
15
+ resolvekit/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ resolvekit/cli/main.py,sha256=UL2le9Sq0hIiM5QkgZZUwdh2tnLxR02bZqd1ALoSbKU,738
17
+ resolvekit/config.py,sha256=yQzJrRo4vC9mdq4_sHFufiMEpMYpJ17Qs74TsCgUPRs,3317
18
+ resolvekit/constants.py,sha256=BhQjtFJXkZR0rSxy45zzyPxtTzUM3ygfwi47GaFgnrs,5815
19
+ resolvekit/constraints/README.md,sha256=GhUNgqNyamOnWtiQRwqr85OtxPxY3nohcQwI-Uskt7M,3329
20
+ resolvekit/constraints/__init__.py,sha256=YI78gvQmplkA49si1kEB2-lMmdX_MO7DN18XfcEkwtQ,603
21
+ resolvekit/constraints/constraint_engine.py,sha256=vuAM29gwT040sWPKRhrwGN-9qkVlpVev3RYpTJQEIZQ,4134
22
+ resolvekit/constraints/hierarchy_validator.py,sha256=tAdyEnq4Rg93Y5sjIu6V_M20_OmVyGyBtLiIvHGvutQ,5658
23
+ resolvekit/constraints/membership_validator.py,sha256=qvUDZoOU1erAKPdIDOaK7mUtMnrOXPBCkVOKinZ7cqQ,1915
24
+ resolvekit/constraints/protocols.py,sha256=7de5utULltgZbxCMchh3PoF67pIvy8i1vv4Utarn0Kk,924
25
+ resolvekit/constraints/temporal_validator.py,sha256=mAtIwErmj0coko1ujmT4zWn7b-QmVvumgDlH_PgIz8U,1378
26
+ resolvekit/constraints/type_validator.py,sha256=2K8gNvN3xzc2eesPuUOdXzVLWEIYT-LTZx9S24JEMPE,1281
27
+ resolvekit/data/README.md,sha256=3SP439S6KSeaWlrk_nfvAuU8Px0LIAsUgKXmit8OHUA,4249
28
+ resolvekit/data/__init__.py,sha256=Vc81HnWrrDgafjN-klJawwLHyY7KU-E1zTpj7DhlpCY,405
29
+ resolvekit/data/alias_repository.py,sha256=L-ej7a75Dog0kFLqDIYtED0BMlDwHvBgN3x2MzbN2P8,6972
30
+ resolvekit/data/code_repository.py,sha256=Xs3JSKVEYE8UkTldL3xjNiTon804zlaBNwTOZ6ycuUs,2780
31
+ resolvekit/data/context_filters.py,sha256=u8pWVLRyryG7UuiozSzj5AmmuK2-y-97oev7_6_-iCg,1692
32
+ resolvekit/data/db_manager.py,sha256=tocuQVbh8E5pxRApyLiRFOi5JRqhWZbPJ5JSFRZvuG8,6293
33
+ resolvekit/data/entity_repository.py,sha256=CndYSBinzhr7VFQFfRRLyHRMBS19_PN4nkDYgmNW2Kk,15258
34
+ resolvekit/data/membership_repository.py,sha256=IVDubcfjzHbp8sRxwIvg7lVG4xNh9jUQKEyRjpES51o,3701
35
+ resolvekit/data/query_builder.py,sha256=KJONi8a9vBQJxOEzZAOCFrTRU-5-V8I9QvgkGXyeeiY,5824
36
+ resolvekit/data/schema.py,sha256=g72TjBXkzJm1rJBMxi_FFD02fqUCtS2vWqtl9wfLBi0,3926
37
+ resolvekit/disambiguation/README.md,sha256=vq_qvhuGmrzRRjDjmZWH1bAOWwk8YdzoyYkx5pZoQyo,2423
38
+ resolvekit/disambiguation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ resolvekit/extraction/README.md,sha256=YOjXgoWxylQiyonrbSduUSkLV-zzxT37gv7jyiSc0_I,5397
40
+ resolvekit/extraction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ resolvekit/matchers/README.md,sha256=BCCY60z0net_niFEwrAumiQctW24w2v4yzru7p8C1r8,2466
42
+ resolvekit/matchers/__init__.py,sha256=LodewJZ-SK4gb7ThKYLC1MewQoMh9PTevxyY5xibiAY,2339
43
+ resolvekit/matchers/alias_exact.py,sha256=q-wbFzUGDorJ-vkbmWVUUa8AFSKPzkR7QKj4g1OJFxM,1910
44
+ resolvekit/matchers/canonical_name.py,sha256=A5dIES0EZnM4nzThsntBxknawH92Z_cXDXCf20r2WTc,1876
45
+ resolvekit/matchers/cascade.py,sha256=8indUpJua1Y3-qgz1QCxh_O_USKZ3hzr3d8NRopr3-o,4593
46
+ resolvekit/matchers/code_validators.py,sha256=XOaTnlpbE1RiJ7NpesSwRkZ_Jd9JGVbmC2tWqZRlMSk,7693
47
+ resolvekit/matchers/exact_code.py,sha256=DpTLuL7b1fj-3mwAeUxiJhgV6UapEcLlt8VdpMt1vE8,6162
48
+ resolvekit/matchers/fts_matcher.py,sha256=LZ8Gx11krLHqumrMtKvnld6xwUI8lCcdQtMs7VZvHvg,3132
49
+ resolvekit/matchers/fuzzy_matcher.py,sha256=NMr7PQrpSB9jtMCVCtwex8-Rqe1b1bT_lsF1LbWvl3w,4060
50
+ resolvekit/matchers/priorities.py,sha256=rkNXAsjUZ7VjNFlMMXjE4QU1-aW_s0TaMP9BG4fVUv8,5572
51
+ resolvekit/matchers/protocols.py,sha256=5lh1FWoqxVEAVhK3nLJ6bE4HoaU-Mdrv2eUnZI68h8A,1840
52
+ resolvekit/normalization/README.md,sha256=sTFiMLohy4QYxau1yXC1PFuxzh98A55D9J41EFQOI7c,5660
53
+ resolvekit/normalization/__init__.py,sha256=D4O8UDgyLaFR293JhSBVZneI8UMlUDlCE8iyBMOgOw8,198
54
+ resolvekit/normalization/normalizer.py,sha256=qYe8r-1XVokjy7JfdY-w_c-Q5B2MI7B5oIAwjea_0L8,4430
55
+ resolvekit/overlays/README.md,sha256=27J3NZyrNHdiN_ZMcRwN2nsFNROkX_Gs3HJfcT9AOJ0,5696
56
+ resolvekit/overlays/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ resolvekit/types.py,sha256=-x49oUSz0gbkqDxhWCzs_tgwTc3KkT7ZMrgDpYDzEgg,17845
58
+ resolvekit/utils/README.md,sha256=uEkPsEJEPlzihsBr1fq8C_aySKucwp9AtKF6s6-oBvs,4218
59
+ resolvekit/utils/__init__.py,sha256=NpRdvjDYdZk9Ro94COtwZWsbzGNBsyvATzhJrSwLktA,1173
60
+ resolvekit/utils/cache.py,sha256=l29xSSRORe9tzhQldwy0DCgUuozU7ElOMJw5gpBLJbU,3144
61
+ resolvekit/utils/dates.py,sha256=vftaufH6iDYUC0TS5iIXCqZkV705jjUi0MrqjCYE2FY,8606
62
+ resolvekit/utils/errors.py,sha256=2QuTqko1soyG7HPQmh7ulbWj3zGz2I26eCHDkZMj5zs,4168
63
+ resolvekit/utils/files.py,sha256=JFBqzaSOb5pjWk_sYUsI10vuZ8sH1BF2QE510EqkK4A,8332
64
+ resolvekit/utils/logging.py,sha256=OOXbAmw87XRMrNktzGXTe04c5PxPtf5IAURwReB-D_U,6325
65
+ resolvekit/utils/text.py,sha256=OwVzNSXyFWLM4idKBZfLDoeEYKuS3itWJ_fotjSk2Cg,10971
66
+ resolvekit/utils/validation.py,sha256=T1mB4bSmNQGV7ivnbOjsGtzpkQhochNeHPiB_OUL9gI,7424
67
+ resolvekit-0.0.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
68
+ resolvekit-0.0.1.dist-info/entry_points.txt,sha256=9J3lM9GnLnIJgVRv-Z8sQ4l-to8EhoJEx1SuXnkqF2g,48
69
+ resolvekit-0.0.1.dist-info/METADATA,sha256=v6qY2k78_KkHuWUSQ_NXUQwst2ewcCynnQLzUkM3WOM,1638
70
+ resolvekit-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.24
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ resolvekit = resolvekit:main
3
+