From 33f08441c0ffb473533bc2327a0b323e33f71292 Mon Sep 17 00:00:00 2001 From: Alex Nelson Date: Wed, 27 Nov 2024 14:41:38 -0500 Subject: [PATCH] Add type signatures in support of strict type-review on example.py This patch does not take the last step of adding the `--strict` flag in type review. This patch satisfies a run of the type checker in strict mode against the script `/example.py` and all of the library functions that script depends on. Additionally, all touched `__init__` methods observed to not have `*args` & `**kwargs` catch-alls had those added and incorporated into `super()` calls (which will assist with tying to, e.g., knowledge base namespace helpers available in the ultimate parent class `UcoThing`). One effect reflected back into the example script is that the EXIF dictionary incorporation logic needed its own keyword parameter, because the `**kwargs` catch-all parameter being used was an atypical usage versus the pass-through-to-superclass functionality of `**kwargs`. This patch also adjusted one class position, moving `MessageThread` under `ObservableObject` instead of `UcoObject`. A follow-on patch will do the same for `CaseInvestigation`. Signed-off-by: Alex Nelson --- case_mapping/case/investigation.py | 8 +-- case_mapping/drafting/entities.py | 8 ++- case_mapping/uco/identity.py | 12 ++-- case_mapping/uco/location.py | 7 +-- case_mapping/uco/observable.py | 90 +++++++++++++++++++----------- example.py | 2 +- 6 files changed, 78 insertions(+), 49 deletions(-) diff --git a/case_mapping/case/investigation.py b/case_mapping/case/investigation.py index 39f6fc2..5aee80c 100644 --- a/case_mapping/case/investigation.py +++ b/case_mapping/case/investigation.py @@ -47,7 +47,9 @@ def __init__( class CaseInvestigation(UcoObject): - def __init__(self, name=None, focus=None, description=None, core_objects=None): + def __init__( + self, *args: Any, focus=None, core_objects=None, **kwargs: Any + ) -> None: """ An investigative action is a CASE object that represents the who, where, when of investigation :param name: The name of an investigation (e.g., Murder of Suspect B,.) @@ -57,13 +59,11 @@ def __init__(self, name=None, focus=None, description=None, core_objects=None): object e.g., Persons involved in investigation, Investigation into a Murder, object refrences a case-object for a phone investigative action """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "case-investigation:Investigation" self._str_vars( **{ - "uco-core:name": name, "case-investigation:focus": focus, - "uco-core:description": description, } ) self.append_core_objects(core_objects) diff --git a/case_mapping/drafting/entities.py b/case_mapping/drafting/entities.py index 0e4d636..e0e4d63 100755 --- a/case_mapping/drafting/entities.py +++ b/case_mapping/drafting/entities.py @@ -1,3 +1,5 @@ +from typing import Any + from ..base import Facet, UcoObject, unpack_args_array @@ -175,6 +177,7 @@ def __init__( class SocialMediaActivityFacet(Facet): def __init__( self, + *args: Any, body=None, page_title=None, author_identifier=None, @@ -187,7 +190,8 @@ def __init__( created_time=None, application=None, url=None, - ): + **kwargs: Any, + ) -> None: """ Used to represent activity on social platfomrs :param body: The text of the post/message @@ -203,7 +207,7 @@ def __init__( :param application: the application used for creating the post :param application: the URL of the post """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = ["drafting:SocialMediaActivityFacet", "uco-core:Facet"] diff --git a/case_mapping/uco/identity.py b/case_mapping/uco/identity.py index 7f2d31c..954c4c0 100644 --- a/case_mapping/uco/identity.py +++ b/case_mapping/uco/identity.py @@ -1,14 +1,14 @@ -from typing import Dict, Optional +from typing import Any, Dict, Optional from ..base import Facet, IdentityAbstraction, UcoObject class BirthInformationFacet(Facet): - def __init__(self, birthdate=None): + def __init__(self, *args: Any, birthdate=None, **kwargs: Any) -> None: """ :param birthdate: the date of birth of an identity """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-identity:BirthInformationFacet" self._datetime_vars(**{"uco-identity:birthdate": birthdate}) @@ -31,12 +31,14 @@ def __init__(self, name: Optional[str] = None, facets=None): class SimpleNameFacet(Facet): - def __init__(self, given_name=None, family_name=None): + def __init__( + self, *args: Any, given_name=None, family_name=None, **kwargs: Any + ) -> None: """ :param given_name: Full name of the identity of person :param family_name: Family name of identity of person """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-identity:SimpleNameFacet" self._str_vars( **{ diff --git a/case_mapping/uco/location.py b/case_mapping/uco/location.py index ac8a68b..c8deb2f 100644 --- a/case_mapping/uco/location.py +++ b/case_mapping/uco/location.py @@ -1,13 +1,12 @@ -from typing import Optional +from typing import Any, Optional from ..base import Facet, UcoObject class Location(UcoObject): - def __init__(self, facets=None): - super().__init__() + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) self["@type"] = "uco-location:Location" - self.append_facets(facets) class LatLongCoordinatesFacet(Facet): diff --git a/case_mapping/uco/observable.py b/case_mapping/uco/observable.py index fdee589..9b0495f 100644 --- a/case_mapping/uco/observable.py +++ b/case_mapping/uco/observable.py @@ -209,7 +209,9 @@ def __init__( class AccountFacet(Facet): - def __init__(self, identifier=None, is_active=True, issuer_id=None): + def __init__( + self, *args: Any, identifier=None, is_active=True, issuer_id=None, **kwargs: Any + ) -> None: """ Used to represent user accounts :param is_active: Active unless specified otherwise (False) @@ -217,7 +219,7 @@ def __init__(self, identifier=None, is_active=True, issuer_id=None): :param issuer_id: The id of issuing body for application (e.g., kb:organization-skypeapp-cc44c2ae-bdd3-4df8-9ca3-1f58d682d62b) """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:AccountFacet" self._bool_vars(**{"uco-observable:isActive": is_active}) self._str_vars( @@ -292,6 +294,7 @@ def __init__( class ContentDataFacet(Facet): def __init__( self, + *args: Any, byte_order=None, magic_number=None, mime_type=None, @@ -301,7 +304,8 @@ def __init__( is_encrypted=None, hash_method=None, hash_value=None, - ): + **kwargs: Any, + ) -> None: """ The characteristics of a block of digital data. :param byte_order: Byte order of data. Example - "BigEndian" @@ -314,7 +318,7 @@ def __init__( :param hash_method: The algorithm used to calculate the hash value :param hash_value: The cryptographic hash of this content """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:ContentDataFacet" self._str_vars( **{ @@ -334,7 +338,7 @@ def __init__( } if hash_method is not None or hash_value is not None or hash_value != "-": - data = { + data: dict[str, Any] = { "@id": self.prefix_label + ":" + str(local_uuid()), "@type": "uco-types:Hash", } @@ -392,7 +396,15 @@ def __init__(self, range_offset=None, range_size=None): class DeviceFacet(Facet): - def __init__(self, device_type=None, manufacturer=None, model=None, serial=None): + def __init__( + self, + *args: Any, + device_type=None, + manufacturer=None, + model=None, + serial=None, + **kwargs: Any, + ) -> None: """ Characteristics of a piece of electronic equipment. :param device_type: The type of device (e.g., "camera") @@ -400,7 +412,7 @@ def __init__(self, device_type=None, manufacturer=None, model=None, serial=None) :param model: The model of the device (e.g., "Powershot SX540") :param serial: The serial phone_number of the device (e.g., "1296-3219-8792-CL918") """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:DeviceFacet" self._node_reference_vars(**{"uco-observable:manufacturer": manufacturer}) self._str_vars( @@ -519,7 +531,9 @@ def __init__( class UrlHistoryFacet(Facet): - def __init__(self, browser=None, history_entries=None): + def __init__( + self, *args: Any, browser=None, history_entries=None, **kwargs: Any + ) -> None: """ :param browser_info: An observable object containing a URLHistoryFacet :param history_entries: A list of dictionaries, each dict has the @@ -536,7 +550,7 @@ def __init__(self, browser=None, history_entries=None): "uco-observable:url": url_object, "uco-observable:visitCount": int, """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:URLHistoryFacet" self._node_reference_vars( **{ @@ -561,7 +575,7 @@ def __init__(self, browser=None, history_entries=None): self["uco-observable:urlHistoryEntry"] = [] for entry in history_entries: - history_entry = {} + history_entry: dict[str, Any] = dict() history_entry["@id"] = self.prefix_label + ":" + local_uuid() history_entry["@type"] = "uco-observable:URLHistoryEntry" for key, var in entry.items(): @@ -619,6 +633,7 @@ def __init__(self, browser=None, history_entries=None): class UrlFacet(Facet): def __init__( self, + *args: Any, url_address=None, url_port=None, url_host=None, @@ -628,7 +643,8 @@ def __init__( url_query=None, url_scheme=None, url_username=None, - ): + **kwargs: Any, + ) -> None: """ :param url_address: an address of a url (i.e. google.ie) :param url_port: a tcp or udp port of a url for example 3000 @@ -640,7 +656,7 @@ def __init__( :param url_scheme: Identifies the type of URL. (e.g. ssh://) :param url_username: A username that may be required for authentication for a specific resource. (login) """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:URLFacet" self._str_vars( **{ @@ -701,13 +717,15 @@ def __init__( class RasterPictureFacet(Facet): def __init__( self, + *args: Any, camera_id=None, bits_per_pixel=None, picture_height=None, picture_width=None, image_compression_method=None, picture_type=None, - ): + **kwargs: Any, + ) -> None: """ This CASEObject represents the contents of a file or device :param camera_id: An observable cyberitem @@ -717,7 +735,7 @@ def __init__( :param image_compression_method: The compression method used :param picture_type: The type of picture ("jpg", "png" etc.) """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:RasterPictureFacet" self._str_vars( **{ @@ -786,11 +804,11 @@ def __init__( class PhoneAccountFacet(Facet): - def __init__(self, phone_number=None): + def __init__(self, *args: Any, phone_number=None, **kwargs: Any) -> None: """ :param phone_number: The number for this account (e.g., "+16503889249") """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:PhoneAccountFacet" self._str_vars( **{ @@ -800,22 +818,24 @@ def __init__(self, phone_number=None): class EmailAccountFacet(Facet): - def __init__(self, email_address): + def __init__(self, *args: Any, email_address, **kwargs: Any) -> None: """ :param email_address: An ObservableObject (with EmailAdressFacet) """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:EmailAccountFacet" self._node_reference_vars(**{"uco-observable:emailAddress": email_address}) class EmailAddressFacet(Facet): - def __init__(self, email_address_value=None, display_name=None): + def __init__( + self, *args: Any, email_address_value=None, display_name=None, **kwargs: Any + ) -> None: """ Used to represent the value of an email address. :param email_address_value: a single email address (e.g., "bob@example.com") """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:EmailAddressFacet" self._str_vars( **{ @@ -828,6 +848,7 @@ def __init__(self, email_address_value=None, display_name=None): class EmailMessageFacet(Facet): def __init__( self, + *args: Any, msg_to=None, msg_from=None, cc=None, @@ -853,7 +874,8 @@ def __init__( is_mime_encoded=None, allocation_status=None, is_multipart=None, - ): + **kwargs: Any, + ) -> None: """ An instance of an email message, corresponding to the internet message format described in RFC 5322 and related. :param msg_to: A list of ObservableObjects (with EmailAccountFacet) @@ -882,7 +904,7 @@ def __init__( :param is_multipart: A boolean True/False :param allocation_status: """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:EmailMessageFacet" self._str_vars( **{ @@ -928,12 +950,14 @@ def __init__( class EXIFFacet(Facet): - def __init__(self, **kwargs): + def __init__( + self, *args: Any, exif_key_value_pairs: dict[str, str], **kwargs: Any + ) -> None: """ Specifies exchangeable image file format (Exif) metadata tags for image and sound files recorded by digital cameras. :param kwargs: The user provided key/value pairs of exif items (e.g., Make="Canon", etc.). """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:EXIFFacet" self["uco-observable:exifData"] = { @@ -1147,6 +1171,7 @@ def __init__( class MessageFacet(Facet): def __init__( self, + *args: Any, msg_to=None, msg_from=None, message_text=None, @@ -1155,7 +1180,8 @@ def __init__( message_type=None, message_id=None, session_id=None, - ): + **kwargs: Any, + ) -> None: """ Characteristics of an electronic message. :param msg_to: A list of ObservableObjects @@ -1167,7 +1193,7 @@ def __init__( :param message_id: A unique identifier for the message. :param session_id: The priority of the email. """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:MessageFacet" self._str_vars( **{ @@ -1434,13 +1460,13 @@ def __init__( class ApplicationAccountFacet(Facet): - def __init__(self, application=None): + def __init__(self, *args: Any, application=None, **kwargs: Any) -> None: """ An application account facet is a grouping of characteristics unique to an account within a particular software program designed for end users. :param application: An Observable Object (containing an Application Facet) """ - super().__init__() + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:ApplicationAccountFacet" self._node_reference_vars(**{"uco-observable:application": application}) @@ -1620,12 +1646,10 @@ def append_participants(self, *args): self._append_refs("uco-observable:participant", *args) -class MessageThread(UcoObject): - def __init__(self, name=None, facets=None): - super().__init__() +class MessageThread(ObservableObject): + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) self["@type"] = "uco-observable:MessageThread" - self._str_vars(**{"uco-core:name": name}) - self.append_facets(facets) class Message(ObservableObject): diff --git a/example.py b/example.py index 48c0f73..6a9ec21 100755 --- a/example.py +++ b/example.py @@ -117,7 +117,7 @@ def _next_timestamp() -> datetime: ) exif = {"Make": "Canon", "Model": "Powershot"} -file_exif1 = uco.observable.EXIFFacet(**exif) +file_exif1 = uco.observable.EXIFFacet(exif_key_value_pairs=exif) sd_card.append_facets(file1, file_content1, file_raster1, file_exif1) bundle.append_to_uco_object(sd_card)