Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
SimStadt
simstadtpy
Commits
ace2fe1b
Commit
ace2fe1b
authored
Mar 13, 2026
by
Eric Duminil
Browse files
Create proj folder if needed
parent
36d8921a
Changes
1
Show whitespace changes
Inline
Side-by-side
src/simstadt/runner.py
View file @
ace2fe1b
...
@@ -36,6 +36,7 @@ log = logging.getLogger(__name__)
...
@@ -36,6 +36,7 @@ log = logging.getLogger(__name__)
# SimStadt discovery
# SimStadt discovery
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
def
find_simstadt
(
parent_folder
:
Path
,
simstadt_glob
:
str
=
SIMSTADT2_GLOB
)
->
Path
:
def
find_simstadt
(
parent_folder
:
Path
,
simstadt_glob
:
str
=
SIMSTADT2_GLOB
)
->
Path
:
try
:
try
:
found
=
next
(
parent_folder
.
glob
(
simstadt_glob
))
found
=
next
(
parent_folder
.
glob
(
simstadt_glob
))
...
@@ -71,12 +72,17 @@ def get_template_path() -> Path:
...
@@ -71,12 +72,17 @@ def get_template_path() -> Path:
# Low-level workflow helpers
# Low-level workflow helpers
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
def
_simstadt_script
()
->
str
:
def
_simstadt_script
()
->
str
:
return
"SimStadt.bat"
if
platform
.
system
().
lower
()
==
"windows"
else
"./SimStadt.sh"
return
"SimStadt.bat"
if
platform
.
system
().
lower
()
==
"windows"
else
"./SimStadt.sh"
def
_regionchooser_script
()
->
str
:
def
_regionchooser_script
()
->
str
:
return
"RegionChooser.bat"
if
platform
.
system
().
lower
()
==
"windows"
else
"./RegionChooser.sh"
return
(
"RegionChooser.bat"
if
platform
.
system
().
lower
()
==
"windows"
else
"./RegionChooser.sh"
)
def
check_paths
(
repo_path
:
Path
,
workflow_path
:
Path
)
->
None
:
def
check_paths
(
repo_path
:
Path
,
workflow_path
:
Path
)
->
None
:
...
@@ -104,7 +110,9 @@ def prepare_workflow(workflow_path: Path, citygmls: list[str]) -> str:
...
@@ -104,7 +110,9 @@ def prepare_workflow(workflow_path: Path, citygmls: list[str]) -> str:
for
child
in
list
(
citygml_node
):
for
child
in
list
(
citygml_node
):
citygml_node
.
remove
(
child
)
citygml_node
.
remove
(
child
)
else
:
else
:
workflow_node
=
root
.
find
(
".//object[@class='eu.simstadt.workflows.CityGmlWorkflow']"
)
workflow_node
=
root
.
find
(
".//object[@class='eu.simstadt.workflows.CityGmlWorkflow']"
)
if
workflow_node
is
None
:
if
workflow_node
is
None
:
raise
ValueError
(
"Broken workflow!"
)
raise
ValueError
(
"Broken workflow!"
)
citygml_node
=
et
.
SubElement
(
workflow_node
,
"void"
)
citygml_node
=
et
.
SubElement
(
workflow_node
,
"void"
)
...
@@ -155,7 +163,11 @@ def copy_workflow_from_template(
...
@@ -155,7 +163,11 @@ def copy_workflow_from_template(
def
_get_all_files
(
folder
:
Path
)
->
dict
[
Path
,
float
]:
def
_get_all_files
(
folder
:
Path
)
->
dict
[
Path
,
float
]:
return
{
f
:
f
.
stat
().
st_mtime
for
f
in
folder
.
glob
(
"**/*"
)
if
f
.
is_file
()
and
f
.
name
!=
PARAMS
}
return
{
f
:
f
.
stat
().
st_mtime
for
f
in
folder
.
glob
(
"**/*"
)
if
f
.
is_file
()
and
f
.
name
!=
PARAMS
}
def
_compare_written_files
(
repo_path
:
Path
,
before
:
dict
,
after
:
dict
)
->
list
[
Path
]:
def
_compare_written_files
(
repo_path
:
Path
,
before
:
dict
,
after
:
dict
)
->
list
[
Path
]:
...
@@ -173,13 +185,16 @@ def _compare_written_files(repo_path: Path, before: dict, after: dict) -> list[P
...
@@ -173,13 +185,16 @@ def _compare_written_files(repo_path: Path, before: dict, after: dict) -> list[P
# Public execution API
# Public execution API
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
def
get_simstadt_output
(
path
:
Path
)
->
str
:
def
get_simstadt_output
(
path
:
Path
)
->
str
:
"""Run SimStadt with the given path and return stdout regardless of exit code.
"""Run SimStadt with the given path and return stdout regardless of exit code.
Useful for extracting version information from the startup banner.
Useful for extracting version information from the startup banner.
"""
"""
with
chdir
(
get_simstadt_folder
()):
with
chdir
(
get_simstadt_folder
()):
result
=
subprocess
.
run
([
_simstadt_script
(),
str
(
path
)],
text
=
True
,
capture_output
=
True
,
check
=
False
)
result
=
subprocess
.
run
(
[
_simstadt_script
(),
str
(
path
)],
text
=
True
,
capture_output
=
True
,
check
=
False
)
return
result
.
stdout
return
result
.
stdout
...
@@ -188,7 +203,10 @@ def run_simstadt(workflow_path: Path, name: str) -> str:
...
@@ -188,7 +203,10 @@ def run_simstadt(workflow_path: Path, name: str) -> str:
with
chdir
(
get_simstadt_folder
()):
with
chdir
(
get_simstadt_folder
()):
log
.
info
(
"Launching %s:"
,
name
)
log
.
info
(
"Launching %s:"
,
name
)
result
=
subprocess
.
run
(
result
=
subprocess
.
run
(
[
_simstadt_script
(),
str
(
workflow_path
)],
text
=
True
,
capture_output
=
True
,
check
=
False
[
_simstadt_script
(),
str
(
workflow_path
)],
text
=
True
,
capture_output
=
True
,
check
=
False
,
)
)
if
result
.
returncode
!=
0
:
if
result
.
returncode
!=
0
:
log
.
warning
(
" Workflow failed!
\n
%s"
,
result
.
stdout
)
log
.
warning
(
" Workflow failed!
\n
%s"
,
result
.
stdout
)
...
@@ -197,13 +215,18 @@ def run_simstadt(workflow_path: Path, name: str) -> str:
...
@@ -197,13 +215,18 @@ def run_simstadt(workflow_path: Path, name: str) -> str:
log
.
info
(
" Workflow finished successfully!
\n
"
)
log
.
info
(
" Workflow finished successfully!
\n
"
)
return
result
.
stdout
return
result
.
stdout
#TODO: Add get_hull
# TODO: Add get_hull
def
run_regionchooser
(
*
params
:
str
)
->
str
:
def
run_regionchooser
(
*
params
:
str
)
->
str
:
"""Invoke the SimStadt RegionChooser CLI. Returns stdout."""
"""Invoke the SimStadt RegionChooser CLI. Returns stdout."""
with
chdir
(
get_simstadt_folder
()):
with
chdir
(
get_simstadt_folder
()):
result
=
subprocess
.
run
(
result
=
subprocess
.
run
(
[
_regionchooser_script
(),
*
params
],
text
=
True
,
capture_output
=
True
,
check
=
True
[
_regionchooser_script
(),
*
params
],
text
=
True
,
capture_output
=
True
,
check
=
True
,
)
)
log
.
debug
(
result
.
stdout
)
log
.
debug
(
result
.
stdout
)
return
result
.
stdout
return
result
.
stdout
...
@@ -236,6 +259,7 @@ def _resolve_project(citygml_path: Path, project_path: Path | None) -> tuple[Pat
...
@@ -236,6 +259,7 @@ def _resolve_project(citygml_path: Path, project_path: Path | None) -> tuple[Pat
return
citygml_path
.
parent
,
citygml_path
.
name
return
citygml_path
.
parent
,
citygml_path
.
name
if
project_path
is
not
None
:
if
project_path
is
not
None
:
project_path
.
mkdir
(
exist_ok
=
True
,
parents
=
True
)
dest
=
project_path
/
citygml_path
.
name
dest
=
project_path
/
citygml_path
.
name
if
not
dest
.
exists
():
if
not
dest
.
exists
():
shutil
.
copy
(
citygml_path
,
dest
)
shutil
.
copy
(
citygml_path
,
dest
)
...
@@ -283,8 +307,12 @@ def run_workflow_with_citygml(
...
@@ -283,8 +307,12 @@ def run_workflow_with_citygml(
if
destination
is
None
:
if
destination
is
None
:
destination
=
random_id
()
+
"_"
+
template_name
.
rsplit
(
"_"
,
1
)[
-
1
]
destination
=
random_id
()
+
"_"
+
template_name
.
rsplit
(
"_"
,
1
)[
-
1
]
resolved_project_path
,
citygml_filename
=
_resolve_project
(
citygml_path
,
project_path
)
resolved_project_path
,
citygml_filename
=
_resolve_project
(
workflow_path
=
copy_workflow_from_template
(
template_path
,
resolved_project_path
,
destination
,
replaces
)
citygml_path
,
project_path
)
workflow_path
=
copy_workflow_from_template
(
template_path
,
resolved_project_path
,
destination
,
replaces
)
output_files
=
run_workflow
(
workflow_path
,
[
citygml_filename
])
output_files
=
run_workflow
(
workflow_path
,
[
citygml_filename
])
if
description
is
None
:
if
description
is
None
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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