Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/pyrobird/README.md is written in an unsupported language. File is not indexed.

0001 # pyrobird
0002 
0003 [![PyPI - Version](https://img.shields.io/pypi/v/pyrobird.svg)](https://pypi.org/project/pyrobird)
0004 [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyrobird.svg)](https://pypi.org/project/pyrobird)
0005 
0006 -----
0007 
0008 ## Installation
0009 
0010 ```bash
0011 pip install pyrobird
0012 ```
0013 
0014 Optional dependencies:
0015 
0016 - `batch` - install playwright, that allows to make screenshots in batch mode
0017 - `xrootd` - install libraries to read xrootd located files and URLs starting with `root://`
0018 - `dev` - install pytest and other development requirements, mainly to run tests
0019 
0020 If using `batch` for screenshots, after installing playwright, you need to install browser binaries:
0021 
0022 ```bash
0023 python -m playwright install chromium
0024 ```
0025 
0026 If installed via pip, `xrootd` library requires compilation, so the system should have cmake,
0027 compiler and some xrootd dependencies installed.
0028 
0029 For debian/ubuntu the packages to install to use xrootd: 
0030 
0031 ```bash
0032 sudo apt install build-essential libxrootd-client-dev cmake zlib1g-dev uuid-dev libssl-dev python3-dev
0033 
0034 ```
0035 
0036 Development installation 
0037 
0038 It is recommended to use [uv](https://docs.astral.sh/uv/getting-started/installation/)
0039 
0040 ```bash
0041 cd pyrobird                 # directory inside main firebird repo. NOT pyrobird/pyrobird - this is lib
0042 uv venv                     # create virtual environment
0043 source .venv/bin/activate   # activate it
0044 uv sync                     # install all requirements
0045 ```
0046 
0047 Still possible without uv
0048 
0049 ```bash
0050 python -m pip install --editable .[dev,batch]
0051 
0052 # with xrootd
0053 python -m pip install --editable .[dev,batch,xrootd]
0054 ```
0055 
0056 Running with Gunicorn (development mode)
0057 
0058 ```bash
0059 gunicorn --bind 127.0.0.1:5454 pyrobird.server:flask_app --log-level debug --capture-output
0060 ```
0061 
0062 
0063 ## Contributing
0064 
0065 - [PEP8](https://peps.python.org/pep-0008/) is required
0066 - [Use Numpy style dockstring comments](https://numpydoc.readthedocs.io/en/latest/format.html)
0067 - [pytest](https://docs.pytest.org/en/latest/) is used for unit tests. Aim for comprehensive coverage of the new code.
0068 - Utilize [type hints](https://docs.python.org/3/library/typing.html) wherever is possible to enhance readability and reduce errors.
0069 - Use of specific exceptions for error handling is better. As described in the [Python documentation](https://docs.python.org/3/tutorial/errors.html) rather than general exceptions.
0070 - Contributions are subject to code review. Please submit pull requests (PRs) against the `main` branch for any contributions.
0071 - Manage dependencies appropriately. Add new dependencies to `pyproject.toml`. Provide a justification for new dependencies
0072 
0073 ## Testing
0074 
0075 To install dependencies with testing libraries included 
0076 
0077 ```bash
0078 pip install .[test]
0079 ```
0080 
0081 Navigate to the pyrobird/tests and execute:
0082 
0083 ```bash
0084 pytest
0085 
0086 # To stop immediately on error and enter debugging mode
0087 pytest -x --pdb 
0088 ```
0089 
0090 
0091 ## Development install
0092 
0093 ```
0094 python -m pip install --upgrade --editable  .[dev]
0095 ```
0096 
0097 # Pyrobird Server
0098 
0099 This server allows Firebird to work with local files and the local file system as
0100 well as to complement frontend features such as opening XRootD files, etc.
0101 
0102 Serve pyrobird locally and have access to files in current directory: 
0103 
0104 ```bash
0105 pyrobird serve
0106 ```
0107 
0108 **pyrobird** (backend) allows **Firebird** (frontend) to access certain files on your system. 
0109 For this reason pyrobird server has multiple endpoints such as `/api/v1/download` 
0110 which allows to download files. There are library files served and by default Firebird
0111 has access to files in your current directory or a directory provided via `--work-path` flag
0112 
0113 
0114 #### **Available Options**
0115 
0116 | Option                     | Short | Type    | Default | Description                                                                                                                                                                                                                                   |
0117 |----------------------------|-------|---------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
0118 | `--allow-any-file`         |       | Flag    | `False` | Allow unrestricted access to download files in the system. When enabled, the server allows downloads of all files which the running user has access to. **Use with caution**: It is considered dangerous in production environments.            |
0119 | `--allow-cors`             |       | Flag    | `False` | Enable CORS for downloaded files. This option should be used if you need to support web applications from different domains accessing the files, such as serving your server from a central Firebird server.                                       |
0120 | `--disable-files`          |       | Flag    | `False` | Disable all file access: local downloads and conversions, and conversions of remote `http://`, `https://` and `root://` files.                                                                                                                  |
0121 | `--work-path TEXT`         |       | String  | `CWD`   | Set the base directory path for file downloads. Defaults to the current working directory. Use this option to specify where the server should look for files when handling download requests.                                                       |
0122 | `--remote-hosts TEXT`      |       | String  | empty   | Comma-separated host names that remote conversions may read from. An entry that starts with a dot, such as `.jlab.org`, also matches its subdomains. Empty allows any host.                                                                     |
0123 | `--host TEXT`              |       | String  | `127.0.0.1` | Address to listen on. Defaults to `127.0.0.1`, or `0.0.0.0` inside Docker and Kubernetes containers. Apptainer and Singularity keep `127.0.0.1`.                                                                                         |
0124 | `--port INTEGER`           |       | Integer | `5454`  | Port to listen on.                                                                                                                                                                                                                            |
0125 
0126 
0127 > `--allow-any-file` - allows unrestricted access to download files in a system.
0128 > When enabled, the server allows downloads of all files that user has access to.
0129 > When disabled - only files in `--work-path` and its subdirectories are allowed to be downloaded.
0130 > This option could be considered safe on personal machines with a single user, 
0131 > who runs localhost server in a terminal
0132 > 
0133 > (!) It is considered dangerous in all other cases: farms, interactive nodes, production environments, servers, etc.
0134 > Just think `/etc/passwd` will be accessible through  `localhost:port/api/v1/download?f=/etc/passwd`
0135 > 
0136 > So security wise, it is better to use `--work-path` than `--allow-any-file`
0137 
0138 #### Bind address
0139 
0140 By default the server listens on `127.0.0.1`, so only this machine can reach it.
0141 Inside Docker and Kubernetes containers it listens on `0.0.0.0`, because the container
0142 has its own network and loopback is not reachable from the host. Apptainer and
0143 Singularity (for example, eic-shell) share the host network, so the server keeps
0144 `127.0.0.1` there and the browser on the host reaches it directly.
0145 
0146 Whenever the server listens on an address that other machines can reach, it prints a
0147 warning with the work path. Pass `--host 127.0.0.1` to serve this machine only.
0148 
0149 
0150 - Start server with default settings, Firebird works with files in current directory:
0151    ```bash
0152   pyrobird serve
0153    ```
0154 
0155 - Set where Firebird will take files from:
0156    
0157    ```bash
0158    pyrobird serve --work-path=/home/username/datafiles
0159    ```
0160 
0161    Now if you set file `local://filename.root` in Firebird UI,
0162    the file `/home/username/datafiles/filename.root` will be opened
0163 
0164 
0165 ## API Documentation
0166 
0167 This is technical explanation of what is under the hood of the server part
0168 
0169 ## Features
0170 
0171 - **Secure File Downloading**: Download files with access control to prevent unauthorized access.
0172 - **EDM4eic Event Processing**: Extract and convert specific events from EDM4eic files to JSON.
0173 - **Static File Serving**: Serve frontend assets seamlessly alongside API endpoints.
0174 - **Dynamic Configuration**: Serve configuration files with real-time server information.
0175 - **CORS Support**: Enable Cross-Origin Resource Sharing for specified routes.
0176 
0177 ### Configuration Options
0178 
0179 Set these keys in the Flask config, for example in a WSGI file through
0180 `configure_flask_app({...})`. `pyrobird serve` also reads the ones that have a
0181 command line option from environment variables of the same name.
0182 Boolean keys accept `True`/`False` or the strings `"true"`, `"1"`, `"false"`, `"0"`.
0183 
0184 - **PYROBIRD_DOWNLOAD_PATH**: `str[getcwd()]`, the work path. Relative file names resolve against it, and in restricted mode every local file must lie inside it once symlinks are resolved (`--work-path`).
0185 - **PYROBIRD_DOWNLOAD_IS_DISABLED**: `bool[False]`, disables all file access: downloads, local conversions and remote conversions (`--disable-files`).
0186 - **PYROBIRD_DOWNLOAD_IS_UNRESTRICTED**: `bool[False]`, allows unrestricted access to download any file, including sensitive ones (`--allow-any-file`).
0187 - **PYROBIRD_CORS_IS_ALLOWED**: `bool[False]`, enables Cross-Origin Resource Sharing (CORS) for the API and config routes (`--allow-cors`). Read from the environment at import time as well.
0188 - **PYROBIRD_REMOTE_HOSTS**: `str or list[empty]`, host names that remote conversions may read from (`--remote-hosts`). An entry that starts with a dot also matches subdomains. The check covers the requested URL; HTTP and XRootD redirects are followed.
0189 - **PYROBIRD_CONVERT_MAX_ENTRIES**: `int[1000]`, the most entries one convert request may name.
0190 - **PYROBIRD_API_BASE_URL**: `str[empty]`, the API base URL that the frontend uses (`--api-url`). Empty means the URL the browser used to reach the server.
0191 - **PYROBIRD_FIREBIRD_CONFIG_PATH**: `str[empty]`, a `config.jsonc` to serve instead of the one bundled with the frontend (`--config`).
0192 - **PYROBIRD_USER_CONFIGS**: `dict[empty]`, frontend config values (`{"key": value}`) merged over the `userConfigs` map of `config.jsonc`. A JSON object string also works.
0193 - **PYROBIRD_STARTUP_COMMANDS**: `str or list[empty]`, commands the frontend runs once the display is ready (`--startup-commands`).
0194 
0195 
0196 
0197 
0198 The API provides endpoints for downloading files, processing EDM4eic events, and serving configuration files. It also includes static file serving for frontend assets.
0199 
0200 ---
0201 
0202 ### Download File
0203 
0204 #### **Endpoint**
0205 
0206 ```
0207 GET /api/v1/download
0208 GET /api/v1/download/<path:filename>
0209 ```
0210 
0211 #### **Description**
0212 
0213 Allows users to download specified files. The download can be restricted based on configuration settings to prevent unauthorized access to sensitive files.
0214 
0215 #### **Parameters**
0216 
0217 - **Query Parameters**:
0218     - `filename` (optional): The name or path of the file to download.
0219     - `f` (optional): An alternative parameter for the filename.
0220 
0221 - **Path Parameters**:
0222     - `filename` (optional): The path of the file to download.
0223 
0224 **Note**: You can provide the filename either as a query parameter or as part of the URL path.
0225 
0226 #### **Usage**
0227 
0228 1. **Download via Query Parameter**
0229 
0230    ```bash
0231    curl -O "http://localhost:5454/api/v1/download?filename=example.txt"
0232    ```
0233 
0234 2. **Download via URL Path**
0235 
0236    ```bash
0237    curl -O "http://localhost:5454/api/v1/download/example.txt"
0238    ```
0239 
0240 #### **Security Considerations**
0241 
0242 - **Access Control**: Keep `PYROBIRD_DOWNLOAD_IS_UNRESTRICTED` off unless one trusted user runs the server.
0243 - **Path Traversal**: In restricted mode a file must resolve, symlinks included, to a path inside
0244   `PYROBIRD_DOWNLOAD_PATH`. The check compares whole path components, so `/data/work-secret` is not
0245   inside `/data/work`.
0246 
0247 ---
0248 
0249 ### Convert EDM4eic or EDM4hep Events
0250 
0251 #### **Endpoint**
0252 
0253 ```
0254 GET /api/v1/convert/<file_type>/<entries>
0255 GET /api/v1/convert/<file_type>/<entries>/<path:filename>
0256 ```
0257 
0258 #### **Description**
0259 
0260 Converts entries of an EDM4eic or EDM4hep ROOT file to Firebird DEX and returns it as JSON.
0261 Supports local files and remote `http://`, `https://` and `root://` files.
0262 
0263 A local file passes the same access check as a download. A remote file needs file access
0264 enabled (no `--disable-files`) and, when `PYROBIRD_REMOTE_HOSTS` is set, a host from that list.
0265 
0266 Requested entries the file does not hold are skipped, and the server logs one warning that lists
0267 them. A request with no entry in the file fails with `400`, and the error names the file's entry
0268 count. The in-browser converter applies the same rules. A request may name at most
0269 `PYROBIRD_CONVERT_MAX_ENTRIES` entries (default 1000), counted as requested: `0-1999` fails even on a
0270 10-entry file.
0271 
0272 #### **Parameters**
0273 
0274 - **Path Parameters**:
0275     - `file_type` (required): `auto` (detect from branch types), `edm4eic` or `edm4hep`.
0276     - `entries` (required): Entries to convert: `3`, `1-5` or `1,2-5,8`.
0277     - `filename` (optional): The path or URL of the ROOT file.
0278 
0279 - **Query Parameters**:
0280     - `filename` (optional): The name or path of the file to process.
0281     - `f` (optional): An alternative parameter for the filename.
0282     - `collections` (or `c`, optional): Comma-separated collection groups to
0283       convert, same values as `pyrobird convert --collections`
0284       (e.g. `tracker_hits,tracks,mc_particles`). Empty means all groups.
0285 
0286 **Note**: You can provide the filename either as a query parameter or as part of the URL path.
0287 
0288 #### **Usage**
0289 
0290 1. **Process Local File via Query Parameter**
0291 
0292    ```bash
0293    curl "http://localhost:5454/api/v1/convert/edm4eic/5?filename=path/to/file.edm4eic.root"
0294    ```
0295 
0296 2. **Process Remote File via URL Path**
0297 
0298    ```bash
0299    curl "http://localhost:5454/api/v1/convert/edm4eic/5/http://example.com/data/file.edm4eic.root"
0300    ```
0301 
0302 ### Asset Configuration
0303 
0304 #### **Endpoint**
0305 
0306 ```
0307 GET /assets/config.jsonc
0308 ```
0309 
0310 #### **Description**
0311 
0312 Serves the asset configuration file (`config.jsonc`) with additional server information injected dynamically:
0313 `apiBaseUrl` (the URL the browser used, unless `PYROBIRD_API_BASE_URL` is set), `serverHost`, `serverPort`,
0314 `servedByPyrobird`, and `userConfigs` merged with `PYROBIRD_USER_CONFIGS`.
0315 
0316 A missing file under `/assets/` returns `404`. Other unknown paths return the frontend's
0317 `index.html`, so the frontend's routes load directly.
0318 
0319 #### **Usage**
0320 
0321 ```bash
0322 curl "http://localhost:5454/assets/config.jsonc"
0323 ```
0324 
0325 ### Batch Screenshots
0326 
0327 ```bash
0328 pyrobird screenshot --url "/display?dex=asset://data/example-cherenkov.firebird.json&event=2" --output-path check.png
0329 ```
0330 
0331 The command serves the frontend itself on `127.0.0.1` and a free port (`--port` picks a fixed one),
0332 opens the page in headless Chromium, waits until `window.firebird.ready` is true, saves the image in
0333 `screenshots/` and stops the server. A path `--url`, or a localhost URL on port 5454 or without a port,
0334 is pointed at that server with its path and query kept; other URLs, such as a development server on
0335 `localhost:4200` or https://seeeic.org, are captured as given without starting a server, so they need no
0336 built frontend. `--ready-timeout` sets the wait in seconds.
0337 
0338 The exit code tells whether the capture shows a finished display:
0339 
0340 | Code | Meaning |
0341 |------|---------|
0342 | `0`  | The display reported ready without errors. |
0343 | `1`  | The server, the browser or the capture failed. |
0344 | `2`  | The display never reported ready. The screenshot is still saved. |
0345 | `3`  | The display reported errors in `window.firebird.errors`. The screenshot is still saved. |
0346 
0347 ### Publishing
0348 
0349 Check the packages before an upload: the wheel must hold the frontend, the sample data, the license
0350 and the frontend's third-party license notices, and stay under PyPI's 100 MiB file limit.
0351 
0352 ```bash
0353 pip install --upgrade build twine
0354 python -m build                      # or: uv build
0355 python scripts/check_dist.py dist/   # exits with 1 when a check fails
0356 python -m twine upload dist/*
0357 
0358 # You will have to setup your pip authentication key
0359 ```
0360 
0361 ## License
0362 
0363 GPL-3.0-or-later (`LICENSE`). The wheel also ships the license notices of the npm packages bundled
0364 into the frontend: `pyrobird/server/static/3rdpartylicenses.txt`, which `python build.py cp_ng`
0365 copies from the production build.