From eddba8d39ea07c6f0e7626f7999a8e591461f100 Mon Sep 17 00:00:00 2001 From: Dan Johnson Date: Sun, 3 Nov 2024 05:43:29 -0800 Subject: [PATCH] ci: fix documentation workflow and dependencies --- .flake8 | 36 ++++++++++++++++++ .github/dependabot.yml | 14 +++---- .github/workflows/ci.yml | 19 ++++++++++ .github/workflows/documentation.yml | 44 +++++++++++---------- README.md | 10 ++--- mypy.ini | 26 +++++++++++++ requirements-docs.txt | 4 +- src/utilities/__init__.py | 14 +++++++ src/utilities/resource_path.py | 59 +++++++++++++++++++++++++---- tests/unit/test_ui_controller.py | 5 ++- 10 files changed, 187 insertions(+), 44 deletions(-) create mode 100644 .flake8 create mode 100644 mypy.ini create mode 100644 src/utilities/__init__.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..2514377 --- /dev/null +++ b/.flake8 @@ -0,0 +1,36 @@ +[flake8] +max-line-length = 100 +exclude = + .git, + __pycache__, + build, + dist, + *.egg-info + .venv + venv + env + .env + .tox + .pytest_cache + .mypy_cache + .coverage + htmlcov + +per-file-ignores = + # Allow unused imports in __init__.py + __init__.py: F401 + # Allow long lines in test files + tests/*: E501 + +ignore = + # Allow line break before binary operator + W503 + # Allow line break after binary operator + W504 + # Allow multiple spaces around operators + E221 + E222 + # Allow multiple spaces after ',' + E241 + +max-complexity = 12 \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8ea509e..3de990d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,8 +4,8 @@ updates: directory: "/" schedule: interval: "weekly" - day: "monday" - time: "09:00" + day: "monday" + time: "09:00" open-pull-requests-limit: 10 target-branch: "main" labels: @@ -14,7 +14,6 @@ updates: reviewers: - "dsj7419" groups: - test-dependencies: patterns: - "pytest*" @@ -22,17 +21,15 @@ updates: - "flake8" - "black" - "mypy" - gui-dependencies: patterns: - "PyQt5*" commit-message: prefix: "deps" include: "scope" - ignore: - dependency-name: "PyQt5*" - update-types: ["version-update:semver-major"] + update-types: ["version-update:semver-major"] - package-ecosystem: "github-actions" directory: "/" @@ -52,11 +49,10 @@ updates: prefix: "ci" include: "scope" - - package-ecosystem: "pip" directory: "/docs" schedule: - interval: "monthly" s + interval: "monthly" labels: - "dependencies" - "documentation" @@ -64,4 +60,4 @@ updates: docs-dependencies: patterns: - "mkdocs*" - - "*-material*" \ No newline at end of file + - "*-material*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d565c86..e6f3e60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,3 +100,22 @@ jobs: files: ./tests/reports/coverage/coverage.xml fail_ci_if_error: true verbose: true + + - name: Create Test Report Directory + if: always() + run: mkdir -p tests/reports + + - name: Generate Test Summary + if: always() + run: | + echo "{\"success\": ${{ job.status == 'success' }}, \"timestamp\": \"$(date -u +'%Y-%m-%dT%H:%M:%SZ')\"}" > tests/reports/latest_results.json + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-results-${{ matrix.os }} + path: | + tests/reports/**/* + retention-days: 14 + if-no-files-found: warn diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 0456c39..5358af2 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -15,6 +15,7 @@ on: - "**.md" - "mkdocs.yml" - "requirements-docs.txt" + workflow_dispatch: # Allow manual triggers jobs: build: @@ -22,7 +23,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 # Fetch all history for proper versioning + fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 @@ -35,25 +36,30 @@ jobs: python -m pip install --upgrade pip pip install -r requirements-docs.txt - - name: Check documentation links + - name: Install git run: | - mkdocs build --strict + sudo apt-get update + sudo apt-get install -y git - - name: Deploy Documentation + - name: Configure Git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Build documentation + run: mkdocs build --strict --verbose + + - name: Deploy to GitHub Pages if: github.ref == 'refs/heads/main' && github.event_name == 'push' - uses: peaceiris/actions-gh-pages@v3 + run: | + mkdocs gh-deploy --force + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload documentation artifact + if: always() + uses: actions/upload-artifact@v3 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./site - commit_message: | - Deploy documentation updates - - Triggered by ${{ github.sha }} - user_name: "github-actions[bot]" - user_email: "github-actions[bot]@users.noreply.github.com" - full_commit_message: | - Deploy documentation updates - - Triggered by ${{ github.sha }} - Commit messages: - ${{ github.event.commits[0].message }} + name: documentation + path: site + retention-days: 14 diff --git a/README.md b/README.md index ede09f9..b79c6d1 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,17 @@ Ready to dive in? You have two options: Get the latest version of GynTree as a standalone application directly from the [Latest Release](https://github.com/dsj7419/GynTree/releases/latest). 2. **Install from Source**: - Check out our [Installation Guide](./assets/docs/guides/INSTALL.md) to get GynTree up and running from the source code on your system in no time! + Check out our [Installation Guide](./docs/getting-started/installation.md.md) to get GynTree up and running from the source code on your system in no time! ## 📖 Documentation -- [User Guide](./assets/docs/guides/user_guide.md): Learn how to use GynTree effectively. -- [Configuration](./assets/docs/guides/configuration.md): Customize GynTree to suit your needs. -- [API Reference](./assets/docs/api/api_reference.md): For developers looking to extend GynTree's functionality. +- [User Guide](./docs/guides/user_guide/basic_usage.md): Learn how to use GynTree effectively. +- [Configuration](./docs/user-guide/configuration.md): Customize GynTree to suit your needs. +- [API Reference](./docs/api/overview.md): For developers looking to extend GynTree's functionality. ## 🤝 Contributing -We welcome contributions from the community! Whether it's bug reports, feature requests, or code contributions, check out our [Contributing Guide](.github/CONTRIBUTING.md) to get started. +We welcome contributions from the community! Whether it's bug reports, feature requests, or code contributions, check out our [Contributing Guide](./docs/contributing/guidelines.md) to get started. ## 📜 License diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..2ae7e49 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,26 @@ +[mypy] +python_version = 3.12 +warn_return_any = True +warn_unused_configs = True +disallow_untyped_defs = True +disallow_incomplete_defs = True +check_untyped_defs = True +disallow_untyped_decorators = False +no_implicit_optional = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_no_return = True +warn_unreachable = True +strict_equality = True +explicit_package_bases = True + +# PyQt5 stubs handling +[mypy-PyQt5.*] +ignore_missing_imports = True + +# Third party libraries +[mypy-psutil.*] +ignore_missing_imports = True + +[mypy-pytest.*] +ignore_missing_imports = True \ No newline at end of file diff --git a/requirements-docs.txt b/requirements-docs.txt index da14036..9a38731 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,7 +1,9 @@ # Documentation mkdocs==1.5.3 mkdocs-material==9.5.3 +mkdocs-material-extensions>=1.3 mkdocs-awesome-pages-plugin==2.9.2 mkdocs-minify-plugin==0.7.1 mkdocs-git-revision-date-localized-plugin>=1.2.0 -mkdocs-material-extensions>=1.3 \ No newline at end of file +pymdown-extensions>=10.2 +pygments>=2.16 \ No newline at end of file diff --git a/src/utilities/__init__.py b/src/utilities/__init__.py new file mode 100644 index 0000000..42d3ec4 --- /dev/null +++ b/src/utilities/__init__.py @@ -0,0 +1,14 @@ +"""Utilities package for GynTree.""" + +from .resource_path import ResourcePathManager, get_resource_path +from .theme_manager import ThemeManager +from .error_handler import handle_exception +from .logging_decorator import log_method + +__all__ = [ + 'ResourcePathManager', + 'get_resource_path', + 'ThemeManager', + 'handle_exception', + 'log_method' +] \ No newline at end of file diff --git a/src/utilities/resource_path.py b/src/utilities/resource_path.py index 582fd8e..5f41989 100644 --- a/src/utilities/resource_path.py +++ b/src/utilities/resource_path.py @@ -1,15 +1,39 @@ +""" +Module for managing resource paths across different environments. +Handles both development and production (PyInstaller) environments. +""" + import os import sys from pathlib import Path +from typing import Optional class ResourcePathManager: - """Manages resource paths across different environments (dev/production)""" + """ + Manages resource paths across different environments (dev/production). + + Attributes: + _base_path (Path): Base path for resource resolution + + Properties: + base_path (Path): Read-only access to base path + """ - def __init__(self): - self._base_path = self._determine_base_path() + def __init__(self) -> None: + """Initialize the resource path manager.""" + self._base_path: Path = self._determine_base_path() def _determine_base_path(self) -> Path: - """Determine the base path for resources""" + """ + Determine the base path for resources. + + Returns: + Path: Base path for resource resolution + + Notes: + - Checks for PyInstaller bundle first + - Falls back to project root directory + """ try: # Check if running as PyInstaller bundle base_path = Path(sys._MEIPASS) @@ -23,9 +47,16 @@ def _determine_base_path(self) -> Path: def get_resource_path(self, relative_path: str) -> str: """ - Get absolute path to resource, works both for: - - Development - - PyInstaller bundles + Get absolute path to resource, works both for development and PyInstaller bundles. + + Args: + relative_path: Path relative to either src or root directory + + Returns: + str: Absolute path to the resource + + Raises: + FileNotFoundError: If resource cannot be found """ resource_path = self.base_path / relative_path @@ -42,11 +73,23 @@ def get_resource_path(self, relative_path: str) -> str: @property def base_path(self) -> Path: + """Get the base path for resource resolution.""" return self._base_path # Global instance _manager = ResourcePathManager() def get_resource_path(relative_path: str) -> str: - """Global function to get resource path""" + """ + Global function to get resource path. + + Args: + relative_path: Path relative to either src or root directory + + Returns: + str: Absolute path to the resource + + Raises: + FileNotFoundError: If resource cannot be found + """ return _manager.get_resource_path(relative_path) \ No newline at end of file diff --git a/tests/unit/test_ui_controller.py b/tests/unit/test_ui_controller.py index 62a84a5..6cc8fce 100644 --- a/tests/unit/test_ui_controller.py +++ b/tests/unit/test_ui_controller.py @@ -1,8 +1,9 @@ import logging import pytest -from PyQt5.QtCore import QMetaObject, Qt, QTimer -from PyQt5.QtWidgets import QMessageBox, QWidget +from typing import Any, Dict +from PyQt5.QtWidgets import QWidget +from unittest.mock import MagicMock, patch from controllers.UIController import UIController