matchlab 0.1.0.dev1__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.
- matchlab/__init__.py +55 -0
- matchlab/adapters/__init__.py +24 -0
- matchlab/adapters/base.py +446 -0
- matchlab/adapters/duckdb.py +659 -0
- matchlab/cli.py +177 -0
- matchlab/core/__init__.py +1 -0
- matchlab/core/dataframes.py +254 -0
- matchlab/core/dsu.py +62 -0
- matchlab/core/exceptions.py +40 -0
- matchlab/core/hash.py +141 -0
- matchlab/core/kinds.py +12 -0
- matchlab/core/logging.py +190 -0
- matchlab/core/resolver_output.py +173 -0
- matchlab/core/schemas.py +82 -0
- matchlab/core/sql.py +12 -0
- matchlab/document.py +329 -0
- matchlab/eval/__init__.py +11 -0
- matchlab/eval/judgements.py +41 -0
- matchlab/eval/metrics.py +244 -0
- matchlab/eval/samples.py +415 -0
- matchlab/eval/tui/__init__.py +66 -0
- matchlab/eval/tui/app.py +418 -0
- matchlab/eval/tui/modals.py +84 -0
- matchlab/eval/tui/styles.tcss +184 -0
- matchlab/eval/tui/widgets/__init__.py +1 -0
- matchlab/eval/tui/widgets/assignment.py +72 -0
- matchlab/eval/tui/widgets/styling.py +75 -0
- matchlab/eval/tui/widgets/table.py +285 -0
- matchlab/lineage.py +239 -0
- matchlab/locations.py +347 -0
- matchlab/models/__init__.py +10 -0
- matchlab/models/comparison.py +67 -0
- matchlab/models/dedupers/__init__.py +5 -0
- matchlab/models/dedupers/base.py +38 -0
- matchlab/models/dedupers/naive.py +77 -0
- matchlab/models/linkers/__init__.py +9 -0
- matchlab/models/linkers/base.py +41 -0
- matchlab/models/linkers/deterministic.py +229 -0
- matchlab/models/linkers/splinklinker.py +262 -0
- matchlab/models/linkers/weighteddeterministic.py +143 -0
- matchlab/models/models.py +198 -0
- matchlab/progress.py +455 -0
- matchlab/recordstep.py +181 -0
- matchlab/resolvers/__init__.py +10 -0
- matchlab/resolvers/base.py +63 -0
- matchlab/resolvers/components.py +66 -0
- matchlab/resolvers/resolvers.py +409 -0
- matchlab/sources.py +291 -0
- matchlab/specs.py +129 -0
- matchlab/steps.py +284 -0
- matchlab/testkit/__init__.py +104 -0
- matchlab/testkit/_generate.py +240 -0
- matchlab/testkit/compare.py +178 -0
- matchlab/testkit/entities.py +290 -0
- matchlab/testkit/features.py +146 -0
- matchlab/testkit/linked.py +527 -0
- matchlab/testkit/matchers.py +233 -0
- matchlab/testkit/models.py +165 -0
- matchlab/testkit/sources.py +327 -0
- matchlab/transformers/__init__.py +24 -0
- matchlab/transformers/base.py +41 -0
- matchlab/transformers/clean.py +48 -0
- matchlab/transformers/explode.py +67 -0
- matchlab/transformers/group.py +56 -0
- matchlab/transformers/select.py +31 -0
- matchlab/transformers/transform.py +101 -0
- matchlab-0.1.0.dev1.dist-info/METADATA +88 -0
- matchlab-0.1.0.dev1.dist-info/RECORD +72 -0
- matchlab-0.1.0.dev1.dist-info/WHEEL +5 -0
- matchlab-0.1.0.dev1.dist-info/entry_points.txt +2 -0
- matchlab-0.1.0.dev1.dist-info/licenses/LICENSE +21 -0
- matchlab-0.1.0.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Transform, a plan node that reshapes one record step with a `Transformer`.
|
|
2
|
+
|
|
3
|
+
`Transform` is to `Transformer` what `Model` is to a `Deduper`/`Linker`, the lazy plan
|
|
4
|
+
node that wraps a serialisable methodology, folds its configuration into a cache key,
|
|
5
|
+
and runs it on collect. Its single input is a `RecordStep`, so transforms chain, each
|
|
6
|
+
its own cached artifact.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import ClassVar
|
|
10
|
+
|
|
11
|
+
import polars as pl
|
|
12
|
+
|
|
13
|
+
from matchlab.adapters import Adapter, Fingerprint
|
|
14
|
+
from matchlab.core.kinds import StepKind
|
|
15
|
+
from matchlab.recordstep import IdentifierRead, RecordStep
|
|
16
|
+
from matchlab.specs import TransformSpec
|
|
17
|
+
from matchlab.transformers.base import Transformer
|
|
18
|
+
from matchlab.transformers.clean import Clean
|
|
19
|
+
from matchlab.transformers.explode import Explode
|
|
20
|
+
from matchlab.transformers.group import Group
|
|
21
|
+
from matchlab.transformers.select import Select
|
|
22
|
+
|
|
23
|
+
_TRANSFORMER_CLASSES: dict[str, type[Transformer]] = {}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_transformer_class(transformer_class: type[Transformer]) -> None:
|
|
27
|
+
"""Register a custom transformer so it can be named in a plan (and a document)."""
|
|
28
|
+
if not issubclass(transformer_class, Transformer):
|
|
29
|
+
raise ValueError("The argument is not a subclass of Transformer.")
|
|
30
|
+
_TRANSFORMER_CLASSES[transformer_class.__name__] = transformer_class
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
for _builtin in (Select, Clean, Group, Explode):
|
|
34
|
+
add_transformer_class(_builtin)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Transform(RecordStep):
|
|
38
|
+
"""A record step reshaped by one transformer."""
|
|
39
|
+
|
|
40
|
+
kind: ClassVar[StepKind] = StepKind.TRANSFORM
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
upstream: RecordStep,
|
|
45
|
+
transformer: Transformer | type[Transformer] | str,
|
|
46
|
+
transformer_settings: dict | None = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
"""Define a transform.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
upstream: The record step to reshape.
|
|
52
|
+
transformer: A `Transformer` instance, or a subclass / its registered name
|
|
53
|
+
to build from `transformer_settings`.
|
|
54
|
+
transformer_settings: The configuration dict, when `transformer` is a class
|
|
55
|
+
or a name. Ignored when it is already an instance.
|
|
56
|
+
"""
|
|
57
|
+
if isinstance(transformer, Transformer):
|
|
58
|
+
self.transformer = transformer
|
|
59
|
+
else:
|
|
60
|
+
transformer_class = (
|
|
61
|
+
_TRANSFORMER_CLASSES[transformer]
|
|
62
|
+
if isinstance(transformer, str)
|
|
63
|
+
else transformer
|
|
64
|
+
)
|
|
65
|
+
self.transformer = transformer_class(**(transformer_settings or {}))
|
|
66
|
+
|
|
67
|
+
self.transformer_class = type(self.transformer)
|
|
68
|
+
self._input = upstream
|
|
69
|
+
super().__init__(upstream=(upstream,))
|
|
70
|
+
|
|
71
|
+
# -- Step contract ----------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
def __str__(self) -> str:
|
|
74
|
+
"""A transform is drawn with the transformer implementing it."""
|
|
75
|
+
return f"{self.kind}({self.transformer_class.__name__})"
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def spec(self) -> TransformSpec:
|
|
79
|
+
"""The serialisable spec for this transform."""
|
|
80
|
+
return TransformSpec(
|
|
81
|
+
transformer_class=self.transformer_class.__name__,
|
|
82
|
+
transformer_settings=self.transformer.model_dump(mode="json"),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def _execute(self, adapter: Adapter, fp: Fingerprint) -> None:
|
|
86
|
+
reshaped = self.transformer.apply(self._input._read_cache(adapter))
|
|
87
|
+
adapter.store_transform(fp, reshaped)
|
|
88
|
+
|
|
89
|
+
# -- RecordStep contract ------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
def _read_cache(self, adapter: Adapter) -> pl.DataFrame:
|
|
92
|
+
if self._fp is None: # collect orders upstream first
|
|
93
|
+
raise RuntimeError(
|
|
94
|
+
"This transform has not been collected. Call collect() first."
|
|
95
|
+
)
|
|
96
|
+
return adapter.read_transform(self._fp)
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def _identifier_reads(self) -> tuple[IdentifierRead, ...]:
|
|
100
|
+
"""A transform reads the same records as its input, so the reads delegate up."""
|
|
101
|
+
return self._input._identifier_reads
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: matchlab
|
|
3
|
+
Version: 0.1.0.dev1
|
|
4
|
+
Summary: A local-first library for building, running and evaluating entity resolution pipelines.
|
|
5
|
+
Author: Department for Business and Trade
|
|
6
|
+
Project-URL: Documentation, https://uktrade.github.io/matchlab/
|
|
7
|
+
Project-URL: Repository, https://github.com/uktrade/matchlab.git
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Python: <3.14,>=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: adbc-driver-manager>=1.9.0
|
|
20
|
+
Requires-Dist: duckdb>=1.1.1
|
|
21
|
+
Requires-Dist: faker>=36.1.1
|
|
22
|
+
Requires-Dist: frozendict>=2.4.6
|
|
23
|
+
Requires-Dist: pandas>=2.3.3
|
|
24
|
+
Requires-Dist: platformdirs>=4.5.0
|
|
25
|
+
Requires-Dist: polars-hash>=0.5.3
|
|
26
|
+
Requires-Dist: polars>=1.32.3
|
|
27
|
+
Requires-Dist: pyarrow>=17.0.0
|
|
28
|
+
Requires-Dist: pydantic>=2.9.2
|
|
29
|
+
Requires-Dist: rich>=13.9.4
|
|
30
|
+
Requires-Dist: splink<4.1.0,>=4.0.5
|
|
31
|
+
Requires-Dist: sqlalchemy>=2.0.35
|
|
32
|
+
Requires-Dist: sqlglot[c]>=30.0.3
|
|
33
|
+
Requires-Dist: textual>=0.80
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# matchlab
|
|
37
|
+
|
|
38
|
+
**A local-first library for building, running and evaluating entity resolution pipelines.**
|
|
39
|
+
|
|
40
|
+
Record matching is a chore. matchlab makes it a pipeline you can build, run, query and measure — on your machine, against your warehouse, with nothing to deploy.
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from matchlab import Source
|
|
44
|
+
from matchlab.models.dedupers import NaiveDeduper
|
|
45
|
+
|
|
46
|
+
companies = Source(
|
|
47
|
+
location=warehouse,
|
|
48
|
+
name="crn",
|
|
49
|
+
extract_transform="select pk, company, town from companies",
|
|
50
|
+
key_field="pk",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
entities = (
|
|
54
|
+
companies.clean({"name": "lower(crn_company)"})
|
|
55
|
+
.dedupe(model_class=NaiveDeduper, model_settings={"unique_fields": ["name"]})
|
|
56
|
+
.resolve()
|
|
57
|
+
.collect()
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
entities.lookup_key(from_source="crn", to_sources=["dh"], key="a1")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Read the [full documentation](https://uktrade.github.io/matchlab/).
|
|
64
|
+
|
|
65
|
+
## What it does
|
|
66
|
+
|
|
67
|
+
* **A lazy plan.** `Source(...).dedupe(...).resolve()` builds a tree of steps. Nothing runs until you `collect()`.
|
|
68
|
+
* **Content-addressed caching.** Re-collecting an unchanged plan does no work. Adding a step runs only that step.
|
|
69
|
+
* **Materialised resolver output.** A collected resolver writes a complete `(root, leaf, key, source)` table, so lookups are reads, not re-derivations.
|
|
70
|
+
* **Measurement as a first-class job.** Sample clusters, record judgements, score precision and recall, and compare methodologies on equal terms.
|
|
71
|
+
|
|
72
|
+
## What it doesn't do
|
|
73
|
+
|
|
74
|
+
No server, no accounts, no permissions, nothing to deploy. If you need a shared, governed matching service, matchlab is not that.
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```shell
|
|
79
|
+
pip install matchlab
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Coming from Matchbox?
|
|
83
|
+
|
|
84
|
+
matchlab is the successor to `matchbox-db`, with the server removed and the client API rebuilt. It's a hard break — see the [migration guide](https://uktrade.github.io/matchlab/migration/matchbox-to-matchlab/).
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
See our full development guide and coding standards on our [contribution guide](https://uktrade.github.io/matchlab/contributing/).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
matchlab/__init__.py,sha256=GoBEpiGNfnxOxA3KXMWHaqZVjh4HnrATZayGv-wQeS4,1200
|
|
2
|
+
matchlab/cli.py,sha256=Ka-clRCiPnxI5jmehjGCgdNyADcPFcnl3cuPI1rynYg,6209
|
|
3
|
+
matchlab/document.py,sha256=6iWbZsiX9dm2TFHTTtu4WpKf8tjglrY4dKZcqB39Di0,13419
|
|
4
|
+
matchlab/lineage.py,sha256=qJWPGpXVnuH8xQBZ-0L6PZjKg6b74xX9j6koY-N4Org,8870
|
|
5
|
+
matchlab/locations.py,sha256=6zvXWBXaQFBbOhicsILqW0cLoY17e5Yow3xIBEtfwtw,13435
|
|
6
|
+
matchlab/progress.py,sha256=t2PAj0YG2vAHguMFn9J0NL07R2K6wEnAkGELQpFNYNM,21330
|
|
7
|
+
matchlab/recordstep.py,sha256=n2aEpePo4GqWxo2r37N6pJbF-DLGNQpqFHEoxFc-2-I,7380
|
|
8
|
+
matchlab/sources.py,sha256=TdS4c2crd-pqeXATYE80TyG5B1oWgh0PzkSt_2fdpkE,12414
|
|
9
|
+
matchlab/specs.py,sha256=zIWNIZ0YsWqAFh-19JFCYLQSgZwuM6vGoaJgEC5z5uM,4638
|
|
10
|
+
matchlab/steps.py,sha256=91y9Klh25vyxdRtWP4bj-4fXSmX41tLX4sCqChUgSAg,12932
|
|
11
|
+
matchlab/adapters/__init__.py,sha256=QN8tGB0LJtLtxtEaq1aFZD_XHAQiR_e2CUPGoVJj4gg,554
|
|
12
|
+
matchlab/adapters/base.py,sha256=HEIrave447Rm26ZzZicPHgjeyJRJ9wa7DzhedryzANI,18738
|
|
13
|
+
matchlab/adapters/duckdb.py,sha256=tsKlQo_nAJCU4ySHjhnbwL-MmbLVRIG1EPV9E_D-EiQ,28663
|
|
14
|
+
matchlab/core/__init__.py,sha256=ftFTAWUmTIzJh01EkAvmJ8V4p2L33itVQ6t_JGxWzZg,68
|
|
15
|
+
matchlab/core/dataframes.py,sha256=8dSUyjVbC09YFFMnjOdHXqROJtt5SXSYOONxxIl88gY,8018
|
|
16
|
+
matchlab/core/dsu.py,sha256=nhOdQsVZw8AltxH0bBPaCp2YJQ7Y8h2zS7wDle9moVk,1946
|
|
17
|
+
matchlab/core/exceptions.py,sha256=qHnc2s6bFPvUQBmJ9oOk02-9zx-fLUPmGVUG7rblZx0,1305
|
|
18
|
+
matchlab/core/hash.py,sha256=E4jjov9asj-EGJxNTcsJP-J5h6Ju8pLLTQsmjBJqp2w,4714
|
|
19
|
+
matchlab/core/kinds.py,sha256=LKzyFY1bTCIiQRTV0LiALeVWcPp4Ol1h2TvaSN_mV5Y,255
|
|
20
|
+
matchlab/core/logging.py,sha256=LbdeEhyESwTTikD5pgZBKRInE0XRMSylmAZIv6VMOOk,8640
|
|
21
|
+
matchlab/core/resolver_output.py,sha256=chm1CUJP09gZlszLdKHG0_V9WfQu5_DoumLeT85UmU8,7899
|
|
22
|
+
matchlab/core/schemas.py,sha256=I5YjvMU8IsFLURM1AsLOxB7UjoYvVDlno2MQqNKnAZk,2638
|
|
23
|
+
matchlab/core/sql.py,sha256=swcsYb9vgdxIUbwBeMOIY4j1epvRWkr3qjuKbJbP3HA,432
|
|
24
|
+
matchlab/eval/__init__.py,sha256=Lb-Lm1FwHMD-0yB-WONdX58y0G4dDlo-Zz93OQMhTlo,233
|
|
25
|
+
matchlab/eval/judgements.py,sha256=IZgWXH2-ltzlyfbzB8-COgKzNRg851c63Z7oKA4Ce7A,1450
|
|
26
|
+
matchlab/eval/metrics.py,sha256=yQHpjzSBFLsMwMAPDiWNcUrPZx-OkTindY5Mb5BjInk,9747
|
|
27
|
+
matchlab/eval/samples.py,sha256=ZXBvUJzLEG6KV_wTl4Q5BvliuJC4T1LOYwKM1zsUooA,16546
|
|
28
|
+
matchlab/eval/tui/__init__.py,sha256=T77U0fWsMlAQnsUEVah0-tonP1M-4aW92fGExoJgFWg,2528
|
|
29
|
+
matchlab/eval/tui/app.py,sha256=CFw43oO_kct0fDwl8iVKupFEOgPxCWqy6-3pPlJX0sg,15033
|
|
30
|
+
matchlab/eval/tui/modals.py,sha256=WwfH82-_vTtS0G_xCjhig5f1N7BMMr35-WMA0GQPKBk,2692
|
|
31
|
+
matchlab/eval/tui/styles.tcss,sha256=ioZ8trLoH0roS5LZDrXeo3IIzh4sA9Pi8hrEDF0dpBs,3220
|
|
32
|
+
matchlab/eval/tui/widgets/__init__.py,sha256=AJsdcJTQy0LIOegAxSRFjCR-DW5jCodClYdPRKfXJsc,56
|
|
33
|
+
matchlab/eval/tui/widgets/assignment.py,sha256=djYry92TIjSwOxPERyeBdM9imcu1ngd8zrDwHQ2TNQk,2316
|
|
34
|
+
matchlab/eval/tui/widgets/styling.py,sha256=va69ALl74yjdgG4Wf7y0iEd5apJmIUoLf27WOv74K74,2346
|
|
35
|
+
matchlab/eval/tui/widgets/table.py,sha256=gXXDXDgwFXpXrCv1Grw-gryT-RSl441tsTpr-GT3M6I,11043
|
|
36
|
+
matchlab/models/__init__.py,sha256=cOfN9Um4r7XuBkC8dfTPRYefmQruxGm6kw6R9SJWvgw,225
|
|
37
|
+
matchlab/models/comparison.py,sha256=ahx5CjsK-NNLdWiHW6JIqyXJLlQ1MQZ9-_XnrlneehI,2447
|
|
38
|
+
matchlab/models/models.py,sha256=DgiGsqP9ps3c3mexZUzw5T9YwzNg-GusHMIoxGlzvT0,7588
|
|
39
|
+
matchlab/models/dedupers/__init__.py,sha256=J7JZSAnA8C-qyarathk369unktvpBa2njJ2POslVx0k,121
|
|
40
|
+
matchlab/models/dedupers/base.py,sha256=z_7AS-UfsiQXa_e14R-a_mD1aSeZrTtg4jgYpmDnBA0,1246
|
|
41
|
+
matchlab/models/dedupers/naive.py,sha256=aHlSvwY6fbLjH4adEFFVbyVui3azm6gRKQ5amb-fibE,2432
|
|
42
|
+
matchlab/models/linkers/__init__.py,sha256=qbj6hITLFBuONO0_fn3yPknTUAWjzWcFSQzIyi75Rmc,339
|
|
43
|
+
matchlab/models/linkers/base.py,sha256=Xt7ninASXRsuE46FuGqp1kterqG8X9E7BhcifSqnlPM,1366
|
|
44
|
+
matchlab/models/linkers/deterministic.py,sha256=yX1kEdxMmu8HYZst2eHLx-JqOQYM0sFedJLapwI7U0w,8956
|
|
45
|
+
matchlab/models/linkers/splinklinker.py,sha256=jVMClcKBKSXNkLSrJQMF33J4CxdbwXPNilYIAk4vD3E,9949
|
|
46
|
+
matchlab/models/linkers/weighteddeterministic.py,sha256=m8j1oGTbuOuvuALiZlt20dXhMKs8YfisXpekegaqr5A,4584
|
|
47
|
+
matchlab/resolvers/__init__.py,sha256=G1lbpQK_NrKabHBR7rd25ou1KKLQqjmHAcAz8LaXUiY,256
|
|
48
|
+
matchlab/resolvers/base.py,sha256=fYq8_tAeprq_dFVclhIGhb4DQWW8Rq_DRFB-CAg-qWc,2056
|
|
49
|
+
matchlab/resolvers/components.py,sha256=h0EuH6jdQaplXhdWnWk3sk2-QtcKH4y_hH5EG1LxL98,2033
|
|
50
|
+
matchlab/resolvers/resolvers.py,sha256=dmbaqsTfU6-qNksMDj_6QwuApN68f3VT26yluzawhPI,17605
|
|
51
|
+
matchlab/testkit/__init__.py,sha256=7e3ynGwMoPDc8gIILa2FROyzxVMqXJa5bBt7qIQ1vos,4411
|
|
52
|
+
matchlab/testkit/_generate.py,sha256=-ZeCrDJVWqmRRKDVmAtAm-xR61q1fblANDCRNM89vHk,8408
|
|
53
|
+
matchlab/testkit/compare.py,sha256=y_6wYqTNemikn7SMG1BCovgm6_l3hvl5vu5d2dZzj5E,6513
|
|
54
|
+
matchlab/testkit/entities.py,sha256=ho1VtZZIimaIIDFgH9kj3HHjRFluurgR9WMRB74yssI,10188
|
|
55
|
+
matchlab/testkit/features.py,sha256=m-X0ItSwlyvX48hQAI8kQNmMA50s__wGnWsw2kqhLV8,4692
|
|
56
|
+
matchlab/testkit/linked.py,sha256=pc1_LmfrL7Jku5yoOXWlnDosNYCQok4KBqDoN7l1nwU,19882
|
|
57
|
+
matchlab/testkit/matchers.py,sha256=JgobKrMVW8wK-INxH4qBzWqoqJootnpC5SZDQ3lwJBU,9773
|
|
58
|
+
matchlab/testkit/models.py,sha256=Ng0kysLxTuiglqO2bnaXljT_OHOLDi7_DSgNe0Dg4a4,6532
|
|
59
|
+
matchlab/testkit/sources.py,sha256=fUL5SefxnOypHrOKiY7DoXDRIvn4tpd7QIF4nstZ9U8,11250
|
|
60
|
+
matchlab/transformers/__init__.py,sha256=zNTpHycQKe6TRsjRDe9_7rbJpjNiVmbPZreOKtB9dhg,771
|
|
61
|
+
matchlab/transformers/base.py,sha256=tW7oIzbAG4exXFcJ2iKKjTyc9t4AgfXF_TjxMR6SpkU,1483
|
|
62
|
+
matchlab/transformers/clean.py,sha256=NvCfl7-KOL-7Wr0-DpKB40tnXhnfrvQvavMitr9N8eE,1992
|
|
63
|
+
matchlab/transformers/explode.py,sha256=k8Q__0aFdntyGxkffu2KWSJmCVCu7ImvJtRt-32Q5j4,2934
|
|
64
|
+
matchlab/transformers/group.py,sha256=SZ5iR646uuiwHyZusTTGfYcFi0dJAmWyXpw9FnY2mxI,2319
|
|
65
|
+
matchlab/transformers/select.py,sha256=s3NmMgL5IS7ifeIhj5ABQJ46XULW6s_kQKASOq7G0sQ,1125
|
|
66
|
+
matchlab/transformers/transform.py,sha256=ws6yS1Z9EZ4fuPB2zOKcNJXSo2Ku-bkKoTh8QpP_bMY,3916
|
|
67
|
+
matchlab-0.1.0.dev1.dist-info/licenses/LICENSE,sha256=7fhYMrjTXiy7Sf-9lBtZHNc4IjHTcfqmGW0AcjFMJJo,1090
|
|
68
|
+
matchlab-0.1.0.dev1.dist-info/METADATA,sha256=hzYyHGefEbnebD4gstmQZZo2nT9stGl93RIwCwmFcF8,3304
|
|
69
|
+
matchlab-0.1.0.dev1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
70
|
+
matchlab-0.1.0.dev1.dist-info/entry_points.txt,sha256=giDdKIeNDxGNWrvoVuLA5mtQjwStupSwxDYmrRjM9Rs,47
|
|
71
|
+
matchlab-0.1.0.dev1.dist-info/top_level.txt,sha256=1ZVLg12gZgkOUbN5CfX-KmLTbHGRbZqFEZPqrfRVN-Y,9
|
|
72
|
+
matchlab-0.1.0.dev1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Department for Business and Trade
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
matchlab
|