From 3f83fa07f8e88c84087eb7c187ad3243d3d0a8a7 Mon Sep 17 00:00:00 2001 From: resulyurttakalan Date: Wed, 15 Mar 2023 19:24:31 +0300 Subject: [PATCH 1/2] - bump version to 0.1.5 - add assocation table support - add new tests for m2m relationship - upgrade isort pre-commit hook version --- .pre-commit-config.yaml | 2 +- pytest_sqlalchemy_mock/model_mocker.py | 18 +++++++-------- requirements-dev.txt | 3 +-- setup.py | 2 +- tests/conftest.py | 6 ++++- tests/data.py | 22 ++++++++++++++++++ tests/db.py | 32 ++++++++++++++++++++++++-- tests/test_pytest_sqlalchemy_mock.py | 26 +++++++++++++++++---- 8 files changed, 90 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eafbbe9..55400ec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: exclude: '.*\.pth$' - id: debug-statements - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/PyCQA/flake8 diff --git a/pytest_sqlalchemy_mock/model_mocker.py b/pytest_sqlalchemy_mock/model_mocker.py index f414037..097d2f8 100644 --- a/pytest_sqlalchemy_mock/model_mocker.py +++ b/pytest_sqlalchemy_mock/model_mocker.py @@ -5,6 +5,7 @@ if TYPE_CHECKING: from typing import List, Tuple + from sqlalchemy import Table from sqlalchemy.orm import Session MOCK_CONFIG_TYPE = List[Tuple[str, List]] @@ -19,18 +20,15 @@ def __init__(self, session: Session, base, mock_config: MOCK_CONFIG_TYPE): self._base = base self._mock_config = mock_config - def get_model_class_with_table_name(self, table_name: str): - for mapper in self._base.registry.mappers: - cls = mapper.class_ - if cls.__tablename__ == table_name: - return cls + def get_table_by_name(self, table_name: str) -> Table: + return self._base.metadata.tables.get(table_name) def create_all(self): for model_config in self._mock_config: table_name, data = model_config - model_class = self.get_model_class_with_table_name(table_name) - if model_class: + table = self.get_table_by_name(table_name) + + if table is not None: for datum in data: - instance = model_class(**datum) - self._session.add(instance) - self._session.commit() + instance = table.insert().values(**datum) + self._session.execute(instance) diff --git a/requirements-dev.txt b/requirements-dev.txt index fd6536e..51432d5 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,5 @@ -sqlalchemy +sqlalchemy==2.0.6 flake8 pytest pytest-cov pre-commit -sqlalchemy diff --git a/setup.py b/setup.py index 6314ee1..a187d20 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def read(fname): description="pytest sqlalchemy plugin for mock", long_description=read("README.md"), long_description_content_type="text/markdown", - version="0.1.4", + version="0.1.5", author="Resul Yurttakalan", author_email="resulyrt93@gmail.com", url="https://github.com/resulyrt93/pytest-sqlalchemy-mock", diff --git a/tests/conftest.py b/tests/conftest.py index fcbc4f9..fc5c081 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,4 +11,8 @@ def sqlalchemy_declarative_base(): @pytest.fixture(scope="function") def sqlalchemy_mock_config(): - return [("user", MockData.USER_DATA)] + return [ + ("user", MockData.USER_DATA), + ("department", MockData.DEPARTMENT_DATA), + ("user_department", MockData.USER_DEPARTMENT_DATA), + ] diff --git a/tests/data.py b/tests/data.py index e3ff5f8..0408730 100644 --- a/tests/data.py +++ b/tests/data.py @@ -20,3 +20,25 @@ class MockData: "join_date": datetime(2009, 11, 20, 21, 3, 12), }, ] + + DEPARTMENT_DATA = [ + { + "id": 1, + "name": "Accounting", + }, + { + "id": 2, + "name": "Sales", + }, + ] + + USER_DEPARTMENT_DATA = [ + { + "user_id": 1, + "department_id": 1, + }, + { + "user_id": 2, + "department_id": 2, + }, + ] diff --git a/tests/db.py b/tests/db.py index 666590c..f84544e 100644 --- a/tests/db.py +++ b/tests/db.py @@ -1,9 +1,23 @@ -from sqlalchemy import Boolean, Column, DateTime, Integer, String, func -from sqlalchemy.orm import declarative_base +from typing import List + +from sqlalchemy import (Boolean, Column, DateTime, ForeignKey, Integer, String, + func) +from sqlalchemy.orm import Mapped, declarative_base, relationship +from sqlalchemy.testing.schema import Table Base = declarative_base() +user_department_association_table = Table( + "user_department", + Base.metadata, + Column("user_id", Integer, ForeignKey("user.id"), primary_key=True), + Column( + "department_id", Integer, ForeignKey("department.id"), primary_key=True + ), +) + + class User(Base): __tablename__ = "user" @@ -13,3 +27,17 @@ class User(Base): is_admin = Column(Boolean, default=False) city = Column(String) join_date = Column(DateTime(timezone=True), server_default=func.now()) + departments: Mapped[List["Department"]] = relationship( + secondary=user_department_association_table, back_populates="users" + ) + + +class Department(Base): + __tablename__ = "department" + + id = Column(Integer, primary_key=True) + name = Column(String) + users: Mapped[List[User]] = relationship( + secondary=user_department_association_table, + back_populates="departments", + ) diff --git a/tests/test_pytest_sqlalchemy_mock.py b/tests/test_pytest_sqlalchemy_mock.py index c0d2fb0..8992fe8 100644 --- a/tests/test_pytest_sqlalchemy_mock.py +++ b/tests/test_pytest_sqlalchemy_mock.py @@ -1,17 +1,26 @@ +from sqlalchemy import text + from .data import MockData -from .db import User +from .db import Department, User def test_get_session(session): - assert session.execute("SELECT 5").scalar() == 5 + assert session.execute(text("SELECT 5")).scalar() == 5 def test_session_user_table(session): - assert session.execute("SELECT count(*) from user").scalar() == 0 + assert session.execute(text("SELECT count(*) from user")).scalar() == 0 + + +def test_session_query_for_assocation_table(session): + assert ( + session.execute(text("SELECT count(*) from user_department")).scalar() + == 0 + ) def test_mocked_session_user_table(mocked_session): - user_data = mocked_session.execute("SELECT * from user;").first() + user_data = mocked_session.execute(text("SELECT * from user;")).first() raw_data = MockData.USER_DATA[0] assert user_data[0] == raw_data["id"] assert user_data[1] == raw_data["name"] @@ -25,3 +34,12 @@ def test_mocked_session_user_model(mocked_session): raw_data = MockData.USER_DATA[1] assert user.name == raw_data["name"] assert user.is_admin == raw_data["is_admin"] + assert user.departments[0].name == "Sales" + + +def test_mocked_session_department_model(mocked_session): + department = mocked_session.query(Department).filter_by(id=1).first() + raw_data = MockData.DEPARTMENT_DATA[0] + assert department.name == raw_data["name"] + assert len(department.users) == 1 + assert department.users[0].name == "Kevin" From 974789fd3730fb42a67aa528447cdcf533629836 Mon Sep 17 00:00:00 2001 From: resulyurttakalan Date: Wed, 15 Mar 2023 19:37:13 +0300 Subject: [PATCH 2/2] - remove python 3.7 support --- .github/workflows/tests.yaml | 2 +- setup.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 0831fd4..867a9b8 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.7", "3.8", "3.9", "3.10" ] + python-version: [ "3.8", "3.9", "3.10" ] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} diff --git a/setup.py b/setup.py index a187d20..86118d9 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,6 @@ def read(fname): "Topic :: Software Development :: Testing", "Intended Audience :: Developers", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10",