Skip to content

Commit 902d474

Browse files
authored
Adding json object migration script and documentation. (#1009)
* adding json object migration script * support multiple files in migration script * fixing typo * fixing typo * fixing typo * refactor migration * simplify migration page
1 parent 8e8a185 commit 902d474

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

docs/home/migration.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,35 @@ from bloqade.analog.atom_arrangement import Square
3333
...
3434
```
3535

36+
## Migrating old bloqade JSON files
37+
38+
If you have old bloqade JSON files, you will not be able to directly deserialize them anymore because of the package restructuring. However, we have provided some tools to migrate those JSON files to be compatible with `bloqade-analog`. You can do this by running the following command in the command line for a one or more files:
39+
40+
```sh
41+
python -m bloqade.analog.migrate <path_to_old_json_file1> <path_to_old_json_file2> ...
42+
```
43+
With default arguments this will create a new file with the same name as the old file, but with `-analog` appended to the end of the filename. For example, if you have a file called `my_bloqade.json`, the new file will be called `my_bloqade-analog.json`. You can then use `load` to deserialize this file with the `bloqade-analog` package. There are other options for converting the file, such as setting the indent level for the output file or overwriting the old file. You can see all the options by running:
44+
45+
```sh
46+
python -m bloqade.analog.migrate --help
47+
```
48+
49+
Another option is to use the migration tool in a python script:
50+
51+
```python
52+
from bloqade.analog.migrate import migrate
53+
54+
# set the indent level for the output file
55+
indent: int = ...
56+
# set to True if you want to overwrite the old file, otherwise the new file will be created with -analog appended to the end of the filename
57+
overwrite: bool = ...
58+
f
59+
or filename in ["file1.json", "file2.json", ...]:
60+
migrate(filename, indent=indent, overwrite=overwrite)
61+
```
62+
This will migrate all the files in the list to the new format.
63+
64+
3665
## Having trouble, comments, or concerns?
3766

3867
Please open an issue on our [GitHub](https://github.com/QuEraComputing/bloqade-analog/issues)

src/bloqade/analog/migrate.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from typing import IO, Any, Dict, List
2+
from dataclasses import field, dataclass
3+
4+
import simplejson as json
5+
6+
7+
@dataclass
8+
class JSONWalker:
9+
has_done_something: bool = field(init=False, default=False)
10+
11+
def walk_dict(self, obj: Dict[str, Any]) -> Dict[str, Any]:
12+
new_obj = {}
13+
for key, value in obj.items():
14+
15+
if key.startswith("bloqade.analog."):
16+
new_obj[key] = self.walk(value)
17+
elif key.startswith("bloqade."):
18+
new_obj[key.replace("bloqade.", "bloqade.analog.")] = self.walk(value)
19+
self.has_done_something = True
20+
else:
21+
new_obj[key] = self.walk(value)
22+
23+
return new_obj
24+
25+
def walk(self, obj: Dict[str, Any] | List[Any]) -> Dict[str, Any] | List[Any]:
26+
if isinstance(obj, dict):
27+
return self.walk_dict(obj)
28+
elif isinstance(obj, list):
29+
return list(map(self.walk, obj))
30+
else:
31+
return obj
32+
33+
def convert(self, obj: Dict[str, Any] | List[Any]):
34+
self.has_done_something = False
35+
new_obj = self.walk(obj)
36+
return new_obj, self.has_done_something
37+
38+
39+
def _migrate(input_oi: IO[str], output_oi: IO[str], indent: int | None = None):
40+
obj = json.load(input_oi)
41+
new_obj, has_done_something = JSONWalker().convert(obj)
42+
43+
if has_done_something:
44+
json.dump(new_obj, output_oi, indent=indent)
45+
46+
47+
def migrate(
48+
filename: str,
49+
indent: int | None = None,
50+
overwrite: bool = False,
51+
):
52+
new_filename = filename if overwrite else filename.replace(".json", "-analog.json")
53+
with open(filename, "r") as in_io, open(new_filename, "w") as out_io:
54+
_migrate(in_io, out_io, indent)
55+
56+
57+
def _entry():
58+
import argparse
59+
60+
import tqdm
61+
62+
parser = argparse.ArgumentParser()
63+
64+
parser.add_argument("filenames", type=str, nargs="*")
65+
parser.add_argument("--indent", type=int, default=None)
66+
parser.add_argument(
67+
"--overwrite",
68+
action="store_true",
69+
help="Overwrite the original file",
70+
default=False,
71+
)
72+
73+
args = parser.parse_args()
74+
for filename in tqdm.tqdm(args.filenames):
75+
migrate(filename, args.indent, args.overwrite)
76+
77+
78+
if __name__ == "__main__":
79+
_entry()

tests/test_migrate.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import io
2+
3+
import simplejson as json
4+
5+
from bloqade.analog.migrate import _migrate
6+
7+
8+
def test_walk_dict():
9+
10+
obj = {
11+
"key1": "value1",
12+
"bloqade.key2": "value2",
13+
"bloqade.analog.key3": "value3",
14+
"nested": {"key4": "bloqade.value4", "bloqade.key5": "value5"},
15+
"list": [{"key6": "value6"}, {"bloqade.key7": "value7"}],
16+
}
17+
18+
expected = {
19+
"key1": "value1",
20+
"bloqade.analog.key2": "value2",
21+
"bloqade.analog.key3": "value3",
22+
"nested": {"key4": "bloqade.value4", "bloqade.analog.key5": "value5"},
23+
"list": [{"key6": "value6"}, {"bloqade.analog.key7": "value7"}],
24+
}
25+
26+
obj_str = json.dumps(obj)
27+
expected_str = json.dumps(expected)
28+
29+
in_io = io.StringIO(obj_str)
30+
out_io = io.StringIO()
31+
32+
_migrate(in_io, out_io)
33+
34+
assert out_io.getvalue() == expected_str

0 commit comments

Comments
 (0)