aceiot-models-cli 0.3.2__tar.gz → 0.4.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 (87) hide show
  1. aceiot_models_cli-0.4.0/.github/workflows/release.yml +87 -0
  2. aceiot_models_cli-0.4.0/.github/workflows/tests.yml +123 -0
  3. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/hive.db-wal +0 -0
  4. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.pre-commit-config.yaml +13 -6
  5. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/CHANGELOG.md +27 -0
  6. aceiot_models_cli-0.4.0/CONTRIBUTING.md +133 -0
  7. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/PKG-INFO +11 -3
  8. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/README.md +5 -0
  9. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/pyproject.toml +21 -7
  10. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/cli.py +34 -24
  11. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/config.py +3 -1
  12. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/repl/core.py +8 -2
  13. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/repl/executor.py +58 -24
  14. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/repl/volttron_repl.py +25 -18
  15. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/test_serializers.py +11 -11
  16. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/utils/api_helpers.py +8 -8
  17. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/volttron_commands.py +38 -33
  18. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_config.py +8 -2
  19. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_error_handling.py +12 -15
  20. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_utils.py +9 -7
  21. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_volttron_commands.py +11 -19
  22. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_volttron_directory_upload.py +8 -10
  23. aceiot_models_cli-0.4.0/tox.ini +48 -0
  24. aceiot_models_cli-0.3.2/EXECUTIVE_SUMMARY.md +0 -151
  25. aceiot_models_cli-0.3.2/EXTRACTION_SUMMARY.md +0 -60
  26. aceiot_models_cli-0.3.2/IMPLEMENTATION_SUMMARY.md +0 -81
  27. aceiot_models_cli-0.3.2/IMPLEMENTATION_UPDATE_SUMMARY.md +0 -73
  28. aceiot_models_cli-0.3.2/MISSING_FEATURES.md +0 -53
  29. aceiot_models_cli-0.3.2/NEW_USE_CASES.md +0 -137
  30. aceiot_models_cli-0.3.2/PYPI_SETUP.md +0 -120
  31. aceiot_models_cli-0.3.2/REFACTORING_COMPLETE.md +0 -49
  32. aceiot_models_cli-0.3.2/REPL_IMPLEMENTATION_SPECIFICATION.md +0 -304
  33. aceiot_models_cli-0.3.2/ROADMAP.md +0 -172
  34. aceiot_models_cli-0.3.2/TEST_PLAN.md +0 -245
  35. aceiot_models_cli-0.3.2/UX_SPECIFICATION_REPL_MODE.md +0 -802
  36. aceiot_models_cli-0.3.2/VOLTTRON_CLI_UX_DESIGN.md +0 -261
  37. aceiot_models_cli-0.3.2/VOLTTRON_DEPLOYMENT_USER_FLOW.md +0 -127
  38. aceiot_models_cli-0.3.2/VOLTTRON_DESIGN_SUMMARY.md +0 -64
  39. aceiot_models_cli-0.3.2/VOLTTRON_IMPLEMENTATION_SUMMARY.md +0 -128
  40. aceiot_models_cli-0.3.2/VOLTTRON_REPL_UX_DESIGN.md +0 -318
  41. aceiot_models_cli-0.3.2/ace-api-kit +0 -1
  42. aceiot_models_cli-0.3.2/datamover/README.md +0 -52
  43. aceiot_models_cli-0.3.2/datamover/config +0 -6
  44. aceiot_models_cli-0.3.2/datamover/conftest.py +0 -6
  45. aceiot_models_cli-0.3.2/datamover/datamover/__init__.py +0 -0
  46. aceiot_models_cli-0.3.2/datamover/datamover/agent.py +0 -265
  47. aceiot_models_cli-0.3.2/datamover/setup.py +0 -72
  48. aceiot_models_cli-0.3.2/datamover/tests/test_datamover.py +0 -589
  49. aceiot_models_cli-0.3.2/datamover 3/README.md +0 -52
  50. aceiot_models_cli-0.3.2/datamover 3/config +0 -6
  51. aceiot_models_cli-0.3.2/datamover 3/conftest.py +0 -6
  52. aceiot_models_cli-0.3.2/datamover 3/datamover/__init__.py +0 -0
  53. aceiot_models_cli-0.3.2/datamover 3/datamover/agent.py +0 -265
  54. aceiot_models_cli-0.3.2/datamover 3/setup.py +0 -72
  55. aceiot_models_cli-0.3.2/datamover 3/tests/test_datamover.py +0 -589
  56. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.github/workflows/publish.yml +0 -0
  57. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.github/workflows/test.yml +0 -0
  58. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.gitignore +0 -0
  59. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/config.json +0 -0
  60. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/hive.db +0 -0
  61. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/hive.db-shm +0 -0
  62. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/memory.db +0 -0
  63. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/sessions/session-1753211745508-yuylk957g-auto-save-1753211775510.json +0 -0
  64. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/sessions/session-1753218717423-518j1u7mc-auto-save-1753218747424.json +0 -0
  65. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/sessions/session-1753226483889-l6t8sliyv-auto-save-1753226513890.json +0 -0
  66. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/sessions/session-1753244606046-hwadu65zx-auto-save-1753244636047.json +0 -0
  67. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/sessions/session-1753281994715-c69q6r8uu-auto-save-1753282024716.json +0 -0
  68. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.hive-mind/sessions/session-1753300987160-kalws26dy-auto-save-1753301017161.json +0 -0
  69. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/.python-version +0 -0
  70. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/ACEIOT_MODELS_REQUIREMENTS.md +0 -0
  71. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/LICENSE +0 -0
  72. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/MANIFEST.in +0 -0
  73. /aceiot_models_cli-0.3.2/adr_demo_container-2025-05-01-2025-07-14.csv → /aceiot_models_cli-0.4.0/adr_demo_container-2025-05-01-2025-06-14.parquet +0 -0
  74. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/example-config.yaml +0 -0
  75. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/__init__.py +0 -0
  76. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/formatters.py +0 -0
  77. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/repl/__init__.py +0 -0
  78. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/repl/context.py +0 -0
  79. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/repl/parser.py +0 -0
  80. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/src/aceiot_models_cli/utils/__init__.py +0 -0
  81. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/__init__.py +0 -0
  82. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/conftest.py +0 -0
  83. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_cli.py +0 -0
  84. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_client_commands.py +0 -0
  85. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_point_commands.py +0 -0
  86. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_repl.py +0 -0
  87. {aceiot_models_cli-0.3.2 → aceiot_models_cli-0.4.0}/tests/test_site_commands.py +0 -0
@@ -0,0 +1,87 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ dry_run:
9
+ description: 'Dry run (do not publish)'
10
+ required: false
11
+ default: true
12
+ type: boolean
13
+
14
+ jobs:
15
+ test-matrix:
16
+ name: Test Python ${{ matrix.python-version }}
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ fail-fast: true
20
+ matrix:
21
+ # NOTE: Currently only testing on Python 3.13 because aceiot-models 0.2.7
22
+ # requires Python>=3.13. Once aceiot-models is updated to support Python 3.10+,
23
+ # we can re-enable testing on: ["3.10", "3.11", "3.12", "3.13"]
24
+ python-version: ["3.13"]
25
+
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+
29
+ - name: Set up Python ${{ matrix.python-version }}
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@v4
36
+
37
+ - name: Install dependencies
38
+ run: |
39
+ uv pip install --system -e ".[dev]"
40
+
41
+ - name: Run tests
42
+ run: |
43
+ uv run pytest tests -v
44
+
45
+ build-and-publish:
46
+ name: Build and Publish
47
+ needs: test-matrix
48
+ runs-on: ubuntu-latest
49
+ permissions:
50
+ id-token: write
51
+ contents: read
52
+
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+
56
+ - name: Set up Python
57
+ uses: actions/setup-python@v5
58
+ with:
59
+ python-version: '3.13'
60
+
61
+ - name: Install uv
62
+ uses: astral-sh/setup-uv@v4
63
+
64
+ - name: Build package
65
+ run: |
66
+ uv build
67
+
68
+ - name: Check package
69
+ run: |
70
+ uv pip install --system twine
71
+ twine check dist/*
72
+
73
+ - name: List distribution files
74
+ run: |
75
+ ls -la dist/
76
+
77
+ - name: Publish to PyPI
78
+ if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && !inputs.dry_run)
79
+ uses: pypa/gh-action-pypi-publish@release/v1
80
+ with:
81
+ verbose: true
82
+
83
+ - name: Dry run notification
84
+ if: github.event_name == 'workflow_dispatch' && inputs.dry_run
85
+ run: |
86
+ echo "This was a dry run. Package was built but not published."
87
+ echo "To publish, run the workflow again with dry_run set to false."
@@ -0,0 +1,123 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main, develop ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ name: Test Python ${{ matrix.python-version }}
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - name: Install uv
28
+ uses: astral-sh/setup-uv@v4
29
+ with:
30
+ enable-cache: true
31
+ cache-dependency-glob: |
32
+ pyproject.toml
33
+ requirements*.txt
34
+
35
+ - name: Install dependencies
36
+ run: |
37
+ uv pip install --system -e ".[dev]"
38
+
39
+ - name: Run tests with pytest
40
+ run: |
41
+ uv run pytest tests -v --cov=aceiot_models_cli --cov-report=term-missing --cov-report=xml
42
+
43
+ - name: Upload coverage to Codecov
44
+ if: matrix.python-version == '3.13'
45
+ uses: codecov/codecov-action@v4
46
+ with:
47
+ file: ./coverage.xml
48
+ fail_ci_if_error: false
49
+ verbose: true
50
+
51
+ lint:
52
+ name: Lint
53
+ runs-on: ubuntu-latest
54
+
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+
58
+ - name: Set up Python
59
+ uses: actions/setup-python@v5
60
+ with:
61
+ python-version: '3.13'
62
+
63
+ - name: Install uv
64
+ uses: astral-sh/setup-uv@v4
65
+
66
+ - name: Install dependencies
67
+ run: |
68
+ uv pip install --system ruff
69
+
70
+ - name: Run ruff check
71
+ run: |
72
+ uv run ruff check src tests
73
+
74
+ - name: Run ruff format check
75
+ run: |
76
+ uv run ruff format --check src tests
77
+
78
+ type-check:
79
+ name: Type Check
80
+ runs-on: ubuntu-latest
81
+
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+
85
+ - name: Set up Python
86
+ uses: actions/setup-python@v5
87
+ with:
88
+ python-version: '3.13'
89
+
90
+ - name: Install uv
91
+ uses: astral-sh/setup-uv@v4
92
+
93
+ - name: Install dependencies
94
+ run: |
95
+ uv pip install --system -e ".[dev]"
96
+ uv pip install --system pyright
97
+
98
+ - name: Run pyright
99
+ run: |
100
+ uv run pyright src
101
+
102
+ tox:
103
+ name: Tox Test Suite
104
+ runs-on: ubuntu-latest
105
+
106
+ steps:
107
+ - uses: actions/checkout@v4
108
+
109
+ - name: Set up Python
110
+ uses: actions/setup-python@v5
111
+ with:
112
+ python-version: '3.13'
113
+
114
+ - name: Install uv
115
+ uses: astral-sh/setup-uv@v4
116
+
117
+ - name: Install tox and tox-uv
118
+ run: |
119
+ uv pip install --system tox tox-uv
120
+
121
+ - name: Run tox
122
+ run: |
123
+ uv run tox
@@ -1,6 +1,6 @@
1
1
  repos:
2
2
  - repo: https://github.com/pre-commit/pre-commit-hooks
3
- rev: v4.6.0
3
+ rev: v5.0.0
4
4
  hooks:
5
5
  - id: trailing-whitespace
6
6
  - id: end-of-file-fixer
@@ -13,15 +13,22 @@ repos:
13
13
  - id: mixed-line-ending
14
14
 
15
15
  - repo: https://github.com/astral-sh/ruff-pre-commit
16
- rev: v0.5.0
16
+ rev: v0.8.7
17
17
  hooks:
18
18
  - id: ruff
19
19
  args: [--fix]
20
20
  - id: ruff-format
21
21
 
22
- - repo: https://github.com/pre-commit/mirrors-mypy
23
- rev: v1.10.0
22
+ - repo: https://github.com/RobertCraigie/pyright-python
23
+ rev: v1.1.401
24
24
  hooks:
25
- - id: mypy
26
- additional_dependencies: [types-requests, types-pyyaml]
25
+ - id: pyright
26
+ language_version: python3.10
27
+ additional_dependencies:
28
+ - aceiot-models>=0.2.4
29
+ - click>=8.2.1
30
+ - requests>=2.31.0
31
+ - rich>=13.7.0
32
+ - pyyaml>=6.0.1
33
+ - pandas>=2.0.0
27
34
  exclude: ^tests/
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.0] - 2025-07-26
11
+
12
+ ### Added
13
+ - Full Python 3.10+ support now that aceiot-models 0.3.3 supports it
14
+ - Multi-version Python testing infrastructure with tox (3.10, 3.11, 3.12, 3.13)
15
+ - GitHub Actions CI/CD workflow for automated testing across all Python versions
16
+ - Pre-commit hooks for code quality checks
17
+ - CONTRIBUTING.md with development and testing guidelines
18
+ - Automated release workflow with testing
19
+
20
+ ### Changed
21
+ - Updated requires-python from >=3.13 to >=3.10
22
+ - Fixed datetime.UTC usage for Python 3.10 compatibility (using timezone.utc)
23
+ - Updated development dependencies to include tox and pre-commit
24
+ - Enhanced CI/CD pipeline infrastructure for multi-version testing
25
+ - Updated aceiot-models dependency to 0.3.3
26
+
27
+ ### Fixed
28
+ - Removed local path override for aceiot-models dependency
29
+ - Fixed CI/CD workflows to use uv run for all commands
30
+ - Updated test to match new APIClient._request method name
31
+ - Resolved variable shadowing in deploy function
32
+ - Fixed missing Any import in volttron_commands
33
+ - Resolved all pyright type checking errors
34
+
8
35
  ## [0.3.2] - 2025-07-26
9
36
 
10
37
  ### Changed
@@ -0,0 +1,133 @@
1
+ # Contributing to ACE IoT Models CLI
2
+
3
+ We welcome contributions to the ACE IoT Models CLI! This document provides guidelines for contributing to the project.
4
+
5
+ ## Development Setup
6
+
7
+ ### Prerequisites
8
+
9
+ - Python 3.10 or higher
10
+ - [uv](https://github.com/astral-sh/uv) (recommended) or pip
11
+
12
+ ### Setting up your development environment
13
+
14
+ 1. Clone the repository:
15
+ ```bash
16
+ git clone https://github.com/ACE-IoT-Solutions/aceiot-models-cli.git
17
+ cd aceiot-models-cli
18
+ ```
19
+
20
+ 2. Install the package in development mode with dev dependencies:
21
+ ```bash
22
+ # Using uv (recommended)
23
+ uv pip install -e ".[dev]"
24
+
25
+ # Or using pip
26
+ pip install -e ".[dev]"
27
+ ```
28
+
29
+ ## Testing
30
+
31
+ We test against multiple Python versions to ensure compatibility. All code must pass tests on Python 3.10, 3.11, 3.12, and 3.13.
32
+
33
+ ### Running tests locally
34
+
35
+ #### Using pytest directly:
36
+ ```bash
37
+ # Run all tests
38
+ pytest
39
+
40
+ # Run with coverage
41
+ pytest --cov=aceiot_models_cli --cov-report=term-missing
42
+
43
+ # Run specific test file
44
+ pytest tests/test_cli.py
45
+
46
+ # Run with verbose output
47
+ pytest -v
48
+ ```
49
+
50
+ #### Using tox for multi-version testing:
51
+ ```bash
52
+ # Install tox if not already installed
53
+ uv pip install tox tox-uv
54
+
55
+ # Run tests on all Python versions
56
+ tox
57
+
58
+ # Run tests on specific Python version
59
+ tox -e py310
60
+
61
+ # Run only linting
62
+ tox -e lint
63
+
64
+ # Run only type checking
65
+ tox -e type
66
+
67
+ # Run formatting
68
+ tox -e format
69
+ ```
70
+
71
+ ### Code Quality
72
+
73
+ Before submitting a pull request, ensure your code meets our quality standards:
74
+
75
+ 1. **Formatting**: Code must be formatted with ruff
76
+ ```bash
77
+ ruff format src tests
78
+ ```
79
+
80
+ 2. **Linting**: Code must pass ruff checks
81
+ ```bash
82
+ ruff check src tests
83
+ ```
84
+
85
+ 3. **Type Checking**: Code must pass pyright type checks
86
+ ```bash
87
+ pyright src
88
+ ```
89
+
90
+ 4. **Tests**: All tests must pass
91
+ ```bash
92
+ pytest
93
+ ```
94
+
95
+ You can run all checks at once using tox:
96
+ ```bash
97
+ tox
98
+ ```
99
+
100
+ ## Pull Request Process
101
+
102
+ 1. Fork the repository and create your branch from `main`
103
+ 2. Make your changes and add tests for new functionality
104
+ 3. Ensure all tests pass on all supported Python versions
105
+ 4. Update documentation as needed
106
+ 5. Submit a pull request with a clear description of your changes
107
+
108
+ ### CI/CD
109
+
110
+ Our GitHub Actions workflow will automatically:
111
+ - Run tests on Python 3.10, 3.11, 3.12, and 3.13
112
+ - Check code formatting with ruff
113
+ - Run type checking with pyright
114
+ - Generate coverage reports
115
+
116
+ All checks must pass before a PR can be merged.
117
+
118
+ ## Release Process
119
+
120
+ Releases are managed through GitHub releases and automatically published to PyPI. Only maintainers can create releases.
121
+
122
+ ### Creating a Release
123
+
124
+ 1. Update version in `pyproject.toml`
125
+ 2. Update `CHANGELOG.md` with release notes
126
+ 3. Commit changes: `git commit -m "chore: bump version to X.Y.Z"`
127
+ 4. Create and push tag: `git tag vX.Y.Z && git push origin vX.Y.Z`
128
+ 5. Create GitHub release
129
+ 6. GitHub Actions will automatically run tests and publish to PyPI
130
+
131
+ ## Questions?
132
+
133
+ If you have questions, please open an issue on GitHub.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aceiot-models-cli
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: Command-line interface for ACE IoT Aerodrome API using aceiot-models package
5
5
  Project-URL: Homepage, https://github.com/ACE-IoT-Solutions/aceiot-models-cli
6
6
  Project-URL: Repository, https://github.com/ACE-IoT-Solutions/aceiot-models-cli
@@ -13,11 +13,14 @@ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
16
19
  Classifier: Programming Language :: Python :: 3.13
17
20
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
18
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
- Requires-Python: >=3.13
20
- Requires-Dist: aceiot-models>=0.2.4
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: aceiot-models==0.3.3
21
24
  Requires-Dist: click-repl>=0.3.0
22
25
  Requires-Dist: click>=8.2.1
23
26
  Requires-Dist: email-validator>=2.1.0
@@ -34,6 +37,11 @@ Description-Content-Type: text/markdown
34
37
 
35
38
  A command-line interface for interacting with the ACE IoT API using the `aceiot-models` package. This CLI provides comprehensive access to ACE IoT's fleet management capabilities for IoT devices, sites, and data points.
36
39
 
40
+ ## Requirements
41
+
42
+ - Python 3.10 or higher
43
+ - An ACE IoT API key
44
+
37
45
  ## Features
38
46
 
39
47
  - Complete CLI for ACE IoT API operations
@@ -2,6 +2,11 @@
2
2
 
3
3
  A command-line interface for interacting with the ACE IoT API using the `aceiot-models` package. This CLI provides comprehensive access to ACE IoT's fleet management capabilities for IoT devices, sites, and data points.
4
4
 
5
+ ## Requirements
6
+
7
+ - Python 3.10 or higher
8
+ - An ACE IoT API key
9
+
5
10
  ## Features
6
11
 
7
12
  - Complete CLI for ACE IoT API operations
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aceiot-models-cli"
3
- version = "0.3.2"
3
+ version = "0.4.0"
4
4
  description = "Command-line interface for ACE IoT Aerodrome API using aceiot-models package"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -12,14 +12,17 @@ classifiers = [
12
12
  "Intended Audience :: Developers",
13
13
  "License :: OSI Approved :: MIT License",
14
14
  "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
15
18
  "Programming Language :: Python :: 3.13",
16
19
  "Topic :: Software Development :: Libraries :: Python Modules",
17
20
  "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
18
21
  ]
19
22
  keywords = ["aceiot", "iot", "api", "cli", "bacnet"]
20
- requires-python = ">=3.13"
23
+ requires-python = ">=3.10"
21
24
  dependencies = [
22
- "aceiot-models>=0.2.4",
25
+ "aceiot-models==0.3.3",
23
26
  "click>=8.2.1",
24
27
  "requests>=2.31.0",
25
28
  "requests-toolbelt>=1.0.0",
@@ -50,11 +53,14 @@ dev = [
50
53
  "pytest>=8.4.1",
51
54
  "pytest-cov>=6.0.0",
52
55
  "ruff>=0.12.4",
56
+ "tox>=4.0.0",
57
+ "tox-uv>=1.0.0",
58
+ "pre-commit>=3.0.0",
53
59
  ]
54
60
 
55
61
  [tool.ruff]
56
62
  line-length = 100
57
- target-version = "py313"
63
+ target-version = "py310"
58
64
  fix = true
59
65
 
60
66
  [tool.ruff.lint]
@@ -89,11 +95,19 @@ addopts = [
89
95
  ]
90
96
 
91
97
  [tool.mypy]
92
- python_version = "3.13"
98
+ python_version = "3.10"
93
99
  warn_return_any = true
94
100
  warn_unused_configs = true
95
101
  disallow_untyped_defs = true
96
102
  strict_optional = true
97
103
 
98
- [tool.uv.sources]
99
- aceiot-models = { path = "../aceiot-models" }
104
+ [tool.pyright]
105
+ pythonVersion = "3.10"
106
+ typeCheckingMode = "basic"
107
+ exclude = [
108
+ "**/test_serializers.py",
109
+ "tests/**",
110
+ ]
111
+
112
+ # [tool.uv.sources]
113
+ # aceiot-models = { path = "../aceiot-models" } # For local development only
@@ -180,6 +180,7 @@ def create_client(
180
180
 
181
181
  # Convert model to dict for API
182
182
  from aceiot_models.serializers import serialize_for_api
183
+
183
184
  client_dict = serialize_for_api(client_data)
184
185
  result = client.create_client(client_dict)
185
186
  print_success(f"Client '{name}' created successfully")
@@ -222,11 +223,7 @@ def list_sites(
222
223
  # Handle client_name filtering differently
223
224
  if client_name:
224
225
  # Use get_client_sites for specific client
225
- result = client.get_client_sites(
226
- client_name=client_name,
227
- page=page,
228
- per_page=per_page
229
- )
226
+ result = client.get_client_sites(client_name=client_name, page=page, per_page=per_page)
230
227
  else:
231
228
  # Get all sites
232
229
  result = client.get_sites(
@@ -317,8 +314,13 @@ def get_site(ctx: Context, site_name: str) -> None:
317
314
  @click.option("--start", required=True, help="Start time (ISO format, e.g., 2024-01-01T00:00:00Z)")
318
315
  @click.option("--end", required=True, help="End time (ISO format, e.g., 2024-01-02T00:00:00Z)")
319
316
  @click.option("--output-file", "-o", help="Output file path (defaults to <site>-<start>-<end>.csv)")
320
- @click.option("--format", "-f", type=click.Choice(["csv", "parquet", "auto"]), default="auto",
321
- help="Output format (auto detects from file extension, defaults to csv)")
317
+ @click.option(
318
+ "--format",
319
+ "-f",
320
+ type=click.Choice(["csv", "parquet", "auto"]),
321
+ default="auto",
322
+ help="Output format (auto detects from file extension, defaults to csv)",
323
+ )
322
324
  @click.option("--include-metadata", is_flag=True, help="Include point metadata in output")
323
325
  @click.pass_context
324
326
  def site_timeseries(
@@ -371,8 +373,8 @@ def site_timeseries(
371
373
  format = "csv" # Default to CSV when no file specified
372
374
 
373
375
  # Clean up timestamps for filename (remove colons and timezone indicators)
374
- start_clean = start.replace(':', '-').replace('Z', '').replace('+', '_')
375
- end_clean = end.replace(':', '-').replace('Z', '').replace('+', '_')
376
+ start_clean = start.replace(":", "-").replace("Z", "").replace("+", "_")
377
+ end_clean = end.replace(":", "-").replace("Z", "").replace("+", "_")
376
378
 
377
379
  # Use appropriate extension based on format
378
380
  extension = ".parquet" if format == "parquet" else ".csv"
@@ -391,7 +393,7 @@ def site_timeseries(
391
393
  format = "csv"
392
394
  # Add .csv extension if missing
393
395
  if not output_path.suffix:
394
- output_path = output_path.with_suffix('.csv')
396
+ output_path = output_path.with_suffix(".csv")
395
397
  output_file = str(output_path)
396
398
 
397
399
  # Ensure output_path is always a Path object
@@ -400,15 +402,17 @@ def site_timeseries(
400
402
  try:
401
403
  # Validate time format
402
404
  try:
403
- datetime.fromisoformat(start.replace('Z', '+00:00'))
404
- datetime.fromisoformat(end.replace('Z', '+00:00'))
405
+ datetime.fromisoformat(start.replace("Z", "+00:00"))
406
+ datetime.fromisoformat(end.replace("Z", "+00:00"))
405
407
  except ValueError as e:
406
408
  print_error(f"Invalid time format: {e}")
407
409
  print_error("Use ISO format, e.g., 2024-01-01T00:00:00Z")
408
410
  ctx.exit(1)
409
411
 
410
412
  # Fetch timeseries data directly using site endpoint
411
- console.print(f"[cyan]Fetching timeseries data for site '{site_name}' from {start} to {end}...[/cyan]")
413
+ console.print(
414
+ f"[cyan]Fetching timeseries data for site '{site_name}' from {start} to {end}...[/cyan]"
415
+ )
412
416
 
413
417
  with console.status("Loading data...", spinner="dots"):
414
418
  response = client.get_site_timeseries(site_name, start, end)
@@ -420,7 +424,9 @@ def site_timeseries(
420
424
 
421
425
  # Get unique points from the data
422
426
  unique_points = {sample.get("name") for sample in all_samples if sample.get("name")}
423
- console.print(f"[green]✓ Fetched {len(all_samples)} data samples from {len(unique_points)} points[/green]")
427
+ console.print(
428
+ f"[green]✓ Fetched {len(all_samples)} data samples from {len(unique_points)} points[/green]"
429
+ )
424
430
 
425
431
  # If metadata is requested, fetch point details
426
432
  point_metadata = {}
@@ -466,13 +472,15 @@ def site_timeseries(
466
472
  # Add metadata if requested
467
473
  if include_metadata and sample.get("name") in point_metadata:
468
474
  metadata = point_metadata[sample.get("name")]
469
- row.update({
470
- "point_id": metadata["id"],
471
- "site": metadata["site"],
472
- "point_type": metadata["point_type"],
473
- "unit": metadata["unit"],
474
- "description": metadata["description"],
475
- })
475
+ row.update(
476
+ {
477
+ "point_id": metadata["id"],
478
+ "site": metadata["site"],
479
+ "point_type": metadata["point_type"],
480
+ "unit": metadata["unit"],
481
+ "description": metadata["description"],
482
+ }
483
+ )
476
484
 
477
485
  df_data.append(row)
478
486
 
@@ -496,7 +504,9 @@ def site_timeseries(
496
504
  df.to_parquet(output_path, index=False, engine="pyarrow")
497
505
 
498
506
  # Summary
499
- console.print(f"\n[green]✓ Successfully exported {len(df)} rows to {output_path.name}[/green]")
507
+ console.print(
508
+ f"\n[green]✓ Successfully exported {len(df)} rows to {output_path.name}[/green]"
509
+ )
500
510
  console.print(f" Full path: {output_path.absolute()}")
501
511
  console.print(f" Time range: {df['timestamp'].min()} to {df['timestamp'].max()}")
502
512
  console.print(f" Unique points: {df['point_name'].nunique()}")
@@ -668,8 +678,7 @@ def list_discovered_points(ctx: Context, site_name: str, page: int, per_page: in
668
678
  # Convert Point objects back to dicts for JSON output
669
679
  json_result = result.copy() # Keep original structure
670
680
  json_result["items"] = [
671
- point.model_dump() if isinstance(point, Point) else point
672
- for point in points
681
+ point.model_dump() if isinstance(point, Point) else point for point in points
673
682
  ]
674
683
  click.echo(format_json(json_result))
675
684
  else:
@@ -895,6 +904,7 @@ def repl_mode(ctx: Context) -> None:
895
904
  # Add the volttron command group to the CLI
896
905
  cli.add_command(volttron)
897
906
 
907
+
898
908
  # Entry point
899
909
  def main() -> None:
900
910
  """Main entry point for the CLI."""
@@ -118,7 +118,9 @@ def init_config(api_key: str | None = None, api_url: str | None = None) -> None:
118
118
  config_path = get_default_config_path()
119
119
 
120
120
  # Check if config already exists
121
- if config_path.exists() and not click.confirm(f"Config file already exists at {config_path}. Overwrite?"):
121
+ if config_path.exists() and not click.confirm(
122
+ f"Config file already exists at {config_path}. Overwrite?"
123
+ ):
122
124
  return
123
125
 
124
126
  # Get values from user if not provided