Browse Source

Rewrite python template to make them pip installable

tags/v0.3.9-rc1
haixuantao 1 year ago
parent
commit
a4940401c2
10 changed files with 134 additions and 33 deletions
  1. +4
    -3
      binaries/cli/src/template/python/dataflow-template.yml
  2. +1
    -3
      binaries/cli/src/template/python/listener/listener-template.py
  3. +59
    -12
      binaries/cli/src/template/python/mod.rs
  4. +1
    -0
      binaries/cli/src/template/python/node-name/README.md
  5. +11
    -0
      binaries/cli/src/template/python/node-name/node_name/__init__.py
  6. +5
    -0
      binaries/cli/src/template/python/node-name/node_name/__main__.py
  7. +21
    -0
      binaries/cli/src/template/python/node-name/node_name/main.py
  8. +23
    -0
      binaries/cli/src/template/python/node-name/pyproject.toml
  9. +9
    -0
      binaries/cli/src/template/python/node-name/tests/test_node_name.py
  10. +0
    -15
      binaries/cli/src/template/python/node/node-template.py

+ 4
- 3
binaries/cli/src/template/python/dataflow-template.yml View File

@@ -1,19 +1,20 @@
nodes:
- id: talker_1
path: talker_1/talker_1.py
path: talker-1/talker_1/main.py
inputs:
tick: dora/timer/millis/100
outputs:
- speech

- id: talker_2
path: talker_2/talker_2.py
path: talker-2/talker_2/main.py
inputs:
tick: dora/timer/secs/2
outputs:
- speech

- id: listener_1
path: listener_1/listener_1.py
path: listener-1/listener_1/main.py
inputs:
speech-1: talker_1/speech
speech-2: talker_2/speech

+ 1
- 3
binaries/cli/src/template/python/listener/listener-template.py View File

@@ -6,6 +6,4 @@ node = Node()
for event in node:
if event["type"] == "INPUT":
message = event["value"][0].as_py()
print(
f"""I heard {message} from {event["id"]}"""
)
print(f"""I heard {message} from {event["id"]}""")

+ 59
- 12
binaries/cli/src/template/python/mod.rs View File

@@ -4,7 +4,13 @@ use std::{
path::{Path, PathBuf},
};

const NODE_PY: &str = include_str!("node/node-template.py");
const MAIN_PY: &str = include_str!("node-name/node_name/main.py");
const _MAIN_PY: &str = include_str!("node-name/node_name/__main__.py");
const _INIT_PY: &str = include_str!("node-name/node_name/__init__.py");
const _TEST_PY: &str = include_str!("node-name/tests/test_node_name.py");
const PYPROJECT_TOML: &str = include_str!("node-name/pyproject.toml");
const README_MD: &str = include_str!("node-name/README.md");

const TALKER_PY: &str = include_str!("talker/talker-template.py");
const LISTENER_PY: &str = include_str!("listener/listener-template.py");

@@ -17,23 +23,64 @@ pub fn create(args: crate::CommandNew) -> eyre::Result<()> {
} = args;

match kind {
crate::Kind::CustomNode => create_custom_node(name, path, NODE_PY),
crate::Kind::CustomNode => create_custom_node(name, path, MAIN_PY),
crate::Kind::Dataflow => create_dataflow(name, path),
}
}

fn replace_space(file: &str, name: &str) -> String {
let file = file.replace("node-name", &name.replace(" ", "-"));
file.replace("node_name", &name.replace(" ", "_"))
}
fn create_custom_node(
name: String,
path: Option<PathBuf>,
template_scripts: &str,
main: &str,
) -> Result<(), eyre::ErrReport> {
// create directories
let root = path.as_deref().unwrap_or_else(|| Path::new(&name));
fs::create_dir(root)
.with_context(|| format!("failed to create directory `{}`", root.display()))?;
let root = path.unwrap_or_else(|| PathBuf::from(name.replace(" ", "-")));
let module_path = root.join(name.replace(" ", "_"));
fs::create_dir(&root)
.with_context(|| format!("failed to create directory `{}`", &root.display()))?;

fs::create_dir(&module_path)
.with_context(|| format!("failed to create directory `{}`", &root.display()))?;

fs::create_dir(&root.join("tests"))
.with_context(|| format!("failed to create directory `{}`", &root.display()))?;

// PYPROJECT.toml
let node_path = root.join("pyproject.toml");
let pyproject = replace_space(PYPROJECT_TOML, &name);
fs::write(&node_path, pyproject)
.with_context(|| format!("failed to write `{}`", node_path.display()))?;

// README.md
let node_path = root.join("README.md");
fs::write(&node_path, README_MD.replace("name", &name))
.with_context(|| format!("failed to write `{}`", node_path.display()))?;

// main.py
let node_path = module_path.join("main.py");
fs::write(&node_path, main)
.with_context(|| format!("failed to write `{}`", node_path.display()))?;

// __main__.py
let node_path = module_path.join("__main__.py");
fs::write(&node_path, _MAIN_PY)
.with_context(|| format!("failed to write `{}`", node_path.display()))?;

// __init__.py
let node_path = module_path.join("__init__.py");
fs::write(&node_path, _INIT_PY)
.with_context(|| format!("failed to write `{}`", node_path.display()))?;

let node_path = root.join(format!("{name}.py"));
fs::write(&node_path, template_scripts)
// tests/tests_node_name.py
let node_path = root
.join("tests")
.join(format!("tests_{}.py", name.replace(" ", "_")));
let file = replace_space(_TEST_PY, &name);
fs::write(&node_path, file)
.with_context(|| format!("failed to write `{}`", node_path.display()))?;

println!(
@@ -64,11 +111,11 @@ fn create_dataflow(name: String, path: Option<PathBuf>) -> Result<(), eyre::ErrR
fs::write(&dataflow_yml_path, dataflow_yml)
.with_context(|| format!("failed to write `{}`", dataflow_yml_path.display()))?;

create_custom_node("talker_1".into(), Some(root.join("talker_1")), TALKER_PY)?;
create_custom_node("talker_2".into(), Some(root.join("talker_2")), TALKER_PY)?;
create_custom_node("talker 1".into(), Some(root.join("talker-1")), TALKER_PY)?;
create_custom_node("talker 2".into(), Some(root.join("talker-2")), TALKER_PY)?;
create_custom_node(
"listener_1".into(),
Some(root.join("listener_1")),
"listener 1".into(),
Some(root.join("listener-1")),
LISTENER_PY,
)?;



+ 1
- 0
binaries/cli/src/template/python/node-name/README.md View File

@@ -0,0 +1 @@
# name

+ 11
- 0
binaries/cli/src/template/python/node-name/node_name/__init__.py View File

@@ -0,0 +1,11 @@
import os

# Define the path to the README file relative to the package directory
readme_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "README.md")

# Read the content of the README file
try:
with open(readme_path, "r", encoding="utf-8") as f:
__doc__ = f.read()
except FileNotFoundError:
__doc__ = "README file not found."

+ 5
- 0
binaries/cli/src/template/python/node-name/node_name/__main__.py View File

@@ -0,0 +1,5 @@
from .main import main


if __name__ == "__main__":
main()

+ 21
- 0
binaries/cli/src/template/python/node-name/node_name/main.py View File

@@ -0,0 +1,21 @@
import os
from dora import Node

RUNNER_CI = True if os.getenv("CI") == "true" else False


def main():
node = Node()

for event in node:
if event["type"] == "INPUT":
print(
f"""Node received:
id: {event["id"]},
value: {event["value"]},
metadata: {event["metadata"]}"""
)


if __name__ == "__main__":
main()

+ 23
- 0
binaries/cli/src/template/python/node-name/pyproject.toml View File

@@ -0,0 +1,23 @@
[tool.poetry]
name = "node-name"
version = "0.0.1"
authors = ["author"]
description = "Node Name"
license = "MIT License"
homepage = "https://github.com/dora-rs/dora.git"
documentation = "https://github.com/dora-rs/dora/blob/main/node-hub/node-name/README.md"
readme = "README.md"
packages = [{ include = "node_name" }]

[tool.poetry.dependencies]
dora-rs = "^0.3.6"
numpy = "< 2.0.0"
pyarrow = ">= 5.0.0"
python = "^3.7"

[tool.poetry.scripts]
node-name = "node_name.main:main"

[build-system]
requires = ["poetry-core>=1.8.0"]
build-backend = "poetry.core.masonry.api"

+ 9
- 0
binaries/cli/src/template/python/node-name/tests/test_node_name.py View File

@@ -0,0 +1,9 @@
import pytest


def test_import_main():
from node_name.main import main

# Check that everything is working, and catch dora Runtime Exception as we're not running in a dora dataflow.
with pytest.raises(RuntimeError):
main()

+ 0
- 15
binaries/cli/src/template/python/node/node-template.py View File

@@ -1,15 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from dora import Node

node = Node()

event = node.next()
if event["type"] == "INPUT":
print(
f"""Node received:
id: {event["id"]},
value: {event["value"]},
metadata: {event["metadata"]}"""
)

Loading…
Cancel
Save