Interface to query and modify by-component assembly inheritance contents.
The by-component is contained in two separate forms: As an actual OSCAL by-component assembly,
and multiple dicts providing direct lookup of inheritance statement by uuid.
The dicts are created by the ByComponentInterface constructor, parsed and the responsibility and provided statements
are separated into three catagories:
isolated responsibilities - A responsibility with no provided statement
isolated provided - A provided statement with no referring responsibility statements
export set - A set with a single responsibility and referred provided statement
For updating ByComponent inheritance and satisfied statements, the interface provides a method to reconcile the
the by-component assembly and merge input inherited and satisfied statements.
Source code in trestle/core/crm/bycomp_interface.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 | class ByComponentInterface:
"""
Interface to query and modify by-component assembly inheritance contents.
The by-component is contained in two separate forms: As an actual OSCAL by-component assembly,
and multiple dicts providing direct lookup of inheritance statement by uuid.
The dicts are created by the ByComponentInterface constructor, parsed and the responsibility and provided statements
are separated into three catagories:
isolated responsibilities - A responsibility with no provided statement
isolated provided - A provided statement with no referring responsibility statements
export set - A set with a single responsibility and referred provided statement
For updating ByComponent inheritance and satisfied statements, the interface provides a method to reconcile the
the by-component assembly and merge input inherited and satisfied statements.
"""
def __init__(self, by_comp: ossp.ByComponent):
"""Initialize export writer for a single by-component assembly."""
self._by_comp: ossp.ByComponent = by_comp
self._provided_dict: Dict[str, ossp.Provided] = {}
self._responsibility_dict: Dict[str, ossp.Responsibility] = {}
self._responsibility_by_provided: Dict[str, List[ossp.Responsibility]] = {}
self._inherited_dict: Dict[str, ossp.Inherited] = self._create_inherited_dict()
self._satisfied_dict: Dict[str, ossp.Satisfied] = self._create_satisfied_dict()
if by_comp.export:
self._provided_dict = self._create_provided_dict()
self._responsibility_dict = self._create_responsibility_dict()
self._responsibility_by_provided = self._create_responsibility_by_provided_dict()
def _create_provided_dict(self) -> Dict[str, ossp.Provided]:
provided_dict: Dict[str, ossp.Provided] = {}
for provided in as_list(self._by_comp.export.provided):
provided_dict[provided.uuid] = provided
return provided_dict
def _create_responsibility_dict(self) -> Dict[str, ossp.Responsibility]:
responsibility_dict: Dict[str, ossp.Responsibility] = {}
for responsibility in as_list(self._by_comp.export.responsibilities):
responsibility_dict[responsibility.uuid] = responsibility
return responsibility_dict
def _create_responsibility_by_provided_dict(self) -> Dict[str, List[ossp.Responsibility]]:
responsibility_by_provided: Dict[str, List[ossp.Responsibility]] = {}
for responsibility in as_list(self._by_comp.export.responsibilities):
if responsibility.provided_uuid is None:
continue
if responsibility.provided_uuid not in responsibility_by_provided:
responsibility_by_provided[responsibility.provided_uuid] = [responsibility]
else:
existing_list: List[ossp.Responsibility] = responsibility_by_provided[responsibility.provided_uuid]
existing_list.append(responsibility)
return responsibility_by_provided
def _create_inherited_dict(self) -> Dict[str, ossp.Inherited]:
inherited_dict: Dict[str, ossp.Inherited] = {}
for inherited in as_list(self._by_comp.inherited):
inherited_dict[str(inherited.provided_uuid)] = inherited
return inherited_dict
def _create_satisfied_dict(self) -> Dict[str, ossp.Satisfied]:
satisfied_dict: Dict[str, ossp.Satisfied] = {}
for satisfied in as_list(self._by_comp.satisfied):
satisfied_dict[str(satisfied.responsibility_uuid)] = satisfied
return satisfied_dict
def get_isolated_responsibilities(self) -> List[ossp.Responsibility]:
"""Return all isolated exported responsibilities."""
all_responsibilities: List[ossp.Responsibility] = []
for resp in as_dict(self._responsibility_dict).values():
if resp.provided_uuid is None:
all_responsibilities.append(resp)
return all_responsibilities
def get_isolated_provided(self) -> List[ossp.Provided]:
"""Return all isolated exported provided capabilities."""
all_provided: List[ossp.Provided] = []
for provided in as_dict(self._provided_dict).values():
if not self._provided_has_responsibilities(provided.uuid):
all_provided.append(provided)
return all_provided
def get_export_sets(self) -> List[Tuple[ossp.Responsibility, ossp.Provided]]:
"""Return a dictionary of every responsibility relationship with provided."""
all_export_sets: List[Tuple[ossp.Responsibility, ossp.Provided]] = []
for provided_uuid, responsibilities in as_dict(self._responsibility_by_provided).items():
# Ensure the provided object exists in the dictionary.
# If it doesn't this is a bug.
if provided_uuid not in self._provided_dict:
raise TrestleError(f'Provided capability {provided_uuid} not found')
provided: ossp.Provided = self._provided_dict[provided_uuid]
for responsibility in responsibilities:
shared_responsibility: Tuple[ossp.Responsibility, ossp.Provided] = (responsibility, provided)
all_export_sets.append(shared_responsibility)
return all_export_sets
def reconcile_inheritance_by_component(
self, incoming_inherited: List[ossp.Inherited], incoming_satisfied: List[ossp.Satisfied]
) -> ossp.ByComponent:
"""
Reconcile the inherited and satisfied statements in the by-component assembly with changes from the export.
Notes:
A statement is determined as existing if the provided uuid or responsibility uuid is in the existing
by-component assembly. If existing, the description will be updated if it has changed.
Any existing inherited or satisfied statements that are not in the incoming export will be removed.
If a statement is in the incoming export, but not in the existing by-component assembly, it will be added.
"""
new_inherited: List[ossp.Inherited] = []
new_satisfied: List[ossp.Satisfied] = []
# Create a copy of the input by-component assembly to reconcile and return
new_by_comp: ossp.ByComponent = copy.deepcopy(self._by_comp)
for statement in incoming_inherited:
if statement.provided_uuid in self._inherited_dict:
existing_statement = self._inherited_dict[str(statement.provided_uuid)]
# Update the description if it has changed
existing_statement.description = statement.description
statement = existing_statement
new_inherited.append(statement)
new_by_comp.inherited = none_if_empty(new_inherited)
for statement in incoming_satisfied:
if statement.responsibility_uuid in self._satisfied_dict:
existing_statement = self._satisfied_dict[str(statement.responsibility_uuid)]
# Update the description if it has changed
existing_statement.description = statement.description
statement = existing_statement
new_satisfied.append(statement)
new_by_comp.satisfied = none_if_empty(new_satisfied)
return new_by_comp
def _provided_has_responsibilities(self, provided_uuid: str) -> bool:
"""Return whether a provided UUID has responsibilities."""
return provided_uuid in self._responsibility_by_provided
|
Functions
__init__(by_comp)
Initialize export writer for a single by-component assembly.
Source code in trestle/core/crm/bycomp_interface.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 | def __init__(self, by_comp: ossp.ByComponent):
"""Initialize export writer for a single by-component assembly."""
self._by_comp: ossp.ByComponent = by_comp
self._provided_dict: Dict[str, ossp.Provided] = {}
self._responsibility_dict: Dict[str, ossp.Responsibility] = {}
self._responsibility_by_provided: Dict[str, List[ossp.Responsibility]] = {}
self._inherited_dict: Dict[str, ossp.Inherited] = self._create_inherited_dict()
self._satisfied_dict: Dict[str, ossp.Satisfied] = self._create_satisfied_dict()
if by_comp.export:
self._provided_dict = self._create_provided_dict()
self._responsibility_dict = self._create_responsibility_dict()
self._responsibility_by_provided = self._create_responsibility_by_provided_dict()
|
get_export_sets()
Return a dictionary of every responsibility relationship with provided.
Source code in trestle/core/crm/bycomp_interface.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 | def get_export_sets(self) -> List[Tuple[ossp.Responsibility, ossp.Provided]]:
"""Return a dictionary of every responsibility relationship with provided."""
all_export_sets: List[Tuple[ossp.Responsibility, ossp.Provided]] = []
for provided_uuid, responsibilities in as_dict(self._responsibility_by_provided).items():
# Ensure the provided object exists in the dictionary.
# If it doesn't this is a bug.
if provided_uuid not in self._provided_dict:
raise TrestleError(f'Provided capability {provided_uuid} not found')
provided: ossp.Provided = self._provided_dict[provided_uuid]
for responsibility in responsibilities:
shared_responsibility: Tuple[ossp.Responsibility, ossp.Provided] = (responsibility, provided)
all_export_sets.append(shared_responsibility)
return all_export_sets
|
get_isolated_provided()
Return all isolated exported provided capabilities.
Source code in trestle/core/crm/bycomp_interface.py
105
106
107
108
109
110
111 | def get_isolated_provided(self) -> List[ossp.Provided]:
"""Return all isolated exported provided capabilities."""
all_provided: List[ossp.Provided] = []
for provided in as_dict(self._provided_dict).values():
if not self._provided_has_responsibilities(provided.uuid):
all_provided.append(provided)
return all_provided
|
get_isolated_responsibilities()
Return all isolated exported responsibilities.
Source code in trestle/core/crm/bycomp_interface.py
| def get_isolated_responsibilities(self) -> List[ossp.Responsibility]:
"""Return all isolated exported responsibilities."""
all_responsibilities: List[ossp.Responsibility] = []
for resp in as_dict(self._responsibility_dict).values():
if resp.provided_uuid is None:
all_responsibilities.append(resp)
return all_responsibilities
|
reconcile_inheritance_by_component(incoming_inherited, incoming_satisfied)
Reconcile the inherited and satisfied statements in the by-component assembly with changes from the export.
Notes
A statement is determined as existing if the provided uuid or responsibility uuid is in the existing
by-component assembly. If existing, the description will be updated if it has changed.
Any existing inherited or satisfied statements that are not in the incoming export will be removed.
If a statement is in the incoming export, but not in the existing by-component assembly, it will be added.
Source code in trestle/core/crm/bycomp_interface.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 | def reconcile_inheritance_by_component(
self, incoming_inherited: List[ossp.Inherited], incoming_satisfied: List[ossp.Satisfied]
) -> ossp.ByComponent:
"""
Reconcile the inherited and satisfied statements in the by-component assembly with changes from the export.
Notes:
A statement is determined as existing if the provided uuid or responsibility uuid is in the existing
by-component assembly. If existing, the description will be updated if it has changed.
Any existing inherited or satisfied statements that are not in the incoming export will be removed.
If a statement is in the incoming export, but not in the existing by-component assembly, it will be added.
"""
new_inherited: List[ossp.Inherited] = []
new_satisfied: List[ossp.Satisfied] = []
# Create a copy of the input by-component assembly to reconcile and return
new_by_comp: ossp.ByComponent = copy.deepcopy(self._by_comp)
for statement in incoming_inherited:
if statement.provided_uuid in self._inherited_dict:
existing_statement = self._inherited_dict[str(statement.provided_uuid)]
# Update the description if it has changed
existing_statement.description = statement.description
statement = existing_statement
new_inherited.append(statement)
new_by_comp.inherited = none_if_empty(new_inherited)
for statement in incoming_satisfied:
if statement.responsibility_uuid in self._satisfied_dict:
existing_statement = self._satisfied_dict[str(statement.responsibility_uuid)]
# Update the description if it has changed
existing_statement.description = statement.description
statement = existing_statement
new_satisfied.append(statement)
new_by_comp.satisfied = none_if_empty(new_satisfied)
return new_by_comp
|