Skip to content

Commit e45735f

Browse files
committed
start cli
1 parent e5f73ab commit e45735f

File tree

10 files changed

+236
-0
lines changed

10 files changed

+236
-0
lines changed

mpcontribs-lux/mpcontribs/lux/cli/__init__.py

Whitespace-only changes.

mpcontribs-lux/mpcontribs/lux/cli/display/__init__.py

Whitespace-only changes.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import pathlib
2+
import tempfile
3+
4+
from rich import print
5+
from rich.markup import escape
6+
from rich.text import Text
7+
from rich.tree import Tree
8+
9+
from mpcontribs.lux.cli.project.utils import build_scaffold
10+
11+
12+
# github.com/textualize/rich/blob/master/examples/tree.py
13+
def walk_directory(directory: pathlib.Path, tree: Tree) -> None:
14+
"""Recursively build a Tree with directory contents."""
15+
paths = sorted(
16+
pathlib.Path(directory).iterdir(),
17+
key=lambda path: (path.is_file(), path.name.lower()),
18+
)
19+
for path in paths:
20+
if path.name.startswith("."):
21+
continue
22+
if path.is_dir():
23+
style = "dim" if path.name.startswith("__") else ""
24+
branch = tree.add(
25+
f"[bold bright_blue] [link file://{path}]{escape(path.name)}",
26+
style=style,
27+
guide_style=style,
28+
)
29+
walk_directory(path, branch)
30+
else:
31+
text_filename = Text(path.name, "white")
32+
text_filename.stylize(f"link file://{path}")
33+
tree.add(text_filename)
34+
35+
36+
def visualize_scaffold(
37+
user_space: str,
38+
projects: set[str],
39+
structure: str,
40+
include_analysis: bool,
41+
include_pipeline: bool,
42+
include_readme: bool,
43+
extra_reqs: bool,
44+
):
45+
tree = Tree(
46+
f"[bold bright_blue] [link file://{user_space}]{user_space}",
47+
guide_style="white",
48+
)
49+
50+
user_space_root = pathlib.Path(__file__).parent.parent.parent.joinpath(
51+
"projects", user_space
52+
)
53+
54+
with tempfile.TemporaryDirectory(prefix=str(user_space_root)) as tmpdir:
55+
build_scaffold(
56+
pathlib.Path(tmpdir),
57+
user_space,
58+
projects,
59+
structure,
60+
include_analysis,
61+
include_pipeline,
62+
include_readme,
63+
extra_reqs,
64+
)
65+
66+
walk_directory(pathlib.Path(tmpdir), tree)
67+
print(tree)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import click
2+
3+
from mpcontribs.lux.cli.project import project
4+
from mpcontribs.lux.cli.schema import schema
5+
6+
7+
@click.group()
8+
def lux(): ...
9+
10+
11+
lux.add_command(project)
12+
lux.add_command(schema)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import click
2+
3+
from mpcontribs.lux.cli.project.scaffold import scaffold
4+
5+
6+
@click.group()
7+
def project(): ...
8+
9+
10+
project.add_command(scaffold)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import pathlib
2+
3+
import click
4+
5+
from mpcontribs.lux.cli.display.tree import visualize_scaffold
6+
from mpcontribs.lux.cli.project.utils import build_scaffold
7+
8+
9+
@click.command()
10+
@click.option("--user-space", default=None)
11+
@click.option("--projects", multiple=True, default=None)
12+
@click.option("--structure", type=click.Choice(["directory", "module"]), default=None)
13+
@click.option("--include-analysis", is_flag=True, default=True)
14+
@click.option("--include-pipeline", is_flag=True, default=True)
15+
@click.option("--include-readme", is_flag=True, default=True)
16+
@click.option("--extra-reqs", is_flag=True, default=True)
17+
def scaffold(
18+
user_space,
19+
projects,
20+
structure,
21+
include_analysis,
22+
include_pipeline,
23+
include_readme,
24+
extra_reqs,
25+
):
26+
if any([not x for x in (user_space, structure, projects)]):
27+
user_space = click.prompt("Name space for user project")
28+
structure = click.prompt("Structure of user project [directory, module]")
29+
projects = click.prompt(
30+
"Project names to scaffold in user project name space"
31+
).split(" ")
32+
include_analysis = click.confirm("Include analysis module?")
33+
include_pipeline = click.confirm("Include pipeline module?")
34+
include_readme = click.confirm("Include project README.md?")
35+
extra_reqs = click.confirm(
36+
"Include file for extra python requirements/libraries?"
37+
)
38+
39+
projects = set(projects)
40+
41+
click.echo(
42+
"The following project scaffold will be created in 'mpcontribs-lux.mpcontribs.projects':"
43+
)
44+
visualize_scaffold(
45+
user_space,
46+
projects,
47+
structure,
48+
include_analysis,
49+
include_pipeline,
50+
include_readme,
51+
extra_reqs,
52+
)
53+
if click.confirm("Proceed? y/N", abort=True):
54+
user_space_root = pathlib.Path(__file__).parent.parent.parent.joinpath(
55+
"projects", user_space
56+
)
57+
58+
user_space_root.mkdir()
59+
60+
build_scaffold(
61+
user_space_root,
62+
user_space,
63+
projects,
64+
structure,
65+
include_analysis,
66+
include_pipeline,
67+
include_readme,
68+
extra_reqs,
69+
)
70+
click.echo(
71+
f"Project scaffold created at 'mpcontribs-lux.mpcontribs.projects.{user_space}'!"
72+
)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import pathlib
2+
3+
4+
def build_scaffold(
5+
root,
6+
user_space,
7+
projects,
8+
structure,
9+
include_analysis,
10+
include_pipeline,
11+
include_readme,
12+
extra_reqs,
13+
):
14+
for proj in projects:
15+
proj_dir = root / proj
16+
proj_dir.mkdir()
17+
pathlib.Path(proj_dir, "__init__.py").touch()
18+
19+
if include_readme:
20+
pathlib.Path(proj_dir, "README.md").touch()
21+
if extra_reqs:
22+
pathlib.Path(proj_dir, "pip-extra-requirements.txt").touch()
23+
24+
match structure:
25+
case "directory":
26+
schema_dir = pathlib.Path(proj_dir) / "schemas"
27+
schema_dir.mkdir()
28+
pathlib.Path(schema_dir, "__init__.py").touch()
29+
pathlib.Path(schema_dir, "schema_1.py").touch()
30+
31+
if include_analysis:
32+
analysis_dir = pathlib.Path(proj_dir) / "analysis"
33+
analysis_dir.mkdir()
34+
pathlib.Path(analysis_dir, "__init__.py").touch()
35+
pathlib.Path(analysis_dir, "analysis_1.py").touch()
36+
37+
if include_pipeline:
38+
pipeline_dir = pathlib.Path(proj_dir) / "pipelines"
39+
pipeline_dir.mkdir()
40+
pathlib.Path(pipeline_dir, "__init__.py").touch()
41+
pathlib.Path(pipeline_dir, "pipeline_1.py").touch()
42+
43+
case "module":
44+
pathlib.Path(proj_dir, "schema_1.py").touch()
45+
46+
if include_analysis:
47+
pathlib.Path(proj_dir, "analysis_1.py").touch()
48+
49+
if include_pipeline:
50+
pathlib.Path(proj_dir, "pipeline_1.py").touch()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import click
2+
3+
from mpcontribs.lux.cli.schema.autogen import autogen
4+
5+
6+
@click.group()
7+
def schema():
8+
pass
9+
10+
11+
schema.add_command(autogen)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import click
2+
3+
4+
@click.command()
5+
def autogen():
6+
# TODO: SchemaGenerator(file).pydantic_schema from --file, write output to --output-file (?)
7+
...

mpcontribs-lux/pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,14 @@ authors = [
3535
Homepage = "https://github.com/materialsproject/MPContribs"
3636
Documentation = "https://docs.materialsproject.org/services/mpcontribs"
3737

38+
[project.scripts]
39+
lux = "mpcontribs.lux.cli.entry_point:lux"
40+
3841
[project.optional-dependencies]
42+
cli = [
43+
"click",
44+
"rich",
45+
]
3946
test = [
4047
"pre-commit",
4148
"pytest",

0 commit comments

Comments
 (0)