Source code for apsbits.api.create_new_instrument

#!/usr/bin/env python3
"""
Create a new instrument from a fixed template.

Copies the template directory and updates pyproject.toml and .templatesyncignore.
"""

__version__ = "1.0.0"

import argparse
import os
import re
import shutil
import sys
from pathlib import Path


[docs] def copy_instrument(destination_dir: Path) -> None: """ Copy template directory to the destination. :param template_dir: Path to the template directory. :param destination_dir: Path to the new instrument directory. :return: None """ demo_template_path: Path = ( Path(__file__).resolve().parent.parent / "demo_instrument" ).resolve() shutil.copytree(str(demo_template_path), str(destination_dir))
[docs] def create_qserver(qserver_dir: Path, name: str) -> None: """ Create a qserver config file in the destination directory. """ demo_qserver_path: Path = ( Path(__file__).resolve().parent.parent / "demo_qserver" ).resolve() os.makedirs(qserver_dir, exist_ok=True) # Copy all yml files from demo_qserver to destination qserver dir for yml_file in demo_qserver_path.glob("*"): shutil.copy2(yml_file, qserver_dir) # Update startup module in qs-config.yml qs_config_path = qserver_dir / "qs-config.yml" with open(qs_config_path, "r") as f: config_contents = f.read() # Replace demo_instrument with new name in startup module path updated_contents = config_contents.replace( "startup_module: demo_instrument.startup", f"startup_module: {name}.startup" ) with open(qs_config_path, "w") as f: f.write(updated_contents) new_script_path = qserver_dir / "qs_host.sh" # Read script contents with open(new_script_path, "r") as src: script_contents = src.read() # Replace demo package name with new instrument name updated_contents = script_contents.replace("demo_instrument", name) # Write updated script with open(new_script_path, "w") as dest: dest.write(updated_contents) # Make script executable os.chmod(new_script_path, new_script_path.stat().st_mode | 0o755)
[docs] def main() -> None: """ Parse arguments and create the instrument. :return: None """ parser = argparse.ArgumentParser( description="Create an instrument from a fixed template." ) parser.add_argument( "name", type=str, help="New instrument name; must be a valid package name." ) args = parser.parse_args() if re.fullmatch(r"[a-z][_a-z0-9]*", args.name) is None: print(f"Error: Invalid instrument name '{args.name}'.", file=sys.stderr) sys.exit(1) main_path: Path = Path(os.getcwd()).resolve() new_instrument_dir: Path = main_path / "src" / args.name new_qserver_dir: Path = main_path / "src" / f"{args.name}_qserver" print( f"Creating instrument '{args.name}' from demo_instrument into \ '{new_instrument_dir}'." ) if new_instrument_dir.exists(): print(f"Error: Destination '{new_instrument_dir}' exists.", file=sys.stderr) sys.exit(1) try: copy_instrument(new_instrument_dir) print(f"Template copied to '{new_instrument_dir}'.") except Exception as exc: print(f"Error copying instrument: {exc}", file=sys.stderr) sys.exit(1) try: create_qserver(new_qserver_dir, args.name) print(f"Qserver config created in '{new_qserver_dir}'.") except Exception as exc: print(f"Error creating qserver config: {exc}", file=sys.stderr) sys.exit(1) print(f"Instrument '{args.name}' created.")
if __name__ == "__main__": main()