"""
actions when sub init in cli, including mkdir, touch files and render templates in templates fold
"""
import os
import sys
import json
import shutil
## note conf here is not from config.json, since there is no such file at the phase
## the source of the conf here should be interactive cli or specify json file from sub init -f config.json
[docs]def env_init(path, conf=None, fromfile=None, include_main=True):
"""
initialize a subway project including:
mkdir .subway, and inputs/outputs check inputs/outputs dirs if possible
create config.json and empty history.json within .subway
render an example main.py
:param path: str. absolute path for subway project dir
:param conf: Optional[Dict], Default None, indicates a simple default config is applied.
:param fromfile: Optional[str]. Default None, indicates a default example main.py will be rendered.
If specified as a full path, the corresponding file will be copied into subway project
as entry point.
:param include_main: Optional[bool], default True. If False, main.py is not rendered.
:return: None.
"""
if not conf:
conf = default_conf(path)
mkdirs(path, conf)
render_config(path, conf)
render_history(path)
if include_main:
render_main(path, conf, fromfile)
[docs]def default_conf(path):
"""
generate default config dict for subway project
:param path: str. ``conf["work_dir] = path``
:return: Dict. The default config dict.
"""
conf = {}
conf["inputs_dir"] = "inputs"
conf["outputs_dir"] = "outputs"
conf["check_inputs_dir"] = "cinputs"
conf["check_outputs_dir"] = "coutputs"
conf["work_dir"] = path # not necessary, can serve as a double check
conf["resource_limit"] = {}
conf["entry_point"] = "main.py"
conf["_py"] = sys.executable
return conf
[docs]def mkdirs(path, conf):
"""
mkdirs for "inputs_dir", "outputs_dir", "check_inputs_dir", "check_outputs_dir",
if they are mentioned in conf dict
:param path: str. full path for subway project.
:param conf: Dict. config dict for subway project.
:return: None
"""
os.mkdir(os.path.join(path, ".subway"))
for d in ["inputs_dir", "outputs_dir", "check_inputs_dir", "check_outputs_dir"]:
_mkdir(path, conf, d)
[docs]def _mkdir(path, conf, key):
if conf.get(key):
os.mkdir(os.path.join(path, conf.get(key)))
[docs]def render_config(path, conf):
"""
generate config.json based on conf dict within .subway dir
:param path: str. full path for subway project.
:param conf: Dict. config dict for subway project.
:return: None
"""
with open(os.path.join(path, ".subway", "config.json"), "w") as f:
json.dump(conf, f, indent=2)
[docs]def render_history(path):
"""
generate empty history.json with only ``{}`` within .subway dir
:param path: str. full path for subway project.
:return: None
"""
with open(os.path.join(path, ".subway", "history.json"), "w") as f:
json.dump({}, f, indent=2)
[docs]def render_main(path, conf, fromfile=None):
"""
render main.py as detailed as possible and make its permission 700 (executable).
:param path: str. full path for subway project.
:param conf: Dict. config dict for subway project.
:param fromfile: Optional[str]. Default None, indicates a default example main.py will be rendered.
If specified as a full path, the corresponding file will be copied into subway project
as entry point.
:return: None.
"""
if not conf:
entry_point = "main.py"
else:
entry_point = conf.get("entry_point", "main.py")
if not fromfile:
mainpy = """#! {_py}
import os
from subway import cons
cons.work_dir = os.path.dirname(os.path.abspath(__file__))
from subway.config import conf, history
from subway.workflow import main_once, main_rt
from subway.plugins import DebugSub, DebugChk
if __name__ == "__main__":
main_once(DebugChk(), DebugSub())
""".format(
_py=sys.executable
)
with open(os.path.join(path, entry_point), "w") as f:
f.writelines([mainpy])
else: # fromfile
shutil.copyfile(fromfile, os.path.join(path, entry_point))
os.chmod(os.path.join(path, entry_point), 0o700)