pax_global_header00006660000000000000000000000064145672062230014521gustar00rootroot0000000000000052 comment=f8379271f6341e73b63343fab3cd8d82c7e1e386 sphinx-sqlalchemy-0.3.0/000077500000000000000000000000001456720622300151725ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/.github/000077500000000000000000000000001456720622300165325ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/.github/dependabot.yml000066400000000000000000000011301456720622300213550ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: github-actions directory: / commit-message: prefix: ⬆️ schedule: interval: monthly - package-ecosystem: pip directory: / commit-message: prefix: ⬆️ schedule: interval: monthly sphinx-sqlalchemy-0.3.0/.github/workflows/000077500000000000000000000000001456720622300205675ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/.github/workflows/tests.yml000066400000000000000000000043531456720622300224610ustar00rootroot00000000000000name: CI on: push: branches: [main] tags: - 'v*' pull_request: jobs: pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.8" - uses: pre-commit/action@v3.0.0 tests: name: tests on py${{ matrix.python-version }} with sphinx~=${{ matrix.sphinx-version }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] sphinx-version: ["7.0"] os: ['ubuntu-latest'] include: - python-version: "3.8" sphinx-version: "5.0" os: 'ubuntu-latest' - python-version: "3.8" sphinx-version: "6.0" os: 'ubuntu-latest' steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install sphinx~=${{ matrix.sphinx-version }} -e .[dev] - name: Test with pytest run: pytest -vv --cov=sphinx_sqlalchemy env: SQLALCHEMY_WARN_20: 1 all-good: # This job does nothing and is only used for the branch protection # see https://github.com/marketplace/actions/alls-green#why if: always() needs: - pre-commit - tests runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} publish: name: Publish to PyPi needs: [pre-commit, tests] if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') runs-on: ubuntu-latest steps: - name: Checkout source uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: 3.8 - name: install flit run: | pip install flit~=3.4 - name: Build and publish run: | flit publish env: FLIT_USERNAME: __token__ FLIT_PASSWORD: ${{ secrets.PYPI_KEY }} sphinx-sqlalchemy-0.3.0/.gitignore000066400000000000000000000034301456720622300171620ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ .vscode/ .idea/ sphinx-sqlalchemy-0.3.0/.pre-commit-config.yaml000066400000000000000000000023141456720622300214530ustar00rootroot00000000000000ci: autoupdate_schedule: monthly autofix_prs: true exclude: &exclude_files > (?x)^( performance-benchmarks/.*/.*\.py )$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: check-json - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: - id: isort - repo: https://github.com/asottile/pyupgrade rev: v3.15.0 hooks: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/psf/black rev: 24.1.1 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.2.0 hooks: - id: ruff # - repo: https://github.com/PyCQA/flake8 # rev: '6.1.0' # hooks: # - id: flake8 # additional_dependencies: # - flake8-bugbear==20.1.4 # - flake8-builtins==1.5.3 # - flake8-comprehensions==3.2.3 # - flake8-rst-docstrings==0.0.14 # - flake8-markdown==0.2.0 - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.8.0 hooks: - id: mypy additional_dependencies: - "sqlalchemy[mypy]==1.4.22" files: ^(sphinx_sqlalchemy/.*py)$ sphinx-sqlalchemy-0.3.0/.readthedocs.yml000066400000000000000000000003071456720622300202600ustar00rootroot00000000000000version: 2 build: os: ubuntu-22.04 tools: python: "3.8" python: install: - method: pip path: . extra_requirements: - docs sphinx: builder: html fail_on_warning: true sphinx-sqlalchemy-0.3.0/CHANGELOG.md000066400000000000000000000016371456720622300170120ustar00rootroot00000000000000# Changelog ## v0.3.0 (February 2024) * 🔧 Move to sphinx-extensions2 organisation by @chrisjsewell in https://github.com/sphinx-extensions2/sphinx-sqlalchemy/pull/17 * 👌 Improve parsing of multiline docstrings by @AlexTorx in https://github.com/sphinx-extensions2/sphinx-sqlalchemy/pull/15 * 🐛 FIX: Exception when rendering `CheckConstraints` by @Starbat in https://github.com/sphinx-extensions2/sphinx-sqlalchemy/pull/19 ## v0.2.0 (November 2023) * 🐛 FIX: Skip non-columns by @rclaasen in https://github.com/sphinx-extensions2/sphinx-sqlalchemy/pull/2 * ⬆️ Update sphinx version to 5,6,7 by @chrisjsewell in https://github.com/sphinx-extensions2/sphinx-sqlalchemy/pull/6 * ⬆️ Update sqlachemy version to 2 by @chrisjsewell in https://github.com/sphinx-extensions2/sphinx-sqlalchemy/pull/12 ## v0.1.1 (November 2021) ✨ NEW: Nested parse class docstrings ## v0.1.0 (November 2021) Initial release. sphinx-sqlalchemy-0.3.0/LICENSE000066400000000000000000000020551456720622300162010ustar00rootroot00000000000000MIT License Copyright (c) 2021 Chris Sewell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sphinx-sqlalchemy-0.3.0/README.md000066400000000000000000000003431456720622300164510ustar00rootroot00000000000000# sphinx-sqlalchemy [![PyPI][pypi-badge]][pypi-link] Sphinx extension for documenting SQLAlchemy ORMs [pypi-badge]: https://img.shields.io/pypi/v/sphinx-sqlalchemy.svg [pypi-link]: https://pypi.org/project/sphinx-sqlalchemy sphinx-sqlalchemy-0.3.0/docs/000077500000000000000000000000001456720622300161225ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/docs/conf.py000066400000000000000000000003661456720622300174260ustar00rootroot00000000000000"""Sphinx configuration file.""" import os import sys # add example module to the python path sys.path.insert(0, os.path.dirname(__file__)) extensions = ["sphinx_sqlalchemy"] html_title = "sphinx-sqlalchemy documentation" html_theme = "furo" sphinx-sqlalchemy-0.3.0/docs/example/000077500000000000000000000000001456720622300175555ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/docs/example/__init__.py000066400000000000000000000000311456720622300216600ustar00rootroot00000000000000"""An example module.""" sphinx-sqlalchemy-0.3.0/docs/example/models.py000066400000000000000000000020331456720622300214100ustar00rootroot00000000000000"""Example SQLAlchemy ORM models.""" from sqlalchemy import CheckConstraint, Column, ForeignKey, UniqueConstraint, orm, types Base = orm.declarative_base() class User(Base): """A ``user``.""" __tablename__ = "dbusers" __table_args__ = (UniqueConstraint("first_name", "last_name"),) pk = Column(types.Integer, primary_key=True) first_name = Column(types.String, doc="The name of the user.") last_name = Column(types.String(255), doc="The surname of the user.") dob = Column(types.Date, nullable=False, doc="The date of birth.") class Address(Base): """An address.""" __tablename__ = "addresses" __table_args__ = (CheckConstraint("number>0", name="check1"),) pk = Column(types.Integer, primary_key=True) number = Column(types.Integer, nullable=False, doc="The number of the address.") postcode = Column( types.String, nullable=False, index=True, doc="The postcode of the address." ) user_id = Column(types.Integer, ForeignKey("dbusers.pk")) user = orm.relationship("User") sphinx-sqlalchemy-0.3.0/docs/index.rst000066400000000000000000000011041456720622300177570ustar00rootroot00000000000000sphinx-sqlalchemy ================= Sphinx extension for documenting SQLAlchemy ORMs. Usage ----- Install ``sphinx_sqlalchemy``: .. code-block:: bash pip install sphinx_sqlalchemy Add ``sphinx_sqlalchemy`` to your ``conf.py``: .. code-block:: python extensions = [ 'sphinx_sqlalchemy', ] Example ------- :: .. sqla-model:: example.models.User .. sqla-model:: ~example.models.Address .. sqla-model:: example.models.User .. sqla-model:: ~example.models.Address This was created from: .. literalinclude:: example/models.py :lines: 1- sphinx-sqlalchemy-0.3.0/pyproject.toml000066400000000000000000000034121456720622300201060ustar00rootroot00000000000000[build-system] requires = ["flit_core >=3.2,<4"] build-backend = "flit_core.buildapi" [project] name = "sphinx_sqlalchemy" dynamic = ["version"] description = "Sphinx extension for documenting SQLAlchemy ORMs" authors = [{name = "Chris Sewell", email = "chrisj_sewell@hotmail.com"}] license = {text = "MIT License"} readme = "README.md" classifiers = [ "Development Status :: 4 - Beta", "Framework :: Sphinx :: Extension", "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Python Modules", ] keywords = ["sphinx", "extension"] requires-python = "~=3.8" dependencies = [ "sphinx>=5,<8", "sqlalchemy~=2.0", ] [project.urls] Homepage = "http://github.com/sphinx-extensions2/sphinx-sqlalchemy" Documentation = "https://sphinx-sqlalchemy.readthedocs.io" [project.optional-dependencies] dev = [ "pytest", "pytest-cov", "sphinx-pytest", "syrupy~=4.0", ] docs = ["furo"] [tool.ruff] line-length = 100 extend-select = ["B0", "C4", "ICN", "ISC", "N", "RUF", "SIM"] [tool.isort] profile = "black" src_paths = ["sphinx_sqlalchemy", "tests"] [tool.mypy] show_error_codes = true check_untyped_defs = true scripts_are_modules = true warn_unused_ignores = true warn_redundant_casts = true plugins = ["sqlalchemy.ext.mypy.plugin"] [[tool.mypy.overrides]] module = 'docutils.*' ignore_missing_imports = true sphinx-sqlalchemy-0.3.0/sphinx_sqlalchemy/000077500000000000000000000000001456720622300207255ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/sphinx_sqlalchemy/__init__.py000066400000000000000000000006701456720622300230410ustar00rootroot00000000000000"""Sphinx extension for documenting SQLAlchemy ORMs""" from typing import TYPE_CHECKING __version__ = "0.3.0" if TYPE_CHECKING: from sphinx.application import Sphinx def setup(app: "Sphinx") -> dict: """Sphinx extension setup function.""" from .main import setup_extension setup_extension(app) return { "version": __version__, "parallel_read_safe": True, "parallel_write_safe": True, } sphinx-sqlalchemy-0.3.0/sphinx_sqlalchemy/main.py000066400000000000000000000166301456720622300222310ustar00rootroot00000000000000import importlib import logging from typing import List, Optional, Set from docutils import nodes from docutils.statemachine import StringList # from docutils.parsers.rst import directives from sphinx.application import Sphinx from sphinx.util.docstrings import prepare_docstring from sphinx.util.docutils import SphinxDirective from sqlalchemy import Column, Constraint, inspect from sqlalchemy.orm.mapper import Mapper from sqlalchemy.sql.elements import ClauseElement from sqlalchemy.sql.schema import ( CheckConstraint, ForeignKeyConstraint, Index, PrimaryKeyConstraint, UniqueConstraint, ) logger = logging.getLogger(__name__) def setup_extension(app: Sphinx) -> None: """Set up the sphinx extension.""" app.add_directive("sqla-model", SqlaModelDirective) class SqlaModelDirective(SphinxDirective): """A sphinx directive to document an SQLAlchemy Model""" required_arguments = 1 final_argument_whitespace = True has_content = False # option_spec = {"col-doc": directives.flag} def run(self) -> List[nodes.Node]: """Run the directive""" # get module.class from argument if "." not in self.arguments[0]: raise self.error( f"Argument not of format 'module.class': {self.arguments[0]}" ) module_name, class_name = self.arguments[0].rsplit(".", 1) # check whether to show the module prefix show_module = True if module_name.startswith("~"): show_module = False module_name = module_name[1:] # try to load the class try: module = importlib.import_module(module_name) except Exception as exc: raise self.error(f"Could not import module '{module_name}': {exc}") klass = getattr(module, class_name, None) if klass is None: raise self.error(f"No class '{class_name}' in module '{module_name}'") mapper: Optional[Mapper] = inspect(klass, raiseerr=False) if mapper is None: raise self.error( f"Class '{class_name}' in module '{module_name}' is not an SQLAlchemy Model" ) # create initial structure: # # # # Term # # ... main = nodes.definition_list(classes=["simple", "sqla"]) def_list = nodes.definition_list_item() main += def_list name = nodes.Text(f"{module_name}.{class_name}" if show_module else class_name) if mapper.local_table is not None: def_list += nodes.term( "", name, nodes.Text(" ("), nodes.emphasis(text=f"{mapper.class_.__tablename__}"), nodes.Text(")"), ) else: def_list += nodes.term("", name) definition = nodes.definition() def_list += definition self.add_content(mapper, definition) return [main] def add_content(self, mapper: Mapper, definition: nodes.definition) -> None: """Add content to the definition node.""" # class documentation if mapper.class_.__doc__: docstring_lines = prepare_docstring( mapper.class_.__doc__, self.state.document.settings.tab_width ) self.state.nested_parse( StringList(docstring_lines), self.content_offset, definition, ) # column documentation if mapper.columns: columns = [] for column in mapper.columns: # Skip column expressions without a data type, # eg. query_expressions. See query_expression on # https://docs.sqlalchemy.org/en/14/orm/loading_columns.html if not isinstance(column, Column): logger.warning(f"Skipping column '{column.name}' {type(column)}") else: columns.append(column) definition += nodes.rubric(text="Columns:") doc_column = any(column.doc for column in columns) cols = 3 if doc_column else 2 definition += nodes.table( "", nodes.tgroup( "", *([nodes.colspec()] * cols + [nodes.tbody()]), cols=cols ), classes=["colwidths-auto"], align="left", ) body = definition[-1][-1][-1] for column in columns: row = nodes.row() body += row col_name = f"{column.name}" if column.unique or column.primary_key: col_name += "*" if column.foreign_keys: col_name = "→ " + col_name if column.primary_key: row += nodes.entry( "", nodes.paragraph("", "", nodes.emphasis(text=col_name)) ) else: row += nodes.entry("", nodes.paragraph(text=col_name)) col_type = f"{column.type}" if column.nullable: col_type += "?" row += nodes.entry("", nodes.paragraph(text=col_type)) if doc_column: row += nodes.entry("", nodes.paragraph(text=f"{column.doc or ''}")) # table constraints if mapper.local_table is not None and mapper.local_table.constraints: constraints: Set[Constraint] = mapper.local_table.constraints definition += nodes.rubric(text="Constraints:") definition += nodes.bullet_list() for text in sorted(contraint_to_str(c) for c in constraints): definition[-1] += nodes.list_item("", nodes.paragraph(text=text)) # table indexes if mapper.local_table is not None and mapper.local_table.indexes: definition += nodes.rubric(text="Indexes:") definition += nodes.bullet_list() for text in sorted(index_to_str(c) for c in mapper.local_table.indexes): definition[-1] += nodes.list_item("", nodes.paragraph(text=text)) def check_constraint_to_str(constraint: CheckConstraint) -> str: if isinstance(constraint.sqltext, ClauseElement): text = constraint.sqltext.compile(compile_kwargs={"literal_binds": True}) else: text = getattr(constraint.sqltext, "text", "") return f"CHECK ({text})" def contraint_to_str(constraint: Constraint) -> str: """Convert a constraint to a string.""" if isinstance(constraint, PrimaryKeyConstraint): return f"PRIMARY KEY ({', '.join(c.name for c in constraint.columns)})" if isinstance(constraint, ForeignKeyConstraint): from_keys = ", ".join( f"{el.column.table.name}.{el.column.name}" for el in constraint.elements ) to_keys = ", ".join(str(c) for c in constraint.column_keys) return f"FOREIGN KEY ({from_keys} → {to_keys})" if isinstance(constraint, UniqueConstraint): return f"UNIQUE ({', '.join(c.name for c in constraint.columns)})" if isinstance(constraint, CheckConstraint): return check_constraint_to_str(constraint) return "UNKNOWN" def index_to_str(index: Index) -> str: """Convert an index to a string.""" return f"{index.name} ({', '.join(c.name for c in index.columns)})" sphinx-sqlalchemy-0.3.0/tests/000077500000000000000000000000001456720622300163345ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/tests/__snapshots__/000077500000000000000000000000001456720622300211525ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/tests/__snapshots__/test_basic.ambr000066400000000000000000000061671456720622300241470ustar00rootroot00000000000000# serializer version: 1 # name: test_basic ''' module1.TestUser ( dbusers ) A user . Columns: pk* INTEGER first_name VARCHAR? The name of the user. last_name VARCHAR(255)? The surname of the user. dob DATE The date of birth. Constraints: CHECK (length(trim('first_name')) > 0) PRIMARY KEY (pk) UNIQUE (first_name, last_name) ''' # --- sphinx-sqlalchemy-0.3.0/tests/__snapshots__/test_docstrings.ambr000066400000000000000000000151321456720622300252350ustar00rootroot00000000000000# serializer version: 1 # name: test_multiline_docstring_d212 ''' module2.TestUserMultilineDocstringD212 ( dbusers_d212 ) A user . The user has a multi-line docstring: This is an indented code block This is the last line of the docstring. Columns:
pk* INTEGER first_name VARCHAR? The name of the user. last_name VARCHAR(255)? The surname of the user. dob DATE The date of birth. Constraints: PRIMARY KEY (pk) UNIQUE (first_name, last_name) ''' # --- # name: test_multiline_docstring_d213 ''' module2.TestUserMultilineDocstringD213 ( dbusers_d213 ) A user . The user has a multi-line docstring: This is an indented code block This is the last line of the docstring. Columns:
pk* INTEGER first_name VARCHAR? The name of the user. last_name VARCHAR(255)? The surname of the user. dob DATE The date of birth. Constraints: PRIMARY KEY (pk) UNIQUE (first_name, last_name) ''' # --- sphinx-sqlalchemy-0.3.0/tests/conftest.py000066400000000000000000000000531456720622300205310ustar00rootroot00000000000000pytest_plugins = "sphinx.testing.fixtures" sphinx-sqlalchemy-0.3.0/tests/modules/000077500000000000000000000000001456720622300200045ustar00rootroot00000000000000sphinx-sqlalchemy-0.3.0/tests/modules/module1.py000066400000000000000000000012111456720622300217170ustar00rootroot00000000000000from sqlalchemy import CheckConstraint, Column, UniqueConstraint, func, orm, types Base = orm.declarative_base() class TestUser(Base): """A ``user``.""" __tablename__ = "dbusers" __table_args__ = ( UniqueConstraint("first_name", "last_name"), CheckConstraint( func.length(func.trim("first_name")) > 0, "check_project_has_name" ), ) pk = Column(types.Integer, primary_key=True) first_name = Column(types.String, doc="The name of the user.") last_name = Column(types.String(255), doc="The surname of the user.") dob = Column(types.Date, nullable=False, doc="The date of birth.") sphinx-sqlalchemy-0.3.0/tests/modules/module2.py000066400000000000000000000023141456720622300217250ustar00rootroot00000000000000from sqlalchemy import Column, UniqueConstraint, orm, types Base = orm.declarative_base() class TestUserMultilineDocstringD212(Base): """ A ``user``. The user has a multi-line docstring:: This is an indented code block This is the last line of the docstring. """ __tablename__ = "dbusers_d212" __table_args__ = (UniqueConstraint("first_name", "last_name"),) pk = Column(types.Integer, primary_key=True) first_name = Column(types.String, doc="The name of the user.") last_name = Column(types.String(255), doc="The surname of the user.") dob = Column(types.Date, nullable=False, doc="The date of birth.") class TestUserMultilineDocstringD213(Base): """A ``user``. The user has a multi-line docstring:: This is an indented code block This is the last line of the docstring. """ __tablename__ = "dbusers_d213" __table_args__ = (UniqueConstraint("first_name", "last_name"),) pk = Column(types.Integer, primary_key=True) first_name = Column(types.String, doc="The name of the user.") last_name = Column(types.String(255), doc="The surname of the user.") dob = Column(types.Date, nullable=False, doc="The date of birth.") sphinx-sqlalchemy-0.3.0/tests/test_basic.py000066400000000000000000000010041456720622300210210ustar00rootroot00000000000000"""Basic tests""" import os.path import sys from sphinx_pytest.plugin import CreateDoctree def test_basic(sphinx_doctree_no_tr: CreateDoctree, snapshot): """Basic test""" sys.path.insert(0, os.path.join(os.path.dirname(__file__), "modules")) sphinx_doctree_no_tr.set_conf({"extensions": ["sphinx_sqlalchemy"]}) result = sphinx_doctree_no_tr(".. sqla-model:: module1.TestUser") assert not result.warnings assert "\n".join([li.rstrip() for li in result.pformat().splitlines()]) == snapshot sphinx-sqlalchemy-0.3.0/tests/test_docstrings.py000066400000000000000000000024421456720622300221260ustar00rootroot00000000000000"""Basic tests""" import os.path import sys from sphinx_pytest.plugin import CreateDoctree def test_multiline_docstring_d212(sphinx_doctree_no_tr: CreateDoctree, snapshot): """Basic test for models with multiline docstring with D212 format see: https://docs.astral.sh/ruff/rules/multi-line-summary-first-line """ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "modules")) sphinx_doctree_no_tr.set_conf({"extensions": ["sphinx_sqlalchemy"]}) result = sphinx_doctree_no_tr( ".. sqla-model:: module2.TestUserMultilineDocstringD212" ) assert not result.warnings assert "\n".join([li.rstrip() for li in result.pformat().splitlines()]) == snapshot def test_multiline_docstring_d213(sphinx_doctree_no_tr: CreateDoctree, snapshot): """Basic test for models with multiline docstring with D213 format see: https://docs.astral.sh/ruff/rules/multi-line-summary-second-line """ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "modules")) sphinx_doctree_no_tr.set_conf({"extensions": ["sphinx_sqlalchemy"]}) result = sphinx_doctree_no_tr( ".. sqla-model:: module2.TestUserMultilineDocstringD213" ) assert not result.warnings assert "\n".join([li.rstrip() for li in result.pformat().splitlines()]) == snapshot sphinx-sqlalchemy-0.3.0/tox.ini000066400000000000000000000013011456720622300165000ustar00rootroot00000000000000# To use tox, see https://tox.readthedocs.io # Simply pip or conda install tox # If you use conda, you may also want to install tox-conda # then run `tox` or `tox -- {pytest args}` # run in parallel using `tox -p` [tox] envlist = py38 [testenv] usedevelop = true [testenv:py{38,39,310,311}] description = Run unit tests with this Python version extras = dev setenv = SQLALCHEMY_WARN_20 = 1 commands = pytest {posargs} [testenv:py38-docs] description = Create the documentation extras = docs whitelist_externals = echo rm commands = rm -rf docs/_build/html sphinx-build -nW --keep-going -b html docs/ docs/_build/html commands_post = echo "open docs/_build/html/index.html"