Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
strategy:
matrix:
os: ["ubuntu-latest"]
version: ["3.9", "3.10", "3.11"]
version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- name: Checkout 🔖
uses: actions/checkout@v3
Expand Down
22 changes: 6 additions & 16 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.6.0
hooks:
- id: check-added-large-files
- id: check-ast
Expand All @@ -12,29 +12,19 @@ repos:
- id: check-json
- id: check-toml
- id: check-yaml
exclude: mkdocs.yml
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
exclude: test/data/schema/wrong_syntax.py
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.0.0
rev: v1.15.0
hooks:
- id: mypy
exclude: test/data/schema/wrong_syntax.py
- repo: https://github.com/dosisod/refurb
rev: v1.11.1
rev: v2.0.0
hooks:
- id: refurb
exclude: test/data/schema/wrong_syntax.py
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.0.247'
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.4
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/tcort/markdown-link-check
rev: 'v3.11.2'
hooks:
- id: markdown-link-check
args: [-q]
exclude: test/data/schema/wrong_syntax.py
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ While in this phase, we will denote breaking changes with a minor increase.

## 0.4.3

### Fixed
### Added

* Added support for python `3.12`

### Changed

* Bump all dependencies to the latest version and introduce necessary adaptation in the source code (affecting only `dac info`):
- `build~=0.9` -> `build==1.2.2`
- `toml~=0.10` -> `toml==0.10.2`
- `typer[all]~=0.7` -> `typer[all]==0.15.2`
- `wheel~=0.38` -> `wheel==0.45.1`
* Prevent installation with python > `3.11`
* Prevent installation with python > `3.12`

## 0.4.2

Expand Down
35 changes: 0 additions & 35 deletions mkdocs.yml

This file was deleted.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "dac"
dynamic = ["version"]
description = "Tool to distribute data as code"
readme = "README.md"
requires-python = ">=3.9,<3.12"
requires-python = ">=3.9,<3.13"
license = { text = "MIT" }
authors = [
{ name = "Francesco Calcavecchia", email = "francesco.calcavecchia@gmail.com" },
Expand Down
1 change: 0 additions & 1 deletion requirements-docs.txt

This file was deleted.

2 changes: 1 addition & 1 deletion src/dac/_input/pyproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ def generate_pyproject_toml(self) -> str:
def _get_list_of_project_dependencies(self) -> List[str]:
splitted_by_newline = self.project_dependencies.splitlines()
splitted_by_newline_or_comma = [s for ss in splitted_by_newline for s in ss.split(";")]
return sorted(map(lambda x: x.strip(), splitted_by_newline_or_comma))
return sorted(map(str.strip, splitted_by_newline_or_comma))
64 changes: 47 additions & 17 deletions src/dac/_version_management.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,60 @@
import tempfile
import re
import subprocess
from typing import Optional
from pathlib import Path


def find_latest_version(pkg_name: str, major: Optional[int] = None) -> str:
output = subprocess.check_output(
[
"pip",
"install",
"--no-deps",
"--ignore-installed",
"--no-cache-dir",
"--dry-run",
f"{pkg_name}{f'=={major}.*' if major is not None else ''}",
],
stderr=subprocess.DEVNULL,
pip_log = _pretend_pip_install(pkg_name=pkg_name, major=major)
would_install_line = _extract_would_install_line(pip_log=pip_log)
package_with_version = _extract_package_with_version(
pip_log_would_install_line=would_install_line, pkg_name=pkg_name, major=major
)
output_lines = output.decode("utf-8").splitlines()
would_install_line = [line for line in output_lines if "Would install" in line][0]
regex_rule = f"{pkg_name.replace('_', '-')}-{major if major is not None else ''}.[^ ]+"
match = re.search(regex_rule, would_install_line.replace("_", "-"))
assert match is not None
return match[0][len(f"{pkg_name}-") :]
return package_with_version[len(f"{pkg_name}-") :]


def increase_minor(version: str) -> str:
major, minor, patch = version.split(".")
assert major.isdigit() and minor.isdigit()
return f"{major}.{int(minor) + 1}.0"


def _pretend_pip_install(pkg_name: str, major: Optional[int]) -> str:
with tempfile.NamedTemporaryFile() as log_file:
result = subprocess.run(
[
"pip",
"install",
"--no-deps",
"--ignore-installed",
"--dry-run",
f"--log={log_file.name}",
f"{pkg_name}{f'=={major}.*' if major is not None else ''}",
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
if result.returncode != 0:
raise subprocess.SubprocessError(
f"Something went wrong while using pip to find the version of {pkg_name}{f'(major version {major})' if major else ''}.\n\nSTDOUT: {result.stdout}\n\nSTDERR: {result.stderr}"
)
return Path(log_file.name).read_text()


def _extract_would_install_line(pip_log: str) -> str:
would_install_lines = [line for line in pip_log.splitlines() if "Would install" in line]
assert (
len(would_install_lines) == 1
), f"Expected exactly one line containing 'Would install' in the pip log generated by pip installing the requested package, but found {len(would_install_lines)} lines."
return would_install_lines[0]


def _extract_package_with_version(pip_log_would_install_line: str, pkg_name: str, major: Optional[int]) -> str:
regex_rule = f"{pkg_name.replace('_', '-')}-{major if major is not None else ''}.[^ ]+"
match = re.search(regex_rule, pip_log_would_install_line.replace("_", "-"))
assert (
match is not None and match[0] != ""
), f"It was not possible to determine the version, because we could not find a match to the regex {regex_rule} in {pip_log_would_install_line.replace('_', '-')}"
return match[0]
6 changes: 3 additions & 3 deletions test/integration_test/version_management_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def test_if_find_latest_version_is_called_then_return_latest_version():


def test_if_find_latest_version_is_called_with_major_constraint_then_return_latest_major_version():
assert "0.25.3" == find_latest_version(pkg_name="pandas", major=0)
assert "1.5.3" == find_latest_version(pkg_name="pandas", major=1)


def test_if_pkg_does_not_exist_then_find_package_raises_exception():
Expand All @@ -23,5 +23,5 @@ def test_if_next_version_without_major_spec_then_return_latest_version_with_mino


def test_if_next_version_with_major_spec_then_return_minor_upgrade_for_that_major():
result = invoke_dac_next_version(pkg_name="pandas", major=0)
assert result.stdout == "0.26.0\n"
result = invoke_dac_next_version(pkg_name="pandas", major=1)
assert result.stdout == "1.6.0\n"
4 changes: 2 additions & 2 deletions test/unit_test/_packing/data_as_code_project_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_if_project_init_is_inspected_then_load_and_schema_is_found():
def test_if_project_load_is_inspected_then_has_same_content_as_original():
with input_with_self_contained_data() as config:
with data_as_code_project(config=config) as proj_dir:
project_load_path = proj_dir / "src" / config.pyproject.project_name / f"{DaCProjectFactory.load_file_name}"
project_load_path = proj_dir / "src" / config.pyproject.project_name / str(DaCProjectFactory.load_file_name)
assert project_load_path.exists()
assert filecmp.cmp(config.load_path, project_load_path)

Expand All @@ -41,7 +41,7 @@ def test_if_project_schema_is_inspected_then_has_same_content_as_original():
with input_with_self_contained_data() as config:
with data_as_code_project(config=config) as proj_dir:
project_schema_path = (
proj_dir / "src" / config.pyproject.project_name / f"{DaCProjectFactory.schema_file_name}"
proj_dir / "src" / config.pyproject.project_name / str(DaCProjectFactory.schema_file_name)
)
assert project_schema_path.exists()
assert filecmp.cmp(config.schema_path, project_schema_path)
Expand Down
56 changes: 21 additions & 35 deletions test/unit_test/_version_management/find_latest_test.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,40 @@
import subprocess
from test.data import get_pip_log_with_dash, get_pip_log_with_underscore
from unittest.mock import MagicMock
from unittest.mock import patch

from dac._version_management import find_latest_version
from pytest import MonkeyPatch, fixture


def test_if_pkg_name_uses_dash_separator_and_pip_log_dash_then_correct_latest_version(mock_pip_output_with_dash: None):
latest_version = find_latest_version(pkg_name="investing-algorithm-framework")
assert latest_version == "2.3.2"
def test_if_pkg_name_uses_dash_separator_and_pip_log_dash_then_correct_latest_version():
with patch("dac._version_management._pretend_pip_install") as mock_pretend_pip_install:
mock_pretend_pip_install.return_value = get_pip_log_with_dash()

latest_version = find_latest_version(pkg_name="investing-algorithm-framework")

def test_if_pkg_name_uses_dash_separator_and_pip_log_underscore_then_correct_latest_version(
mock_pip_output_with_underscore: None,
):
latest_version = find_latest_version(pkg_name="investing-algorithm-framework")
assert latest_version == "2.3.2"
assert latest_version == "2.3.2"


def test_if_pkg_name_uses_underscore_separator_and_pip_log_dash_then_correct_latest_version(
mock_pip_output_with_dash: None,
):
latest_version = find_latest_version(pkg_name="investing_algorithm_framework")
assert latest_version == "2.3.2"
def test_if_pkg_name_uses_dash_separator_and_pip_log_underscore_then_correct_latest_version():
with patch("dac._version_management._pretend_pip_install") as mock_pretend_pip_install:
mock_pretend_pip_install.return_value = get_pip_log_with_underscore()

latest_version = find_latest_version(pkg_name="investing-algorithm-framework")

def test_if_pkg_name_uses_underscore_separator_and_pip_log_underscore_then_correct_latest_version(
mock_pip_output_with_underscore: None,
):
latest_version = find_latest_version(pkg_name="investing_algorithm_framework")
assert latest_version == "2.3.2"
assert latest_version == "2.3.2"


@fixture
def mock_pip_output_with_dash(monkeypatch: MonkeyPatch):
output = MagicMock()
output.decode.return_value = get_pip_log_with_dash()
def test_if_pkg_name_uses_underscore_separator_and_pip_log_dash_then_correct_latest_version():
with patch("dac._version_management._pretend_pip_install") as mock_pretend_pip_install:
mock_pretend_pip_install.return_value = get_pip_log_with_dash()

def return_foo(*args, **kwargs) -> str:
return output
latest_version = find_latest_version(pkg_name="investing_algorithm_framework")

monkeypatch.setattr(subprocess, "check_output", return_foo)
assert latest_version == "2.3.2"


@fixture
def mock_pip_output_with_underscore(monkeypatch: MonkeyPatch):
output = MagicMock()
output.decode.return_value = get_pip_log_with_underscore()
def test_if_pkg_name_uses_underscore_separator_and_pip_log_underscore_then_correct_latest_version():
with patch("dac._version_management._pretend_pip_install") as mock_pretend_pip_install:
mock_pretend_pip_install.return_value = get_pip_log_with_underscore()

def return_foo(*args, **kwargs) -> str:
return output
latest_version = find_latest_version(pkg_name="investing_algorithm_framework")

monkeypatch.setattr(subprocess, "check_output", return_foo)
assert latest_version == "2.3.2"