diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d7829c..f9e08e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,30 +23,35 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -e ".[dev]" - pip install sphinx + uv sync --extra dev + uv pip install sphinx - name: Run linting (flake8) run: | - make lint + uv run make lint - name: Run core tests run: | # Run core tests only (excluding extra modules) - python -m unittest discover -s tests -p "test_*.py" -v | grep -v "extra\." || true + uv run python -m unittest discover -s tests -p "test_*.py" -v | grep -v "extra\." || true - name: Run tests without mypy run: | # Run make test but ignore mypy failures - flake8 ioc/ tests/ - python -m unittest discover -s tests -p "test_*.py" 2>&1 | grep -v "extra\." || echo "Some tests may require optional dependencies" - sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html || true + uv run flake8 ioc/ tests/ + uv run python -m unittest discover -s tests -p "test_*.py" 2>&1 | grep -v "extra\." || echo "Some tests may require optional dependencies" + uv run sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html || true - name: Run tests with type checking (optional) run: | - make test-strict || echo "Type checking found issues (this is optional)" + uv run make test-strict || echo "Type checking found issues (this is optional)" continue-on-error: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c6b963a..486a486 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,16 +23,21 @@ jobs: with: python-version: '3.11' + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install build dependencies run: | - python -m pip install --upgrade pip - pip install build twine + uv pip install build twine - name: Build package run: | - python -m build + uv run python -m build - name: Check package run: | - twine check dist/* + uv run twine check dist/* \ No newline at end of file diff --git a/.github/workflows/test-matrix.yml b/.github/workflows/test-matrix.yml index cb8c890..07209dd 100644 --- a/.github/workflows/test-matrix.yml +++ b/.github/workflows/test-matrix.yml @@ -30,22 +30,27 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install core dependencies run: | - python -m pip install --upgrade pip - pip install -e . + uv sync - name: Run core tests run: | - python -m unittest discover -s tests/ioc_test -p "test_*.py" -v + uv run python -m unittest discover -s tests/ioc_test -p "test_*.py" -v - name: Install dev dependencies run: | - pip install -e ".[dev]" + uv sync --extra dev - name: Run linting run: | - flake8 ioc/ tests/ + uv run flake8 ioc/ tests/ - name: Summary if: always() diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b46de26..4c398bc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,18 +21,23 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -e ".[dev]" + uv sync --extra dev - name: Run flake8 run: | - flake8 ioc/ tests/ + uv run flake8 ioc/ tests/ - name: Run mypy (optional) run: | - mypy ioc/ || true + uv run mypy ioc/ || true continue-on-error: true test-core: @@ -49,15 +54,20 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install core dependencies run: | - python -m pip install --upgrade pip - pip install -e . + uv sync - name: Run core tests (excluding extras) run: | # Run only core tests, excluding extra package tests - python -m unittest discover -s tests -p "test_*.py" -v 2>&1 | grep -v "extra\." | tee test_output.txt + uv run python -m unittest discover -s tests -p "test_*.py" -v 2>&1 | grep -v "extra\." | tee test_output.txt # Check results if grep -q "FAILED" test_output.txt; then @@ -86,10 +96,15 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install dependencies with ${{ matrix.extras }} run: | - python -m pip install --upgrade pip - pip install -e ".[${{ matrix.extras }}]" + uv sync --extra ${{ matrix.extras }} - name: Check if extras tests exist and dependencies are available id: check_tests @@ -132,7 +147,7 @@ jobs: - name: Run tests for ${{ matrix.extras }} if: steps.check_tests.outputs.should_run == 'true' run: | - python -m unittest discover -s $(echo "${{ matrix.test_module }}" | tr '.' '/') -p "test_*.py" -v + uv run python -m unittest discover -s $(echo "${{ matrix.test_module }}" | tr '.' '/') -p "test_*.py" -v continue-on-error: true test-all-extras: @@ -149,10 +164,15 @@ jobs: with: python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install all dependencies run: | - python -m pip install --upgrade pip - pip install -e ".[flask,jinja2,redis,dev]" + uv sync --extra flask --extra jinja2 --extra redis --extra dev - name: Create smart test runner run: | @@ -222,7 +242,7 @@ jobs: - name: Run all tests with smart error handling run: | - python smart_test_runner.py + uv run python smart_test_runner.py docs: runs-on: ubuntu-latest @@ -235,15 +255,20 @@ jobs: with: python-version: '3.11' + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -e . - pip install sphinx + uv sync + uv pip install sphinx - name: Build documentation run: | - sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html + uv run sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html - name: Upload documentation artifacts uses: actions/upload-artifact@v4 @@ -263,15 +288,21 @@ jobs: with: python-version: '3.11' + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + cache-dependency-glob: "pyproject.toml" + - name: Install build dependencies run: | - python -m pip install --upgrade pip - pip install build twine + uv sync + uv pip install build twine - name: Build package run: | - python -m build + uv run python -m build - name: Check package run: | - twine check dist/* + uv run twine check dist/* diff --git a/Makefile b/Makefile index ae21410..d23aff2 100755 --- a/Makefile +++ b/Makefile @@ -1,40 +1,42 @@ all: build -build: clean - pip install build twine +build-install: + uv pip install build twine flake8 sphinx + +build: build-install clean rm -rf dist/ - python -m build - twine check dist/* + uv run python -m build + uv run twine check dist/* -upload-prod: build +upload-prod: build-install build export TWINE_USERNAME=__token__ - bash -c 'read -s -p "Enter your Production PyPI token: " TWINE_PASSWORD; echo; export TWINE_PASSWORD; python -m twine upload dist/*' + bash -c 'read -s -p "Enter your Production PyPI token: " TWINE_PASSWORD; echo; export TWINE_PASSWORD; uv run twine upload dist/*' -upload-test: build +upload-test: build-install build export TWINE_USERNAME=__token__ - bash -c 'read -s -p "Enter your Test PyPI token: " TWINE_PASSWORD; echo; export TWINE_PASSWORD; python -m twine upload --repository testpypi dist/*' + bash -c 'read -s -p "Enter your Test PyPI token: " TWINE_PASSWORD; echo; export TWINE_PASSWORD; uv run twine upload --repository testpypi dist/*' clean: rm -rf build/ dist/ *.egg-info/ __pycache__/ .pytest_cache/ .mypy_cache/ find . -type f -name "*.pyc" -delete find . -type d -name "__pycache__" -delete -test: - flake8 ioc/ tests/ - python -m unittest discover -s tests -p "test_*.py" - sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html +test: build-install + uv run flake8 ioc/ tests/ + uv run python -m unittest discover -s tests -p "test_*.py" + LC_ALL=C.UTF-8 LANG=C.UTF-8 uv run sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html -test-strict: - flake8 ioc/ tests/ - mypy ioc/ - python -m unittest discover -s tests -p "test_*.py" - sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html +test-strict: build-install + uv run flake8 ioc/ tests/ + uv run mypy ioc/ + uv run python -m unittest discover -s tests -p "test_*.py" + LC_ALL=C.UTF-8 LANG=C.UTF-8 uv run sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html -lint: - flake8 ioc/ tests/ +lint: build-install + uv run flake8 ioc/ tests/ -typecheck: - mypy ioc/ +typecheck: build-install + uv run mypy ioc/ -unittest: - python -m unittest discover -s tests -p "test_*.py" -v +unittest: build-install + uv run python -m unittest discover -s tests -p "test_*.py" -v diff --git a/ioc/loader.py b/ioc/loader.py index f3cb0ea..cbec85f 100644 --- a/ioc/loader.py +++ b/ioc/loader.py @@ -17,19 +17,16 @@ import yaml from ioc.component import Definition, Reference, WeakReference, ContainerBuilder -import ioc.helper import ioc.exceptions -from . import misc - -from .misc import OrderedDictYAMLLoader +import ioc.misc class Loader(object): - def fix_config(self, config: dict[str, Any]) -> 'ioc.helper.Dict': + def fix_config(self, config: dict[str, Any]) -> 'ioc.misc.Dict': for key, value in config.items(): if isinstance(value, dict): config[key] = self.fix_config(value) - return ioc.helper.Dict(config) + return ioc.misc.Dict(config) class YamlLoader(Loader): def support(self, file: str) -> bool: @@ -42,7 +39,7 @@ def load(self, file: str, container_builder: ContainerBuilder) -> None: content = f.read() try: - data = yaml.load(content, OrderedDictYAMLLoader) + data = yaml.load(content, ioc.misc.OrderedDictYAMLLoader) except yaml.scanner.ScannerError as e: raise ioc.exceptions.LoadingError("file %s, \nerror: %s" % (file, e)) @@ -109,23 +106,23 @@ def load(self, file: str, container_builder: ContainerBuilder) -> None: container_builder.add(id, definition) def set_reference(self, value: Any) -> Any: - if misc.is_scalar(value) and value[0:1] == '@': + if ioc.misc.is_string(value) and value[0:1] == '@': if '#' in value: id, method = value.split("#") return Reference(id[1:], method) return Reference(value[1:]) - if misc.is_scalar(value) and value[0:2] == '#@': + if ioc.misc.is_string(value) and value[0:2] == '#@': return WeakReference(value[2:]) - if misc.is_iterable(value): + if ioc.misc.is_iterable(value): return self.set_references(value) return value def set_references(self, arguments: Union[list[Any], dict[str, Any]]) -> Union[list[Any], dict[str, Any]]: - for pos in misc.get_keys(arguments): + for pos in ioc.misc.get_keys(arguments): arguments[pos] = self.set_reference(arguments[pos]) return arguments diff --git a/ioc/misc.py b/ioc/misc.py index ae7b776..8cd10c5 100644 --- a/ioc/misc.py +++ b/ioc/misc.py @@ -64,7 +64,7 @@ def deepcopy(value: Any) -> Any: return value -def is_scalar(value: Any) -> bool: +def is_string(value: Any) -> bool: return isinstance(value, (str)) def is_iterable(value: Any) -> bool: