1# Cirq modules 2 3Cirq has a modular architecture and is organized in a monorepo, all of the modules follow the same folder structure. 4Each module is structured as follows. Let's take as example a module named `cirq-example`: 5 6``` 7cirq-example 8├── cirq_example 9│ ├── __init__.py 10│ ├── _version.py 11│ ├── json_resolver_cache.py 12│ └── json_test_data 13│ ├── __init__.py 14│ └── spec.py 15├── LICENSE 16├── README.rst 17├── requirements.txt 18├── setup.cfg 19└── setup.py 20``` 21 22Note that typically there is only a single top level package, `cirq_example` - but there might be exceptions. 23 24Additionally, there is a metapackage "cirq" that's a completely different beast and just depends on the modules. 25This enables `pip install cirq` to have all the included modules to be installed for our users. 26 27All modules should depend on `cirq-core`, which is the central, core library for Cirq. 28 29## Packaging 30 31Each package gets published to PyPi as a separate package. To build all the wheel files locally, use 32 33```bash 34dev_tools/packaging/produce-package.sh ./dist `./dev_tools/packaging/generate-dev-version-id.sh` 35``` 36 37Packages are versioned together, share the same version number, and are released together. 38 39## Setting up a new module 40 41To setup a new module follow these steps: 42 431. Create the folder structure above, copy the files based on an existing module 44 1. LICENSE should be the same 45 2. README.rst will be the documentation that appears in PyPi 46 3. setup.py should specify an `install_requires` configuration that has `cirq-core=={module.version}` at the minimum 472. Setup JSON serialization for each top level python package 48 49 50### Setting up JSON serialization 51 521. Add the `<top_level_package>/json_resolver_cache.py` file 53 ```python 54 @functools.lru_cache() # coverage: ignore 55 def _class_resolver_dictionary() -> Dict[str, ObjectFactory]: # coverage: ignore 56 return {} 57 ``` 582. Register the resolver cache - at _the end_ of the `<top_level_package>/__init__.py`: 59 ```python 60 61 # Registers cirq_example's public classes for JSON serialization. 62 from cirq.protocols.json_serialization import _register_resolver 63 from cirq_example.json_resolver_cache import _class_resolver_dictionary 64 _register_resolver(_class_resolver_dictionary) 65 66 ``` 673. Add the `<top_level_package>/json_test_data` folder with the following content: 68 1. `spec.py` contains the core test specification for JSON testing, that plugs into the central framework: 69 ```python 70 import pathlib 71 import cirq_example 72 from cirq_example.json_resolver_cache import _class_resolver_dictionary 73 74 from cirq.testing.json import ModuleJsonTestSpec 75 76 TestSpec = ModuleJsonTestSpec( 77 name="cirq_example", 78 packages=[cirq_example], 79 test_data_path=pathlib.Path(__file__).parent, 80 not_yet_serializable=[], 81 should_not_be_serialized=[], 82 resolver_cache=_class_resolver_dictionary(), 83 deprecated={}, 84 ) 85 ``` 86 2. `__init__.py` should import `TestSpec` from `spec.py` 87 3. in `cirq/protocols/json_serialization_test.py` add `'cirq_example':None` to the `TESTED_MODULES` variable. `TESTED_MODULES` is also used to prepare the test framework for deprecation warnings. 88 With new modules, we use`None` as there is no deprecation setup. 89 90You can run `check/pytest-changed-files` and that should execute the json_serialization_test.py as well. 91 92That's it! Now, you can follow the [Serialization guide](./serialization.md) for adding and removing serializable objects. 93 94# Utilities 95 96## List modules 97 98To iterate through modules, you can list them by invoking `dev_tools/modules.py`. 99 100```bash 101python dev_tools/modules.py --list 102``` 103 104There are different modes of listing (e.g the folder, package-path, top level package), 105you can refer to `python dev_tools/modules.py --list --help` for the most up to date features. 106