Skip to content
Closed
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
58 changes: 58 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Testing
.pytest_cache/
.coverage
htmlcov/
coverage.xml
.tox/

# Claude settings
.claude/

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
282 changes: 282 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[tool.poetry]
name = "odoo-stubs"
version = "0.0.1"
description = "Type stubs for Odoo"
authors = ["Trinh Anh Ngoc <[email protected]>"]
readme = "README.md"
homepage = "https://github.com/odoo-ide/odoo-stubs"
repository = "https://github.com/odoo-ide/odoo-stubs"
packages = [{include = "odoo-stubs"}]

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.group.dev.dependencies]
pytest = "^7.0"
pytest-cov = "^4.0"
pytest-mock = "^3.10"


[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--cov=odoo-stubs",
"--cov-report=term-missing",
"--cov-report=html",
"--cov-report=xml",
"--cov-fail-under=80"
]
markers = [
"unit: marks tests as unit tests (fast)",
"integration: marks tests as integration tests (slower)",
"slow: marks tests as slow tests"
]

[tool.coverage.run]
source = ["odoo-stubs"]
omit = [
"tests/*",
"setup.py",
"*/__pycache__/*",
"*/migrations/*",
"*/venv/*",
"*/.venv/*"
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:"
]
show_missing = true
skip_covered = false

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
80 changes: 80 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import pytest
import tempfile
import shutil
from pathlib import Path
from typing import Generator


@pytest.fixture
def temp_dir() -> Generator[Path, None, None]:
"""Provide a temporary directory that gets cleaned up after test."""
temp_path = Path(tempfile.mkdtemp())
try:
yield temp_path
finally:
shutil.rmtree(temp_path, ignore_errors=True)


@pytest.fixture
def sample_stub_content():
"""Provide sample stub file content for testing."""
return '''
from typing import Any, Optional

class Model:
def __init__(self) -> None: ...
def create(self, vals: dict[str, Any]) -> "Model": ...
def search(self, domain: list[tuple[str, str, Any]]) -> "Model": ...
def write(self, vals: dict[str, Any]) -> bool: ...
def unlink(self) -> bool: ...

def browse(self, ids: list[int]) -> "Model": ...
'''.strip()


@pytest.fixture
def mock_odoo_env(monkeypatch):
"""Mock basic Odoo environment for testing."""
class MockEnv:
def __init__(self):
self.cr = MockCursor()
self.uid = 1
self.context = {}

def __getitem__(self, model_name):
return MockModel(model_name)

class MockCursor:
def execute(self, query, params=None):
pass

def fetchall(self):
return []

def fetchone(self):
return None

class MockModel:
def __init__(self, name):
self._name = name

def create(self, vals):
return self

def search(self, domain):
return self

def browse(self, ids):
return self

mock_env = MockEnv()
monkeypatch.setattr("odoo.api.Environment", lambda: mock_env)
return mock_env


@pytest.fixture
def stub_file(temp_dir, sample_stub_content):
"""Create a temporary stub file for testing."""
stub_file = temp_dir / "test_model.pyi"
stub_file.write_text(sample_stub_content)
return stub_file
Empty file added tests/integration/__init__.py
Empty file.
67 changes: 67 additions & 0 deletions tests/test_infrastructure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pytest
from pathlib import Path


def test_stub_files_exist():
"""Test that stub files are present in the project."""
stub_dir = Path("odoo-stubs")
assert stub_dir.exists(), "odoo-stubs directory should exist"
assert stub_dir.is_dir(), "odoo-stubs should be a directory"

# Check for key stub files
key_files = ["__init__.pyi", "models.pyi", "fields.pyi", "api.pyi"]
for file_name in key_files:
stub_file = stub_dir / file_name
assert stub_file.exists(), f"{file_name} should exist in odoo-stubs"


def test_imports_work():
"""Test that basic imports work without errors."""
try:
import sys
sys.path.insert(0, str(Path.cwd()))
# This should not raise any import errors
assert True
except ImportError as e:
pytest.fail(f"Import failed: {e}")


@pytest.mark.unit
def test_temp_dir_fixture(temp_dir):
"""Test the temp_dir fixture works correctly."""
assert temp_dir.exists()
assert temp_dir.is_dir()

# Create a test file in temp dir
test_file = temp_dir / "test.txt"
test_file.write_text("test content")
assert test_file.read_text() == "test content"


@pytest.mark.unit
def test_sample_stub_content_fixture(sample_stub_content):
"""Test the sample_stub_content fixture provides valid content."""
assert isinstance(sample_stub_content, str)
assert "class Model:" in sample_stub_content
assert "def create(" in sample_stub_content


@pytest.mark.unit
def test_stub_file_fixture(stub_file):
"""Test the stub_file fixture creates a valid file."""
assert stub_file.exists()
assert stub_file.suffix == ".pyi"
assert "class Model:" in stub_file.read_text()


def test_project_structure():
"""Test that the project has the expected structure."""
# Check key directories exist
assert Path("odoo-stubs").exists()
assert Path("tests").exists()
assert Path("tests/unit").exists()
assert Path("tests/integration").exists()

# Check configuration files
assert Path("pyproject.toml").exists()
assert Path("setup.py").exists()
Empty file added tests/unit/__init__.py
Empty file.