followthemoney 4.1.2__py3-none-any.whl → 4.2.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.
- followthemoney/__init__.py +1 -1
- followthemoney/entity.py +15 -0
- followthemoney/helpers.py +12 -14
- followthemoney/property.py +15 -5
- followthemoney/schema/Risk.yaml +43 -0
- followthemoney/schema/Vessel.yaml +3 -0
- followthemoney/statement/entity.py +38 -3
- followthemoney/types/topic.py +32 -0
- {followthemoney-4.1.2.dist-info → followthemoney-4.2.1.dist-info}/METADATA +5 -5
- {followthemoney-4.1.2.dist-info → followthemoney-4.2.1.dist-info}/RECORD +13 -12
- {followthemoney-4.1.2.dist-info → followthemoney-4.2.1.dist-info}/WHEEL +0 -0
- {followthemoney-4.1.2.dist-info → followthemoney-4.2.1.dist-info}/entry_points.txt +0 -0
- {followthemoney-4.1.2.dist-info → followthemoney-4.2.1.dist-info}/licenses/LICENSE +0 -0
followthemoney/__init__.py
CHANGED
|
@@ -9,7 +9,7 @@ from followthemoney.statement import Statement, StatementEntity, SE
|
|
|
9
9
|
from followthemoney.dataset import Dataset, DefaultDataset, DS
|
|
10
10
|
from followthemoney.util import set_model_locale
|
|
11
11
|
|
|
12
|
-
__version__ = "4.1
|
|
12
|
+
__version__ = "4.2.1"
|
|
13
13
|
|
|
14
14
|
# Data model singleton
|
|
15
15
|
model = Model.instance()
|
followthemoney/entity.py
CHANGED
|
@@ -20,6 +20,21 @@ class ValueEntity(EntityProxy):
|
|
|
20
20
|
applications should use this entity class as the base class.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
+
__slots__ = [
|
|
24
|
+
"schema",
|
|
25
|
+
"id",
|
|
26
|
+
"key_prefix",
|
|
27
|
+
"context",
|
|
28
|
+
"_properties",
|
|
29
|
+
"_size",
|
|
30
|
+
"_caption",
|
|
31
|
+
"datasets",
|
|
32
|
+
"referents",
|
|
33
|
+
"first_seen",
|
|
34
|
+
"last_seen",
|
|
35
|
+
"last_change",
|
|
36
|
+
]
|
|
37
|
+
|
|
23
38
|
def __init__(
|
|
24
39
|
self,
|
|
25
40
|
schema: Schema,
|
followthemoney/helpers.py
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# probably be the first place to break.
|
|
8
8
|
from os.path import splitext
|
|
9
9
|
from typing import Iterable, List, Optional, Set
|
|
10
|
-
from normality import safe_filename
|
|
10
|
+
from normality import safe_filename, squash_spaces
|
|
11
11
|
from mimetypes import guess_extension
|
|
12
12
|
from itertools import product
|
|
13
13
|
from datetime import datetime, timedelta
|
|
@@ -148,23 +148,21 @@ def inline_names(entity: E, related: E) -> None:
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
def combine_names(entity: E) -> E:
|
|
151
|
-
"""
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
(e.g. matching) processes."""
|
|
151
|
+
"""Build a full names from name parts of a Person entity and add them as aliases.
|
|
152
|
+
|
|
153
|
+
This is of course impossible to do culturally correctly for the whole planet at
|
|
154
|
+
once, so it should be mostly used for internal-facing (e.g. matching) processes."""
|
|
155
155
|
if entity.schema.is_a("Person"):
|
|
156
156
|
first_names = entity.get("firstName")
|
|
157
|
-
second_names = entity.get("secondName")
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
father_names = entity.get("fatherName")
|
|
162
|
-
father_names.append("")
|
|
157
|
+
second_names = entity.get("secondName") + [""]
|
|
158
|
+
middle_names = entity.get("middleName") + [""]
|
|
159
|
+
father_names = entity.get("fatherName") + [""]
|
|
160
|
+
mother_names = entity.get("motherName") + [""]
|
|
163
161
|
last_names = entity.get("lastName")
|
|
164
|
-
for (first, second, middle, father, last) in product(
|
|
165
|
-
first_names, second_names, middle_names, father_names, last_names
|
|
162
|
+
for (first, second, middle, father, mother, last) in product(
|
|
163
|
+
first_names, second_names, middle_names, father_names, mother_names, last_names
|
|
166
164
|
):
|
|
167
|
-
name =
|
|
165
|
+
name = squash_spaces(" ".join([first, second, middle, father, mother, last]))
|
|
168
166
|
if name is not None:
|
|
169
167
|
entity.add("alias", name)
|
|
170
168
|
|
followthemoney/property.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from banal import is_mapping, as_bool
|
|
2
3
|
from typing import TYPE_CHECKING, Any, List, Optional, TypedDict
|
|
3
4
|
|
|
@@ -9,6 +10,18 @@ if TYPE_CHECKING:
|
|
|
9
10
|
from followthemoney.schema import Schema
|
|
10
11
|
from followthemoney.model import Model
|
|
11
12
|
|
|
13
|
+
# Invalid property names.
|
|
14
|
+
RESERVED = ["id", "caption", "schema", "schemata", "referents", "datasets"]
|
|
15
|
+
PROP_NAME_RE = re.compile("^[a-z][a-zA-Z0-9]*$")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def check_property_name(name: str) -> bool:
|
|
19
|
+
if name in RESERVED:
|
|
20
|
+
return False
|
|
21
|
+
if not PROP_NAME_RE.match(name):
|
|
22
|
+
return False
|
|
23
|
+
return True
|
|
24
|
+
|
|
12
25
|
|
|
13
26
|
class ReverseSpec(TypedDict, total=False):
|
|
14
27
|
name: str
|
|
@@ -66,9 +79,6 @@ class Property:
|
|
|
66
79
|
"reverse",
|
|
67
80
|
)
|
|
68
81
|
|
|
69
|
-
#: Invalid property names.
|
|
70
|
-
RESERVED = ["id", "caption", "schema", "schemata"]
|
|
71
|
-
|
|
72
82
|
def __init__(self, schema: "Schema", name: str, data: PropertySpec) -> None:
|
|
73
83
|
#: The schema which the property is defined for. This is always the
|
|
74
84
|
#: most abstract schema that has this property, not the possible
|
|
@@ -77,11 +87,11 @@ class Property:
|
|
|
77
87
|
|
|
78
88
|
#: Machine-readable name for this property.
|
|
79
89
|
self.name = const(name)
|
|
90
|
+
if not check_property_name(self.name):
|
|
91
|
+
raise InvalidModel("Invalid name: %s" % self.name)
|
|
80
92
|
|
|
81
93
|
#: Qualified property name, which also includes the schema name.
|
|
82
94
|
self.qname = const("%s:%s" % (schema.name, self.name))
|
|
83
|
-
if self.name in self.RESERVED:
|
|
84
|
-
raise InvalidModel("Reserved name: %s" % self.name)
|
|
85
95
|
|
|
86
96
|
self._hash = hash("<Property(%r)>" % self.qname)
|
|
87
97
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Risk:
|
|
2
|
+
label: Risk
|
|
3
|
+
plural: Risks
|
|
4
|
+
description: "A risk associated with an entity"
|
|
5
|
+
extends:
|
|
6
|
+
- Interval
|
|
7
|
+
matchable: false
|
|
8
|
+
featured:
|
|
9
|
+
- entity
|
|
10
|
+
- country
|
|
11
|
+
- reason
|
|
12
|
+
- status
|
|
13
|
+
- startDate
|
|
14
|
+
required:
|
|
15
|
+
- entity
|
|
16
|
+
caption:
|
|
17
|
+
- reason
|
|
18
|
+
- status
|
|
19
|
+
properties:
|
|
20
|
+
entity:
|
|
21
|
+
label: "Entity"
|
|
22
|
+
reverse:
|
|
23
|
+
name: risks
|
|
24
|
+
label: "Risks"
|
|
25
|
+
type: entity
|
|
26
|
+
range: Thing
|
|
27
|
+
topics:
|
|
28
|
+
label: Topics
|
|
29
|
+
type: topic
|
|
30
|
+
status:
|
|
31
|
+
label: "Status"
|
|
32
|
+
duration:
|
|
33
|
+
label: "Duration"
|
|
34
|
+
type: number
|
|
35
|
+
reason:
|
|
36
|
+
label: "Reason"
|
|
37
|
+
type: text
|
|
38
|
+
country:
|
|
39
|
+
label: "Country"
|
|
40
|
+
type: country
|
|
41
|
+
listingDate:
|
|
42
|
+
label: "Listing date"
|
|
43
|
+
type: date
|
|
@@ -2,6 +2,8 @@ from hashlib import sha1
|
|
|
2
2
|
from collections.abc import Mapping
|
|
3
3
|
from typing import Any, Dict, List, Optional, Set, Type
|
|
4
4
|
from typing import Generator, Iterable, Tuple, TypeVar
|
|
5
|
+
from rigour.langs import LangStr
|
|
6
|
+
from rigour.names.pick import pick_lang_name
|
|
5
7
|
|
|
6
8
|
from followthemoney.model import Model
|
|
7
9
|
from followthemoney.exc import InvalidData
|
|
@@ -163,6 +165,7 @@ class StatementEntity(EntityProxy):
|
|
|
163
165
|
else:
|
|
164
166
|
self.last_change = max(self.last_change, stmt.first_seen)
|
|
165
167
|
else:
|
|
168
|
+
self._caption = None
|
|
166
169
|
if stmt.prop not in self._statements:
|
|
167
170
|
self._statements[stmt.prop] = set()
|
|
168
171
|
self._statements[stmt.prop].add(stmt)
|
|
@@ -296,13 +299,17 @@ class StatementEntity(EntityProxy):
|
|
|
296
299
|
prop_name = self._prop_name(prop, quiet=quiet)
|
|
297
300
|
if prop_name is None or prop_name not in self._statements:
|
|
298
301
|
return []
|
|
302
|
+
if prop_name in self.schema.caption:
|
|
303
|
+
self._caption = None
|
|
299
304
|
return list({s.value for s in self._statements.pop(prop_name, [])})
|
|
300
305
|
|
|
301
306
|
def remove(self, prop: P, value: str, quiet: bool = True) -> None:
|
|
302
307
|
prop_name = self._prop_name(prop, quiet=quiet)
|
|
303
|
-
if prop_name is not None and prop_name in self.
|
|
308
|
+
if prop_name is not None and prop_name in self._statements:
|
|
304
309
|
stmts = {s for s in self._statements[prop_name] if s.value != value}
|
|
305
310
|
self._statements[prop_name] = stmts
|
|
311
|
+
if prop_name in self.schema.caption:
|
|
312
|
+
self._caption = None
|
|
306
313
|
|
|
307
314
|
def itervalues(self) -> Generator[Tuple[Property, str], None, None]:
|
|
308
315
|
for name, statements in self._statements.items():
|
|
@@ -335,6 +342,34 @@ class StatementEntity(EntityProxy):
|
|
|
335
342
|
def properties(self) -> Dict[str, List[str]]:
|
|
336
343
|
return {p: list({s.value for s in vs}) for p, vs in self._statements.items()}
|
|
337
344
|
|
|
345
|
+
@property
|
|
346
|
+
def caption(self) -> str:
|
|
347
|
+
"""The user-facing label to be used for this entity. This checks a list
|
|
348
|
+
of properties defined by the schema (caption) and returns the first
|
|
349
|
+
available value. If no caption is available, return the schema label.
|
|
350
|
+
|
|
351
|
+
This implementation prefers statements where the language property is that
|
|
352
|
+
of the preferred system language."""
|
|
353
|
+
if self._caption is None:
|
|
354
|
+
for prop_ in self.schema.caption:
|
|
355
|
+
stmts = self._statements.get(prop_)
|
|
356
|
+
if stmts is None:
|
|
357
|
+
continue
|
|
358
|
+
prop = self.schema.properties[prop_]
|
|
359
|
+
if prop.type == registry.name and len(stmts) > 1:
|
|
360
|
+
values = [LangStr(s.value, lang=s.lang) for s in stmts]
|
|
361
|
+
name = pick_lang_name(values)
|
|
362
|
+
if name is not None:
|
|
363
|
+
self._caption = name
|
|
364
|
+
break
|
|
365
|
+
else:
|
|
366
|
+
for stmt in sorted(stmts):
|
|
367
|
+
self._caption = stmt.value
|
|
368
|
+
break
|
|
369
|
+
if self._caption is None:
|
|
370
|
+
self._caption = self.schema.label
|
|
371
|
+
return self._caption
|
|
372
|
+
|
|
338
373
|
def iterprops(self) -> List[Property]:
|
|
339
374
|
return [self.schema.properties[p] for p in self._statements.keys()]
|
|
340
375
|
|
|
@@ -353,8 +388,8 @@ class StatementEntity(EntityProxy):
|
|
|
353
388
|
raise InvalidData(msg % (self.id, e))
|
|
354
389
|
|
|
355
390
|
if not isinstance(other, StatementEntity):
|
|
356
|
-
for prop,
|
|
357
|
-
self.
|
|
391
|
+
for prop, value in other.itervalues():
|
|
392
|
+
self.unsafe_add(prop, value, cleaned=True, quiet=True)
|
|
358
393
|
return self
|
|
359
394
|
for stmt in other._iter_stmt():
|
|
360
395
|
if self.id is not None:
|
followthemoney/types/topic.py
CHANGED
|
@@ -55,10 +55,14 @@ class TopicType(EnumType):
|
|
|
55
55
|
"gov.judicial": _("Judicial branch of government"),
|
|
56
56
|
"gov.security": _("Security services"),
|
|
57
57
|
"gov.financial": _("Central banking and financial integrity"),
|
|
58
|
+
"gov.religion": _("Religious leadership"),
|
|
58
59
|
"fin": _("Financial services"),
|
|
59
60
|
"fin.bank": _("Bank"),
|
|
60
61
|
"fin.fund": _("Fund"),
|
|
61
62
|
"fin.adivsor": _("Financial advisor"),
|
|
63
|
+
"mare.detained": _("Maritime detention"),
|
|
64
|
+
"mare.shadow": _("Shadow fleet"),
|
|
65
|
+
"mare.sts": _("Ship-to-ship transfer"),
|
|
62
66
|
"reg.action": _("Regulator action"),
|
|
63
67
|
"reg.warn": _("Regulator warning"),
|
|
64
68
|
"role.pep": _("Politician"),
|
|
@@ -87,5 +91,33 @@ class TopicType(EnumType):
|
|
|
87
91
|
"poi": _("Person of interest"),
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
RISKS = {
|
|
95
|
+
"corp.disqual",
|
|
96
|
+
"crime.boss",
|
|
97
|
+
"crime.fin",
|
|
98
|
+
"crime.fraud",
|
|
99
|
+
"crime.terror",
|
|
100
|
+
"crime.theft",
|
|
101
|
+
"crime.traffick",
|
|
102
|
+
"crime.war",
|
|
103
|
+
"crime",
|
|
104
|
+
"debarment",
|
|
105
|
+
"export.control",
|
|
106
|
+
"export.risk",
|
|
107
|
+
"poi",
|
|
108
|
+
"mare.detained",
|
|
109
|
+
"mare.shadow",
|
|
110
|
+
"reg.action",
|
|
111
|
+
"reg.warn",
|
|
112
|
+
"role.oligarch",
|
|
113
|
+
"role.pep",
|
|
114
|
+
"role.rca",
|
|
115
|
+
"sanction.counter",
|
|
116
|
+
"sanction.linked",
|
|
117
|
+
"sanction",
|
|
118
|
+
"wanted",
|
|
119
|
+
}
|
|
120
|
+
"""A set of topics that imply a counterparty risk in business dealings."""
|
|
121
|
+
|
|
90
122
|
def _locale_names(self, locale: Locale) -> EnumValues:
|
|
91
123
|
return {k: gettext(v) for (k, v) in self._TOPICS.items()}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: followthemoney
|
|
3
|
-
Version: 4.1
|
|
3
|
+
Version: 4.2.1
|
|
4
4
|
Summary: A data model for anti corruption data modeling and analysis.
|
|
5
5
|
Project-URL: Documentation, https://followthemoney.tech/
|
|
6
6
|
Project-URL: Repository, https://github.com/opensanctions/followthemoney.git
|
|
@@ -42,15 +42,15 @@ Requires-Dist: click<9.0.0,>=8.0
|
|
|
42
42
|
Requires-Dist: networkx<3.5,>=2.5
|
|
43
43
|
Requires-Dist: normality<4.0.0,>=3.0.1
|
|
44
44
|
Requires-Dist: openpyxl<4.0.0,>=3.0.5
|
|
45
|
-
Requires-Dist: orjson<4.0,>=3.10.
|
|
45
|
+
Requires-Dist: orjson<4.0,>=3.10.0
|
|
46
46
|
Requires-Dist: phonenumbers<10.0.0,>=8.12.22
|
|
47
|
-
Requires-Dist: prefixdate<1.0.0,>=0.
|
|
48
|
-
Requires-Dist: pydantic<3.0.0,>=2.11.
|
|
47
|
+
Requires-Dist: prefixdate<1.0.0,>=0.5.0
|
|
48
|
+
Requires-Dist: pydantic<3.0.0,>=2.11.0
|
|
49
49
|
Requires-Dist: pytz>=2021.1
|
|
50
50
|
Requires-Dist: pyyaml<7.0.0,>=5.0.0
|
|
51
51
|
Requires-Dist: rdflib<7.2.0,>=6.2.0
|
|
52
52
|
Requires-Dist: requests<3.0.0,>=2.21.0
|
|
53
|
-
Requires-Dist: rigour<2.0.0,>=1.
|
|
53
|
+
Requires-Dist: rigour<2.0.0,>=1.3.1
|
|
54
54
|
Requires-Dist: sqlalchemy[mypy]<3.0.0,>=2.0.0
|
|
55
55
|
Provides-Extra: dev
|
|
56
56
|
Requires-Dist: build; extra == 'dev'
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
followthemoney/__init__.py,sha256=
|
|
1
|
+
followthemoney/__init__.py,sha256=X-mG5wtVuhLqrHVWmz8NnB7mBFYuMwJj_wfYkL63n4M,856
|
|
2
2
|
followthemoney/compare.py,sha256=bZlnj2VMoe67q4Lyq_VwS1a-EJnEK1kC8prbs8jyL9E,5774
|
|
3
|
-
followthemoney/entity.py,sha256=
|
|
3
|
+
followthemoney/entity.py,sha256=bBiX7hNquXemS3vYCUHKtWI_IqX43Z6i8RQDbZ7gXsg,3449
|
|
4
4
|
followthemoney/exc.py,sha256=GyMgwY4QVm87hLevDfV7gM1MJsDqfNCi_UQw7F_A8X8,858
|
|
5
5
|
followthemoney/graph.py,sha256=7X1CGHGvmktS2LSZqld2iXWzG7B831eCNYyBqamqEJ8,10921
|
|
6
|
-
followthemoney/helpers.py,sha256=
|
|
6
|
+
followthemoney/helpers.py,sha256=EsneNJ5DZXHTPUYfXLxGESphsPwCtGiWv-71vvVBWus,7982
|
|
7
7
|
followthemoney/messages.py,sha256=zUEa9CFecU8nRafIzhN6TKCh1kEihiIyIS1qr8PxY4g,806
|
|
8
8
|
followthemoney/model.py,sha256=bWFVNa-DhYzc8BdSXBZdG2ev6Nh9uHx6i4tin8DvEEU,7374
|
|
9
9
|
followthemoney/names.py,sha256=LODQqExKEHdH4z6Mmbhlm0KeKRzGcptaSWzYXZ7lONI,1120
|
|
10
10
|
followthemoney/namespace.py,sha256=utggu9IGA8bhgEYom3OUB1KxkAJR_TrMNbY5MUF_db8,4536
|
|
11
11
|
followthemoney/ontology.py,sha256=WWY_PYQGl5Ket4zZBuZglzQxD2Bh9UqHok6GJNNX7GA,3001
|
|
12
|
-
followthemoney/property.py,sha256=
|
|
12
|
+
followthemoney/property.py,sha256=9qZ_o2iA-1llLMJ3O2hsW7c2XhkFU1YbvVqretGYUSA,7913
|
|
13
13
|
followthemoney/proxy.py,sha256=LD4K1oPABXMX212UZxwLu7XOHRDyVBwTlqudTUsUZRQ,19619
|
|
14
14
|
followthemoney/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
followthemoney/schema.py,sha256=WYnPE4Lego0pJHlojECEv0aO9Miw_YIvEb35HoDo4Zk,18087
|
|
@@ -97,6 +97,7 @@ followthemoney/schema/ProjectParticipant.yaml,sha256=xNehEu90uqUfboNouezhZQ8ZQLx
|
|
|
97
97
|
followthemoney/schema/PublicBody.yaml,sha256=BNfLBqH1OapoEninAjWmqZx_n-G5QUnzzydW7300TiY,301
|
|
98
98
|
followthemoney/schema/RealEstate.yaml,sha256=NWFHXqEHskYQN-kvQESZpu74nztShqoYSZEjZAr-DHM,1363
|
|
99
99
|
followthemoney/schema/Representation.yaml,sha256=sCvFnUDQaElq2cqSB0rILcMYb2gaMZqlzxlHxyX9IGg,792
|
|
100
|
+
followthemoney/schema/Risk.yaml,sha256=2BRVBqb6wiLHxb_V50P-YMAOhjC64UVHDyh5PASpCIA,728
|
|
100
101
|
followthemoney/schema/Sanction.yaml,sha256=-3_NrTp1KPSsSMkttFzwo81zFKplx15w-9EmwPnE8-o,1278
|
|
101
102
|
followthemoney/schema/Security.yaml,sha256=w8Och0cslWjHPAs60HZ6JarEXdIbqGlIbN1NlvgN_7Y,1212
|
|
102
103
|
followthemoney/schema/Similar.yaml,sha256=gD8rZEaPQWzU-rEfsKdn62uEucF3KxYBcPMoSdnxvME,817
|
|
@@ -109,11 +110,11 @@ followthemoney/schema/UnknownLink.yaml,sha256=lneS_HZNgeLyJxwzWnLx0ZoyY3MXt99I_K
|
|
|
109
110
|
followthemoney/schema/UserAccount.yaml,sha256=2bbPKNtt1R3zWSSkaq_SVzRPfFzX74kAxwtIxTymHA8,840
|
|
110
111
|
followthemoney/schema/Value.yaml,sha256=cNHTCtakMTXDW0Qpb6ArZodi9rMJ-Ebvp1WsOIRRzw4,310
|
|
111
112
|
followthemoney/schema/Vehicle.yaml,sha256=Ypl4A5HJFOZfZh3DK0ewN-hyJuCMcovR0mPNddIZrOA,1051
|
|
112
|
-
followthemoney/schema/Vessel.yaml,sha256=
|
|
113
|
+
followthemoney/schema/Vessel.yaml,sha256=zWHUfSK8g6Pz58ZyCaK0AFJ4u_UHjEIUGC4c_7oS11Y,1170
|
|
113
114
|
followthemoney/schema/Video.yaml,sha256=LY3DYMWTHXiAhL0hxBCNCz50cp2sPbUlEhhig5Fbjos,327
|
|
114
115
|
followthemoney/schema/Workbook.yaml,sha256=iikWPElz4klA7SkWH7eae6xqhbkMCIP_3zdeXzFEMU0,354
|
|
115
116
|
followthemoney/statement/__init__.py,sha256=7m2VUCAuqNZXIY0WFJRFkw5UG14QuxATL4f_xbqKwhw,633
|
|
116
|
-
followthemoney/statement/entity.py,sha256=
|
|
117
|
+
followthemoney/statement/entity.py,sha256=r01enw01FbSVguvI8WcsSNYoYG-KWPLNNTNwbe7J7I0,17676
|
|
117
118
|
followthemoney/statement/serialize.py,sha256=9eXzQ1biR2mSxWRID5C7xDdku4b4ZImHeRJ53yLZ0yo,7225
|
|
118
119
|
followthemoney/statement/statement.py,sha256=Ae-EYuzS8S12BkaRqrvMuI1C7YwlRKa5C_pTBELyNMM,8029
|
|
119
120
|
followthemoney/statement/util.py,sha256=B-ozuRc1TWvpop52873Pqt5OPj8H6uk4KyRJLfAhr10,780
|
|
@@ -158,10 +159,10 @@ followthemoney/types/name.py,sha256=ZWGDebv01qByh_yBYOVoS3Edlm3_JVPShQMklKc6ZOA,
|
|
|
158
159
|
followthemoney/types/number.py,sha256=OdVuHDd4IYIIHhx_317JKeMjBAGtsJ2TAcxoZKZ4MkY,3948
|
|
159
160
|
followthemoney/types/phone.py,sha256=r8uRqWinS0CYnYBTs405k5gO4jeatUDgjdzzijoMKJE,3811
|
|
160
161
|
followthemoney/types/string.py,sha256=fqyTauAm4mNnNaoH-yH087RBbNh-G5ZZUO3awTGQUUg,1230
|
|
161
|
-
followthemoney/types/topic.py,sha256=
|
|
162
|
+
followthemoney/types/topic.py,sha256=Mi0Gx0m3bDeTmyuvM6jdRMqv81O03U4eI99R13KGu2Y,4503
|
|
162
163
|
followthemoney/types/url.py,sha256=QFpS_JIV8unFHuh_uGv22SWUUkocBoOpzLsAJWom_gI,1455
|
|
163
|
-
followthemoney-4.1.
|
|
164
|
-
followthemoney-4.1.
|
|
165
|
-
followthemoney-4.1.
|
|
166
|
-
followthemoney-4.1.
|
|
167
|
-
followthemoney-4.1.
|
|
164
|
+
followthemoney-4.2.1.dist-info/METADATA,sha256=M-Hlc_ugS8WclQ3QM9L43YCL4qfegF9FhsGvrTwzWS8,6747
|
|
165
|
+
followthemoney-4.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
166
|
+
followthemoney-4.2.1.dist-info/entry_points.txt,sha256=caoFTlf213jhg5sz3TNSofutjUTzaKtWATuSIdd9Cps,653
|
|
167
|
+
followthemoney-4.2.1.dist-info/licenses/LICENSE,sha256=H6_EVXisnJC0-18CjXIaqrBSFq_VH3OnS7u3dccOv6g,1148
|
|
168
|
+
followthemoney-4.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|