Skip to content

Commit 41a5305

Browse files
Merge pull request #12 from casework/type_review_get_optional__attributes
Finish type signatures of get_optional_..._attributes
2 parents 00ad1b4 + 4ddb41b commit 41a5305

File tree

6 files changed

+90
-54
lines changed

6 files changed

+90
-54
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ jobs:
5454
poetry run mypy --strict case_viewer/lib.py
5555
poetry run pytest --doctest-modules case_viewer/lib.py
5656
poetry run mypy case_viewer/case_viewer.py
57+
poetry run case_viewer --dry-run examples/WirelessNetworkConnection.json

Makefile

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,32 @@ SHELL := /bin/bash
1919
all: \
2020
check-examples
2121
source venv/bin/activate \
22-
&& python3 case_viewer/case_viewer.py \
22+
&& case_viewer \
2323
examples/WirelessNetworkConnection.json
2424

2525
.PHONY: \
2626
check-examples
2727

28-
.mypy.done.log: \
28+
.dry_run.done.log: \
29+
.pytest.done.log
30+
source venv/bin/activate \
31+
&& case_viewer \
32+
--dry-run \
33+
examples/WirelessNetworkConnection.json
34+
touch $@
35+
36+
.mypy_strict.done.log: \
2937
.venv.done.log \
30-
case_viewer/case_viewer.py \
3138
case_viewer/lib.py
3239
source venv/bin/activate \
3340
&& poetry run mypy \
3441
--strict \
3542
case_viewer/lib.py
43+
touch $@
44+
45+
.mypy.done.log: \
46+
.mypy_strict.done.log \
47+
case_viewer/case_viewer.py
3648
source venv/bin/activate \
3749
&& poetry run mypy \
3850
case_viewer/case_viewer.py
@@ -64,7 +76,7 @@ all: \
6476
touch $@
6577

6678
check: \
67-
.pytest.done.log \
79+
.dry_run.done.log \
6880
check-examples
6981

7082
check-examples: \

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ The application relies on Poetry as dependency manager, and all dependencies are
2525

2626
## Usage
2727

28-
> *CASEviewer.py JSON_INPUT*
28+
> `case_viewer JSON_INPUT`
2929
3030
where:
3131

32-
* JSON_INPUT is the file to be processed.
32+
* `JSON_INPUT` is the file to be processed.
3333

3434
For those with `make` available (e.g. in a POSIX command line environment), `make` will run enough from a fresh `git clone` to set up a demonstration call of the viewer against an [example JSON-LD file](examples/WirelessNetworkConnection.json).
3535

case_viewer/case_viewer.py

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#
1313
# We would appreciate acknowledgement if the software is used.
1414

15+
import argparse
1516
import json
1617
import codecs
1718
import sys
@@ -20,9 +21,9 @@
2021
from PyQt5.QtWidgets import *
2122
from PyQt5.QtGui import *
2223
from PyQt5 import QtCore
23-
#import logging
24+
import logging
2425

25-
from lib import JSONLD, get_attribute, get_optional_integer_attribute, \
26+
from .lib import JSONLD, get_attribute, get_optional_integer_attribute, \
2627
get_optional_string_attribute, get_optional_dict_attribute, \
2728
get_optional_list_attribute
2829

@@ -293,6 +294,7 @@ def buildDataCellSites(self, idObject):
293294

294295

295296
def buildDataWirelessNet(self, idObject: str) -> list[list[str]]:
297+
global wireless_net
296298
tData = []
297299
if idObject == ':WirelessNet':
298300
self.headers = ["SSID", "BSID"]
@@ -1085,7 +1087,7 @@ def processRelationConnectedTo(jsonObj):
10851087
{
10861088
"uco-core:source":id_connected_source,
10871089
"uco-core:target":id_connected_target,
1088-
"uco-observable:starTime": startTime,
1090+
"uco-observable:startTime": startTime,
10891091
"uco-observable:endTime": endTime
10901092
})
10911093
except Exception as e:
@@ -1873,62 +1875,76 @@ def number_with_dots(n: Union[int, str]) -> str:
18731875
else:
18741876
raise TypeError('Parameter must be either integer or string')
18751877

1876-
if __name__ == '__main__':
18771878
#--- Gobal variables
1879+
chatMessages: list[dict[str, str]] = []
1880+
chatThreads: list[dict[str, str]] = []
1881+
#chatMessageAttachments = []
1882+
cookies: list[dict[str, str]] = []
1883+
geo_coordinates: list[dict[str, str]] = []
1884+
cell_sites: list[dict[str, str]] = []
1885+
bluetooths: list[dict[str, str]] = []
1886+
searched_items: list[dict[str, str]] = []
1887+
social_media_activities: list[dict[str, str]] = []
1888+
events: list[dict[str, str]] = []
1889+
relationAttachmentsTo: list[dict[str, str]] = []
1890+
relationMappedBy: list[dict[str, str]] = []
1891+
relationConnectedTo: list[dict[str, str]] = []
1892+
smsMessages: list[dict[str, str]] = []
1893+
accounts: list[dict[str, str]] = []
1894+
emailAddresses: list[dict[str, str]] = []
1895+
emailAccounts: list[dict[str, str]] = []
1896+
applications: list[dict[str, str]] = []
1897+
phoneCalls: list[dict[str, str]] = []
1898+
calendars: list[dict[str, str]] = []
1899+
emailMessages: list[dict[str, str]] = []
1900+
filesUncategorized: list[dict[str, str]] = []
1901+
filesImage: list[dict[str, str]] = []
1902+
filesAudio: list[dict[str, str]] = []
1903+
filesText: list[dict[str, str]] = []
1904+
filesPDF: list[dict[str, str]] = []
1905+
filesWord: list[dict[str, str]] = []
1906+
filesRTF: list[dict[str, str]] = []
1907+
filesVideo: list[dict[str, str]] = []
1908+
filesArchive: list[dict[str, str]] = []
1909+
filesDatabase: list[dict[str, str]] = []
1910+
filesApplication: list[dict[str, str]] = []
1911+
webURLs: list[dict[str, str]] = []
1912+
webURLHistory: list[dict[str, str]] = []
1913+
webSearchTerm: list[dict[str, str]] = []
1914+
webBookmark: list[dict[str, str]] = []
1915+
wireless_net: list[dict[str, str]] = []
1916+
1917+
tableData: list[list[str]] = [[]]
1918+
treeData: list[dict[str,str]] = []
1919+
1920+
def main():
18781921
C_GREEN = '\033[32m'
18791922
C_RED = '\033[31m'
18801923
C_BLACK = '\033[0m'
18811924
C_CYAN = '\033[36m'
18821925
EMPTY_DATA = "1900-01-01T00:00:00"
18831926

1884-
chatThreads: list[dict[str, str]] = []
1885-
chatMessages: list[dict[str, str]] = []
1886-
#chatMessageAttachments = []
1887-
cookies: list[dict[str, str]] = []
1888-
geo_coordinates: list[dict[str, str]] = []
1889-
cell_sites: list[dict[str, str]] = []
1890-
bluetooths: list[dict[str, str]] = []
1891-
searched_items: list[dict[str, str]] = []
1892-
social_media_activities: list[dict[str, str]] = []
1893-
events: list[dict[str, str]] = []
1894-
wireless_net: list[dict[str, str]] = []
1895-
relationAttachmentsTo: list[dict[str, str]] = []
1896-
relationMappedBy: list[dict[str, str]] = []
1897-
relationConnectedTo: list[dict[str, str]] = []
1898-
smsMessages: list[dict[str, str]] = []
1899-
accounts: list[dict[str, str]] = []
1900-
emailAddresses: list[dict[str, str]] = []
1901-
emailAccounts: list[dict[str, str]] = []
1902-
applications: list[dict[str, str]] = []
1903-
phoneCalls: list[dict[str, str]] = []
1904-
calendars: list[dict[str, str]] = []
1905-
emailMessages: list[dict[str, str]] = []
1906-
filesUncategorized: list[dict[str, str]] = []
1907-
filesImage: list[dict[str, str]] = []
1908-
filesAudio: list[dict[str, str]] = []
1909-
filesText: list[dict[str, str]] = []
1910-
filesPDF: list[dict[str, str]] = []
1911-
filesWord: list[dict[str, str]] = []
1912-
filesRTF: list[dict[str, str]] = []
1913-
filesVideo: list[dict[str, str]] = []
1914-
filesArchive: list[dict[str, str]] = []
1915-
filesDatabase: list[dict[str, str]] = []
1916-
filesApplication: list[dict[str, str]] = []
1917-
webURLs: list[dict[str, str]] = []
1918-
webURLHistory: list[dict[str, str]] = []
1919-
webSearchTerm: list[dict[str, str]] = []
1920-
webBookmark: list[dict[str, str]] = []
1927+
parser = argparse.ArgumentParser()
1928+
parser.add_argument("--debug", action="store_true")
1929+
parser.add_argument("--dry-run", action="store_true", help="Run application, exiting without initiating GUI.")
1930+
parser.add_argument("input_jsonld")
1931+
args = parser.parse_args()
1932+
1933+
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
19211934

19221935
#--- Read input file in CASE-JSON format
19231936
try:
1924-
f = codecs.open(sys.argv[1], 'r', encoding='utf-8')
1937+
f = codecs.open(args.input_jsonld, 'r', encoding='utf-8')
19251938
except Exception as e:
1926-
print(C_RED + '\n' + "ERROR in trying to open the file " + sys.argv[1])
1939+
print(C_RED + '\n' + "ERROR in trying to open the file " + args.input_jsonld)
19271940
print (e)
19281941
sys.exit('Open file failed.')
19291942
try:
19301943
print(C_CYAN + "Load JSON structure, it might take some time, please wait ...\n")
19311944
json_obj = json.load(f)
1945+
if args.dry_run:
1946+
logging.info("Exiting dry run.")
1947+
sys.exit(0)
19321948
app = QApplication([])
19331949
_widget=QWidget()
19341950
msgBox = QMessageBox()
@@ -1975,9 +1991,11 @@ def number_with_dots(n: Union[int, str]) -> str:
19751991
for facet in dataFacets:
19761992
assert isinstance(facet, dict)
19771993
facet_type = facet["@type"]
1994+
objectType: str
19781995
if isinstance(facet_type, str):
19791996
objectType = facet_type
19801997
elif isinstance(facet_type, list):
1998+
assert isinstance(facet_type[0], str)
19811999
objectType = facet_type[0] # SocialMediaActivityFacet
19822000
else:
19832001
raise TypeError("Unexpected type for property %r: %r." % (facet_type, type(facet_type)))
@@ -2043,8 +2061,6 @@ def number_with_dots(n: Union[int, str]) -> str:
20432061
f.close()
20442062
print(C_CYAN + "\n\nEnd Observables processing!" + C_BLACK + "\n\n")
20452063

2046-
tableData: list[list[str]] = [[]]
2047-
treeData: list[dict[str,str]] = []
20482064
i = 1
20492065
totMessages = 0
20502066

@@ -2210,6 +2226,10 @@ def number_with_dots(n: Union[int, str]) -> str:
22102226
#--- Set the UI layout
22112227
_view = view(treeData, tableData)
22122228
_view.setGeometry(50, 50, 1400, 800)
2213-
_view.setWindowTitle('Cyber items view - ' + sys.argv[1] + ' (n. Observables: ' + number_with_dots(nObjects) + ')')
2229+
_view.setWindowTitle('Cyber items view - ' + args.input_jsonld + ' (n. Observables: ' + number_with_dots(nObjects) + ')')
22142230
_view.show()
22152231
sys.exit(app.exec_())
2232+
2233+
2234+
if __name__ == '__main__':
2235+
main()

case_viewer/lib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@ def get_optional_string_attribute(data: dict[str, JSONLD], property: str, defaul
106106
return return_value
107107
raise TypeError("Unexpected type for property %r: %r." % (property, type(return_value)))
108108

109-
def get_optional_dict_attribute(data: dict[str, JSONLD], property: str, default_value: dict) -> dict:
109+
def get_optional_dict_attribute(data: dict[str, JSONLD], property: str, default_value: dict[str, JSONLD]) -> dict[str, JSONLD]:
110110
return_value: JSONLD = get_attribute(data, property, default_value)
111111
if isinstance(return_value, dict):
112112
return return_value
113113
raise TypeError("Unexpected type for property %r: %r." % (property, type(return_value)))
114114

115-
def get_optional_list_attribute(data: dict[str, JSONLD], property: str, default_value: list) -> list:
115+
def get_optional_list_attribute(data: dict[str, JSONLD], property: str, default_value: list[JSONLD]) -> list[JSONLD]:
116116
return_value: JSONLD = get_attribute(data, property, default_value)
117117
if isinstance(return_value, list):
118118
return return_value

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ argparse = "^1.4.0"
1616
mypy = "^1"
1717
pytest = "^8"
1818

19+
[tool.poetry.scripts]
20+
case_viewer = "case_viewer.case_viewer:main"
21+
1922
[build-system]
2023
requires = ["poetry-core"]
2124
build-backend = "poetry.core.masonry.api"

0 commit comments

Comments
 (0)