-
Notifications
You must be signed in to change notification settings - Fork 0
/
model.py
170 lines (133 loc) · 5.59 KB
/
model.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
import os
from typing import Dict
from enum import Enum
from time import sleep
from logger import logger
from graph import Graph, LoadingError, DecodingError, EmptyGraphError
from algorithms.depth_first_search import DepthFirstSearch
from algorithms.layouting.layout_algorithm import LayoutAlgorithm
from observer import Subject
class MainModel(Subject):
"""
Class which implements the model from MVC
Loads all the algorithms:
"""
class State(Enum):
GRAPH_CHANGED = 0
def __init__(self):
"""
Checks if all needed paths exists and starts to load data which
is needed by the application
"""
Subject.__init__(self)
if not os.path.exists("graphs"):
logger.debug("Making graphs directory")
os.makedirs("graphs")
if not os.path.exists("algorithms"):
logger.debug("Making algorithms directory")
os.makedirs("algorithms")
self.is_connected = False
self.acyclic = False
self.is_undirected_tree = False
self.loaded_graphs: Dict[str, Graph] = dict()
self.layout_algos: Dict[str, LayoutAlgorithm] = dict()
self.algos = dict()
self.load_layouting_algos()
self.load_algos()
self.view = None
def attach(self, observer):
Subject.attach(self, observer)
def load_layouting_algos(self):
excluded_files = frozenset({"layout_algorithm.py", "__pycache__"})
logger.info("CWD: %s" % os.getcwd())
path = "algorithms/layouting/"
if not os.path.exists(path):
logger.debug("Making %s directory" % path)
os.makedirs(path)
# TODO GIBTS KEIN LIST MINUS/REMOVE
entries = set(os.listdir(path)) - excluded_files
# TODO Teil der For-Schleife eigene (pure?)Fkt. auslagern
for file in entries:
module = file[0:-3]
logger.info("Loading %s" % module)
name = "default"
try:
mod = __import__((path+file).replace("/", ".")[0:-3], fromlist=[name])
name= getattr(mod, "class_name")
logger.info("Trying to import %s from %s"% (name, file))
try:
klass = getattr(mod, name)
self.layout_algos[name] = klass
except AttributeError as error:
logger.error(error)
logger.error("The module %s does not have a class with the name %s", module, name)
except AttributeError as e:
logger.error(e)
logger.error("Could not load %s" % module)
logger.error("Each module must have the .class_name attribute")
def load_algos(self):
logger.info("CWD: %s" % os.getcwd())
path = "algorithms/"
excluded_files = frozenset({"__pycache__", "layouting"})
if not os.path.exists(path):
logger.debug("Making %s directory" % path)
os.makedirs(path)
# TODO GIBTS KEIN LIST MINUS/REMOVE
entries = set(os.listdir(path)) - excluded_files
# TODO Teil der For-Schleife eigene (pure?)Fkt. auslagern
for file in entries:
module = file[0:-3]
logger.info("Loading %s" % module)
name = "default"
try:
mod = __import__((path+file).replace("/", ".")[0:-3], fromlist=[name])
name= getattr(mod, "class_name")
logger.info("Trying to import %s from %s"% (name, file))
try:
klass = getattr(mod, name)
self.algos[name] = klass
except AttributeError as error:
logger.error(error)
logger.error("The module %s does not have a class with the name %s", module, name)
except AttributeError as e:
logger.error(e)
logger.error("Could not load %s" % module)
logger.error("Each module must have the .class_name attribute")
def load_graph_from_file(self, name: str, filepath: str, tab) -> None:
"""
Load a graph from the specified file
Mutates: self.loaded_graphs, self.is_undirected_tree, self.subject_state
:param name: The name under which the graph will ne accessible through the whole
apllication
:param filepath: The path from which the graph should be loaded
"""
try:
temp = Graph(filepath)
except LoadingError:
# Sth. is wrong with the file path
raise LoadingError
except DecodingError:
# Sth. is wrong with the syntax of the file
raise DecodingError
# TODO Think about what should happen when name is alredy present in the dict
self.loaded_graphs[name] = temp
self.is_undirected_tree = self.check_undirected_tree(name)
self.subject_state = self.State.GRAPH_CHANGED, name, tab
#TODO This should not be in the model
def check_undirected_tree(self, name: str) -> bool:
"""
Checks if a graph is a undirected tree(connected, acyclic)
Mutates: self.is_connected, self.acyclic
"""
graph = self.loaded_graphs[name]
try:
dfs = DepthFirstSearch(graph, 0)
# Check if all nodes have been visited
if all(dfs.marked):
self.is_connected = True
if not dfs.contains_cycle:
self.acyclic = True
return self.is_connected and self.acyclic
except EmptyGraphError:
logger.error("Graph is empty")
return False