Skip to content
Snippets Groups Projects
Commit 3b6f5f3b authored by martiivGylden's avatar martiivGylden
Browse files

Finsihed refactoring code

parent db6120b1
No related branches found
No related tags found
No related merge requests found
from dataclasses import dataclass from dataclasses import dataclass
import pandas as pd import pandas as pd
import ERFormatConstants as const import ERFormatConstants as const
from dynamics import *
class Threat: class Threat:
"""_summary_ """_summary_
...@@ -26,12 +24,11 @@ class Threat: ...@@ -26,12 +24,11 @@ class Threat:
def __str__(self) -> str: def __str__(self) -> str:
return f"Threat: {self.id}, {self.name}, {self.linkedIndicators}" return f"Threat: {self.id}, {self.name}, {self.linkedIndicators}"
def findIndicatorsThreat(df:pd.DataFrame, diagram: component.Diagram, self): def findIndicatorsThreat(self, df:pd.DataFrame, diagram):
""" """
Links the indicators for the threat to the threat object and updates the metrics dictionary with the indicators Links the indicators for the threat to the threat object and updates the metrics dictionary with the indicators
""" """
componentId = self.componentID # Define the ID of the componen
componentId = self.componentID # Define the ID of the component
lines = df.loc[df['Name']=='Line'] # Find all lines in the diagram lines = df.loc[df['Name']=='Line'] # Find all lines in the diagram
lineSource = lines.loc[lines[const.From] == componentId] # Find the line where the component is the source lineSource = lines.loc[lines[const.From] == componentId] # Find the line where the component is the source
...@@ -42,36 +39,61 @@ class Threat: ...@@ -42,36 +39,61 @@ class Threat:
else: else:
lineOne = lineDestination lineOne = lineDestination
if lineOne[const.From].item() == componentId: # If the component is the source # * LineOne is the line connecting the threat to the Attack, and the relationship line
lineTwo = df.loc[df[const.Id] == lineOne[const.To].item()] # Find the component associated with the line # * First we find the attack component on the other end of theline
else:
lineTwo = df.loc[df[const.Id] == lineOne[const.From].item()] # Find the component associated with the line
if lineOne[const.From].item() == componentId: # If the component is the source
# ? Since lineOne from is the threat component, lineOne to is the attack component
attackComponent = df.loc[df[const.Id] == lineOne[const.To].item()] # Find the component associated with the line
else:
attackComponent = df.loc[df[const.Id] == lineOne[const.From].item()] # Find the component associated with the line
# * Now we need to find the lines associated with the relationship component
lineOneComponentID = lineOne[const.Id].item()
sourceComponent = df.loc[df[const.Id]==lineTwo[const.From].item()] # Defines the source of the line connecting threats/consequences and attacks lines = df.loc[df[const.To] == lineOneComponentID]
destinationComponent = df.loc[df[const.Id]==lineTwo[const.To].item()] # Defines the destination of the line connecting threats/consequences and attacks if lines.empty:
lines = df.loc[df[const.From] == lineOneComponentID]
# * Due to the presence of barriers we need to iterate over the result and find the one that is the relationship component
if componentType == const.ThreatDynamic: # * If the component is a threat for cols, rows in lines.iterrows():
if sourceComponent[const.textArea1].item() == const.Threat: # Checks if source or destination is the threat if rows[const.To] == lineOneComponentID:
self.associatedThreat = sourceComponent potentialID = rows[const.From]
self.associatedAttack = destinationComponent
else:
self.associatedThreat = destinationComponent
self.associatedAttack = sourceComponent
elif componentType == const.ConsequenceDynamic: # * If the component is a consequence
if sourceComponent[const.textArea1].item() == const.Consequence:
self.associatedConsequence = sourceComponent
self.associatedAttack = destinationComponent
else: else:
self.associatedConsequence = destinationComponent potentialID = rows[const.To]
self.associatedAttack = sourceComponent
potentialComponent = df.loc[df[const.Id] == potentialID]
if potentialComponent[const.typeField].item() == const.Threat:
relationshipComponent = potentialComponent
break
# * We now have the relationship component, and the attack component
# * We can now extract the metrics from the relationship component and define the attack
attackComponentID = attackComponent[const.Id].item()
attackType = attackComponent[const.AttackType].item()
attackDescription = attackComponent[const.AttackDescription].item()
attack = Attack(attackComponentID, attackType, attackDescription)
diagram.attacks[attackComponentID] = attack
for i in range(4, len(relationshipComponent.columns), 2):
indicatorID = relationshipComponent[f"Text Area {i}"].item()
if indicatorID == "" or "NaN":
break
indicatorID = int(indicatorID)
indicatorReason = relationshipComponent[f"Text Area {i+1}"].item()
self.linkedIndicators[indicatorID] = indicatorReason
diagram.indicators[indicatorID].threatAssoicates[self.id] = self
# ! After parsing the different components related to the dynamics component, return diagram
# ! the metrics in the component are added to the global metric list and local metric list
self.linkMetric(df, metricsDict)
class Consequence: class Consequence:
"""_summary_ """_summary_
...@@ -93,6 +115,56 @@ class Consequence: ...@@ -93,6 +115,56 @@ class Consequence:
def __str__(self) -> str: def __str__(self) -> str:
return f"Consequence: {self.id}, {self.name}, {self.consequence}, {self.linkedIndicators}" return f"Consequence: {self.id}, {self.name}, {self.consequence}, {self.linkedIndicators}"
def findIndicatorsConsequence(self, df:pd.DataFrame, diagram):
"""
Links the indicators for the consequence to the consequence object and updates the metrics dictionary with the indicators
"""
componentId = self.componentID # Define the ID of the componen
lines = df.loc[df['Name']=='Line'] # Find all lines in the diagram
lineSource = lines.loc[lines[const.From] == componentId] # Find the line where the component is the source
lineDestination = lines.loc[lines[const.To] == componentId] # ! The component SHOULD be source however, to error handle we need to check for destination as well
if lineSource.isnull().values.any() == True: # Checks if the threat is the source or destination
lineOne = lineSource
else:
lineOne = lineDestination
# * Now we need to find the lines associated with the relationship component
lineOneComponentID = lineOne[const.Id].item()
lines = df.loc[df[const.To] == lineOneComponentID]
if lines.empty:
lines = df.loc[df[const.From] == lineOneComponentID]
# * Due to the presence of barriers we need to iterate over the result and find the one that is the relationship component
for cols, rows in lines.iterrows():
if rows[const.To] == lineOneComponentID:
potentialID = rows[const.From]
else:
potentialID = rows[const.To]
potentialComponent = df.loc[df[const.Id] == potentialID]
if potentialComponent[const.typeField].item() == const.Consequence:
relationshipComponent = potentialComponent
break
for i in range(4, len(relationshipComponent.columns), 2):
indicatorID = relationshipComponent[f"Text Area {i}"].item()
if indicatorID == "" or "NaN":
break
indicatorID = int(indicatorID)
indicatorReason = relationshipComponent[f"Text Area {i+1}"].item()
self.linkedIndicators[indicatorID] = indicatorReason
diagram.indicators[indicatorID].consequenceAssociates[self.id] = self
return diagram
class Attack: class Attack:
"""_summary_ """_summary_
...@@ -122,6 +194,42 @@ class ERComponent: ...@@ -122,6 +194,42 @@ class ERComponent:
self.linkedIndicators:dict[int, str] = {} self.linkedIndicators:dict[int, str] = {}
class Indicator:
"""
The metric class is associated with all the dynamics components AND the matrix
The initial creation of metrics is done through the dynamic units, there the init function is used to create the metrics,
and fill them with the correct associated components (erID, bowtieID)
When the object is then accessed again for the matrix parse the metrics are filled with the correct values
"""
def __init__(self, ID, name, value, date, frequency, guide, scale, interpretation) -> None:
"""
Metrics are created when parsing dynamics and are there filled with args
When the matrix is parsed the metrics are filled with the correct values
Args:
ID (str): Unique ID for the metric
name (str): Unique name for the metric
"""
#Metrics found in the dynamics tables
self.erAssociates: dict[int, ERComponent] = {} # ID of the metric used to locate in dynamics matrics
self.threatAssoicates: dict[int, Threat] = {} # ID of the metric used to locate in dynamics matrics
self.consequenceAssociates: dict[int, Consequence] = {} # ID of the metric used to locate in dynamics matrics
self.attackAssociates: dict[int, Attack] = {} # ID of the metric used to locate in dynamics matrics
self.indicatorID = ID # ID of the metric used to locate in dynamics matrics
self.indicatorName = name # Name of the metric
self.value = value # Value of the metric
self.date = date # Date of the metric
self.frequency = frequency # Frequency of the metric
self.measureGuide =guide # Measure guide of the metric
self.scale = scale # Scale of the metric
self.interpretation = interpretation # Interpretation of the metric
def __str__(self) -> str:
return f"Metric: {self.name}, Value: {self.value} Last update: {self.date}"
@dataclass @dataclass
class Diagram(): class Diagram():
# Dicttionaries of threats, consequences, attacks, indicators and ER components # Dicttionaries of threats, consequences, attacks, indicators and ER components
...@@ -136,36 +244,4 @@ class Diagram(): ...@@ -136,36 +244,4 @@ class Diagram():
self.consequences = {} self.consequences = {}
self.attacks = {} self.attacks = {}
self.dynamics = {} self.dynamics = {}
self.metrics = {} self.indicators = {}
\ No newline at end of file
def getThreat(self, id) -> Threat:
"""_summary_
Args:
id (_type_): _description_
Returns:
Threat: _description_
"""
threat = self.threats[id]
return threat
def getConsequence(self, id) -> Consequence:
"""_summary_
Args:
id (_type_): _description_
Returns:
Consequence: _description_
"""
consequence = self.consequences[id]
return consequence
def getAttack(self, id) -> Attack:
attack = self.attacks[id]
return attack
def getIndicator(self, indicaorID) -> ERDynamic:
pass
\ No newline at end of file
import pandas as pd import pandas as pd
import ERFormatConstants as const import ERFormatConstants as const
import components as component import components as component
import dynamics as dynamic
import logging as log import logging as log
import matrices as matrix import matrices as matrix
...@@ -19,9 +18,9 @@ def parseDiagramFile(csvFile) -> component.Diagram: ...@@ -19,9 +18,9 @@ def parseDiagramFile(csvFile) -> component.Diagram:
diagram = parseThreats(df, diagram) # diagram = parseThreats(df, diagram) #
diagram = parseConsequences(df, diagram) diagram = parseConsequences(df, diagram)
diagram = parseAttacks(df, diagram) diagram = parseAttacks(df, diagram)
print("Diagram successfully parsed")
return diagram return diagram
# Function will parse the threats and add them to the dictionary # Function will parse the threats and add them to the dictionary
...@@ -31,15 +30,15 @@ def parseThreats(df,diagram: component.Diagram): ...@@ -31,15 +30,15 @@ def parseThreats(df,diagram: component.Diagram):
threat = component.Threat( threat = component.Threat(
df[const.Id][i], # Component ID df[const.Id][i], # Component ID
df[const.ThreatIDValue][i], # ID from ER df[const.ThreatMethodID][i], # ID from ER
df[const.ThreatName][i], # Name of the threat df[const.ThreatName][i], # Name of the threat
df[const.ThreatDescription][i], df[const.ThreatDescription][i],
df[const.ThreatSource][i], df[const.ThreatSource][i],
df[const.Likelihood][i], df[const.Likelihood][i],
) )
diagram.threats[df[const.ThreatIDValue][i]] = threat diagram.threats[df[const.ThreatMethodID][i]] = threat
threat.findIndicatorsThreat(df, diagram, threat) # Find the indicators associated with the threat threat.findIndicatorsThreat(df, diagram) # Find the indicators associated with the threat
return diagram return diagram
...@@ -56,6 +55,7 @@ def parseConsequences(df, diagram: component.Diagram): ...@@ -56,6 +55,7 @@ def parseConsequences(df, diagram: component.Diagram):
df[const.ConsequenceScore][i], df[const.ConsequenceScore][i],
) )
diagram.consequences[df[const.ConsequenceID][i]] = consequence diagram.consequences[df[const.ConsequenceID][i]] = consequence
consequence.findIndicatorsConsequence(df, diagram) # Find the indicators associated with the consequence
return diagram return diagram
...@@ -85,80 +85,53 @@ def parseArchitectureDiagram(df, diagram: component.Diagram): ...@@ -85,80 +85,53 @@ def parseArchitectureDiagram(df, diagram: component.Diagram):
def parseRelationshipComponentER(df: pd.DataFrame, diagram: component.Diagram, row) -> None: def parseRelationshipComponentER(df: pd.DataFrame, diagram: component.Diagram, row) -> None:
relationshipComponent = df.loc[row] # Define the relationship component relationshipComponent = df.loc[row] # Define the relationship component
print("Parsing ER component: ", relationshipComponent[const.erName])
print(relationshipComponent[const.textArea5])
indicatorList = {} # Define a list over relevant indicators to individual relationship component indicatorList = {} # Define a list over relevant indicators to individual relationship component
erComponents = {} # Define a list over ER components erComponents = {} # Define a list over ER components
#* Iterate over the Relationship component to find all the indicators, and the reasoning for each #* Iterate over the Relationship component to find all the indicators, and the reasoning for each
for i in range(len(6 ,relationshipComponent.columns, 2)): for i in range(6 ,len(relationshipComponent), 2):
indicatorID = relationshipComponent[f"Text Area {i}"].item()
indicatorReason = relationshipComponent[f"Text Area {i+1}"].item() if pd.isnull(relationshipComponent[f"Text Area {i}"]) == True:
break
indicatorID = relationshipComponent[f"Text Area {i}"]
indicatorReason = relationshipComponent[f"Text Area {i+1}"]
indicatorList[indicatorID] = indicatorReason indicatorList[indicatorID] = indicatorReason
# * Find all the lines associated with the component # * Find all the lines associated with the component
linesFrom = df.loc[df[const.From] == relationshipComponent[const.Id].item()] # Find the component associated with the line linesFrom = df.loc[df[const.From] == relationshipComponent[const.Id].item()] # Find the component associated with the line
linesTo = df.loc[df[const.To] == relationshipComponent[const.Id].item()] # Find the component associated with the line linesTo = df.loc[df[const.To] == relationshipComponent[const.Id].item()] # Find the component associated with the line
linesFrom.append(linesTo) # Merge the two dataframes allLines = pd.concat([linesFrom, linesTo]) # Merge the two dataframes
# * Iterate through both lines, and find the ER components related to the relationship component # * Iterate through both lines, and find the ER components related to the relationship component
for i in range(len(linesFrom)): for index, row in allLines.iterrows():
# Defines values objectTo = row[const.To]
erName = linesFrom[const.Name][i].item() objectFrom = row[const.From]
erID = linesFrom[const.erID][i].item()
erDescription = linesFrom[const.erDescription][i].item()
erType = linesFrom[const.erType][i].item()
if df.loc[df[const.Id] == objectTo][const.typeField].item() == "ER":
row = df.loc[df[const.Id] == objectFrom]
else:
row = df.loc[df[const.Id] == objectTo]
# Defines values
name = row[const.erName].item()
entityRelationshipId = row[const.erID].item()
description = row[const.erDescription].item()
entityrelationshipType = row[const.erType].item()
# Create ER component # Create ER component
erComponent = component.ERComponent(erName,erID, erDescription, erType) erComponent = component.ERComponent(name,entityRelationshipId, description, entityrelationshipType)
# Add indicators to the ER component # Add indicators to the ER component
erComponent.linkedIndicators.update(indicatorList) erComponent.linkedIndicators.update(indicatorList)
erComponents[erComponent.id]= erComponent erComponents[erComponent.id]= erComponent
for i in range (indicatorList): for i in indicatorList.keys():
indicatorID = i.key()
# We need to update the indicators with the ER components and the reasoning for the indicator annotation # We need to update the indicators with the ER components and the reasoning for the indicator annotation
diagram.indicators[indicatorID].erAssocaites.update(erComponents) index = int(i)
return diagram diagram.indicators[index].erAssociates.update(erComponents)
def extractMetrics(df, index, startRange):
for j in range(startRange, len(df.columns),2): # Parse all text areas to find metrics
listOfMetrics = []
metricID = "Text Area "+str(j)
metricName = "Text Area "+str(j+1)
if pd.isnull(df[metricID][index]) == False: # If the text area is not empty
log.info("Metric: ID", df[metricID][index], "Name: ", df[metricName][index])
metric = dynamic.Metric(df[metricID][index], df[metricName][index])
listOfMetrics.append(metric)
else:
j=0
break # First empty field indicates no more metrics
return listOfMetrics # Returns metric found in the dynamic component
def joinMetrcs(localMetrics: list, globalMetrics: list) -> list:
"""_summary_
Function will use a local metric list and insert the local metrics into a global metric list
containing all the metrics in the threat landscape
:param localMetrics: List of metrics from a dynamic component
:param globalMetrics: List of metrics from the entire threat landscape
"""
duplicateMetrics = 0 # Counter for duplicate metrics per function run
for i in range(len(globalMetrics)):
for j in range(len(localMetrics)):
if globalMetrics[i].name == localMetrics[j].name: # Local metric already exists in the global metric list
duplicateMetrics += 1
break # Check next entry
else:
globalMetrics.append(localMetrics[j]) # Add the local metric to the global metric list
log.info("New local metric added to global metric list, metric: ", localMetrics[j].name)
log.info("Added all metrics in local list \n, number of duplicate metrics: ", duplicateMetrics, "\n Number of new metrics: ", len(localMetrics)-duplicateMetrics)
return globalMetrics
return diagram
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
import ERFormatConstants as const
import logging as log
import components as component
#Metric class, will be used for all dynamics
class Indicator:
"""
The metric class is associated with all the dynamics components AND the matrix
The initial creation of metrics is done through the dynamic units, there the init function is used to create the metrics,
and fill them with the correct associated components (erID, bowtieID)
When the object is then accessed again for the matrix parse the metrics are filled with the correct values
"""
def __init__(self, ID, name, value, date, frequency, guide, scale, interpretation) -> None:
"""
Metrics are created when parsing dynamics and are there filled with args
When the matrix is parsed the metrics are filled with the correct values
Args:
ID (str): Unique ID for the metric
name (str): Unique name for the metric
"""
#Metrics found in the dynamics tables
self.erAssociates: dict[int, component.ERComponent] = {} # ID of the metric used to locate in dynamics matrics
self.threatAssoicates: dict[str, component.Threat] = {} # ID of the metric used to locate in dynamics matrics
self.consequenceAssociates: dict[str, component.Consequence] = {} # ID of the metric used to locate in dynamics matrics
self.attackAssociates: dict[int, component.Attack] = {} # ID of the metric used to locate in dynamics matrics
self.indicatorID = ID # ID of the metric used to locate in dynamics matrics
self.indicatorName = name # Name of the metric
self.value = value # Value of the metric
self.date = date # Date of the metric
self.frequency = frequency # Frequency of the metric
self.measureGuide =guide # Measure guide of the metric
self.scale = scale # Scale of the metric
self.interpretation = interpretation # Interpretation of the metric
def __str__(self) -> str:
return f"Metric: {self.name}, Value: {self.value} Last update: {self.date}"
def linkMetric(self, df, metricsDict: dict):
"""
Function will extract all the metrics from the dynamics component, add it to the local metric list of the dynamic component,
the function also adds the metric to the global metric list (if its not already there) and and links the dynamic component to the metric,
through the associatedER and associatedAttack lists in the metric class
Args:
df (pandas Dataframe): The original dataframe being parsed from lucidchart
metricsDict (dict): The metricsdict is the global metric list, it contains all the metrics in the diagram
"""
dynamicComponent = df.loc[df[const.Id] == self.componentID] # Finds the dynamic component we are extracting metrics from
for i in range (4, len(dynamicComponent.columns), 2): # Iterate through all the metrics
if(dynamicComponent["Text Area "+str(i)].isnull().values.any() == True): # If there are no metrics left
break # Break the loop
metricID = dynamicComponent["Text Area "+str(i)].item() # Find the metric ID in the component
metricID = int(metricID)
metricName = dynamicComponent["Text Area "+str(i+1)].item() # Find the metric Name
self.metrics.append(metricID) # ? Adds the metric to the metric list associated with the dynamic component specifically
if checkDuplicateMetrics(metricsDict, metricID) == False: # If the metric is in the global list
metric = Metric(metricID, metricName) # Create a new metric object
else:
metric = metricsDict[metricID] # Find the metric
if self.type == const.ThreatDynamic: # If the dynamic component is a threat
if checkDuplicate(metric.bowtieID, self.associatedThreat[const.Id].item()): #* If the threat component is associated with the metric
continue # * We wont add it to the metric threatList and attack list since its already there
metric.bowtieID.append(self.associatedThreat[const.Id].item()) # ? Adds the associated threat to the metric
elif self.type == const.ConsequenceDynamic: # Same procedure as if above
if checkDuplicate(metric.bowtieID, self.associatedConsequence[const.Id].item()):
continue
metric.bowtieID.append(self.associatedConsequence[const.Id].item())
if checkDuplicate(metric.bowtieID, self.associatedAttack[const.Id].item()): #* If the associated component is a duplicate
continue
metric.bowtieID.append(self.associatedAttack[const.Id].item())
metricsDict[metricID] = metric # ! Adds the metric to the global metric list
class ERDynamic(DynamicComponent):
"""
The ER dynamic inherits the dynamic component and adds associated ER components
Contains its own associate function and its own linkMetric function to link metrics
Has a description and a list of associated ER components
Args:
DynamicComponent (class): parent class
"""
def __init__(self, componentID, type, description) -> None:
super().__init__(componentID)
self.description = description # Description of the dynamic
self.associatedERComponents = {} # Associated ER component
self.type = type
def __str__(self) -> str:
return super().__str__() + f"ER Dynamic: {self.type}, {self.description}, Amount of associated components {len(self.associatedERComponents)}"
def associatER(self, df, metricsDict: dict):
"""
Function will associate the ER dynamic with the correct components
The function will also link the metrics to the ER dynamic component
The function will also add the metrics to the global metric list
Args:
df (pandas Dataframe): The original dataframe being parsed from lucidchart
metricsDict (dict): The metricsdict is the global metric list, it contains all the metrics in the diagram
"""
componentId = self.componentID # Define the ID of the component
#Find the lines associated with the component
lines = df.loc[df['Name']=='Line'] # Find all lines in the diagram
relevantLines = [] # List of lines relevant to the component
for i in range(len(lines)):
line = lines.iloc[i]
if line[const.From] == componentId or line[const.To] == componentId: # If the line is associated with the component
relevantLines.append(lines.iloc[i]) # Add the line to the relevant lines list
for i in range(len(relevantLines)):
line = relevantLines[i]
lineSource = line[const.From] # The source of the line
lineDestination = line[const.To]
if lineSource == componentId: # If the line is associated with the component
associatedComponentID = lineDestination
else:
associatedComponentID = lineSource
associatedComponent = df.iloc[df.index[df[const.Id] == associatedComponentID]] # Find the component associated with the line
associatedComponentRegularID = associatedComponent[const.textArea3].item() # Find the ID of the associated component
associatedComponentName = associatedComponent[const.textArea1].item() # Find the description of the associated component
self.associatedERComponents[associatedComponentRegularID] = associatedComponentName # Add the associated component to the list of associated components
self.linkMetric(df, metricsDict) # Link the metrics to the ER dynamic component
def linkMetric(self,df, metricsDict):
"""
Links the metrics to the ER dynamic component and adds the metrics to the global metric list
Args:
df (Dataframe): The original dataframe being parsed from lucidchart
metricsDict (dict): The metricsdict is the global metric list, it contains all the metrics in the diagram
"""
dynamicComponent = df.loc[df[const.Id] == self.componentID] # Find the dynamic component
for i in range (6, len(dynamicComponent.columns), 2): # Iterate through all the metrics
if(dynamicComponent["Text Area "+str(i)].isnull().values.any() == True): # No more metrics
break
metricID = dynamicComponent["Text Area "+str(i)].item() # Find the metric ID
metricID = int(metricID)
metricName = dynamicComponent["Text Area "+str(i+1)].item() # Find the metric ID
self.metrics.append(metricID) # ? Adds the metric to the metric list associated with the dynamic component specifically
if checkDuplicateMetrics(metricsDict, metricID) == False: # If the metric is not a duplicate
metric = Metric(metricID, metricName) # Create a new metric object
else:
metric = metricsDict[metricID]
for i in self.associatedERComponents.keys():
erID = i
if checkDuplicate(metric.erID, erID): #* If the associated component is a duplicate
continue
metric.erID.append(erID)
metricsDict[metricID] = metric # ! Adds the metric to the global metric list
def checkDuplicateMetrics(metricsDict: dict, metricID: str):
"""_summary_
Function will check if the diagrams metric dict contains a metric,
with the same ID as the one which is listed in the dynamics component, if it does
"""
if metricID in metricsDict.keys():
return True
else:
return False
def checkDuplicate(list: list, id: str):
"""_summary_
Check if the already contains the associated component
"""
if id in list:
return True
else:
return False
\ No newline at end of file
import dynamics as dyn
import diagramParser as parse import diagramParser as parse
def main(): def main():
...@@ -6,7 +5,7 @@ def main(): ...@@ -6,7 +5,7 @@ def main():
dynamicMetricsBowtie = [] # List of metrics for the bowtie model dynamicMetricsBowtie = [] # List of metrics for the bowtie model
dynamicMetricsArchitecture = [] # List of metrics for the architecture dynamicMetricsArchitecture = [] # List of metrics for the architecture
#parse.parseDiagramFile('diagrams/Thesis Bow-Tie and architecture - Meta model-2.csv') # Parse the diagram #parse.parseDiagramFile('diagrams/Thesis Bow-Tie and architecture - Meta model-2.csv') # Parse the diagram
diagram = parse.parseDiagramFile('diagrams/DiagramTest3.csv') # Parse the diagram diagram = parse.parseDiagramFile('diagrams/TestIter2.csv') # Parse the diagram
if __name__=="__main__": if __name__=="__main__":
......
import pandas as pd import pandas as pd
import ERFormatConstants as const import ERFormatConstants as const
import components as component import components as component
import dynamics as dynamic
"""_summary_ """_summary_
Parses csv table and returns a dataframe Parses csv table and returns a dataframe
...@@ -10,7 +9,7 @@ This is quite a big EDGE case and will only work for the specific table shape th ...@@ -10,7 +9,7 @@ This is quite a big EDGE case and will only work for the specific table shape th
""" """
def parseTable(df, diagram: component.Diagram) -> component.Diagram: def parseTable(df, diagram: component.Diagram) -> component.Diagram:
cols = [const.Metric_ID, const.Metric_Name, const.Value, const.Measure_date, const.Frequency ,const.Measurement_guide, const.Scale, const.Interpretation] cols = [const.indicatorID, const.indicatorName, const.Value, const.Measure_date, const.Frequency ,const.Measurement_guide, const.Scale, const.Interpretation]
table = df.loc[df[const.Name]=='Table'] # Defines the table table = df.loc[df[const.Name]=='Table'] # Defines the table
...@@ -26,11 +25,11 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram: ...@@ -26,11 +25,11 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram:
# * Etc # * Etc
startStandardIndicators = 21-4 # Column 21-4 startStandardIndicators = 10 # Column 21-4
stopStandardIndicators = 180-4 # First loop needs to stop at column 180-4, 4 columns are removed in diagramParser.py stopStandardIndicators = 169 # First loop needs to stop at column 180-4, 4 columns are removed in diagramParser.py
interval = len(cols) interval = len(cols)
startSpecialIndicators = 196-4 # Text area 185 startSpecialIndicators = 185 # Text area 185
stopSpecializedIndicators = len(table.columns)-2 stopSpecializedIndicators = len(table.columns)
...@@ -46,7 +45,7 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram: ...@@ -46,7 +45,7 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram:
indicatorID1 = int(indicatorID1) # Convert indicator to int indicatorID1 = int(indicatorID1) # Convert indicator to int
#* Create indicator object #* Create indicator object
indicator1 = dynamic.Indicator( indicator1 = component.Indicator(
indicatorID1, indicatorID1,
indicatorName1, indicatorName1,
Value1, Value1,
...@@ -70,7 +69,7 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram: ...@@ -70,7 +69,7 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram:
IndicatorID2 = int(IndicatorID2) IndicatorID2 = int(IndicatorID2)
indicator2 = dynamic.Indicator( indicator2 = component.Indicator(
IndicatorID2, IndicatorID2,
IndicatorName2, IndicatorName2,
Value2, Value2,
...@@ -88,43 +87,59 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram: ...@@ -88,43 +87,59 @@ def parseTable(df, diagram: component.Diagram) -> component.Diagram:
break break
IndicatorID = table["Text Area "+str(i)].item() # Define the Metric ID IndicatorID = table["Text Area "+str(i)].item() # Define the Metric ID
IndicatorID = int(IndicatorID)
IndicatorName = table["Text Area "+str(i+1)].item() # Define the Metric Name IndicatorName = table["Text Area "+str(i+1)].item() # Define the Metric Name
Value = table["Text Area "+str(i+2)].item() # Define the Value Value = table["Text Area "+str(i+2)].item() # Define the Value
MeasureDate = table["Text Area "+str(i+3)].item() # Define the Measure Date MeasureDate = table["Text Area "+str(i+3)].item() # Define the Measure Date
Frequency = table["Text Area "+str(i+4)].item() # Define the Frequency Frequency = table["Text Area "+str(i+4)].item() # Define the Frequency
Guide = table["Text Area "+str(i+5)].item() # Define the Measurement guide Guide = table["Text Area "+str(i+5)].item() # Define the Measurement guide
Scale = table["Text Area "+str(i+6)].item()
Interpretation = table["Text Area "+str(i+7)].item()
indicator = dynamic.Indicator( indicator = component.Indicator(
IndicatorID, IndicatorID,
IndicatorName, IndicatorName,
Value, Value,
MeasureDate, MeasureDate,
Frequency, Frequency,
Guide Guide,
Scale,
Interpretation
) )
diagram.indicators[IndicatorID] = indicator # Insert indicator into diagram dictionary diagram.indicators[IndicatorID] = indicator # Insert indicator into diagram dictionary
# ! Parsing will then continue from the last row, row 24, and onwards with usual text areas for specialized indicators # ! Parsing will then continue from the last row, row 24, and onwards with usual text areas for specialized indicators
for i in range(startSpecialIndicators, stopSpecializedIndicators, interval): for i in range(startSpecialIndicators, stopSpecializedIndicators, interval):
if stopSpecializedIndicators == 191:
break
if i >= stopSpecializedIndicators: if i >= stopSpecializedIndicators:
break break
IndicatorID = table["Text Area "+str(i)].item() # Define the Metric ID IndicatorID = table["Text Area "+str(i)].item() # Define the Metric ID
IndicatorID = int(IndicatorID)
IndicatorName = table["Text Area "+str(i+1)].item() # Define the Metric Name IndicatorName = table["Text Area "+str(i+1)].item() # Define the Metric Name
Value = table["Text Area "+str(i+2)].item() # Define the Value Value = table["Text Area "+str(i+2)].item() # Define the Value
MeasureDate = table["Text Area "+str(i+3)].item() # Define the Measure Date MeasureDate = table["Text Area "+str(i+3)].item() # Define the Measure Date
Frequency = table["Text Area "+str(i+4)].item() # Define the Frequency Frequency = table["Text Area "+str(i+4)].item() # Define the Frequency
Guide = table["Text Area "+str(i+5)].item() # Define the Measurement guide Guide = table["Text Area "+str(i+5)].item() # Define the Measurement guide
Scale = table["Text Area "+str(i+6)].item()
Interpretation = table["Text Area "+str(i+7)].item()
indicator = dynamic.Indicator(
indicator = component.Indicator(
IndicatorID, IndicatorID,
IndicatorName, IndicatorName,
Value, Value,
MeasureDate, MeasureDate,
Frequency, Frequency,
Guide Guide,
Scale,
Interpretation
) )
diagram.indicators[IndicatorID] = indicator diagram.indicators[IndicatorID] = indicator
return diagram return diagram
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment