# TerminalTelemetry
A modern, cyberpunk-inspired terminal emulator with integrated network device monitoring capabilities. This application combines terminal functionality with real-time network telemetry in a highly customizable interface.

## Installation
### From PyPI
```bash
pip install TerminalTelemetry
```
### From GitHub
```bash
git clone https://github.com/scottpeterman/termtel.git
cd termtel
pip install -r requirements.txt
```
#### to launch
```commandline
python -m termtel.termtel
# or
termtel
```
## Features
- **Modern Terminal Emulator**
- Multi-session support with tabbed interface
- Customizable themes (Cyberpunk, Dark Mode, Light Mode, Retro Green, Retro Amber, Neon Blue)
- Session management and quick connect functionality
- Secure credential storage
- **Network Device Telemetry**
- Real-time interface utilization monitoring with graphs
- Automatic device type detection
- LLDP/CDP neighbor discovery
- ARP table visualization
- Routing table analysis with prefix lookup
- Support for multiple network operating systems (Cisco IOS, Arista EOS, Cisco NXOS)
- **Security Features**
- PBKDF2-HMAC-SHA256 key derivation (480,000 iterations)
- Fernet (AES-128-CBC) encryption with HMAC authentication
- Platform-specific secure storage locations
- Machine-specific binding
- Rate-limited authentication
- Cross-platform secure credential management
- Zero plaintext storage of sensitive data
```mermaid
flowchart TB
subgraph FileSystem ["File System Structure"]
direction TB
ConfigDir["Config Directory\n(.config/Termtel)"] --> SaltFile[".salt file\n(16 bytes random salt)"]
ConfigDir --> CredsFile["credentials.yaml"]
ConfigDir --> KeyringFile["System Keyring\n(machine_id)"]
subgraph CredsYAML ["credentials.yaml structure"]
direction TB
Root["Root"] --> LastMod["last_modified: ISO timestamp"]
Root --> CredsList["credentials: []"]
CredsList --> Cred1["Credential 1\n- host\n- port\n- username\n- encrypted_password\n- display_name\n- uuid"]
CredsList --> Cred2["Credential 2\n..."]
end
end
subgraph Encryption ["Encryption Process"]
direction TB
SaveCred["Save Credentials"] --> CheckLock{"Is Unlocked?"}
CheckLock -->|No| Error["Raise Error"]
CheckLock -->|Yes| Process["Process Each Credential"]
Process --> CopyDict["Create Copy of Credential Dict"]
CopyDict --> CheckPW{"Has Password?"}
CheckPW -->|No| AddToList["Add to Encrypted List"]
CheckPW -->|Yes| EncryptPW["Encrypt Password\n(Fernet)"]
EncryptPW --> Store["Store as UTF-8"]
Store --> AddToList
AddToList --> DumpYAML["Dump to YAML"]
end
subgraph Decryption ["Decryption Process"]
direction TB
LoadCred["Load Credentials"] --> VerifyLock{"Is Unlocked?"}
VerifyLock -->|No| LoadError["Raise Error"]
VerifyLock -->|Yes| ReadYAML["Read YAML File"]
ReadYAML --> ProcessCreds["Process Each Credential"]
ProcessCreds --> CopyCred["Create Copy of Credential"]
CopyCred --> CheckEncPW{"Has Encrypted\nPassword?"}
CheckEncPW -->|No| AddDecList["Add to Decrypted List"]
CheckEncPW -->|Yes| DecryptPW["Decrypt Password\n(Fernet)"]
DecryptPW --> UTF8["Convert to UTF-8"]
UTF8 --> AddDecList
end
subgraph KeyManagement ["Key Management"]
direction TB
MasterPW["Master Password"] --> PBKDF2["PBKDF2-HMAC-SHA256\n(480000 iterations)"]
Salt[".salt file"] --> PBKDF2
PBKDF2 --> DerivedKey["32-byte Derived Key"]
DerivedKey --> FernetKey["Fernet Instance"]
end
KeyManagement -.-> Encryption
KeyManagement -.-> Decryption
Encryption --> FileSystem
FileSystem --> Decryption
```
### Requirements
- Python 3.9 or higher
- PyQt6
- Additional dependencies will be automatically installed
## Usage
After installation, you can launch TerminalTelemetry using either of these commands:
```bash
# Launch with console
termtel
```
### First Time Setup
1. When first launched, you'll be prompted to create a master password for secure credential storage
- The master password is used with PBKDF2 key derivation
- A unique salt is generated and stored securely
- Credentials are encrypted using Fernet (AES-128-CBC)
2. Credentials are stored securely based on your platform:
- Windows: Uses APPDATA directory and MachineGuid
- macOS: Uses Application Support directory and hardware serial
- Linux: Uses .config directory and machine-id
3. Connect to devices using the connection panel
- Credentials are encrypted at rest
- Session data is protected in memory
- Machine-specific binding prevents credential theft
### Theme Selection
The application supports multiple themes which can be selected from the menu:
- Cyberpunk (Default)
- Dark Mode
- Light Mode
- Retro Green
- Retro Amber
- Neon Blue
## Development
To set up a development environment:
```bash
git clone https://github.com/scottpeterman/termtel.git
cd termtel
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e .[dev]
```
### Security Considerations for Development
When contributing, ensure:
1. All cryptographic operations use approved algorithms
2. Platform-specific code is properly isolated
3. Error handling follows security best practices
4. Regular security audits are performed
5. Dependencies are kept updated
## Configuration
The application stores its configuration in platform-specific locations:
```
Windows: %APPDATA%/TerminalTelemetry/
macOS: ~/Library/Application Support/TerminalTelemetry/
Linux: ~/.config/TerminalTelemetry/
```
## License
This project is licensed under the GNU General Public License v3 (GPLv3).
## Author
Scott Peterman (github.com/scottpeterman)
## Acknowledgments
- PyQt6 for the GUI framework
- NAPALM for network device interaction
- paramiko for all things SSH
- TextFSM, thanks for the templates
- The open-source community for various supporting libraries
Raw data
{
"_id": null,
"home_page": "https://github.com/scottpeterman/termtel",
"name": "TerminalTelemetry",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "terminal, telemetry, ssh, network, automation, pyqt6",
"author": "Scott Peterman",
"author_email": "scottpeterman@gmail.com",
"download_url": null,
"platform": null,
"description": "# TerminalTelemetry\r\n\r\nA modern, cyberpunk-inspired terminal emulator with integrated network device monitoring capabilities. This application combines terminal functionality with real-time network telemetry in a highly customizable interface.\r\n\r\n\r\n\r\n## Installation\r\n\r\n### From PyPI\r\n\r\n```bash\r\npip install TerminalTelemetry\r\n```\r\n\r\n### From GitHub\r\n\r\n```bash\r\ngit clone https://github.com/scottpeterman/termtel.git\r\ncd termtel\r\npip install -r requirements.txt\r\n\r\n```\r\n\r\n#### to launch\r\n```commandline\r\npython -m termtel.termtel\r\n# or\r\ntermtel\r\n```\r\n## Features\r\n\r\n- **Modern Terminal Emulator**\r\n - Multi-session support with tabbed interface\r\n - Customizable themes (Cyberpunk, Dark Mode, Light Mode, Retro Green, Retro Amber, Neon Blue)\r\n - Session management and quick connect functionality\r\n - Secure credential storage\r\n\r\n- **Network Device Telemetry**\r\n - Real-time interface utilization monitoring with graphs\r\n - Automatic device type detection\r\n - LLDP/CDP neighbor discovery\r\n - ARP table visualization\r\n - Routing table analysis with prefix lookup\r\n - Support for multiple network operating systems (Cisco IOS, Arista EOS, Cisco NXOS)\r\n\r\n- **Security Features**\r\n - PBKDF2-HMAC-SHA256 key derivation (480,000 iterations)\r\n - Fernet (AES-128-CBC) encryption with HMAC authentication\r\n - Platform-specific secure storage locations\r\n - Machine-specific binding\r\n - Rate-limited authentication\r\n - Cross-platform secure credential management\r\n - Zero plaintext storage of sensitive data\r\n\r\n```mermaid\r\nflowchart TB\r\n subgraph FileSystem [\"File System Structure\"]\r\n direction TB\r\n ConfigDir[\"Config Directory\\n(.config/Termtel)\"] --> SaltFile[\".salt file\\n(16 bytes random salt)\"]\r\n ConfigDir --> CredsFile[\"credentials.yaml\"]\r\n ConfigDir --> KeyringFile[\"System Keyring\\n(machine_id)\"]\r\n\r\n subgraph CredsYAML [\"credentials.yaml structure\"]\r\n direction TB\r\n Root[\"Root\"] --> LastMod[\"last_modified: ISO timestamp\"]\r\n Root --> CredsList[\"credentials: []\"]\r\n CredsList --> Cred1[\"Credential 1\\n- host\\n- port\\n- username\\n- encrypted_password\\n- display_name\\n- uuid\"]\r\n CredsList --> Cred2[\"Credential 2\\n...\"]\r\n end\r\n end\r\n\r\n subgraph Encryption [\"Encryption Process\"]\r\n direction TB\r\n SaveCred[\"Save Credentials\"] --> CheckLock{\"Is Unlocked?\"}\r\n CheckLock -->|No| Error[\"Raise Error\"]\r\n CheckLock -->|Yes| Process[\"Process Each Credential\"]\r\n Process --> CopyDict[\"Create Copy of Credential Dict\"]\r\n CopyDict --> CheckPW{\"Has Password?\"}\r\n CheckPW -->|No| AddToList[\"Add to Encrypted List\"]\r\n CheckPW -->|Yes| EncryptPW[\"Encrypt Password\\n(Fernet)\"]\r\n EncryptPW --> Store[\"Store as UTF-8\"]\r\n Store --> AddToList\r\n AddToList --> DumpYAML[\"Dump to YAML\"]\r\n end\r\n\r\n subgraph Decryption [\"Decryption Process\"]\r\n direction TB\r\n LoadCred[\"Load Credentials\"] --> VerifyLock{\"Is Unlocked?\"}\r\n VerifyLock -->|No| LoadError[\"Raise Error\"]\r\n VerifyLock -->|Yes| ReadYAML[\"Read YAML File\"]\r\n ReadYAML --> ProcessCreds[\"Process Each Credential\"]\r\n ProcessCreds --> CopyCred[\"Create Copy of Credential\"]\r\n CopyCred --> CheckEncPW{\"Has Encrypted\\nPassword?\"}\r\n CheckEncPW -->|No| AddDecList[\"Add to Decrypted List\"]\r\n CheckEncPW -->|Yes| DecryptPW[\"Decrypt Password\\n(Fernet)\"]\r\n DecryptPW --> UTF8[\"Convert to UTF-8\"]\r\n UTF8 --> AddDecList\r\n end\r\n\r\n subgraph KeyManagement [\"Key Management\"]\r\n direction TB\r\n MasterPW[\"Master Password\"] --> PBKDF2[\"PBKDF2-HMAC-SHA256\\n(480000 iterations)\"]\r\n Salt[\".salt file\"] --> PBKDF2\r\n PBKDF2 --> DerivedKey[\"32-byte Derived Key\"]\r\n DerivedKey --> FernetKey[\"Fernet Instance\"]\r\n end\r\n\r\n KeyManagement -.-> Encryption\r\n KeyManagement -.-> Decryption\r\n Encryption --> FileSystem\r\n FileSystem --> Decryption\r\n```\r\n\r\n\r\n### Requirements\r\n\r\n- Python 3.9 or higher\r\n- PyQt6\r\n- Additional dependencies will be automatically installed\r\n\r\n## Usage\r\n\r\nAfter installation, you can launch TerminalTelemetry using either of these commands:\r\n\r\n```bash\r\n# Launch with console\r\ntermtel\r\n\r\n```\r\n\r\n### First Time Setup\r\n\r\n1. When first launched, you'll be prompted to create a master password for secure credential storage\r\n - The master password is used with PBKDF2 key derivation\r\n - A unique salt is generated and stored securely\r\n - Credentials are encrypted using Fernet (AES-128-CBC)\r\n\r\n2. Credentials are stored securely based on your platform:\r\n - Windows: Uses APPDATA directory and MachineGuid\r\n - macOS: Uses Application Support directory and hardware serial\r\n - Linux: Uses .config directory and machine-id\r\n\r\n3. Connect to devices using the connection panel\r\n - Credentials are encrypted at rest\r\n - Session data is protected in memory\r\n - Machine-specific binding prevents credential theft\r\n\r\n### Theme Selection\r\n\r\nThe application supports multiple themes which can be selected from the menu:\r\n- Cyberpunk (Default)\r\n- Dark Mode\r\n- Light Mode\r\n- Retro Green\r\n- Retro Amber\r\n- Neon Blue\r\n\r\n## Development\r\n\r\nTo set up a development environment:\r\n\r\n```bash\r\ngit clone https://github.com/scottpeterman/termtel.git\r\ncd termtel\r\npython -m venv venv\r\nsource venv/bin/activate # On Windows: venv\\Scripts\\activate\r\npip install -e .[dev]\r\n```\r\n\r\n### Security Considerations for Development\r\n\r\nWhen contributing, ensure:\r\n1. All cryptographic operations use approved algorithms\r\n2. Platform-specific code is properly isolated\r\n3. Error handling follows security best practices\r\n4. Regular security audits are performed\r\n5. Dependencies are kept updated\r\n\r\n## Configuration\r\n\r\nThe application stores its configuration in platform-specific locations:\r\n\r\n```\r\nWindows: %APPDATA%/TerminalTelemetry/\r\nmacOS: ~/Library/Application Support/TerminalTelemetry/\r\nLinux: ~/.config/TerminalTelemetry/\r\n```\r\n\r\n## License\r\n\r\nThis project is licensed under the GNU General Public License v3 (GPLv3).\r\n\r\n## Author\r\n\r\nScott Peterman (github.com/scottpeterman)\r\n\r\n## Acknowledgments\r\n\r\n- PyQt6 for the GUI framework\r\n- NAPALM for network device interaction\r\n- paramiko for all things SSH\r\n- TextFSM, thanks for the templates\r\n- The open-source community for various supporting libraries\r\n",
"bugtrack_url": null,
"license": null,
"summary": "Terminal Telemetry - A PyQt6 Terminal Emulator with Device Telemetry",
"version": "0.9.4",
"project_urls": {
"Bug Tracker": "https://github.com/scottpeterman/termtel/issues",
"Documentation": "https://github.com/scottpeterman/termtel/wiki",
"Homepage": "https://github.com/scottpeterman/termtel"
},
"split_keywords": [
"terminal",
" telemetry",
" ssh",
" network",
" automation",
" pyqt6"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "373767d96e3147bba78076540dc92e4be203becb9a8876c29644ed6647224a55",
"md5": "75bb087b50516b6c201402a6fe0362d1",
"sha256": "5dc505e7cd7d5ff93cb25f49e77fb048b2f81ba349f60659f209cc4a486998a1"
},
"downloads": -1,
"filename": "TerminalTelemetry-0.9.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "75bb087b50516b6c201402a6fe0362d1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 32270154,
"upload_time": "2025-01-02T04:52:20",
"upload_time_iso_8601": "2025-01-02T04:52:20.611316Z",
"url": "https://files.pythonhosted.org/packages/37/37/67d96e3147bba78076540dc92e4be203becb9a8876c29644ed6647224a55/TerminalTelemetry-0.9.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-02 04:52:20",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "scottpeterman",
"github_project": "termtel",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "annotated-types",
"specs": [
[
">=",
"0.6.0"
]
]
},
{
"name": "anyio",
"specs": [
[
">=",
"4.2.0"
]
]
},
{
"name": "backports.tarfile",
"specs": [
[
">=",
"1.2.0"
]
]
},
{
"name": "bcrypt",
"specs": [
[
">=",
"4.1.2"
]
]
},
{
"name": "bottle",
"specs": [
[
">=",
"0.12.25"
]
]
},
{
"name": "certifi",
"specs": [
[
">=",
"2024.8.30"
]
]
},
{
"name": "cffi",
"specs": [
[
">=",
"1.17.1"
]
]
},
{
"name": "charset-normalizer",
"specs": [
[
">=",
"3.4.0"
]
]
},
{
"name": "click",
"specs": [
[
">=",
"8.1.7"
]
]
},
{
"name": "clr-loader",
"specs": [
[
">=",
"0.2.6"
]
]
},
{
"name": "colorama",
"specs": [
[
">=",
"0.4.6"
]
]
},
{
"name": "contourpy",
"specs": [
[
">=",
"1.3.0"
]
]
},
{
"name": "cryptography",
"specs": [
[
">=",
"41.0.7"
]
]
},
{
"name": "cycler",
"specs": [
[
">=",
"0.12.1"
]
]
},
{
"name": "et_xmlfile",
"specs": [
[
">=",
"2.0.0"
]
]
},
{
"name": "exceptiongroup",
"specs": [
[
">=",
"1.2.0"
]
]
},
{
"name": "fastapi",
"specs": [
[
">=",
"0.109.0"
]
]
},
{
"name": "Flask",
"specs": [
[
">=",
"2.2.2"
]
]
},
{
"name": "fonttools",
"specs": [
[
">=",
"4.55.2"
]
]
},
{
"name": "future",
"specs": [
[
">=",
"1.0.0"
]
]
},
{
"name": "h11",
"specs": [
[
">=",
"0.14.0"
]
]
},
{
"name": "httptools",
"specs": [
[
">=",
"0.6.1"
]
]
},
{
"name": "idna",
"specs": [
[
">=",
"3.6"
]
]
},
{
"name": "igraph",
"specs": [
[
">=",
"0.10.8"
]
]
},
{
"name": "importlib_metadata",
"specs": [
[
">=",
"8.5.0"
]
]
},
{
"name": "importlib_resources",
"specs": [
[
">=",
"6.4.5"
]
]
},
{
"name": "itsdangerous",
"specs": [
[
">=",
"2.2.0"
]
]
},
{
"name": "jaraco.classes",
"specs": [
[
">=",
"3.4.0"
]
]
},
{
"name": "jaraco.context",
"specs": [
[
">=",
"6.0.1"
]
]
},
{
"name": "jaraco.functools",
"specs": [
[
">=",
"4.1.0"
]
]
},
{
"name": "Jinja2",
"specs": [
[
">=",
"3.1.3"
]
]
},
{
"name": "junos-eznc",
"specs": [
[
">=",
"2.7.2"
]
]
},
{
"name": "keyring",
"specs": [
[
">=",
"25.5.0"
]
]
},
{
"name": "kiwisolver",
"specs": [
[
">=",
"1.4.7"
]
]
},
{
"name": "ldap3",
"specs": [
[
">=",
"2.9.1"
]
]
},
{
"name": "lxml",
"specs": [
[
">=",
"5.3.0"
]
]
},
{
"name": "MarkupSafe",
"specs": [
[
">=",
"2.1.3"
]
]
},
{
"name": "matplotlib",
"specs": [
[
">=",
"3.9.3"
]
]
},
{
"name": "more-itertools",
"specs": [
[
">=",
"10.5.0"
]
]
},
{
"name": "n2g",
"specs": [
[
">=",
"0.3.3"
]
]
},
{
"name": "napalm",
"specs": [
[
">=",
"5.0.0"
]
]
},
{
"name": "ncclient",
"specs": [
[
">=",
"0.6.15"
]
]
},
{
"name": "netaddr",
"specs": [
[
">=",
"1.3.0"
]
]
},
{
"name": "netmiko",
"specs": [
[
">=",
"4.4.0"
]
]
},
{
"name": "netutils",
"specs": [
[
">=",
"1.10.0"
]
]
},
{
"name": "networkx",
"specs": [
[
">=",
"3.2.1"
]
]
},
{
"name": "ntc_templates",
"specs": [
[
">=",
"7.4.0"
]
]
},
{
"name": "numpy",
"specs": [
[
">=",
"2.0.2"
]
]
},
{
"name": "openpyxl",
"specs": [
[
">=",
"3.1.5"
]
]
},
{
"name": "packaging",
"specs": [
[
">=",
"24.1"
]
]
},
{
"name": "paramiko",
"specs": [
[
">=",
"3.5.0"
]
]
},
{
"name": "passlib",
"specs": [
[
">=",
"1.7.4"
]
]
},
{
"name": "pillow",
"specs": [
[
">=",
"11.0.0"
]
]
},
{
"name": "proxy_tools",
"specs": [
[
">=",
"0.1.0"
]
]
},
{
"name": "pyasn1",
"specs": [
[
">=",
"0.6.1"
]
]
},
{
"name": "pycparser",
"specs": [
[
">=",
"2.21"
]
]
},
{
"name": "pydantic",
"specs": [
[
">=",
"2.5.3"
]
]
},
{
"name": "pydantic_core",
"specs": [
[
">=",
"2.14.6"
]
]
},
{
"name": "pyeapi",
"specs": [
[
">=",
"1.0.4"
]
]
},
{
"name": "PyJWT",
"specs": [
[
">=",
"2.9.0"
]
]
},
{
"name": "PyNaCl",
"specs": [
[
">=",
"1.5.0"
]
]
},
{
"name": "pynetbox",
"specs": [
[
">=",
"7.4.0"
]
]
},
{
"name": "pynxos",
"specs": [
[
">=",
"0.0.5"
]
]
},
{
"name": "pyparsing",
"specs": [
[
">=",
"3.2.0"
]
]
},
{
"name": "PyQt6",
"specs": [
[
">=",
"6.7.1"
]
]
},
{
"name": "PyQt6-Charts",
"specs": [
[
">=",
"6.7.0"
]
]
},
{
"name": "PyQt6-Charts-Qt6",
"specs": [
[
">=",
"6.7.3"
]
]
},
{
"name": "PyQt6-Qt6",
"specs": [
[
">=",
"6.7.3"
]
]
},
{
"name": "PyQt6-WebEngine",
"specs": [
[
">=",
"6.7.0"
]
]
},
{
"name": "PyQt6-WebEngine-Qt6",
"specs": [
[
">=",
"6.7.3"
]
]
},
{
"name": "PyQt6-WebEngineSubwheel-Qt6",
"specs": [
[
">=",
"6.7.3"
]
]
},
{
"name": "PyQt6_sip",
"specs": [
[
">=",
"13.8.0"
]
]
},
{
"name": "pyserial",
"specs": [
[
">=",
"3.5"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
">=",
"2.9.0.post0"
]
]
},
{
"name": "python-dotenv",
"specs": [
[
">=",
"1.0.0"
]
]
},
{
"name": "python-igraph",
"specs": [
[
">=",
"0.10.8"
]
]
},
{
"name": "python-multipart",
"specs": [
[
">=",
"0.0.6"
]
]
},
{
"name": "pythonnet",
"specs": [
[
">=",
"3.0.3"
]
]
},
{
"name": "pywebview",
"specs": [
[
">=",
"4.4.1"
]
]
},
{
"name": "pywin32-ctypes",
"specs": [
[
">=",
"0.2.3"
]
]
},
{
"name": "PyYAML",
"specs": [
[
">=",
"6.0.1"
]
]
},
{
"name": "requests",
"specs": [
[
">=",
"2.32.3"
]
]
},
{
"name": "scp",
"specs": [
[
">=",
"0.15.0"
]
]
},
{
"name": "six",
"specs": [
[
">=",
"1.17.0"
]
]
},
{
"name": "sniffio",
"specs": [
[
">=",
"1.3.0"
]
]
},
{
"name": "starlette",
"specs": [
[
">=",
"0.35.1"
]
]
},
{
"name": "svgwrite",
"specs": [
[
">=",
"1.4.3"
]
]
},
{
"name": "textfsm",
"specs": [
[
">=",
"1.1.3"
]
]
},
{
"name": "texttable",
"specs": [
[
">=",
"1.7.0"
]
]
},
{
"name": "transitions",
"specs": [
[
">=",
"0.9.2"
]
]
},
{
"name": "ttp",
"specs": [
[
">=",
"0.9.5"
]
]
},
{
"name": "ttp-templates",
"specs": [
[
">=",
"0.3.7"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
">=",
"4.9.0"
]
]
},
{
"name": "urllib3",
"specs": [
[
">=",
"2.2.3"
]
]
},
{
"name": "uvicorn",
"specs": [
[
">=",
"0.26.0"
]
]
},
{
"name": "watchfiles",
"specs": [
[
">=",
"0.21.0"
]
]
},
{
"name": "websockets",
"specs": [
[
">=",
"12.0"
]
]
},
{
"name": "Werkzeug",
"specs": [
[
">=",
"3.1.3"
]
]
},
{
"name": "yamlordereddictloader",
"specs": [
[
">=",
"0.4.2"
]
]
},
{
"name": "zipp",
"specs": [
[
">=",
"3.21.0"
]
]
}
],
"lcname": "terminaltelemetry"
}