citrascope 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. citrascope-0.1.0/.devcontainer/devcontainer.json +22 -0
  2. citrascope-0.1.0/.env.example +8 -0
  3. citrascope-0.1.0/.flake8 +3 -0
  4. citrascope-0.1.0/.github/copilot-instructions.md +66 -0
  5. citrascope-0.1.0/.github/dependabot.yml +12 -0
  6. citrascope-0.1.0/.github/workflows/docker-publish.yml +29 -0
  7. citrascope-0.1.0/.github/workflows/publish.yml +24 -0
  8. citrascope-0.1.0/.github/workflows/pytest.yml +32 -0
  9. citrascope-0.1.0/.gitignore +143 -0
  10. citrascope-0.1.0/.pre-commit-config.yaml +33 -0
  11. citrascope-0.1.0/.vscode/launch.json +25 -0
  12. citrascope-0.1.0/Dockerfile +30 -0
  13. citrascope-0.1.0/PKG-INFO +158 -0
  14. citrascope-0.1.0/README.md +116 -0
  15. citrascope-0.1.0/citrascope/__init__.py +0 -0
  16. citrascope-0.1.0/citrascope/__main__.py +23 -0
  17. citrascope-0.1.0/citrascope/api/abstract_api_client.py +23 -0
  18. citrascope-0.1.0/citrascope/api/citra_api_client.py +101 -0
  19. citrascope-0.1.0/citrascope/citra_scope_daemon.py +90 -0
  20. citrascope-0.1.0/citrascope/hardware/abstract_astro_hardware_adapter.py +110 -0
  21. citrascope-0.1.0/citrascope/hardware/indi_adapter.py +290 -0
  22. citrascope-0.1.0/citrascope/logging/__init__.py +3 -0
  23. citrascope-0.1.0/citrascope/logging/_citrascope_logger.py +35 -0
  24. citrascope-0.1.0/citrascope/settings/__init__.py +0 -0
  25. citrascope-0.1.0/citrascope/settings/_citrascope_settings.py +42 -0
  26. citrascope-0.1.0/citrascope/tasks/runner.py +156 -0
  27. citrascope-0.1.0/citrascope/tasks/scope/base_telescope_task.py +205 -0
  28. citrascope-0.1.0/citrascope/tasks/scope/static_telescope_task.py +16 -0
  29. citrascope-0.1.0/citrascope/tasks/scope/tracking_telescope_task.py +28 -0
  30. citrascope-0.1.0/citrascope/tasks/task.py +43 -0
  31. citrascope-0.1.0/docs/index.md +47 -0
  32. citrascope-0.1.0/pyproject.toml +83 -0
  33. citrascope-0.1.0/tests/test_api_client.py +31 -0
  34. citrascope-0.1.0/tests/test_hardware_adapter.py +53 -0
  35. citrascope-0.1.0/tests/utils.py +68 -0
@@ -0,0 +1,22 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/python
3
+ {
4
+ "name": "Python 3",
5
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6
+ "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye",
7
+
8
+ // Features to add to the dev container. More info: https://containers.dev/features.
9
+ // "features": {},
10
+
11
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
12
+ // "forwardPorts": [],
13
+
14
+ // Use 'postCreateCommand' to run commands after the container is created.
15
+ "postCreateCommand": "sudo apt-get update && sudo apt-get install -y cmake libdbus-1-dev && python3 -m pip install --upgrade pip && pip3 install pre-commit && pip3 install ."
16
+
17
+ // Configure tool-specific properties.
18
+ // "customizations": {},
19
+
20
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
21
+ // "remoteUser": "root"
22
+ }
@@ -0,0 +1,8 @@
1
+ CITRASCOPE_PERSONAL_ACCESS_TOKEN=citra_pat_xxx
2
+ CITRASCOPE_TELESCOPE_ID=xxx
3
+ # CITRASCOPE_INDI_SERVER_URL=127.0.0.1
4
+ # use host.docker.internal with devcontainer for accessing a localhost indi server
5
+ CITRASCOPE_INDI_SERVER_URL=host.docker.internal
6
+ CITRASCOPE_INDI_SERVER_PORT=7624
7
+ CITRASCOPE_INDI_TELESCOPE_NAME=Telescope Simulator
8
+ CITRASCOPE_INDI_CAMERA_NAME=CCD Simulator
@@ -0,0 +1,3 @@
1
+ [flake8]
2
+ max-line-length = 120
3
+ extend-ignore = E203, W503
@@ -0,0 +1,66 @@
1
+ # Copilot Instructions for CitraScope
2
+
3
+ ## Overview
4
+ This project is a Python package for interacting with astronomical data and services. It includes modules for API clients, INDI client integration, logging, settings management, and task execution. Tests are located in the `tests/` directory.
5
+
6
+ ## Coding Guidelines
7
+ - Follow PEP8 for Python code style.
8
+ - Use type hints for all public functions and methods.
9
+ - Write docstrings for all modules, classes, and functions.
10
+ - Prefer logging via the custom logger in `citrascope/logging/` over print statements.
11
+ - Organize code into logical modules as per the existing structure.
12
+
13
+ ## Directory Structure
14
+ - `citrascope/api/`: API client code
15
+ - `citrascope/indi/`: INDI client integration
16
+ - `citrascope/logging/`: Logging utilities
17
+ - `citrascope/settings/`: Settings and configuration
18
+ - `citrascope/tasks/`: Task runner and definitions
19
+ - `tests/`: Unit and integration tests
20
+ - `docs/`: Project documentation
21
+
22
+ ## Testing
23
+ - All new features and bug fixes should include corresponding tests in `tests/`.
24
+ - Use pytest for running tests.
25
+ - Test files should be named `test_*.py`.
26
+
27
+ ## Copilot Usage
28
+ - When implementing new features, follow the module structure and add tests.
29
+ - For bug fixes, describe the issue and expected behavior in comments or commit messages.
30
+ - For refactoring, ensure no breaking changes and all tests pass.
31
+ - Use Copilot to suggest code, refactor, and generate tests, but always review suggestions for correctness and style.
32
+
33
+ ## Common Tasks
34
+ - Add new API integrations in `citrascope/api/`.
35
+ - Extend INDI client features in `citrascope/indi/`.
36
+ - Update logging logic in `citrascope/logging/`.
37
+ - Change settings in `citrascope/settings/`.
38
+ - Add or modify tasks in `citrascope/tasks/`.
39
+ - Write or update tests in `tests/`.
40
+
41
+ ## Important Packages
42
+
43
+ This project relies on several key Python packages. Below are some of the most important ones and their roles:
44
+
45
+ - **Click**: Used for building the command-line interface (CLI). The main entry point for the application (`python -m citrascope start`) is implemented using Click.
46
+ - **Pydantic-Settings**: Manages configuration and settings, ensuring type safety and validation for environment variables.
47
+ - **Requests** and **HTTPX**: Handle HTTP requests for interacting with the Citra.space API.
48
+ - **Python-Dateutil**: Provides robust date and time parsing utilities.
49
+ - **PyINDI-Client**: Interfaces with INDI telescope hardware, enabling communication with telescope and camera devices.
50
+ - **Skyfield**: Used for astronomical calculations, such as determining celestial positions.
51
+ - **Pytest** and **Pytest-Cov**: Facilitate unit testing and code coverage analysis.
52
+
53
+ ### Development Dependencies
54
+ - **Black**: Ensures consistent code formatting.
55
+ - **Pre-Commit**: Runs code quality checks automatically before commits.
56
+ - **Isort**: Sorts imports to maintain a clean and organized structure.
57
+ - **Mypy**: Performs static type checking.
58
+ - **Flake8**: Enforces code style and linting rules.
59
+ - **Sphinx**: Generates project documentation.
60
+
61
+ For a complete list of dependencies, refer to the `pyproject.toml` file.
62
+
63
+ ## Additional Notes
64
+ - Keep dependencies minimal and update `pyproject.toml` as needed.
65
+ - Document any major changes in `docs/index.md`.
66
+ - Use pre-commit hooks for code quality.
@@ -0,0 +1,12 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for more information:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+ # https://containers.dev/guide/dependabot
6
+
7
+ version: 2
8
+ updates:
9
+ - package-ecosystem: "devcontainers"
10
+ directory: "/"
11
+ schedule:
12
+ interval: weekly
@@ -0,0 +1,29 @@
1
+ name: Build and Push Docker Image
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ build-and-push:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout code
12
+ uses: actions/checkout@v4
13
+
14
+ - name: Set up Docker Buildx
15
+ uses: docker/setup-buildx-action@v3
16
+
17
+ - name: Log in to Docker Hub
18
+ uses: docker/login-action@v3
19
+ with:
20
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
21
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
22
+
23
+ - name: Build and push (multi-arch)
24
+ uses: docker/build-push-action@v5
25
+ with:
26
+ context: .
27
+ push: true
28
+ platforms: linux/amd64,linux/arm64
29
+ tags: ${{ secrets.DOCKERHUB_USERNAME }}/citrascope:latest
@@ -0,0 +1,24 @@
1
+ name: Publish Python 🐍 package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build-and-publish:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - name: Set up Python
13
+ uses: actions/setup-python@v5
14
+ with:
15
+ python-version: '3.12'
16
+ - name: Install build tools
17
+ run: pip install build twine
18
+ - name: Build package
19
+ run: python -m build
20
+ - name: Publish to PyPI
21
+ env:
22
+ TWINE_USERNAME: __token__
23
+ TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
24
+ run: twine upload dist/*
@@ -0,0 +1,32 @@
1
+ name: Pytest
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v4
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: '3.12'
19
+ - name: Install project prerequisites
20
+ run: sudo apt-get update && sudo apt-get install -y libglib2.0-dev libdbus-1-dev libjpeg-dev zlib1g-dev
21
+ - name: Install dependencies
22
+ run: |
23
+ pip install --upgrade pip
24
+ pip install .[dev,test]
25
+ - name: Run pytest with coverage
26
+ run: |
27
+ pytest --cov=citrascope --cov-report=term-missing --cov-report=xml --cov-branch
28
+ - name: Upload coverage report
29
+ uses: actions/upload-artifact@v4
30
+ with:
31
+ name: coverage-xml
32
+ path: coverage.xml
@@ -0,0 +1,143 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ prod.env
106
+ .env.prod
107
+ .env
108
+ .venv
109
+ env/
110
+ venv/
111
+ ENV/
112
+ env.bak/
113
+ venv.bak/
114
+
115
+ # Spyder project settings
116
+ .spyderproject
117
+ .spyproject
118
+
119
+ # Rope project settings
120
+ .ropeproject
121
+
122
+ # mkdocs documentation
123
+ /site
124
+
125
+ # mypy
126
+ .mypy_cache/
127
+ .dmypy.json
128
+ dmypy.json
129
+
130
+ # Pyre type checker
131
+ .pyre/
132
+ .vscode/extensions.json
133
+ .vscode/settings.json
134
+ .vscode/tasks.json
135
+
136
+ as_headers/
137
+
138
+ certs/
139
+ de421.bsp
140
+ citra_image.fits
141
+ /images/*
142
+ .DS_Store
143
+ hip_main.dat
@@ -0,0 +1,33 @@
1
+ repos:
2
+
3
+ - repo: https://github.com/pre-commit/pre-commit-hooks
4
+ rev: v6.0.0
5
+ hooks:
6
+ - id: check-added-large-files
7
+ exclude: data
8
+ - id: check-case-conflict
9
+ - id: check-yaml
10
+ - id: debug-statements
11
+ - id: end-of-file-fixer
12
+ exclude: data
13
+ - id: trailing-whitespace
14
+ exclude: data
15
+
16
+ - repo: https://github.com/pycqa/isort
17
+ rev: 7.0.0
18
+ hooks:
19
+ - id: isort
20
+
21
+ - repo: https://github.com/psf/black
22
+ rev: 25.9.0
23
+ hooks:
24
+ - id: black
25
+
26
+ - repo: local
27
+ hooks:
28
+ - id: pytest
29
+ name: pytest
30
+ entry: pytest
31
+ language: system
32
+ types: [python]
33
+ pass_filenames: false
@@ -0,0 +1,25 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ "version": "0.2.0",
5
+ "configurations": [
6
+ {
7
+ "name": "Python: citrascope dev start",
8
+ "type": "python",
9
+ "request": "launch",
10
+ "module": "citrascope",
11
+ "args": ["--dev", "start"],
12
+ "console": "integratedTerminal",
13
+ "justMyCode": false
14
+ },
15
+ {
16
+ "name": "Python: citrascope dev start DEBUG logging",
17
+ "type": "python",
18
+ "request": "launch",
19
+ "module": "citrascope",
20
+ "args": ["--dev", "--log-level", "DEBUG", "start"],
21
+ "console": "integratedTerminal",
22
+ "justMyCode": false
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,30 @@
1
+ # syntax=docker/dockerfile:1
2
+ FROM python:3.12
3
+
4
+
5
+ # Install system dependencies (match devcontainer setup)
6
+ RUN apt-get update && \
7
+ apt-get install -y git cmake libdbus-1-dev libglib2.0-dev libjpeg-dev zlib1g-dev && \
8
+ rm -rf /var/lib/apt/lists/*
9
+
10
+ # Set working directory
11
+ WORKDIR /app
12
+
13
+
14
+ # Copy local code into the image
15
+ COPY . /app
16
+
17
+
18
+ # Upgrade pip and install Python dependencies
19
+ RUN python3 -m pip install --upgrade pip && pip install .
20
+
21
+ # Environment variables (can be overridden at runtime)
22
+ ENV CITRASCOPE_PERSONAL_ACCESS_TOKEN=""
23
+ ENV CITRASCOPE_TELESCOPE_ID=""
24
+ ENV CITRASCOPE_INDI_SERVER_URL="indi"
25
+ ENV CITRASCOPE_INDI_TELESCOPE_NAME="Telescope Simulator"
26
+ ENV CITRASCOPE_INDI_CAMERA_NAME="CCD Simulator"
27
+
28
+
29
+ # Default command; can be overridden at runtime for flexibility
30
+ CMD ["python3", "-m", "citrascope", "start"]
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: citrascope
3
+ Version: 0.1.0
4
+ Summary: Remotely control a telescope while it polls for tasks, collects and edge processes data, and delivers results and data for further processing.
5
+ Author-email: Christopher Stevens <chris@citra.space>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.9
8
+ Requires-Dist: click
9
+ Requires-Dist: httpx
10
+ Requires-Dist: pixelemon
11
+ Requires-Dist: pydantic-settings
12
+ Requires-Dist: pyindi-client
13
+ Requires-Dist: pytest-cov
14
+ Requires-Dist: python-dateutil
15
+ Requires-Dist: python-json-logger
16
+ Requires-Dist: requests
17
+ Requires-Dist: skyfield
18
+ Requires-Dist: types-python-dateutil
19
+ Provides-Extra: build
20
+ Requires-Dist: build; extra == 'build'
21
+ Provides-Extra: deploy
22
+ Requires-Dist: twine; extra == 'deploy'
23
+ Provides-Extra: dev
24
+ Requires-Dist: black; extra == 'dev'
25
+ Requires-Dist: flake8; extra == 'dev'
26
+ Requires-Dist: flake8-pytest-style; extra == 'dev'
27
+ Requires-Dist: isort; extra == 'dev'
28
+ Requires-Dist: mockito; extra == 'dev'
29
+ Requires-Dist: mypy; extra == 'dev'
30
+ Requires-Dist: pre-commit; extra == 'dev'
31
+ Requires-Dist: pytest; extra == 'dev'
32
+ Requires-Dist: pytest-cov; extra == 'dev'
33
+ Provides-Extra: docs
34
+ Requires-Dist: sphinx; extra == 'docs'
35
+ Requires-Dist: sphinx-autodoc-typehints; extra == 'docs'
36
+ Requires-Dist: sphinx-markdown-builder; extra == 'docs'
37
+ Provides-Extra: test
38
+ Requires-Dist: mockito; extra == 'test'
39
+ Requires-Dist: pytest; extra == 'test'
40
+ Requires-Dist: pytest-cov; extra == 'test'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # CitraScope
44
+ [![Pytest](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml/badge.svg)](https://github.com/citra-space/citrascope/actions/workflows/pytest.yml) [![Build and Push Docker Image](https://github.com/citra-space/citrascope/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/citra-space/citrascope/actions/workflows/docker-publish.yml)
45
+
46
+ Remotely control a telescope while it polls for tasks, collects observations, and delivers data for further processing.
47
+
48
+ ## Features
49
+
50
+ - Connects to Citra.space's API and identifies itself as an online telescope
51
+ - Connects to configured INDI telescope and camera hardware
52
+ - Acts as a task daemon carrying out and remitting photography tasks
53
+
54
+ ## Installation
55
+
56
+ Install CitraScope from PyPI:
57
+
58
+ ```sh
59
+ pip install citrascope
60
+ ```
61
+
62
+ This provides the `citrascope` command-line tool. To see available commands:
63
+
64
+ ```sh
65
+ citrascope --help
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ Run the CLI tool:
71
+
72
+ ```sh
73
+ citrascope start
74
+ ```
75
+
76
+ To connect to the Citra Dev server:
77
+
78
+ ```sh
79
+ citrascope start --dev
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ Settings are managed via environment variables with the prefix `CITRASCOPE_`. You must configure your personal access token and telescope ID, as well as INDI server details. You can set these variables in your shell or in a `.env` file at the project root.
85
+
86
+ Example `.env` file:
87
+
88
+ ```env
89
+ CITRASCOPE_PERSONAL_ACCESS_TOKEN=citra_pat_xxx
90
+ CITRASCOPE_TELESCOPE_ID=xxx
91
+ # CITRASCOPE_INDI_SERVER_URL=127.0.0.1
92
+ CITRASCOPE_INDI_SERVER_URL=host.docker.internal # use with devcontainer for accessing a localhost indi server
93
+ CITRASCOPE_INDI_SERVER_PORT=7624
94
+ CITRASCOPE_INDI_TELESCOPE_NAME=Telescope Simulator
95
+ ```
96
+
97
+ **Variable descriptions:**
98
+
99
+ - `CITRASCOPE_PERSONAL_ACCESS_TOKEN`: Your CitraScope personal access token (required)
100
+ - `CITRASCOPE_TELESCOPE_ID`: Your telescope ID (required)
101
+ - `CITRASCOPE_INDI_SERVER_URL`: Hostname or IP address of the INDI server (default: `host.docker.internal` for devcontainers, or `127.0.0.1` for local)
102
+ - `CITRASCOPE_INDI_SERVER_PORT`: Port for the INDI server (default: `7624`)
103
+ - `CITRASCOPE_INDI_TELESCOPE_NAME`: Name of the INDI telescope device (default: `Telescope Simulator`)
104
+
105
+ You can copy `.env.example` to `.env` and tweak your values.
106
+
107
+ ## Developer Setup
108
+
109
+ If you are developing on macOS or Windows, use the provided [VS Code Dev Container](https://code.visualstudio.com/docs/devcontainers/containers) setup. The devcontainer provides a full Linux environment, which is required for the `pyindi-client` dependency to work. This is necessary because `pyindi-client` only works on Linux, and will not function natively on Mac or Windows.
110
+
111
+ By opening this project in VS Code and choosing "Reopen in Container" (or using the Dev Containers extension), you can develop and run the project seamlessly, regardless of your host OS.
112
+
113
+ The devcontainer also ensures all required system dependencies (like `cmake`) are installed automatically.
114
+
115
+ ### Installing Development Dependencies
116
+
117
+ To install development dependencies (for code style, linting, and pre-commit hooks):
118
+
119
+ ```sh
120
+ pip install '.[dev]'
121
+ ```
122
+
123
+ ### Setting up Pre-commit Hooks
124
+
125
+ This project uses [pre-commit](https://pre-commit.com/) to run code quality checks (like Flake8, Black, isort, etc.) automatically before each commit.
126
+
127
+ After installing the dev dependencies, enable the hooks with:
128
+
129
+ ```sh
130
+ pre-commit install
131
+ ```
132
+
133
+ You can manually run all pre-commit checks on all files with:
134
+
135
+ ```sh
136
+ pre-commit run --all-files
137
+ ```
138
+
139
+ This ensures code style and quality checks are enforced for all contributors.
140
+
141
+ ### Running and Debugging with VS Code
142
+
143
+ If you are using Visual Studio Code, you can run or debug the project directly using the pre-configured launch options in `.vscode/launch.json`:
144
+
145
+ - **Python: citrascope dev start** — Runs the main entry point with development options.
146
+ - **Python: citrascope dev start DEBUG logging** — Runs with development options and sets log level to DEBUG for more detailed output.
147
+
148
+ To use these, open the Run and Debug panel in VS Code, select the desired configuration, and click the Run or Debug button. This is a convenient way to start or debug the app without manually entering commands.
149
+
150
+ ## Running Tests
151
+
152
+ This project uses [pytest](https://pytest.org/) for unit testing. All tests are located in the `tests/` directory.
153
+
154
+ To run tests manually:
155
+
156
+ ```bash
157
+ pytest
158
+ ```