Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b272d31
Initial draft of rewrites
devinslick Nov 1, 2025
0fbe556
Update publishing workflow
devinslick Nov 1, 2025
2fcbd5d
Fix typo
devinslick Nov 1, 2025
845f4d9
Correct imports
devinslick Nov 1, 2025
33b0c5f
Reorg
devinslick Nov 1, 2025
fac23be
Increment version
devinslick Nov 1, 2025
735609a
Fix pyproject.toml
devinslick Nov 1, 2025
49a3b27
Increment to 2.0.0-dev2
devinslick Nov 1, 2025
7569874
dev3
devinslick Nov 1, 2025
8c861b4
Add test scripts, attempt to fix export
devinslick Nov 2, 2025
6b0a05a
Fix test_commands, increment
devinslick Nov 2, 2025
91b258f
Cleanup and version update
devinslick Nov 2, 2025
3534cbe
Update folder for tests, correct docs
devinslick Nov 2, 2025
2f8fb5c
Improve imports for tests
devinslick Nov 2, 2025
d8c37d2
Fix bug prevented fetching locations when only 1 location exists; add…
devinslick Nov 2, 2025
6a0bda6
Add code test coverage
devinslick Nov 2, 2025
bf0ce65
50/50 passing unit tests. 28 client/22 device.
devinslick Nov 2, 2025
32e084e
Add flake8 and improve formatting to pass all checks
devinslick Nov 2, 2025
b0daaed
Update functional/unit test imports
devinslick Nov 2, 2025
8f25b6d
Improve docs and remove unused dependency
devinslick Nov 3, 2025
a094da0
Add HTTP timeouts, fix version format, add type marker, improve export
devinslick Nov 4, 2025
f19e49d
Async context manager + retry/backoff logic
devinslick Nov 4, 2025
39e75a8
Bump dependency, enforce https, santize output, version to stable 2.0
devinslick Nov 4, 2025
df8be3e
Update release documentation, CICD checks
devinslick Nov 4, 2025
e9a3593
Fixed optional location payload and private key usage
devinslick Nov 4, 2025
4a8c2c5
Return type narrowed to Dict[str, str]
devinslick Nov 4, 2025
719c65b
Testing release for merge to main
devinslick Nov 4, 2025
8747d14
Minor fixes and improvements recommended during review
devinslick Nov 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
16 changes: 16 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[flake8]
max-line-length = 120
extend-ignore = E203, W503
exclude =
.git,
__pycache__,
.venv,
venv,
build,
dist,
*.egg-info,
.pytest_cache,
.mypy_cache
per-file-ignores =
# Functional tests import after path manipulation
tests/functional/*.py: E402
87 changes: 48 additions & 39 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
name: Publish Python Package

# 1. Trigger the workflow when a new GitHub Release is published
# Trigger on:
# - pushes to any branch (we'll publish to TestPyPI for non-main branches and to PyPI for main)
# - published GitHub Releases (keep existing behavior for canonical releases)
on:
push:
branches: ["**"]
release:
types: [published]

permissions:
contents: read
id-token: write

jobs:
build_sdist_and_wheel:
name: Build distribution 📦
runs-on: ubuntu-latest
outputs:
dist-path: ${{ steps.upload.outputs.artifact-path }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -18,70 +28,69 @@ jobs:
with:
python-version: "3.x"

# Install the 'build' tool, which creates the distribution files
- name: Install build dependencies
run: python -m pip install build
- name: Install build tooling
run: python -m pip install --upgrade pip build

# Create source and wheel distribution archives in the 'dist/' directory
- name: Build distributions
run: python -m build
run: python -m build --sdist --wheel

# Store the built artifacts for the next jobs to download
- name: Upload distribution artifacts
id: upload
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/

# --- PyPI Release Job (Secure, using OIDC) ---
pypi_publish:
name: Publish to PyPI
needs: [build_sdist_and_wheel] # Ensure the build job succeeds first
# Publish from pushes to non-main branches -> TestPyPI
publish_testpypi:
name: Publish to TestPyPI (branches except main)
runs-on: ubuntu-latest
# Only publish to PyPI for full releases (not pre-releases)
if: github.event.release.prerelease == false

# 2. Use the environment name you configured in PyPI (Optional, but recommended)
environment: pypi

# 3. CRITICAL: This is the mandatory permission for Trusted Publishers (OIDC)
needs: build_sdist_and_wheel
# Only run for pushes (not releases) and only for branches that are NOT main
if: |
github.event_name == 'push' &&
startsWith(github.ref, 'refs/heads/') &&
github.ref != 'refs/heads/main'
environment: testpypi
permissions:
id-token: write
contents: read # Required to read the repository contents
id-token: write
contents: read

steps:
- name: Download all the dists
- name: Download dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/

# 4. The PyPA action handles the OIDC token exchange and Twine upload securely
- name: Publish package distributions to PyPI
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1

# --- TestPyPI Release Job (Optional, for pre-release testing) ---
testpypi_publish:
name: Publish to TestPyPI
needs: [build_sdist_and_wheel]
runs-on: ubuntu-latest

# Use the environment name you configured in TestPyPI
environment: testpypi
with:
# repository-url directs upload to TestPyPI
repository-url: https://test.pypi.org/legacy/

# Publish from pushes to main OR when a Release is published -> Production PyPI
publish_pypi:
name: Publish to PyPI (main branch or GitHub Release)
runs-on: ubuntu-latest
needs: build_sdist_and_wheel
# Run when:
# - push to main branch, or
# - release published event (keeps existing release-based behavior)
if: |
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'release' && github.event.action == 'published')
environment: pypi
permissions:
id-token: write
contents: read

steps:
- name: Download all the dists
- name: Download dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/

# The 'repository-url' is what makes this target TestPyPI
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/

- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
85 changes: 85 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Tests

on:
push:
branches: ["**"]
pull_request:
branches: ["**"]

jobs:
lint:
name: Lint and Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run flake8
run: |
python -m flake8 fmd_api/ tests/ --count --show-source --statistics

- name: Run mypy
run: |
python -m mypy fmd_api/

test:
name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run unit tests with coverage
run: |
python -m pytest tests/unit --cov=fmd_api --cov-branch --cov-report=xml --cov-report=term -v

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
flags: unittests
name: codecov-${{ matrix.os }}-py${{ matrix.python-version }}
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}

- name: Run functional tests (if credentials available)
# Skip on PRs from forks where secrets aren't available
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
run: |
python -m pytest tests/functional -v
env:
# Optional: set up test credentials as repository secrets
FMD_BASE_URL: ${{ secrets.FMD_BASE_URL }}
FMD_ID: ${{ secrets.FMD_ID }}
FMD_PASSWORD: ${{ secrets.FMD_PASSWORD }}
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ __pycache__/
*.pyc
*.pyo
*.pyd
*.zip

# User configuration files
*.env
credentials.txt
*.jpg

# C extensions
*.so
Expand Down Expand Up @@ -39,4 +45,7 @@ env/

# FMD Server and android app files
fmd-server/
fmd-android/
fmd-android/

#credentials file
examples/tests/credentials.txt
Loading
Loading