Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pycomsdk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
com
pycomsdk
Commits
140833ce
Commit
140833ce
authored
Apr 24, 2025
by
Alexandr Sokolov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev_parser_aDOT' into 'dev'
Dev parser a dot See merge request
!4
parents
55ad2207
b05eec3f
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
527 additions
and
39 deletions
+527
-39
.gitignore
.gitignore
+1
-0
README.md
README.md
+0
-0
graph.py
comsdk/graph.py
+10
-0
misc.py
comsdk/misc.py
+2
-1
parser.py
comsdk/parser.py
+86
-26
simplest.py
test_funcs/simplest.py
+64
-0
branching.adot
tests/adot/branching.adot
+5
-5
complex.adot
tests/adot/complex.adot
+3
-3
cycled_v2.adot
tests/adot/cycled_v2.adot
+18
-0
trivial_v2.adot
tests/adot/trivial_v2.adot
+12
-0
attributes.adot
tests/test_aDOT/test_adot_files/attributes.adot
+23
-0
branching.adot
tests/test_aDOT/test_adot_files/branching.adot
+18
-0
cycled.adot
tests/test_aDOT/test_adot_files/cycled.adot
+22
-0
edge_types.adot
tests/test_aDOT/test_adot_files/edge_types.adot
+17
-0
main_graph.adot
tests/test_aDOT/test_adot_files/main_graph.adot
+21
-0
postprocess.adot
tests/test_aDOT/test_adot_files/postprocess.adot
+17
-0
preprocess.adot
tests/test_aDOT/test_adot_files/preprocess.adot
+18
-0
sequential.adot
tests/test_aDOT/test_adot_files/sequential.adot
+18
-0
unit_test_aDOT.py
tests/test_aDOT/unit_test_aDOT.py
+143
-0
node_attrs.adot
tests/test_adot_files/node_attrs.adot
+11
-0
test_parser.py
tests/test_parser.py
+18
-4
No files found.
.gitignore
View file @
140833ce
...
@@ -2,3 +2,4 @@
...
@@ -2,3 +2,4 @@
config_research.json
config_research.json
*.log
*.log
__pycache__
__pycache__
/venv/
README.md
View file @
140833ce
comsdk/graph.py
View file @
140833ce
...
@@ -92,6 +92,15 @@ class Graph:
...
@@ -92,6 +92,15 @@ class Graph:
self
.
term_state
.
is_term_state
=
True
self
.
term_state
.
is_term_state
=
True
self
.
_initialized
=
False
self
.
_initialized
=
False
def
__repr__
(
self
):
return
(
f
"Graph(
\n
"
f
" init_state={self.init_state!r},
\n
"
f
" term_state={self.term_state!r},
\n
"
f
" initialized={self._initialized}
\n
"
f
")"
)
def
run
(
self
,
data
):
def
run
(
self
,
data
):
'''
'''
Goes through the graph and returns boolean denoting whether the graph has finished successfully.
Goes through the graph and returns boolean denoting whether the graph has finished successfully.
...
@@ -114,6 +123,7 @@ class Graph:
...
@@ -114,6 +123,7 @@ class Graph:
return
False
return
False
# cur_state, implicit_parallelization_info = morph(data)
# cur_state, implicit_parallelization_info = morph(data)
cur_state
=
transfer_f
(
data
)
cur_state
=
transfer_f
(
data
)
print
(
cur_state
)
# print(morph)
# print(morph)
if
'__EXCEPTION__'
in
data
:
if
'__EXCEPTION__'
in
data
:
return
False
return
False
...
...
comsdk/misc.py
View file @
140833ce
import
shutil
from
functools
import
reduce
,
partial
from
functools
import
reduce
,
partial
import
os
import
os
import
re
import
re
...
@@ -163,7 +164,7 @@ def is_sequence(obj):
...
@@ -163,7 +164,7 @@ def is_sequence(obj):
'''
'''
Checks whether obj is a sequence (string does not count as a sequence)
Checks whether obj is a sequence (string does not count as a sequence)
'''
'''
return
isinstance
(
obj
,
collections
.
Sequence
)
and
(
not
hasattr
(
obj
,
'strip'
))
return
isinstance
(
obj
,
collections
.
abc
.
Sequence
)
and
(
not
hasattr
(
obj
,
'strip'
))
def
cp
(
from_
,
to_
):
def
cp
(
from_
,
to_
):
'''
'''
...
...
comsdk/parser.py
View file @
140833ce
...
@@ -7,26 +7,26 @@ from comsdk.edge import Edge
...
@@ -7,26 +7,26 @@ from comsdk.edge import Edge
class
Params
():
class
Params
():
__slots__
=
(
__slots__
=
(
'module'
,
'module'
,
'entry_func'
,
'predicate'
,
'selector'
,
'function'
,
'entry_func'
,
'morphism'
,
'parallelism'
,
'comment'
,
'order'
,
'subgraph'
,
'predicate'
,
'keys_mapping'
,
'executable_parameters'
,
'connection_data'
,
'selector'
,
'preprocessor'
,
'postprocessor'
,
'edge_index'
,
'config_section'
,
'function'
,
'morphism'
,
'parallelism'
,
'comment'
,
'order'
,
'subgraph'
)
)
def
__init__
(
self
):
def
__init__
(
self
):
for
slot
in
self
.
__slots__
:
for
slot
in
self
.
__slots__
:
setattr
(
self
,
slot
,
None
)
setattr
(
self
,
slot
,
None
)
self
.
comment
=
""
# Инициализируем как пустую строку вместо None
def
__str__
(
self
):
def
__str__
(
self
):
stri
=
""
stri
=
""
for
s
in
self
.
__slots__
:
for
s
in
self
.
__slots__
:
stri
+=
((
s
+
": {}, "
.
format
(
getattr
(
self
,
s
)))
if
getattr
(
self
,
s
)
is
not
None
else
""
)
attr
=
getattr
(
self
,
s
)
if
attr
is
not
None
and
s
!=
'comment'
:
# Комментарии выводим отдельно
stri
+=
f
"{s}: {attr}, "
if
self
.
comment
:
stri
+=
f
"comment: '{self.comment}'"
return
stri
return
stri
# entities = {}
# entities = {}
...
@@ -121,6 +121,7 @@ class GraphFactory():
...
@@ -121,6 +121,7 @@ class GraphFactory():
subgr
=
parsr
.
parse_file
(
self
.
entities
[
s
]
.
subgraph
)
subgr
=
parsr
.
parse_file
(
self
.
entities
[
s
]
.
subgraph
)
self
.
states
[
s
]
.
replace_with_graph
(
subgr
)
self
.
states
[
s
]
.
replace_with_graph
(
subgr
)
self
.
graph
=
Graph
(
self
.
graph
.
init_state
,
self
.
graph
.
term_state
)
self
.
graph
=
Graph
(
self
.
graph
.
init_state
,
self
.
graph
.
term_state
)
print
(
self
.
graph
)
return
self
.
graph
return
self
.
graph
...
@@ -190,34 +191,73 @@ class Parser():
...
@@ -190,34 +191,73 @@ class Parser():
setattr
(
res
[
i
],
sl
,
vals
[
sl
][
i
])
setattr
(
res
[
i
],
sl
,
vals
[
sl
][
i
])
return
res
return
res
#Props is line "[proFp=smth, ...]"
def
_param_from_props
(
self
,
props
):
def
_param_from_props
(
self
,
props
):
parm
=
Params
()
parm
=
Params
()
comment
=
""
comment
=
""
if
props
==
""
:
if
props
==
""
:
return
parm
return
parm
props
=
props
.
replace
(
"]"
,
''
)
props
=
props
.
replace
(
"]"
,
''
)
# Извлекаем комментарий, но не удаляем его полностью
if
'
\"
'
in
props
:
if
'
\"
'
in
props
:
m
=
[
m
for
m
in
re
.
finditer
(
r'\".*\"'
,
props
)][
0
]
matches
=
[
m
for
m
in
re
.
finditer
(
r'\"(.*?)\"'
,
props
)]
comment
=
props
[
m
.
span
()[
0
]
+
1
:
m
.
span
()[
1
]
-
1
]
if
matches
:
props
=
props
[:
m
.
span
()[
0
]]
+
props
[
m
.
span
()[
1
]:]
comment
=
matches
[
0
]
.
group
(
1
)
.
replace
(
"
\0
"
,
" "
)
# Заменяем комментарий на специальный маркер, чтобы не мешал дальнейшему парсингу
props
=
props
[:
matches
[
0
]
.
start
()]
+
"COMMENT_PLACEHOLDER"
+
props
[
matches
[
0
]
.
end
():]
if
'('
in
props
:
if
'('
in
props
:
mchs
=
[
m
for
m
in
re
.
finditer
(
r'\((\w+,)*\w+\)'
,
props
)]
mchs
=
[
m
for
m
in
re
.
finditer
(
r'\((\w+,)*\w+\)'
,
props
)]
for
m
in
mchs
:
for
m
in
mchs
:
props
=
props
[:
m
.
span
()[
0
]]
+
(
props
[
m
.
span
()[
0
]:
m
.
span
()[
1
]])
.
replace
(
','
,
'
\0
'
)
+
props
[
m
.
span
()[
1
]:]
props
=
props
[:
m
.
span
()[
0
]]
+
(
props
[
m
.
span
()[
0
]:
m
.
span
()[
1
]])
.
replace
(
','
,
'
\0
'
)
+
props
[
m
.
span
()[
1
]:]
props
=
props
.
replace
(
"("
,
""
)
props
=
props
.
replace
(
")"
,
""
)
props
=
props
.
replace
(
"("
,
""
)
rs
=
props
.
split
(
r","
)
#.split(r", ")
props
=
props
.
replace
(
")"
,
""
)
# Восстанавливаем комментарий после обработки скобок
props
=
props
.
replace
(
"COMMENT_PLACEHOLDER"
,
""
)
rs
=
props
.
split
(
r","
)
for
r
in
rs
:
for
r
in
rs
:
r
=
r
.
split
(
r"="
,
1
)
r
=
r
.
split
(
r"="
,
1
)
if
r
[
0
]
in
parm
.
__slots__
:
if
r
[
0
]
in
parm
.
__slots__
:
setattr
(
parm
,
r
[
0
],
r
[
1
])
setattr
(
parm
,
r
[
0
],
r
[
1
])
else
:
else
:
raise
Exception
(
"
\t
ERROR:Unknown parameter: "
+
r
[
0
])
raise
Exception
(
"
\t
ERROR:Unknown parameter: "
+
r
[
0
])
if
comment
!=
""
:
if
comment
!=
""
:
setattr
(
parm
,
"comment"
,
comment
.
replace
(
"
\0
"
,
" "
)
)
setattr
(
parm
,
"comment"
,
comment
)
return
parm
return
parm
#Props is line "[proFp=smth, ...]"
#def _param_from_props(self,props):
# parm = Params()
#comment = ""
#if props =="":
# return parm
#props = props.replace("]", '')
#if '\"' in props:
# удаляеться комментарий
# m = [m for m in re.finditer(r'\".*\"', props)][0]
# comment = props[m.span()[0]+1:m.span()[1]-1]
# props=props[:m.span()[0]]+props[m.span()[1]:]
#if '(' in props:
# mchs = [m for m in re.finditer(r'\((\w+,)*\w+\)', props)]
# for m in mchs:
# props=props[:m.span()[0]]+(props[m.span()[0]:m.span()[1]]).replace(',','\0')+props[m.span()[1]:]
#props = props.replace("(","")
#props = props.replace(")","")
#rs =props.split(r",") #.split(r", ")
#for r in rs:
# r=r.split(r"=", 1)
# if r[0] in parm.__slots__:
# setattr(parm, r[0], r[1])
# else:
# raise Exception("\tERROR:Unknown parameter: "+ r[0])
#if comment != "":
# setattr(parm, "comment", comment.replace("\0", " "))
#return parm
def
_param_from_entln
(
self
,
raw
):
def
_param_from_entln
(
self
,
raw
):
res
=
re
.
split
(
r"\["
,
raw
,
1
)
res
=
re
.
split
(
r"\["
,
raw
,
1
)
return
res
[
0
],
self
.
_param_from_props
(
res
[
1
])
return
res
[
0
],
self
.
_param_from_props
(
res
[
1
])
...
@@ -275,30 +315,49 @@ class Parser():
...
@@ -275,30 +315,49 @@ class Parser():
def
parse_file
(
self
,
filename
):
def
parse_file
(
self
,
filename
):
# @todo В случае, если на вход будет подан файл в отличной от UTF-8 кодировке программа работать не будет
# @todo В случае, если на вход будет подан файл в отличной от UTF-8 кодировке программа работать не будет
file
=
open
(
filename
,
encoding
=
'utf-8'
)
# "r")
with
open
(
filename
,
"r"
,
encoding
=
"utf-8"
)
as
file
:
dot
=
file
.
read
()
dot
=
file
.
read
()
# проверка на правильное количесво скобок
self
.
_check_brackets
(
dot
)
self
.
_check_brackets
(
dot
)
# @todo Возможно стоит заменить данный код на библиотеку Lark
# поиск всех подстрок в кавычках
comments
=
[
m
for
m
in
re
.
finditer
(
r'\".*\"'
,
dot
)]
comments
=
[
m
for
m
in
re
.
finditer
(
r'\".*\"'
,
dot
)]
for
m
in
comments
:
for
m
in
comments
:
# Заменяет пробелы внутри кавычек на специальный символ \0
dot
=
dot
[:
m
.
span
()[
0
]]
+
(
dot
[
m
.
span
()[
0
]:
m
.
span
()[
1
]])
.
replace
(
' '
,
'
\0
'
)
+
dot
[
m
.
span
()[
1
]:]
dot
=
dot
[:
m
.
span
()[
0
]]
+
(
dot
[
m
.
span
()[
0
]:
m
.
span
()[
1
]])
.
replace
(
' '
,
'
\0
'
)
+
dot
[
m
.
span
()[
1
]:]
# Удаляет все пробелы, табы(\t) и возвраты каретки(\r), кроме тех, что внутри кавычек(они заменены на \0)
dot
=
re
.
sub
(
r"[ \t\r]"
,
""
,
dot
)
#deleting all spaces
dot
=
re
.
sub
(
r"[ \t\r]"
,
""
,
dot
)
#deleting all spaces
# Удаляет ключевые слова digraph, а также фигурные скобки { и }
dot
=
re
.
sub
(
r"((digraph)|}|{)"
,
""
,
dot
)
dot
=
re
.
sub
(
r"((digraph)|}|{)"
,
""
,
dot
)
# Удаляет однострочные комментарии, начинающиеся с //
dot
=
re
.
sub
(
r"\/\/.*"
,
""
,
dot
)
dot
=
re
.
sub
(
r"\/\/.*"
,
""
,
dot
)
# Удаляет строки, содержащие только перенос строки (\n)
dot
=
re
.
sub
(
r"^\n$"
,
""
,
dot
)
dot
=
re
.
sub
(
r"^\n$"
,
""
,
dot
)
# @ todo заменить нижние две строки на dotlines = [line.strip() for line in dot.splitlines() if line.strip()]
# разбивает строку на список подстрок
dotlines
=
dot
.
splitlines
()
dotlines
=
dot
.
splitlines
()
# фильтрует пустые подстроки
dotlines
=
list
(
filter
(
None
,
dotlines
))
dotlines
=
list
(
filter
(
None
,
dotlines
))
# записали имя графа в класс GraphFactory
self
.
fact
.
name
=
dotlines
[
0
]
self
.
fact
.
name
=
dotlines
[
0
]
# Удалили из строки
dotlines
=
dotlines
[
1
:]
dotlines
=
dotlines
[
1
:]
# ent_re - regular expr for edges, states, functions properties
# ent_re - regular expr for edges, states, functions properties
# ищет строки вида ИМЯ[атрибуты]
print
(
dotlines
)
ent_re
=
re
.
compile
(
r"^\w+\[.*\]$"
)
ent_re
=
re
.
compile
(
r"^\w+\[.*\]$"
)
# top_re - regular expr for topology properties, most time consuming one
# top_re - regular expr for topology properties, most time consuming one
# Строки вида ИСТОЧНИК->ЦЕЛЬ[атрибуты] или ИСТОЧНИК=>ЦЕЛЬ[атрибуты]
top_re
=
re
.
compile
(
r"^(\w+,?)+(->|=>)(\w+,?)+(\[(\w+=(\(?\w+,?\)?)+,?)+\])?"
)
top_re
=
re
.
compile
(
r"^(\w+,?)+(->|=>)(\w+,?)+(\[(\w+=(\(?\w+,?\)?)+,?)+\])?"
)
# (r"^\w[\w\s,]*(->|=>)\s*\w[\w\s,=\[\]()]*$")
# (r"^\w[\w\s,]*(->|=>)\s*\w[\w\s,=\[\]()]*$")
for
i
,
ln
in
enumerate
(
dotlines
):
for
i
,
ln
in
enumerate
(
dotlines
):
# функция
if
ent_re
.
match
(
ln
):
if
ent_re
.
match
(
ln
):
name
,
parm
=
self
.
_param_from_entln
(
ln
)
name
,
parm
=
self
.
_param_from_entln
(
ln
)
print
(
f
'{parm}'
)
self
.
fact
.
entities
[
name
]
=
parm
self
.
fact
.
entities
[
name
]
=
parm
# топология
elif
top_re
.
match
(
ln
):
elif
top_re
.
match
(
ln
):
self
.
_topology
(
ln
)
self
.
_topology
(
ln
)
return
self
.
fact
.
build
(
Parser
.
subgr_count
)
return
self
.
fact
.
build
(
Parser
.
subgr_count
)
...
@@ -306,6 +365,7 @@ class Parser():
...
@@ -306,6 +365,7 @@ class Parser():
checked
=
[]
checked
=
[]
bushes
=
{}
bushes
=
{}
selectorends
=
{}
selectorends
=
{}
def
generate_cpp
(
self
,
filename
=
None
):
def
generate_cpp
(
self
,
filename
=
None
):
self
.
fact
.
graph
.
init_state
.
input_edges_number
=
0
self
.
fact
.
graph
.
init_state
.
input_edges_number
=
0
states_to_check
=
[
self
.
fact
.
graph
.
init_state
]
states_to_check
=
[
self
.
fact
.
graph
.
init_state
]
...
...
test_funcs/simplest.py
View file @
140833ce
def
dummy_edge
(
data
):
def
dummy_edge
(
data
):
"""Пустое ребро, не изменяет данные"""
pass
pass
def
increment_a_edge
(
data
):
def
increment_a_edge
(
data
):
data
[
'a'
]
+=
1
data
[
'a'
]
+=
1
def
increment_a_double
(
data
):
data
[
'a'
]
*=
2
def
increment_a_array_edge
(
data
):
def
increment_a_array_edge
(
data
):
for
i
in
range
(
len
(
data
[
'a'
])):
for
i
in
range
(
len
(
data
[
'a'
])):
data
[
'a'
][
i
]
+=
1
data
[
'a'
][
i
]
+=
1
...
@@ -15,6 +19,7 @@ def decrement_a_edge(data):
...
@@ -15,6 +19,7 @@ def decrement_a_edge(data):
data
[
'a'
]
-=
1
data
[
'a'
]
-=
1
def
nonzero_predicate
(
data
):
def
nonzero_predicate
(
data
):
"""Предикат: возвращает True если 'a' не равно 0"""
return
data
[
'a'
]
!=
0
return
data
[
'a'
]
!=
0
def
positiveness_predicate
(
data
):
def
positiveness_predicate
(
data
):
...
@@ -30,5 +35,64 @@ def selector_a_nonpositive(data):
...
@@ -30,5 +35,64 @@ def selector_a_nonpositive(data):
res
=
data
[
'a'
]
<=
0
res
=
data
[
'a'
]
<=
0
return
[
res
,
not
res
]
return
[
res
,
not
res
]
def
selector_a_positive
(
data
):
res
=
data
[
'a'
]
>
0
print
(
f
"Selector check: a={data['a']}, continue={res}"
)
return
[
res
,
not
res
]
def
true_predicate
(
data
):
def
true_predicate
(
data
):
return
True
return
True
def
process_a
(
data
):
"""Обработка ветки A: умножает a на 2"""
if
'a'
not
in
data
:
data
[
'a'
]
=
0
# Инициализация по умолчанию
data
[
'a'
]
*=
2
data
[
'processed_by'
]
=
'A'
def
process_b
(
data
):
"""Обработка ветки B: устанавливает b в 10 (вместо добавления)"""
data
[
'b'
]
+=
10
data
[
'processed_by'
]
=
'B'
def
check_condition
(
data
):
"""Предикат для выбора ветки (True - ветка A, False - ветка B)"""
return
data
.
get
(
'value'
,
0
)
%
2
==
0
# Безопасное получение value
def
branch_selector
(
data
):
"""Селектор ветвления на основе check_condition"""
condition
=
check_condition
(
data
)
return
[
condition
,
not
condition
]
def
init_data
(
data
):
data
[
'initialized'
]
=
True
data
[
'processed'
]
=
False
data
[
'value'
]
=
data
.
get
(
'input'
,
0
)
def
validate_data
(
data
):
if
'value'
not
in
data
:
raise
ValueError
(
"Data not initialized"
)
data
[
'valid'
]
=
True
def
process_data
(
data
):
if
not
data
.
get
(
'valid'
,
False
):
raise
ValueError
(
"Invalid data"
)
data
[
'processed'
]
=
True
data
[
'value'
]
*=
2
def
save_result
(
data
):
data
[
'saved'
]
=
True
data
[
'result'
]
=
data
[
'value'
]
def
cleanup
(
data
):
data
[
'clean'
]
=
True
def
branch_selector
(
data
):
"""Селектор ветвления для теста атрибутов"""
return
[
True
,
False
]
class
ThreadParallelizationPolicy
:
"""Тестовая политика параллелизма"""
pass
tests/adot/branching.adot
View file @
140833ce
digraph SIMPLEST {
digraph SIMPLEST {
FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge]
FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge
, comment="name FUNC_A"
]
FUNCB [module=test_funcs.simplest, entry_func=increment_b_edge]
FUNCB [module=test_funcs.simplest, entry_func=increment_b_edge
, comment="name FUNC_B"
]
PRED [module=test_funcs.simplest, entry_func=true_predicate]
PRED [module=test_funcs.simplest, entry_func=true_predicate
, comment="name PRED"
]
INCR_A [predicate=PRED, function=FUNCA]
INCR_A [predicate=PRED, function=FUNCA
, comment="name INCR_A"
]
INCR_B [predicate=PRED, function=FUNCB]
INCR_B [predicate=PRED, function=FUNCB
, comment="name INCR_B"
]
__BEGIN__ -> ROOT
__BEGIN__ -> ROOT
ROOT -> BR1, BR2 [morphism=(INCR_A, INCR_B)]
ROOT -> BR1, BR2 [morphism=(INCR_A, INCR_B)]
...
...
tests/adot/complex.adot
View file @
140833ce
...
@@ -4,9 +4,9 @@ digraph SIMPLEST {
...
@@ -4,9 +4,9 @@ digraph SIMPLEST {
INCR_A [predicate=PRED, function=FUNCA]
INCR_A [predicate=PRED, function=FUNCA]
ST1 [subgraph=
tests
/adot/trivial.adot]
ST1 [subgraph=
.
/adot/trivial.adot]
ST2 [subgraph=
tests
/adot/cycled.adot]
ST2 [subgraph=
.
/adot/cycled.adot]
ST3 [subgraph=
tests
/adot/branching.adot]
ST3 [subgraph=
.
/adot/branching.adot]
__BEGIN__ -> ST1
__BEGIN__ -> ST1
ST1 -> ST2 [morphism=INCR_A]
ST1 -> ST2 [morphism=INCR_A]
...
...
tests/adot/cycled_v2.adot
0 → 100644
View file @
140833ce
digraph CYCLIC {
// Селектор для узла LOOP
SEL_LOOP [module="selectors", entry_func="check_iterations"]
// Объявление функций
FUNC [module=test_funcs.simplest, entry_func=decrement_a_edge]
PRED [module=test_funcs.simplest, entry_func=true_predicate]
MORPH_LOOP [predicate=PRED, function=FUNC]
MORPH_EXIT [function=INC]
LOOP [selector=SEL_LOOP] # Привязка селектора к узлу
// Топология
__BEGIN__ -> LOOP [edge_index=0]
LOOP -> LOOP [morphism=MORPH_LOOP, edge_index=1]
LOOP -> __END__ [morphism=MORPH_EXIT, edge_index=2]
}
\ No newline at end of file
tests/adot/trivial_v2.adot
0 → 100644
View file @
140833ce
digraph TRIVIAL {
// Объявление функций
FUNC [module=test_funcs.simplest, entry_func=increment_a_edge]
PRED [module=test_funcs.simplest, entry_func="always_true"]
MORPH [predicate=PRED, function=FUNC, comment="Basic increment"]
// Топология
__BEGIN__ -> STEP1 [morphism=MORPH, edge_index=0]
STEP1 -> STEP2 [morphism=MORPH, edge_index=1]
STEP2 -> __END__ [morphism=MORPH, edge_index=2]
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/attributes.adot
0 → 100644
View file @
140833ce
digraph ATTRIBUTES_TEST {
// Тестовые функции
FUNC1 [module=test_funcs.simplest, entry_func=increment_a_edge, comment="Функция инкремента A"]
FUNC2 [module=test_funcs.simplest, entry_func=increment_b_edge, comment="Функция инкремента B"]
PRED [module=test_funcs.simplest, entry_func=nonzero_predicate, comment="Предикат проверки ненулевого значения"]
SEL [module=test_funcs.simplest, entry_func=branch_selector, comment="Селектор ветвления"]
// Узлы с атрибутами
NODE1 [selector=SEL, parallelism=threading]
NODE2 [subgraph=./test_adot_files/preprocess.adot]
// Ребра с атрибутами
EDGE1 [predicate=PRED, function=FUNC1, comment="Первое ребро с полным набором атрибутов"]
EDGE2 [function=FUNC1, comment="Второе ребро с множественными морфизмами"]
// Структура графа
__BEGIN__ -> NODE1 [morphism=EDGE1]
NODE1 -> NODE2 [morphism=EDGE2]
NODE2 -> __END__
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/branching.adot
0 → 100644
View file @
140833ce
digraph BRANCHING_TEST {
/ Функции
PROCESS_A [module=test_funcs.simplest, entry_func=process_a]
PROCESS_B [module=test_funcs.simplest, entry_func=process_b]
// Морфизмы
EDGE_A [function=PROCESS_A]
EDGE_B [function=PROCESS_B]
// Граф
__BEGIN__ -> DECISION_POINT
DECISION_POINT -> BRANCH_A [morphism=EDGE_A]
DECISION_POINT -> BRANCH_B [morphism=EDGE_B]
BRANCH_A -> MERGE_POINT
BRANCH_B -> MERGE_POINT
MERGE_POINT -> __END__
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/cycled.adot
0 → 100644
View file @
140833ce
digraph CYCLED {
// Определение функций
DECREMENT_A [module=test_funcs.simplest, entry_func=decrement_a_edge]
NONZERO_PRED [module=test_funcs.simplest, entry_func=positiveness_predicate]
NONPOS_SELECTOR [module=test_funcs.simplest, entry_func=selector_a_positive]
DUMMY_FUNC [module=test_funcs.simplest, entry_func=dummy_edge]
// Определение морфизмов
DECREMENT_EDGE [predicate=NONZERO_PRED, function=DECREMENT_A, comment="Уменьшает a на 1 пока a != 0"]
EXIT_EDGE [function=DUMMY_FUNC, comment="Выход из цикла"]
// Определение узлов
ST1 [comment="Начальное состояние цикла"]
ST2 [selector=NONPOS_SELECTOR, comment="Узел с селектором"]
// Определение графа
__BEGIN__ -> ST1 [comment="Начало выполнения"]
ST1 -> ST2 [morphism=DECREMENT_EDGE, comment="Переход с уменьшением a"]
ST2 -> ST1 [order=1, comment="Продолжение цикла если a > 0"]
ST2 -> __END__ [order=2, morphism=EXIT_EDGE, comment="Выход если a <= 0"]
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/edge_types.adot
0 → 100644
View file @
140833ce
digraph EDGE_TYPES_TEST {
// Определение функций
FUNC_A [module=test_funcs.simplest, entry_func=increment_a_edge]
FUNC_B [module=test_funcs.simplest, entry_func=increment_b_edge]
TRUE_PRED [module=test_funcs.simplest, entry_func=true_predicate]
// Определение разных типов ребер
EDGE_SIMPLE [predicate=TRUE_PRED, function=FUNC_A, comment="Обычное ребро (->)"]
EDGE_PARALLEL [predicate=TRUE_PRED, function=FUNC_B, comment="Параллельное ребро (=>)"]
// Определение узлов
__BEGIN__ -> NODE_START
NODE_START -> NODE_MIDDLE [morphism=EDGE_SIMPLE, order=0]
NODE_START => NODE_MIDDLE [morphism=EDGE_PARALLEL, order=1]
NODE_MIDDLE -> __END__
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/main_graph.adot
0 → 100644
View file @
140833ce
digraph MAIN_GRAPH {
// Функции
MAIN_PROCESS [module=test_funcs.simplest, entry_func=process_data]
/ Функции-предикаты
ALWAYS_TRUE [module=test_funcs.simplest, entry_func=true_predicate, comment = pred_ALWAYS_TRUE]
// Морфизмы
EDGE_MAIN [predicate=ALWAYS_TRUE, function=MAIN_PROCESS, comment = edge_1]
// Главный граф
PREPROCESS [subgraph=./test_adot_files/preprocess.adot]
POSTPROCESS [subgraph=./test_adot_files/postprocess.adot]
__BEGIN__ -> PREPROCESS
PREPROCESS -> MAIN_PROCESS [morphism=EDGE_MAIN]
MAIN_PROCESS -> POSTPROCESS
POSTPROCESS -> __END__
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/postprocess.adot
0 → 100644
View file @
140833ce
digraph POSTPROCESS {
// Функции постобработки
SAVE_RESULT [module=test_funcs.simplest, entry_func=save_result]
CLEANUP [module=test_funcs.simplest, entry_func=cleanup]
/ Функции-предикаты
ALWAYS_TRUE [module=test_funcs.simplest, entry_func=true_predicate, comment = pred_ALWAYS_TRUE_postprocess]
// Морфизмы
EDGE_1 [predicate=ALWAYS_TRUE, function=SAVE_RESULT, comment = edge_1_postprocess]
EDGE_2 [predicate=ALWAYS_TRUE, function=CLEANUP, comment = edge_2_postprocess]
__BEGIN__ -> SAVE
SAVE -> FINAL [morphism=EDGE_1]
FINAL -> __END__ [morphism=EDGE_2]
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/preprocess.adot
0 → 100644
View file @
140833ce
digraph PREPROCESS {
// Функции предобработки
INIT_DATA [module=test_funcs.simplest, entry_func=init_data, comment=""]
VALIDATE [module=test_funcs.simplest, entry_func=validate_data]
/ Функции-предикаты
ALWAYS_TRUE [module=test_funcs.simplest, entry_func=true_predicate, comment = pred_ALWAYS_TRUE]
// Морфизмы
EDGE_1 [predicate=ALWAYS_TRUE, function=INIT_DATA, comment = edge_1]
EDGE_2 [predicate=ALWAYS_TRUE, function=VALIDATE, comment = edge_2]
__BEGIN__ -> INIT
INIT -> VALIDATE [morphism=EDGE_1]
VALIDATE -> __END__ [morphism=EDGE_2]
}
\ No newline at end of file
tests/test_aDOT/test_adot_files/sequential.adot
0 → 100644
View file @
140833ce
digraph SEQUENTIAL_TEST {
// Функции-обработчики
INCREMENT [module=test_funcs.simplest, entry_func=increment_a_edge, comment = func_INCREMENT]
DOUBLE [module=test_funcs.simplest, entry_func=increment_a_double, comment = func_DOUBLE]
// Функции-предикаты
ALWAYS_TRUE [module=test_funcs.simplest, entry_func=true_predicate, comment = pred_ALWAYS_TRUE]
// Морфизмы
EDGE_1 [predicate=ALWAYS_TRUE, function=INCREMENT, comment = edge_1]
EDGE_2 [predicate=ALWAYS_TRUE, function=DOUBLE, comment = edge_2]
// Граф
__BEGIN__ -> STEP_1 [morphism=EDGE_1]
STEP_1 -> STEP_2 [morphism=EDGE_2]
STEP_2 -> __END__
}
\ No newline at end of file
tests/test_aDOT/unit_test_aDOT.py
0 → 100644
View file @
140833ce
import
unittest
import
os
from
comsdk.parser
import
Parser
from
comsdk.graph
import
Graph
class
TestADOTParser
(
unittest
.
TestCase
):
@classmethod
def
setUpClass
(
cls
):
cls
.
test_files_dir
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
"test_adot_files"
)
def
setUp
(
self
):
self
.
parser
=
Parser
()
def
test_sequential_graph
(
self
):
"""Тест последовательного графа"""
graph
=
self
.
parser
.
parse_file
(
os
.
path
.
join
(
self
.
test_files_dir
,
"sequential.adot"
))
self
.
assertIsInstance
(
graph
,
Graph
)
# Проверка структуры
init_state
=
graph
.
init_state
self
.
assertEqual
(
len
(
init_state
.
transfers
),
1
)
# Проверка выполнения
data
=
{
"a"
:
1
}
result
=
graph
.
run
(
data
)
self
.
assertTrue
(
result
)
self
.
assertEqual
(
data
[
"a"
],
4
)
# 1 -> (inc) 2 -> (double) 4
def
test_cycled_graph
(
self
):
"""Тест циклического графа с уменьшением a до 0"""
graph
=
self
.
parser
.
parse_file
(
os
.
path
.
join
(
self
.
test_files_dir
,
"cycled.adot"
))
self
.
assertIsInstance
(
graph
,
Graph
)
# Проверка выполнения
data
=
{
"a"
:
5
}
# Начинаем с 5
result
=
graph
.
run
(
data
)
self
.
assertTrue
(
result
)
self
.
assertEqual
(
data
[
"a"
],
0
,
"Граф должен уменьшать a до 0"
)
# Дополнительная проверка с другим начальным значением
data
=
{
"a"
:
10
}
result
=
graph
.
run
(
data
)
self
.
assertTrue
(
result
)
self
.
assertEqual
(
data
[
"a"
],
0
)
def
test_branching_graph
(
self
):
"""Тест графа с ветвлениями"""
graph
=
self
.
parser
.
parse_file
(
os
.
path
.
join
(
self
.
test_files_dir
,
"branching.adot"
))
self
.
assertIsInstance
(
graph
,
Graph
)
data
=
{
"a"
:
5
,
"b"
:
5
}
result
=
graph
.
run
(
data
)
self
.
assertTrue
(
result
)
self
.
assertEqual
(
data
[
"a"
],
10
)
# 5 * 2 = 10
self
.
assertEqual
(
data
[
"b"
],
15
)
data
=
{
"a"
:
1
,
"b"
:
3
}
result
=
graph
.
run
(
data
)
self
.
assertTrue
(
result
)
self
.
assertEqual
(
data
[
"b"
],
13
)
self
.
assertEqual
(
data
[
"a"
],
2
)
def
test_subgraph_integration
(
self
):
"""Тест интеграции подграфов"""
graph
=
self
.
parser
.
parse_file
(
os
.
path
.
join
(
self
.
test_files_dir
,
"main_graph.adot"
))
self
.
assertIsInstance
(
graph
,
Graph
)
data
=
{
'input'
:
5
}
result
=
graph
.
run
(
data
)
print
(
data
)
self
.
assertTrue
(
result
)
self
.
assertEqual
(
data
[
'value'
],
10
)
# 5 * 2 = 10
self
.
assertTrue
(
data
[
'initialized'
])
self
.
assertTrue
(
data
[
'valid'
])
self
.
assertTrue
(
data
[
'processed'
])
self
.
assertTrue
(
data
[
'saved'
])
self
.
assertTrue
(
data
[
'clean'
])
self
.
assertEqual
(
data
[
'result'
],
10
)
def
test_edge_types
(
self
):
"""Тест разных типов ребер (-> и =>)"""
graph
=
self
.
parser
.
parse_file
(
os
.
path
.
join
(
self
.
test_files_dir
,
"edge_types.adot"
))
self
.
assertIsInstance
(
graph
,
Graph
)
# Проверка структуры графа
start_node
=
graph
.
init_state
.
transfers
[
0
]
.
output_state
self
.
assertEqual
(
len
(
start_node
.
transfers
),
2
,
"Должно быть 2 исходящих ребра"
)
# Проверка типов ребер
edge_simple
=
start_node
.
transfers
[
0
]
.
edge
edge_parallel
=
start_node
.
transfers
[
1
]
.
edge
self
.
assertEqual
(
edge_simple
.
order
,
0
,
"Обычное ребро должно иметь order=0"
)
self
.
assertEqual
(
edge_parallel
.
order
,
1
,
"Параллельное ребро должно иметь order=1"
)
def
test_attributes_parsing
(
self
):
"""Проверка парсинга атрибутов узлов и ребер"""
graph
=
self
.
parser
.
parse_file
(
os
.
path
.
join
(
self
.
test_files_dir
,
"attributes.adot"
))
# Проверка атрибутов состояния NODE1
node1
=
graph
.
init_state
.
transfers
[
0
]
.
output_state
self
.
assertEqual
(
node1
.
selector
.
name
,
"branch_selector"
)
#self.assertEqual(node1.parallelization_policy.__class__.__name__, "ThreadParallelizationPolicy")
#self.assertEqual(node1.comment, "Первый узел с атрибутами")
# Проверка атрибутов состояния NODE2
node2
=
node1
.
transfers
[
0
]
.
output_state
#self.assertEqual(node2.comment, "Второй узел с подграфом")
self
.
assertTrue
(
hasattr
(
node2
,
'_proxy_state'
),
"Должен содержать подграф"
)
# Проверка атрибутов ребра EDGE1
edge1
=
graph
.
init_state
.
transfers
[
0
]
.
edge
self
.
assertEqual
(
edge1
.
pred_f
.
name
,
"nonzero_predicate"
)
self
.
assertEqual
(
edge1
.
morph_f
.
name
,
"increment_a_edge"
)
self
.
assertEqual
(
edge1
.
comment
,
"Первое ребро с полным набором атрибутов"
)
#self.assertEqual(edge1.order, 1) # Проверка edge_index
# Проверка атрибутов ребра EDGE2
edge2
=
node1
.
transfers
[
0
]
.
edge
#self.assertEqual(len(edge2.morph_fs), 2) # Проверка morphisms
#self.assertEqual(edge2.morph_fs[0].name, "increment_a_edge")
#self.assertEqual(edge2.morph_fs[1].name, "increment_b_edge")
# Проверка загрузки подграфа
subgraph
=
node2
.
_proxy_state
#self.assertIsInstance(subgraph, Graph)
#self.assertEqual(subgraph.init_state.name, "__BEGIN__")
class
TestGraphExecution
(
unittest
.
TestCase
):
def
test_parallel_execution
(
self
):
"""Тест параллельного выполнения"""
# Здесь будут тесты реального параллельного выполнения
# с использованием threading/multiprocessing
pass
if
__name__
==
'__main__'
:
unittest
.
main
()
\ No newline at end of file
tests/test_adot_files/node_attrs.adot
0 → 100644
View file @
140833ce
digraph Test {
__BEGIN__ -> NODE_1
NODE_1 [
selector=MY_SELECTOR,
subgraph="subgraph.adot",
parallelism=threading,
comment="Test node with attributes"
]
NODE_1 -> __END__
}
\ No newline at end of file
tests/test_parser.py
View file @
140833ce
import
gc
import
unittest
import
unittest
import
subprocess
import
subprocess
...
@@ -7,18 +8,31 @@ from comsdk.parser import Parser
...
@@ -7,18 +8,31 @@ from comsdk.parser import Parser
path_to_comsdk
=
"/home/lbstr/bmstu/comsdk"
path_to_comsdk
=
"/home/lbstr/bmstu/comsdk"
path_to_pycomsdk
=
"/home/lbstr/bmstu/pycomsdk"
path_to_pycomsdk
=
"/home/lbstr/bmstu/pycomsdk"
class
ParserGoodCheck
(
unittest
.
TestCase
):
class
ParserGoodCheck
(
unittest
.
TestCase
):
def
test_trivial_graph
(
self
):
def
test_trivial_graph
(
self
):
parsr
=
Parser
()
parsr
=
Parser
()
gr
=
parsr
.
parse_file
(
"./tests/adot/trivial.adot"
)
# Проверка загрузки файла
self
.
assertTrue
(
os
.
path
.
exists
(
"./adot/trivial_v2.adot"
))
gr
=
parsr
.
parse_file
(
"./adot/trivial_v2.adot"
)
print
(
gr
)
# Основной сценарий
data
=
{
"a"
:
1
}
data
=
{
"a"
:
1
}
gr
.
run
(
data
)
gr
.
run
(
data
)
self
.
assertEqual
(
data
[
"a"
],
4
)
self
.
assertEqual
(
data
[
"a"
],
4
)
# Проверка повторного использования
data
=
{
"a"
:
4
}
gr
.
run
(
data
)
self
.
assertEqual
(
data
[
"a"
],
7
)
def
test_branching_graph
(
self
):
def
test_branching_graph
(
self
):
parsr
=
Parser
()
parsr
=
Parser
()
gr
=
parsr
.
parse_file
(
"./
tests/
adot/branching.adot"
)
gr
=
parsr
.
parse_file
(
"./adot/branching.adot"
)
data
=
{
"a"
:
1
,
"b"
:
1
}
data
=
{
"a"
:
1
,
"b"
:
1
}
gr
.
run
(
data
)
gr
.
run
(
data
)
self
.
assertEqual
(
data
[
"a"
],
4
)
self
.
assertEqual
(
data
[
"a"
],
4
)
...
@@ -26,14 +40,14 @@ class ParserGoodCheck(unittest.TestCase):
...
@@ -26,14 +40,14 @@ class ParserGoodCheck(unittest.TestCase):
def
test_cycled_graph
(
self
):
def
test_cycled_graph
(
self
):
parsr
=
Parser
()
parsr
=
Parser
()
gr
=
parsr
.
parse_file
(
"./
tests/
adot/cycled.adot"
)
gr
=
parsr
.
parse_file
(
"./adot/cycled.adot"
)
data
=
{
"a"
:
10
}
data
=
{
"a"
:
10
}
gr
.
run
(
data
)
gr
.
run
(
data
)
self
.
assertEqual
(
data
[
"a"
],
0
)
self
.
assertEqual
(
data
[
"a"
],
0
)
def
test_complex_graph
(
self
):
def
test_complex_graph
(
self
):
parsr
=
Parser
()
parsr
=
Parser
()
gr
=
parsr
.
parse_file
(
"./
tests/
adot/complex.adot"
)
gr
=
parsr
.
parse_file
(
"./adot/complex.adot"
)
data
=
{
"a"
:
1
,
"b"
:
1
}
data
=
{
"a"
:
1
,
"b"
:
1
}
gr
.
run
(
data
)
gr
.
run
(
data
)
self
.
assertEqual
(
data
[
"a"
],
4
)
self
.
assertEqual
(
data
[
"a"
],
4
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment