followthemoney 3.8.4__py3-none-any.whl → 3.8.5__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 followthemoney might be problematic. Click here for more details.
- followthemoney/__init__.py +1 -1
- followthemoney/cli/__init__.py +3 -12
- followthemoney/cli/aggregate.py +1 -1
- followthemoney/cli/mapping.py +6 -4
- followthemoney/cli/sieve.py +1 -1
- followthemoney/export/common.py +3 -3
- followthemoney/export/csv.py +10 -12
- followthemoney/export/neo4j.py +1 -1
- followthemoney/graph.py +5 -2
- followthemoney/mapping/csv.py +6 -18
- followthemoney/mapping/sql.py +3 -4
- followthemoney/namespace.py +3 -1
- followthemoney/proxy.py +1 -1
- {followthemoney-3.8.4.dist-info → followthemoney-3.8.5.dist-info}/METADATA +17 -28
- {followthemoney-3.8.4.dist-info → followthemoney-3.8.5.dist-info}/RECORD +18 -18
- {followthemoney-3.8.4.dist-info → followthemoney-3.8.5.dist-info}/licenses/LICENSE +1 -0
- {followthemoney-3.8.4.dist-info → followthemoney-3.8.5.dist-info}/WHEEL +0 -0
- {followthemoney-3.8.4.dist-info → followthemoney-3.8.5.dist-info}/entry_points.txt +0 -0
followthemoney/__init__.py
CHANGED
followthemoney/cli/__init__.py
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
def load_entry_points() -> None:
|
|
5
|
-
|
|
6
|
-
from importlib.metadata import entry_points
|
|
7
|
-
|
|
8
|
-
for ep in entry_points().select(group="followthemoney.cli"):
|
|
9
|
-
ep.load()
|
|
10
|
-
else:
|
|
11
|
-
from pkg_resources import iter_entry_points
|
|
2
|
+
from importlib.metadata import entry_points
|
|
12
3
|
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
for ep in entry_points().select(group="followthemoney.cli"):
|
|
5
|
+
ep.load()
|
|
15
6
|
|
|
16
7
|
|
|
17
8
|
load_entry_points()
|
followthemoney/cli/aggregate.py
CHANGED
followthemoney/cli/mapping.py
CHANGED
|
@@ -60,22 +60,24 @@ def run_mapping(outfile: Path, mapping_yaml: Path, sign: bool = True) -> None:
|
|
|
60
60
|
def stream_mapping(
|
|
61
61
|
infile: Path, outfile: Path, mapping_yaml: Path, sign: bool = True
|
|
62
62
|
) -> None:
|
|
63
|
-
queries: List[Tuple[str, QueryMapping]] = []
|
|
63
|
+
queries: List[Tuple[str, QueryMapping, CSVSource]] = []
|
|
64
64
|
config = load_mapping_file(mapping_yaml)
|
|
65
65
|
for dataset, meta in config.items():
|
|
66
66
|
for data in keys_values(meta, "queries", "query"):
|
|
67
67
|
data.pop("database", None)
|
|
68
68
|
data["csv_url"] = "/dev/null"
|
|
69
69
|
query = model.make_mapping(data, key_prefix=dataset)
|
|
70
|
-
|
|
70
|
+
source = query.source
|
|
71
|
+
assert isinstance(source, CSVSource)
|
|
72
|
+
queries.append((dataset, query, source))
|
|
71
73
|
|
|
72
74
|
try:
|
|
73
75
|
with path_writer(outfile) as outfh:
|
|
74
76
|
with input_file(infile) as fh:
|
|
75
77
|
for record in CSVSource.read_csv(fh):
|
|
76
|
-
for
|
|
78
|
+
for dataset, query, source in queries:
|
|
77
79
|
ns = Namespace(dataset)
|
|
78
|
-
if
|
|
80
|
+
if source.check_filters(record):
|
|
79
81
|
entities = query.map(record)
|
|
80
82
|
for entity in entities.values():
|
|
81
83
|
if sign:
|
followthemoney/cli/sieve.py
CHANGED
|
@@ -3,7 +3,7 @@ from pathlib import Path
|
|
|
3
3
|
from typing import Iterable, Optional
|
|
4
4
|
|
|
5
5
|
from followthemoney import model
|
|
6
|
-
from followthemoney.proxy import
|
|
6
|
+
from followthemoney.proxy import EntityProxy
|
|
7
7
|
from followthemoney.types import registry
|
|
8
8
|
from followthemoney.cli.cli import cli
|
|
9
9
|
from followthemoney.cli.util import InPath, OutPath, path_entities
|
followthemoney/export/common.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Generator, List, Optional, Tuple
|
|
2
2
|
from followthemoney.property import Property
|
|
3
|
-
from followthemoney.proxy import
|
|
3
|
+
from followthemoney.proxy import EntityProxy
|
|
4
4
|
from followthemoney.schema import Schema
|
|
5
5
|
from followthemoney.types import registry
|
|
6
6
|
|
|
@@ -17,12 +17,12 @@ class Exporter(object):
|
|
|
17
17
|
yield prop
|
|
18
18
|
|
|
19
19
|
def exportable_fields(
|
|
20
|
-
self, proxy:
|
|
20
|
+
self, proxy: EntityProxy
|
|
21
21
|
) -> Generator[Tuple[Property, List[str]], None, None]:
|
|
22
22
|
for prop in self.exportable_properties(proxy.schema):
|
|
23
23
|
yield prop, proxy.get(prop)
|
|
24
24
|
|
|
25
|
-
def write(self, proxy:
|
|
25
|
+
def write(self, proxy: EntityProxy, extra: Optional[List[str]] = None) -> None:
|
|
26
26
|
raise NotImplementedError
|
|
27
27
|
|
|
28
28
|
def finalize(self) -> None:
|
followthemoney/export/csv.py
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import csv
|
|
2
|
-
|
|
3
|
-
try:
|
|
4
|
-
from _csv import _writer as csv_writer
|
|
5
|
-
except ImportError:
|
|
6
|
-
# Python 3.8/3.9 work-around:
|
|
7
|
-
from _csv import writer as csv_writer # type: ignore
|
|
8
|
-
|
|
9
|
-
from io import TextIOWrapper
|
|
10
2
|
from pathlib import Path
|
|
11
|
-
from
|
|
3
|
+
from io import TextIOWrapper
|
|
4
|
+
from typing import Any, Dict, List, Optional, Protocol, Tuple
|
|
12
5
|
|
|
13
|
-
from followthemoney.proxy import
|
|
6
|
+
from followthemoney.proxy import EntityProxy
|
|
14
7
|
from followthemoney.export.common import Exporter
|
|
15
8
|
from followthemoney.schema import Schema
|
|
16
9
|
from followthemoney.util import PathLike
|
|
17
10
|
|
|
18
|
-
|
|
11
|
+
|
|
12
|
+
class CSVWriter(Protocol):
|
|
13
|
+
@property
|
|
14
|
+
def dialect(self) -> Any: ...
|
|
15
|
+
def writerow(self, row: Any) -> Any: ...
|
|
16
|
+
def writerows(self, rows: Any) -> None: ...
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
class CSVMixin(object):
|
|
@@ -69,7 +67,7 @@ class CSVExporter(Exporter, CSVMixin):
|
|
|
69
67
|
headers.append(prop.name)
|
|
70
68
|
writer.writerow(headers)
|
|
71
69
|
|
|
72
|
-
def write(self, proxy:
|
|
70
|
+
def write(self, proxy: EntityProxy, extra: Optional[List[str]] = None) -> None:
|
|
73
71
|
writer = self._get_writer(proxy.schema)
|
|
74
72
|
cells = [proxy.id]
|
|
75
73
|
cells.extend(extra or [])
|
followthemoney/export/neo4j.py
CHANGED
|
@@ -150,7 +150,7 @@ class CypherGraphExporter(GraphExporter):
|
|
|
150
150
|
labels = list(node.schema.names)
|
|
151
151
|
else:
|
|
152
152
|
labels = [node.type.name]
|
|
153
|
-
cypher = "MERGE (p { %(id)s })
|
|
153
|
+
cypher = "MERGE (p { %(id)s }) SET p += { %(map)s } SET p :%(label)s;\n"
|
|
154
154
|
self.fh.write(
|
|
155
155
|
cypher
|
|
156
156
|
% {
|
followthemoney/graph.py
CHANGED
|
@@ -5,6 +5,7 @@ This module provides an abstract data object that represents a property
|
|
|
5
5
|
graph. This is used by the exporter modules to convert data
|
|
6
6
|
to a specific output format, like Cypher or NetworkX.
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
import logging
|
|
9
10
|
from typing import Any, Dict, Generator, Iterable, List, Optional
|
|
10
11
|
|
|
@@ -69,6 +70,8 @@ class Node(object):
|
|
|
69
70
|
def from_proxy(cls, proxy: EntityProxy) -> "Node":
|
|
70
71
|
"""For a given :class:`~followthemoney.proxy.EntityProxy`, return a node
|
|
71
72
|
based on the entity."""
|
|
73
|
+
if proxy.id is None:
|
|
74
|
+
raise InvalidModel("Invalid entity proxy: %r" % proxy)
|
|
72
75
|
return cls(registry.entity, proxy.id, proxy=proxy)
|
|
73
76
|
|
|
74
77
|
def __str__(self) -> str:
|
|
@@ -256,11 +259,11 @@ class Graph(object):
|
|
|
256
259
|
"""Add an :class:`~followthemoney.proxy.EntityProxy` to the graph and make
|
|
257
260
|
it either a :class:`~followthemoney.graph.Node` or an
|
|
258
261
|
:class:`~followthemoney.graph.Edge`."""
|
|
259
|
-
if proxy is None:
|
|
262
|
+
if proxy is None or proxy.id is None:
|
|
260
263
|
return
|
|
261
264
|
self.queue(proxy.id, proxy)
|
|
262
265
|
if proxy.schema.edge:
|
|
263
|
-
for
|
|
266
|
+
for source, target in proxy.edgepairs():
|
|
264
267
|
self._add_edge(proxy, source, target)
|
|
265
268
|
else:
|
|
266
269
|
self._add_node(proxy)
|
followthemoney/mapping/csv.py
CHANGED
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import os
|
|
3
3
|
import logging
|
|
4
|
-
from banal.lists import ensure_list
|
|
5
4
|
import requests
|
|
6
5
|
from csv import DictReader
|
|
7
6
|
from urllib.parse import urlparse
|
|
8
|
-
from banal import keys_values
|
|
9
|
-
from typing import
|
|
10
|
-
|
|
11
|
-
Any,
|
|
12
|
-
Dict,
|
|
13
|
-
Generator,
|
|
14
|
-
ItemsView,
|
|
15
|
-
Iterable,
|
|
16
|
-
List,
|
|
17
|
-
Optional,
|
|
18
|
-
Set,
|
|
19
|
-
Tuple,
|
|
20
|
-
cast,
|
|
21
|
-
)
|
|
7
|
+
from banal import keys_values, ensure_list
|
|
8
|
+
from typing import TYPE_CHECKING, cast
|
|
9
|
+
from typing import Any, Dict, Generator, ItemsView, Iterable, List, Optional, Set, Tuple
|
|
22
10
|
|
|
23
11
|
from followthemoney.mapping.source import Record, Source
|
|
24
12
|
from followthemoney.util import sanitize_text
|
|
@@ -48,16 +36,16 @@ class CSVSource(Source):
|
|
|
48
36
|
|
|
49
37
|
def _parse_filters(self, filters: ItemsView[str, Any]) -> FilterList:
|
|
50
38
|
filters_set: FilterList = []
|
|
51
|
-
for
|
|
39
|
+
for key, value in filters:
|
|
52
40
|
values = set(cast(List[Optional[str]], ensure_list(value)))
|
|
53
41
|
filters_set.append((key, values))
|
|
54
42
|
return filters_set
|
|
55
43
|
|
|
56
44
|
def check_filters(self, data: Record) -> bool:
|
|
57
|
-
for
|
|
45
|
+
for k, v in self.filters_set:
|
|
58
46
|
if data.get(k) not in v:
|
|
59
47
|
return False
|
|
60
|
-
for
|
|
48
|
+
for k, v in self.filters_not_set:
|
|
61
49
|
if data.get(k) in v:
|
|
62
50
|
return False
|
|
63
51
|
return True
|
followthemoney/mapping/sql.py
CHANGED
|
@@ -3,8 +3,7 @@ import logging
|
|
|
3
3
|
from uuid import uuid4
|
|
4
4
|
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Union, cast
|
|
5
5
|
from banal import ensure_list, is_listish, keys_values
|
|
6
|
-
from sqlalchemy import MetaData, func
|
|
7
|
-
from sqlalchemy.future import select
|
|
6
|
+
from sqlalchemy import MetaData, func, select
|
|
8
7
|
from sqlalchemy.engine import Engine, create_engine
|
|
9
8
|
from sqlalchemy.sql.elements import Label
|
|
10
9
|
from sqlalchemy.pool import NullPool
|
|
@@ -68,7 +67,7 @@ class SQLSource(Source):
|
|
|
68
67
|
return table.refs[ref]
|
|
69
68
|
raise InvalidMapping("Missing reference: %s" % ref)
|
|
70
69
|
|
|
71
|
-
def apply_filters(self, q: Select) -> Select:
|
|
70
|
+
def apply_filters(self, q: Select[Any]) -> Select[Any]:
|
|
72
71
|
for col, val in self.filters:
|
|
73
72
|
if is_listish(val):
|
|
74
73
|
q = q.where(self.get_column(col).in_(val))
|
|
@@ -88,7 +87,7 @@ class SQLSource(Source):
|
|
|
88
87
|
q = q.where(left == right)
|
|
89
88
|
return q
|
|
90
89
|
|
|
91
|
-
def compose_query(self) -> Select:
|
|
90
|
+
def compose_query(self) -> Select[Any]:
|
|
92
91
|
columns = [self.get_column(r) for r in self.query.refs]
|
|
93
92
|
q = select(*columns)
|
|
94
93
|
q = q.select_from(*[t.alias for t in self.tables])
|
followthemoney/namespace.py
CHANGED
|
@@ -22,6 +22,7 @@ that the combined ID is specific to a dataset, without needing an (expensive)
|
|
|
22
22
|
index look up of each ID first. It can also be generated on the client or
|
|
23
23
|
the server without compromising isolation.
|
|
24
24
|
"""
|
|
25
|
+
|
|
25
26
|
import hmac
|
|
26
27
|
from typing import Any, Optional, Tuple, Union
|
|
27
28
|
|
|
@@ -95,7 +96,8 @@ class Namespace(object):
|
|
|
95
96
|
"""Rewrite an entity proxy so all IDs mentioned are limited to
|
|
96
97
|
the namespace."""
|
|
97
98
|
signed = proxy.clone()
|
|
98
|
-
|
|
99
|
+
if proxy.id is not None:
|
|
100
|
+
signed.id = self.sign(proxy.id)
|
|
99
101
|
if not shallow:
|
|
100
102
|
for prop in proxy.iterprops():
|
|
101
103
|
if prop.type != registry.entity:
|
followthemoney/proxy.py
CHANGED
|
@@ -71,7 +71,7 @@ class EntityProxy(object):
|
|
|
71
71
|
#: A unique identifier for this entity, usually a hashed natural key,
|
|
72
72
|
#: a UUID, or a very simple slug. Can be signed using a
|
|
73
73
|
#: :class:`~followthemoney.namespace.Namespace`.
|
|
74
|
-
self.id = data
|
|
74
|
+
self.id = str(data["id"]) if "id" in data else None
|
|
75
75
|
if not cleaned:
|
|
76
76
|
self.id = sanitize_text(self.id)
|
|
77
77
|
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: followthemoney
|
|
3
|
-
Version: 3.8.
|
|
3
|
+
Version: 3.8.5
|
|
4
4
|
Summary: A data model for anti corruption data modeling and analysis.
|
|
5
5
|
Project-URL: Documentation, https://followthemoney.tech/
|
|
6
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
-
Project-URL: Issues, https://github.com/
|
|
8
|
-
Author-email:
|
|
6
|
+
Project-URL: Repository, https://github.com/opensanctions/followthemoney.git
|
|
7
|
+
Project-URL: Issues, https://github.com/opensanctions/followthemoney/issues
|
|
8
|
+
Author-email: OpenSanctions <info@opensanctions.org>, DARC <hi@dataresearchcenter.org>
|
|
9
9
|
License: MIT License
|
|
10
10
|
|
|
11
11
|
Copyright (c) 2017-2024 Journalism Development Network, Inc.
|
|
12
|
+
Copyright (c) 2025 OpenSanctions Datenbanken GmbH
|
|
12
13
|
|
|
13
14
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
15
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -51,8 +52,7 @@ Requires-Dist: pyyaml<7.0.0,>=5.0.0
|
|
|
51
52
|
Requires-Dist: rdflib<7.2.0,>=6.2.0
|
|
52
53
|
Requires-Dist: requests<3.0.0,>=2.21.0
|
|
53
54
|
Requires-Dist: rigour<1.0.0,>=0.11.1
|
|
54
|
-
Requires-Dist:
|
|
55
|
-
Requires-Dist: sqlalchemy<3.0.0,>=1.4.49
|
|
55
|
+
Requires-Dist: sqlalchemy[mypy]<3.0.0,>=2.0.0
|
|
56
56
|
Requires-Dist: types-pyyaml
|
|
57
57
|
Provides-Extra: dev
|
|
58
58
|
Requires-Dist: build; extra == 'dev'
|
|
@@ -76,17 +76,13 @@ Description-Content-Type: text/markdown
|
|
|
76
76
|
|
|
77
77
|
# Follow the Money
|
|
78
78
|
|
|
79
|
-
[](https://github.com/opensanctions/followthemoney/actions/workflows/build.yml)
|
|
80
80
|
|
|
81
|
-
This repository contains a pragmatic data model for the entities most
|
|
82
|
-
commonly used in investigative reporting: people, companies, assets,
|
|
83
|
-
payments, court cases, etc.
|
|
81
|
+
This repository contains a pragmatic data model for the entities most commonly used in investigative reporting and financial crime investigations: people, companies, assets, payments, ownership relations, court cases, etc.
|
|
84
82
|
|
|
85
|
-
The purpose of this is not to model reality in an ideal data model, but
|
|
86
|
-
rather to have a working data structure for researchers.
|
|
83
|
+
The purpose of this is not to model reality in an ideal data model, but rather to have a working data structure for researchers. Complex legal considerations are simplified to allow for efficient data processing.
|
|
87
84
|
|
|
88
|
-
`followthemoney` also contains code used to validate and normalize many
|
|
89
|
-
of the elements of data, and to map tabular data into the model.
|
|
85
|
+
`followthemoney` also contains code used to validate and normalize many of the elements of data, and to map tabular data into the model.
|
|
90
86
|
|
|
91
87
|
## Documentation
|
|
92
88
|
|
|
@@ -104,12 +100,11 @@ library and the contained ontology:
|
|
|
104
100
|
|
|
105
101
|
* https://followthemoney.tech/explorer/
|
|
106
102
|
|
|
107
|
-
There's also a number of viewers for the RDF schema definitions generated
|
|
108
|
-
from FollowTheMoney, e.g.:
|
|
103
|
+
There's also a number of viewers for the RDF schema definitions generated from FollowTheMoney, eg:
|
|
109
104
|
|
|
110
|
-
* [LODE documentation](http://150.146.207.114/lode/extract?url=https%3A%2F%
|
|
111
|
-
* [WebVOWL](https://service.tib.eu/webvowl/#iri=https://
|
|
112
|
-
* RDF/OWL specification in [XML](https://
|
|
105
|
+
* [LODE documentation](http://150.146.207.114/lode/extract?url=https%3A%2F%2Ffollowthemoney.tech%2Fns%2Fftm.xml&owlapi=true&imported=true&lang=en)
|
|
106
|
+
* [WebVOWL](https://service.tib.eu/webvowl/#iri=https://followthemoney.tech/ns/ftm.xml)
|
|
107
|
+
* RDF/OWL specification in [XML](https://followthemoney.tech/ns/ftm.xml).
|
|
113
108
|
|
|
114
109
|
## Development environment
|
|
115
110
|
|
|
@@ -129,9 +124,7 @@ make test
|
|
|
129
124
|
|
|
130
125
|
## Releasing
|
|
131
126
|
|
|
132
|
-
We release a lot of version of `followthemoney` because even small changes
|
|
133
|
-
to the code base require a pypi release to begin being used in `aleph`. To
|
|
134
|
-
this end, here's the steps for making a release:
|
|
127
|
+
We release a lot of version of `followthemoney` because even small changes to the code base require a pypi release to begin being used in `aleph`. To this end, here's the steps for making a release:
|
|
135
128
|
|
|
136
129
|
```bash
|
|
137
130
|
git pull --rebase
|
|
@@ -142,10 +135,6 @@ bumpversion patch
|
|
|
142
135
|
git push --atomic origin main $(git describe --tags --abbrev=0)
|
|
143
136
|
```
|
|
144
137
|
|
|
145
|
-
This will create a new patch release and upload a distribution of it. If
|
|
146
|
-
the changes are more significant, you can run `bumpversion` with the `minor`
|
|
147
|
-
or `major` arguments.
|
|
138
|
+
This will create a new patch release and upload a distribution of it. If the changes are more significant, you can run `bumpversion` with the `minor` or `major` arguments.
|
|
148
139
|
|
|
149
|
-
When the schema is updated, please update the docs, ideally including the
|
|
150
|
-
diagrams. For the RDF namespace and JavaScript version of the model,
|
|
151
|
-
run `make generate`.
|
|
140
|
+
When the schema is updated, please update the docs, ideally including the diagrams. For the RDF namespace and JavaScript version of the model, run `make generate`.
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
followthemoney/__init__.py,sha256=
|
|
1
|
+
followthemoney/__init__.py,sha256=GTdXf-mlMlK2HNFSllcTQHcDOhWxcMhLGJB7OeyP29I,360
|
|
2
2
|
followthemoney/compare.py,sha256=1GFkCfTzA8QR0CH90kvySR8hvl9hQRUerW5Xw2Ivmpg,5134
|
|
3
3
|
followthemoney/exc.py,sha256=ynZs_UnTVxHR-iBfat_CpVLraYzVX5yLtVf5Ti14hl4,734
|
|
4
|
-
followthemoney/graph.py,sha256=
|
|
4
|
+
followthemoney/graph.py,sha256=9ZNXI3cPR3NFO0hzDj19c1Nx9bgkRWD_EIRgG6zWTPU,10963
|
|
5
5
|
followthemoney/helpers.py,sha256=Btb6BlHg_c-qCXZo-NP_LURKG-qu-QD3Fj1ev_c7Xic,7956
|
|
6
6
|
followthemoney/messages.py,sha256=zUEa9CFecU8nRafIzhN6TKCh1kEihiIyIS1qr8PxY4g,806
|
|
7
7
|
followthemoney/model.py,sha256=FBY6iSbfvsxdjwFlwhs234IbYtl_MwEeTTmoxIFBxC0,6485
|
|
8
|
-
followthemoney/namespace.py,sha256=
|
|
8
|
+
followthemoney/namespace.py,sha256=cp7X8aGaZ8HHf7SOfHr2vJHPI2todz2DoyLdiZLNMyg,4472
|
|
9
9
|
followthemoney/offshore.py,sha256=Pf0tx-7GyhIZRueshDRqPNlxkHfGstmW5yNDID5Mnws,1060
|
|
10
10
|
followthemoney/ontology.py,sha256=7PEoUKISNpkRvVhuLeE3IE9ZiNtdR8mn9_kzZ9yF9l0,2986
|
|
11
11
|
followthemoney/property.py,sha256=zi9ss1v0e8Wmv-FuLtZd2aod5iTLfBekBxuOTgIOUMU,7718
|
|
12
|
-
followthemoney/proxy.py,sha256=
|
|
12
|
+
followthemoney/proxy.py,sha256=PIuo38ev_MJxamO_0MGKh2MdgJiwaletZbq3uKO3Yv4,20054
|
|
13
13
|
followthemoney/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
followthemoney/rdf.py,sha256=9wPs-tqN9QILuvrmH_YheNaFQctyIQqoIEqcS465QHs,343
|
|
15
15
|
followthemoney/schema.py,sha256=Yqv11zhZXMOq1MjKQP44Ie8vIurDrSr5qlqRJEueLK4,18126
|
|
16
16
|
followthemoney/util.py,sha256=6VR-T5-vT-8xpE6__Skrqe_MpE6y6csvNKERTJlsITA,4527
|
|
17
|
-
followthemoney/cli/__init__.py,sha256=
|
|
18
|
-
followthemoney/cli/aggregate.py,sha256=
|
|
17
|
+
followthemoney/cli/__init__.py,sha256=0mmz84uhXRp2qUn3syKnDXofU3MMAAe291s7htqX0Bg,187
|
|
18
|
+
followthemoney/cli/aggregate.py,sha256=xQTFpU3cVVj7fplpX4OJVrRlTVpn6b9kBr_Vb87pKfg,2164
|
|
19
19
|
followthemoney/cli/cli.py,sha256=yrPw2iyKY-E-uRWe6KN9W3ayvz-22vfpe_ZeD0RiI0c,3591
|
|
20
20
|
followthemoney/cli/exports.py,sha256=HsTyIOz1KQSeObp9-9SKzSUBW158XOhpU5_Stv_2HWM,4016
|
|
21
|
-
followthemoney/cli/mapping.py,sha256=
|
|
22
|
-
followthemoney/cli/sieve.py,sha256=
|
|
21
|
+
followthemoney/cli/mapping.py,sha256=PGQ-9T5ss6w6qnZg7IjUZZ3PplY15CcPSxZxkyMFLDM,3370
|
|
22
|
+
followthemoney/cli/sieve.py,sha256=wLB35fCVp1ArZ7FDTbARevBk8jH4vnp65fyBZU7Lk_k,1937
|
|
23
23
|
followthemoney/cli/util.py,sha256=CFcS-PEwpMasMWX_Yg283O_PaAhcPwkvahFNWc13C8c,4769
|
|
24
24
|
followthemoney/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
followthemoney/export/common.py,sha256=
|
|
26
|
-
followthemoney/export/csv.py,sha256=
|
|
25
|
+
followthemoney/export/common.py,sha256=5b-Qlu3MaA0kSzzMAP93FAWncpgiioENnCnHikWYxhs,1021
|
|
26
|
+
followthemoney/export/csv.py,sha256=reWq1jYIv7sY2PEI4JwIxahYNNqnSiPfMCS3kQX4RZ8,2652
|
|
27
27
|
followthemoney/export/excel.py,sha256=pj6zNpIbye_Zm3vhCamcqHEe9Fw-RyjtWQDCFY6608s,2645
|
|
28
28
|
followthemoney/export/graph.py,sha256=v0z1FgadyFk5aQ0A5q8E9R4fSO-Tpi5JU9YTDwnRKD8,2765
|
|
29
|
-
followthemoney/export/neo4j.py,sha256=
|
|
29
|
+
followthemoney/export/neo4j.py,sha256=4Lih9lt3-5ATERhyMcfJfkiETG3tqj9vY4N9s7jiYmw,7049
|
|
30
30
|
followthemoney/export/rdf.py,sha256=E6RiW7oIsJdaBaLAVm6o-MTokARZtqONPuayILqTqo0,786
|
|
31
31
|
followthemoney/mapping/__init__.py,sha256=iwNqzzvrzJNbNDlOCaDLlBTUrNTlnYHIB5cvo_-9oN4,82
|
|
32
|
-
followthemoney/mapping/csv.py,sha256=
|
|
32
|
+
followthemoney/mapping/csv.py,sha256=1eqQk1tn5JSEcr4rrv44XdT5biUk7J0E275uvUNoOrA,3125
|
|
33
33
|
followthemoney/mapping/entity.py,sha256=-x_VBHiVthIrZZ-PVKD3oBAq6LYcsyeYW-9TFv80k7M,5905
|
|
34
34
|
followthemoney/mapping/property.py,sha256=41V16HJh6da7oKdSJWyRcyMkx2XFd6iDm9-4PH7Wihw,5036
|
|
35
35
|
followthemoney/mapping/query.py,sha256=8M6bOlEX2p_bbVwEwTu_1slEtU0cfRJB7ajZp-F07CE,2622
|
|
36
36
|
followthemoney/mapping/source.py,sha256=sri-XpSjeHZbQtqNcz1eJYvwVSBNqGO5JwhWswiEx3c,649
|
|
37
|
-
followthemoney/mapping/sql.py,sha256=
|
|
37
|
+
followthemoney/mapping/sql.py,sha256=iCSOl9uOzJI__1d1XvLtJmLUXhb38MRM_eBnYt7TdP8,4738
|
|
38
38
|
followthemoney/schema/Address.yaml,sha256=9cPZfkNiV-5fNfSzBFcE_dwD0V2_WLpGSLT6kL8GbuQ,1709
|
|
39
39
|
followthemoney/schema/Airplane.yaml,sha256=i3tI4INH6ZtKBqm09fAUtCbieFlha-vPfQURXMDZTIU,622
|
|
40
40
|
followthemoney/schema/Analyzable.yaml,sha256=WvyhjYqI7QzBt3qPDgO7MDasJH1qQtgQMToHkV_xtlU,1237
|
|
@@ -150,8 +150,8 @@ followthemoney/types/registry.py,sha256=hvQ1oIWz_4PpyUnKA5azbaZCulNb5LCIPyC-AQYV
|
|
|
150
150
|
followthemoney/types/string.py,sha256=grDn1OgKWxIzVxGEdp0HjVKIqtQ9W4SW2ty4quv3Pcs,1202
|
|
151
151
|
followthemoney/types/topic.py,sha256=FqV_4YDpmQxZO9m05l3c-nDyDqsZONqBG5aaf5aCkvA,3797
|
|
152
152
|
followthemoney/types/url.py,sha256=r7Pd6Yfn--amwMi_nHoTLMwm5SH8h50SMgQaa2G4PJ0,1492
|
|
153
|
-
followthemoney-3.8.
|
|
154
|
-
followthemoney-3.8.
|
|
155
|
-
followthemoney-3.8.
|
|
156
|
-
followthemoney-3.8.
|
|
157
|
-
followthemoney-3.8.
|
|
153
|
+
followthemoney-3.8.5.dist-info/METADATA,sha256=cOEWYZHcj__KvWhrH43Vtj0DZc998eeRk533xAa0lXw,6168
|
|
154
|
+
followthemoney-3.8.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
155
|
+
followthemoney-3.8.5.dist-info/entry_points.txt,sha256=xvTXjAz0CiZplq4V3iQXlmBexaJyW3zNucIvcDP6L_c,593
|
|
156
|
+
followthemoney-3.8.5.dist-info/licenses/LICENSE,sha256=H6_EVXisnJC0-18CjXIaqrBSFq_VH3OnS7u3dccOv6g,1148
|
|
157
|
+
followthemoney-3.8.5.dist-info/RECORD,,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2017-2024 Journalism Development Network, Inc.
|
|
4
|
+
Copyright (c) 2025 OpenSanctions Datenbanken GmbH
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
7
|
of this software and associated documentation files (the "Software"), to deal
|
|
File without changes
|
|
File without changes
|