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
4 changes: 2 additions & 2 deletions src/odoo_addons_path/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .cli import app
from .main import get_addons_path
from .main import detect_codebase_layout, get_addons_path, get_odoo_version_from_release

__all__ = ["app", "get_addons_path"]
__all__ = ["app", "detect_codebase_layout", "get_addons_path", "get_odoo_version_from_release"]
23 changes: 18 additions & 5 deletions src/odoo_addons_path/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from pathlib import Path

import typer
Expand All @@ -15,7 +16,7 @@ def _add_to_path(path_list: list[str], dirs_to_add: list[Path], is_sorted: bool
path_list.append(resolved_path)


def _detect_codebase_layout(codebase: Path, verbose: bool = False) -> dict:
def detect_codebase_layout(codebase: Path, verbose: bool = False) -> dict:
trobz = TrobzDetector()
c2c = C2CDetector()
odoo_sh = OdooShDetector()
Expand All @@ -32,6 +33,18 @@ def _detect_codebase_layout(codebase: Path, verbose: bool = False) -> dict:
return detected_paths


def get_odoo_version_from_release(odoo_dir: Path) -> str | None:
"""Read the Odoo version (e.g. '18.0') from ``odoo/release.py``."""
release_py = odoo_dir / "odoo" / "release.py"
if not release_py.is_file():
return None
content = release_py.read_text()
match = re.search(r"version_info\s*=\s*\((\d+),\s*(\d+)", content)
if match:
return f"{match.group(1)}.{match.group(2)}"
return None


def _process_paths(
all_paths: dict[str, list[str]],
detected_paths: dict,
Expand Down Expand Up @@ -73,18 +86,18 @@ def get_addons_path(
addons_dir: list[Path] | None = None,
odoo_dir: Path | None = None,
verbose: bool = False,
detected_paths: dict | None = None,
) -> str:
all_paths: dict[str, list[str]] = {
"odoo_dir": [],
"addon_repositories": [],
}

detected_paths = {}
# Skip detector only if both paths are None (no explicit paths provided)
if not addons_dir and not odoo_dir:
detected_paths = _detect_codebase_layout(codebase, verbose)
if detected_paths is None and not addons_dir and not odoo_dir:
detected_paths = detect_codebase_layout(codebase, verbose)

_process_paths(all_paths, detected_paths, addons_dir, odoo_dir)
_process_paths(all_paths, detected_paths or {}, addons_dir, odoo_dir)

result = [path for paths in all_paths.values() for path in paths]
addons_path = ",".join(result)
Expand Down
49 changes: 48 additions & 1 deletion tests/test_get_addons_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pytest

from odoo_addons_path.main import get_addons_path
from odoo_addons_path.main import detect_codebase_layout, get_addons_path, get_odoo_version_from_release


@pytest.fixture
Expand Down Expand Up @@ -72,3 +72,50 @@ def test_layouts(base_dir: Path, layout: str, expected_paths: list[str]):
result = get_addons_path(base_dir)

assert result == expected_addons_path


@pytest.mark.parametrize("layout", ["trobz", "c2c", "doodba", "odoo-sh"])
def test_detect_codebase_layout(base_dir: Path, layout: str):
shutil.copytree(Path(__file__).parent / "data" / layout, base_dir, dirs_exist_ok=True)

result = detect_codebase_layout(base_dir)

assert isinstance(result, dict)
assert "odoo_dir" in result or "addons_dirs" in result or "addons_dir" in result


def test_get_odoo_version_from_release(tmp_path: Path):
release_dir = tmp_path / "odoo"
release_dir.mkdir()
release_py = release_dir / "release.py"
release_py.write_text("version_info = (18, 0, 0, 'final', 0)\nversion = '18.0'\n")

result = get_odoo_version_from_release(tmp_path)

assert result == "18.0"


def test_get_odoo_version_from_release_missing(tmp_path: Path):
result = get_odoo_version_from_release(tmp_path)

assert result is None


def test_get_odoo_version_from_release_no_version_info(tmp_path: Path):
release_dir = tmp_path / "odoo"
release_dir.mkdir()
(release_dir / "release.py").write_text("# no version_info here\n")

result = get_odoo_version_from_release(tmp_path)

assert result is None


def test_get_addons_path_with_detected_paths(base_dir: Path):
shutil.copytree(Path(__file__).parent / "data" / "trobz", base_dir, dirs_exist_ok=True)

detected = detect_codebase_layout(base_dir)
result_auto = get_addons_path(base_dir)
result_predetected = get_addons_path(base_dir, detected_paths=detected)

assert result_auto == result_predetected