Skip to content

Commit 89649a3

Browse files
authored
Merge pull request #83 from casework/support_strict_review_on_example_py
Add type signatures in support of strict type-review on example.py
2 parents 1331422 + 9734853 commit 89649a3

File tree

8 files changed

+176
-86
lines changed

8 files changed

+176
-86
lines changed

case.jsonld

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,6 @@
1616
"uco-core:createdBy": {
1717
"@id": "kb:aef8e4c4-db83-59fd-8f71-b65cd7676c0a"
1818
},
19-
"@context": {
20-
"@vocab": "http://caseontology.org/core#",
21-
"case-investigation": "https://ontology.caseontology.org/case/investigation/",
22-
"drafting": "http://example.org/ontology/drafting/",
23-
"co": "http://purl.org/co/",
24-
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
25-
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
26-
"uco-action": "https://ontology.unifiedcyberontology.org/uco/action/",
27-
"uco-core": "https://ontology.unifiedcyberontology.org/uco/core/",
28-
"uco-identity": "https://ontology.unifiedcyberontology.org/uco/identity/",
29-
"uco-location": "https://ontology.unifiedcyberontology.org/uco/location/",
30-
"uco-role": "https://ontology.unifiedcyberontology.org/uco/role/",
31-
"uco-observable": "https://ontology.unifiedcyberontology.org/uco/observable/",
32-
"uco-tool": "https://ontology.unifiedcyberontology.org/uco/tool/",
33-
"uco-types": "https://ontology.unifiedcyberontology.org/uco/types/",
34-
"uco-vocabulary": "https://ontology.unifiedcyberontology.org/uco/vocabulary/",
35-
"xsd": "http://www.w3.org/2001/XMLSchema#",
36-
"kb": "http://example.org/kb/"
37-
},
3819
"uco-core:object": [
3920
{
4021
"@id": "kb:aef8e4c4-db83-59fd-8f71-b65cd7676c0a",
@@ -579,7 +560,6 @@
579560
"@id": "kb:a19e1e1f-3953-5fb9-92b6-2b46f85752b2",
580561
"@type": "case-investigation:Investigation",
581562
"uco-core:name": "Crime A",
582-
"case-investigation:focus": "Transfer of Illicit Materials",
583563
"uco-core:description": "Inquiry into the transfer of illicit materials and the devices used to do so",
584564
"uco-core:object": [
585565
{
@@ -710,7 +690,8 @@
710690
}
711691
]
712692
}
713-
]
693+
],
694+
"case-investigation:focus": "Transfer of Illicit Materials"
714695
},
715696
{
716697
"@id": "kb:6f79d4ae-d92c-5cad-bbe5-a0afde6f475a",
@@ -1853,5 +1834,24 @@
18531834
}
18541835
]
18551836
}
1856-
]
1837+
],
1838+
"@context": {
1839+
"@vocab": "http://caseontology.org/core#",
1840+
"case-investigation": "https://ontology.caseontology.org/case/investigation/",
1841+
"drafting": "http://example.org/ontology/drafting/",
1842+
"co": "http://purl.org/co/",
1843+
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
1844+
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
1845+
"uco-action": "https://ontology.unifiedcyberontology.org/uco/action/",
1846+
"uco-core": "https://ontology.unifiedcyberontology.org/uco/core/",
1847+
"uco-identity": "https://ontology.unifiedcyberontology.org/uco/identity/",
1848+
"uco-location": "https://ontology.unifiedcyberontology.org/uco/location/",
1849+
"uco-role": "https://ontology.unifiedcyberontology.org/uco/role/",
1850+
"uco-observable": "https://ontology.unifiedcyberontology.org/uco/observable/",
1851+
"uco-tool": "https://ontology.unifiedcyberontology.org/uco/tool/",
1852+
"uco-types": "https://ontology.unifiedcyberontology.org/uco/types/",
1853+
"uco-vocabulary": "https://ontology.unifiedcyberontology.org/uco/vocabulary/",
1854+
"xsd": "http://www.w3.org/2001/XMLSchema#",
1855+
"kb": "http://example.org/kb/"
1856+
}
18571857
}

case_mapping/case/investigation.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from ..base import Facet, UcoObject
77
from ..uco.action import Action
8+
from ..uco.core import ContextualCompilation
89
from ..uco.location import Location
910

1011

@@ -46,8 +47,8 @@ def __init__(
4647
self["@type"] = "case-investigation:InvestigativeAction"
4748

4849

49-
class CaseInvestigation(UcoObject):
50-
def __init__(self, name=None, focus=None, description=None, core_objects=None):
50+
class CaseInvestigation(ContextualCompilation):
51+
def __init__(self, *args: Any, focus=None, **kwargs: Any) -> None:
5152
"""
5253
An investigative action is a CASE object that represents the who, where, when of investigation
5354
:param name: The name of an investigation (e.g., Murder of Suspect B,.)
@@ -57,16 +58,13 @@ def __init__(self, name=None, focus=None, description=None, core_objects=None):
5758
object e.g., Persons involved in investigation, Investigation into a Murder, object refrences a
5859
case-object for a phone investigative action
5960
"""
60-
super().__init__()
61+
super().__init__(*args, **kwargs)
6162
self["@type"] = "case-investigation:Investigation"
6263
self._str_vars(
6364
**{
64-
"uco-core:name": name,
6565
"case-investigation:focus": focus,
66-
"uco-core:description": description,
6766
}
6867
)
69-
self.append_core_objects(core_objects)
7068

7169

7270
class ProvenanceRecord(UcoObject):

case_mapping/drafting/entities.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Any
2+
13
from ..base import Facet, UcoObject, unpack_args_array
24

35

@@ -175,6 +177,7 @@ def __init__(
175177
class SocialMediaActivityFacet(Facet):
176178
def __init__(
177179
self,
180+
*args: Any,
178181
body=None,
179182
page_title=None,
180183
author_identifier=None,
@@ -187,7 +190,8 @@ def __init__(
187190
created_time=None,
188191
application=None,
189192
url=None,
190-
):
193+
**kwargs: Any,
194+
) -> None:
191195
"""
192196
Used to represent activity on social platfomrs
193197
:param body: The text of the post/message
@@ -203,7 +207,7 @@ def __init__(
203207
:param application: the application used for creating the post
204208
:param application: the URL of the post
205209
"""
206-
super().__init__()
210+
super().__init__(*args, **kwargs)
207211

208212
self["@type"] = ["drafting:SocialMediaActivityFacet", "uco-core:Facet"]
209213

case_mapping/uco/core.py

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,85 @@
11
from datetime import datetime
2-
from typing import Any, List, Optional, Union
2+
from typing import Any, Optional, Sequence, Union
33

44
from pytz import timezone
55

66
from ..base import UcoObject, unpack_args_array
77

88

9-
class Bundle(UcoObject):
9+
class Compilation(UcoObject):
10+
def __init__(
11+
self,
12+
*args: Any,
13+
core_objects: Optional[Sequence[UcoObject]] = None,
14+
**kwargs: Any,
15+
) -> None:
16+
"""
17+
A compilation is a grouping of things.
18+
"""
19+
super().__init__(*args, **kwargs)
20+
self["@type"] = "uco-core:Compilation"
21+
if core_objects is not None and len(core_objects) > 0:
22+
self.append_core_objects(core_objects)
23+
24+
@unpack_args_array
25+
def append_to_uco_object(self, *args) -> None:
26+
"""
27+
Add a single/tuple of result(s) to the list of outputs from an action
28+
:param args: A CASE object, or objects, often an observable. (e.g., one of many devices from a search operation)
29+
"""
30+
self._append_observable_objects("uco-core:object", *args)
31+
32+
33+
class ContextualCompilation(Compilation):
34+
def __init__(
35+
self,
36+
*args: Any,
37+
core_objects: Sequence[UcoObject],
38+
**kwargs: Any,
39+
) -> None:
40+
"""
41+
A contextual compilation is a grouping of things sharing some context (e.g., a set of network connections observed on a given day, all accounts associated with a given person).
42+
43+
Future implementation note: At and before CASE 1.3.0, at least one core:object must be supplied at instantiation time of a contextual compilation. At and after CASE 1.4.0, these objects will be optional.
44+
"""
45+
if len(core_objects) == 0:
46+
raise ValueError(
47+
"A ContextualCompilation is required to have at least one UcoObject to link at initiation time. This will become optional in CASE 1.4.0."
48+
)
49+
super().__init__(*args, **kwargs)
50+
self["@type"] = "uco-core:ContextualCompilation"
51+
self.append_core_objects(core_objects)
52+
53+
54+
class EnclosingCompilation(Compilation):
55+
def __init__(
56+
self,
57+
*args: Any,
58+
core_objects: Sequence[UcoObject],
59+
**kwargs: Any,
60+
) -> None:
61+
"""
62+
An enclosing compilation is a container for a grouping of things.
63+
"""
64+
if len(core_objects) == 0:
65+
raise ValueError(
66+
"An EnclosingCompilation is required to have at least one UcoObject to link at initiation time."
67+
)
68+
super().__init__(*args, **kwargs)
69+
self["@type"] = "uco-core:EnclosingCompilation"
70+
self.append_core_objects(core_objects)
71+
72+
73+
class Bundle(EnclosingCompilation):
1074
def __init__(
1175
self,
1276
*args: Any,
1377
**kwargs: Any,
1478
) -> None:
1579
"""
1680
The main CASE Object for representing a case and its activities and objects.
81+
82+
Instantiating this class requires a starter sequence (set, list, or tuple) to be passed using the core_objects parameter. (See EnclosingCompilation.) To confirm conformant CASE will be generated, at least one UcoObject must be passed in this list. However, this does not initially need to be the complete sequence of objects that will be in this Bundle. Other UcoObjects can be added after initialization with bundle.append_to_uco_object.
1783
"""
1884
super().__init__(*args, **kwargs)
1985
self.build = [] # type: ignore
@@ -39,6 +105,7 @@ def __init__(
39105
# Assign caller-selectible prefix label and IRI, after checking
40106
# for conflicts with hard-coded prefixes.
41107
# https://www.w3.org/TR/turtle/#prefixed-name
108+
assert isinstance(self["@context"], dict)
42109
if self.prefix_label in self["@context"]:
43110
raise ValueError(
44111
"Requested prefix label already in use in hard-coded dictionary: '%s'. Please revise caller to use another label."
@@ -51,14 +118,6 @@ def __init__(
51118
def append_to_case_graph(self, *args):
52119
self._append_observable_objects("@graph", *args)
53120

54-
@unpack_args_array
55-
def append_to_uco_object(self, *args):
56-
"""
57-
Add a single/tuple of result(s) to the list of outputs from an action
58-
:param args: A CASE object, or objects, often an observable. (e.g., one of many devices from a search operation)
59-
"""
60-
self._append_observable_objects("uco-core:object", *args)
61-
62121
@unpack_args_array
63122
def append_to_rdfs_comments(self, *args):
64123
self._append_strings("rdfs:comment", *args)
@@ -119,4 +178,8 @@ def _addtime(self, _type: str) -> None:
119178
}
120179

121180

122-
directory = {"uco-core:Bundle": Bundle}
181+
directory = {
182+
"uco-core:Bundle": Bundle,
183+
"uco-core:Compilation": Compilation,
184+
"uco-core:ContextualCompilation": ContextualCompilation,
185+
}

case_mapping/uco/identity.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
from typing import Dict, Optional
1+
from typing import Any, Dict, Optional
22

33
from ..base import Facet, IdentityAbstraction, UcoObject
44

55

66
class BirthInformationFacet(Facet):
7-
def __init__(self, birthdate=None):
7+
def __init__(self, *args: Any, birthdate=None, **kwargs: Any) -> None:
88
"""
99
:param birthdate: the date of birth of an identity
1010
"""
11-
super().__init__()
11+
super().__init__(*args, **kwargs)
1212
self["@type"] = "uco-identity:BirthInformationFacet"
1313
self._datetime_vars(**{"uco-identity:birthdate": birthdate})
1414

@@ -31,12 +31,14 @@ def __init__(self, name: Optional[str] = None, facets=None):
3131

3232

3333
class SimpleNameFacet(Facet):
34-
def __init__(self, given_name=None, family_name=None):
34+
def __init__(
35+
self, *args: Any, given_name=None, family_name=None, **kwargs: Any
36+
) -> None:
3537
"""
3638
:param given_name: Full name of the identity of person
3739
:param family_name: Family name of identity of person
3840
"""
39-
super().__init__()
41+
super().__init__(*args, **kwargs)
4042
self["@type"] = "uco-identity:SimpleNameFacet"
4143
self._str_vars(
4244
**{

case_mapping/uco/location.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
from typing import Optional
1+
from typing import Any, Optional
22

33
from ..base import Facet, UcoObject
44

55

66
class Location(UcoObject):
7-
def __init__(self, facets=None):
8-
super().__init__()
7+
def __init__(self, *args: Any, **kwargs: Any) -> None:
8+
super().__init__(*args, **kwargs)
99
self["@type"] = "uco-location:Location"
10-
self.append_facets(facets)
1110

1211

1312
class LatLongCoordinatesFacet(Facet):

0 commit comments

Comments
 (0)