Skip to content

Commit 1c7e671

Browse files
Add some utils (#50)
* add print_tree * new sort_lattices * add removed unused function
1 parent e9ee229 commit 1c7e671

File tree

3 files changed

+124
-24
lines changed

3 files changed

+124
-24
lines changed

latticejson/cli.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,44 @@ def migrate(files, final, dry_run):
100100
path.write_text(formatted)
101101

102102

103+
@cli.group()
104+
def utils():
105+
"""Some useful utilities."""
106+
pass
107+
108+
109+
@utils.command()
110+
@click.argument("file", type=click.Path(exists=True))
111+
@click.option("--lattice", "-l", type=str, help="Root lattice of tree.")
112+
@click.option(
113+
"--format",
114+
"format_",
115+
type=click.Choice(FORMATS, case_sensitive=False),
116+
help="Source format [optional, default: use file extension]",
117+
)
118+
def tree(file, lattice, format_):
119+
"""Print tree of elements for a given LatticeJSON file."""
120+
from .utils import tree
121+
122+
data = io.load(file, format_, validate)
123+
click.echo(tree(data, lattice))
124+
125+
126+
@utils.command()
127+
@click.argument("file", type=click.Path(exists=True))
128+
@click.option("--lattice", "-l", type=str, help="New root lattice [Default: current]")
129+
@click.option("--warn-unused", "-w", is_flag=True, help="Log removed lattices.")
130+
@click.option(
131+
"--validate/--no-validate", default=True, help="Whether to validate the input file."
132+
)
133+
def remove_unused(file, lattice, warn_unused, validate):
134+
"""Remove unused objects from a LatticeJSON file."""
135+
from .utils import remove_unused
136+
137+
data = remove_unused(io.load(file, validate=validate), lattice, warn_unused)
138+
click.echo(format_json(data))
139+
140+
103141
@cli.group()
104142
def debug():
105143
"""Some useful commands for debugging/development."""

latticejson/convert.py

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from .exceptions import UnknownAttributeWarning, UnknownElementTypeWarning
77
from .parse import parse_elegant, parse_madx
8+
from .utils import sort_lattices
89
from .validate import schema_version
910

1011
NAME_MAP = json.loads((Path(__file__).parent / "map.json").read_text())["map"]
@@ -87,8 +88,8 @@ def to_elegant(latticejson: dict) -> str:
8788
strings.append(element_template(name, elegant_type, attrs))
8889

8990
lattice_template = "{}: LINE=({})".format
90-
for name in sort_lattices(lattices):
91-
strings.append(lattice_template(name, ", ".join(lattices[name])))
91+
for name, children in sort_lattices(latticejson).items():
92+
strings.append(lattice_template(name, ", ".join(children)))
9293

9394
strings.append(f"USE, {latticejson['root']}\n")
9495
return "\n".join(strings)
@@ -111,28 +112,8 @@ def to_madx(latticejson: dict) -> str:
111112
strings.append(element_template(name, elegant_type, attrs))
112113

113114
lattice_template = "{}: LINE=({});".format
114-
for name in sort_lattices(lattices):
115-
strings.append(lattice_template(name, ", ".join(lattices[name])))
115+
for name, children in sort_lattices(latticejson).items():
116+
strings.append(lattice_template(name, ", ".join(children)))
116117

117118
strings.append(f"USE, {latticejson['root']};\n")
118119
return "\n".join(strings)
119-
120-
121-
def sort_lattices(lattices: Dict[str, List[str]]) -> List[str]:
122-
"""Returns a sorted list of lattice names for a given dict of lattices."""
123-
124-
lattices_set = set(lattices)
125-
lattice_names = []
126-
127-
def _sort_lattices(name):
128-
for child_name in lattices[name]:
129-
if child_name in lattices_set:
130-
lattices_set.remove(child_name)
131-
_sort_lattices(child_name)
132-
133-
lattice_names.append(name)
134-
135-
while len(lattices_set) > 0:
136-
_sort_lattices(lattices_set.pop())
137-
138-
return lattice_names

latticejson/utils.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from itertools import chain
2+
from warnings import warn
3+
4+
5+
def tree(latticejson, name=None):
6+
lattices = latticejson["lattices"]
7+
8+
def _tree(name, prefix=""):
9+
string = f"{name}\n"
10+
if name in lattices:
11+
*other, last = lattices[name]
12+
for child in other:
13+
string += f"{prefix}├─── {_tree(child, prefix + '│ ')}"
14+
string += f"{prefix}└─── {_tree(last, prefix + ' ')}"
15+
return string
16+
17+
return _tree(latticejson["root"] if name is None else name)
18+
19+
20+
def sort_lattices(latticejson, root=None, keep_unused=False):
21+
"""Returns a sorted dict of lattice objects."""
22+
lattices = latticejson["lattices"]
23+
lattices_set = set(lattices)
24+
lattices_sorted = {}
25+
26+
def _sort_lattices(name):
27+
lattices_set.remove(name)
28+
for child in lattices[name]:
29+
if child in lattices_set:
30+
_sort_lattices(child)
31+
lattices_sorted[name] = lattices[name]
32+
33+
_sort_lattices(root if root is not None else latticejson["root"])
34+
if keep_unused:
35+
while len(lattices_set) > 0:
36+
_sort_lattices(lattices_set.pop())
37+
else:
38+
for lattice in lattices_set:
39+
warn(f"Discard unused lattice '{lattice}'.")
40+
return lattices_sorted
41+
42+
43+
def remove_unused(latticejson, root=None, warn_unused=False):
44+
"""Remove unused objects starting from the `root` lattice. Also sorts lattices."""
45+
if root is None:
46+
root = latticejson["root"]
47+
elements = latticejson["elements"]
48+
lattices = latticejson["lattices"]
49+
elements_set = set(elements)
50+
lattices_set = set(lattices)
51+
elements_new = {}
52+
lattices_new = {}
53+
54+
def _remove_unused(name):
55+
try:
56+
elements_set.remove(name)
57+
except KeyError:
58+
pass
59+
else:
60+
elements_new[name] = elements[name]
61+
return
62+
63+
try:
64+
lattices_set.remove(name)
65+
except KeyError:
66+
pass
67+
else:
68+
lattice = lattices[name]
69+
for child in lattice:
70+
_remove_unused(child)
71+
lattices_new[name] = lattices[name]
72+
73+
_remove_unused(root)
74+
latticejson_new = latticejson.copy()
75+
latticejson_new["root"] = root
76+
latticejson_new["elements"] = elements_new
77+
latticejson_new["lattices"] = lattices_new
78+
if warn_unused:
79+
for obj in chain(elements_set, lattices_set):
80+
warn(f"Discard unused object '{obj}'.")
81+
return latticejson_new

0 commit comments

Comments
 (0)