👷 Move to Ruff and add pre-commit (#661)
* 👷 Add pre-commit * 🔧 Add pyproject.toml config for Ruff * ➕ Replace isort, flake8, autoflake with Ruff * 🔨 Update lint and format scripts * 🎨 Format with Ruff * 🔧 Update Poetry config
This commit is contained in:
parent
9ba3039106
commit
065fcdc828
35
.pre-commit-config.yaml
Normal file
35
.pre-commit-config.yaml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
default_language_version:
|
||||||
|
python: python3.10
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.4.0
|
||||||
|
hooks:
|
||||||
|
- id: check-added-large-files
|
||||||
|
- id: check-toml
|
||||||
|
- id: check-yaml
|
||||||
|
args:
|
||||||
|
- --unsafe
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v3.7.0
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args:
|
||||||
|
- --py3-plus
|
||||||
|
- --keep-runtime-typing
|
||||||
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||||
|
rev: v0.0.275
|
||||||
|
hooks:
|
||||||
|
- id: ruff
|
||||||
|
args:
|
||||||
|
- --fix
|
||||||
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 23.3.0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
ci:
|
||||||
|
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
|
||||||
|
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
|
@ -35,10 +35,9 @@ SQLAlchemy = ">=1.4.17,<=1.4.41"
|
|||||||
pydantic = "^1.8.2"
|
pydantic = "^1.8.2"
|
||||||
sqlalchemy2-stubs = {version = "*", allow-prereleases = true}
|
sqlalchemy2-stubs = {version = "*", allow-prereleases = true}
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest = "^7.0.1"
|
pytest = "^7.0.1"
|
||||||
mypy = "0.971"
|
mypy = "0.971"
|
||||||
flake8 = "^5.0.4"
|
|
||||||
black = "^22.10.0"
|
black = "^22.10.0"
|
||||||
mkdocs = "^1.2.1"
|
mkdocs = "^1.2.1"
|
||||||
mkdocs-material = "^8.1.4"
|
mkdocs-material = "^8.1.4"
|
||||||
@ -48,8 +47,7 @@ mdx-include = "^1.4.1"
|
|||||||
coverage = {extras = ["toml"], version = "^6.2"}
|
coverage = {extras = ["toml"], version = "^6.2"}
|
||||||
fastapi = "^0.68.1"
|
fastapi = "^0.68.1"
|
||||||
requests = "^2.26.0"
|
requests = "^2.26.0"
|
||||||
autoflake = "^1.4"
|
ruff = "^0.1.1"
|
||||||
isort = "^5.9.3"
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
@ -75,14 +73,6 @@ exclude_lines = [
|
|||||||
"if TYPE_CHECKING:",
|
"if TYPE_CHECKING:",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.isort]
|
|
||||||
profile = "black"
|
|
||||||
known_third_party = ["sqlmodel"]
|
|
||||||
skip_glob = [
|
|
||||||
"sqlmodel/__init__.py",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
# --strict
|
# --strict
|
||||||
disallow_any_generics = true
|
disallow_any_generics = true
|
||||||
@ -104,4 +94,23 @@ strict_equality = true
|
|||||||
module = "sqlmodel.sql.expression"
|
module = "sqlmodel.sql.expression"
|
||||||
warn_unused_ignores = false
|
warn_unused_ignores = false
|
||||||
|
|
||||||
# invalidate CI cache: 1
|
[tool.ruff]
|
||||||
|
select = [
|
||||||
|
"E", # pycodestyle errors
|
||||||
|
"W", # pycodestyle warnings
|
||||||
|
"F", # pyflakes
|
||||||
|
"I", # isort
|
||||||
|
"C", # flake8-comprehensions
|
||||||
|
"B", # flake8-bugbear
|
||||||
|
]
|
||||||
|
ignore = [
|
||||||
|
"E501", # line too long, handled by black
|
||||||
|
"B008", # do not perform function calls in argument defaults
|
||||||
|
"C901", # too complex
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.per-file-ignores]
|
||||||
|
# "__init__.py" = ["F401"]
|
||||||
|
|
||||||
|
[tool.ruff.isort]
|
||||||
|
known-third-party = ["sqlmodel", "sqlalchemy", "pydantic", "fastapi"]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place sqlmodel docs_src tests --exclude=__init__.py
|
ruff sqlmodel tests docs_src scripts --fix
|
||||||
black sqlmodel tests docs_src
|
black sqlmodel tests docs_src scripts
|
||||||
isort sqlmodel tests docs_src
|
|
||||||
|
@ -4,6 +4,5 @@ set -e
|
|||||||
set -x
|
set -x
|
||||||
|
|
||||||
mypy sqlmodel
|
mypy sqlmodel
|
||||||
flake8 sqlmodel tests docs_src
|
ruff sqlmodel tests docs_src scripts
|
||||||
black sqlmodel tests docs_src --check
|
black sqlmodel tests docs_src --check
|
||||||
isort sqlmodel tests docs_src scripts --check-only
|
|
||||||
|
@ -5,12 +5,12 @@ from sqlalchemy.engine import create_mock_engine as create_mock_engine
|
|||||||
from sqlalchemy.engine import engine_from_config as engine_from_config
|
from sqlalchemy.engine import engine_from_config as engine_from_config
|
||||||
from sqlalchemy.inspection import inspect as inspect
|
from sqlalchemy.inspection import inspect as inspect
|
||||||
from sqlalchemy.schema import BLANK_SCHEMA as BLANK_SCHEMA
|
from sqlalchemy.schema import BLANK_SCHEMA as BLANK_SCHEMA
|
||||||
|
from sqlalchemy.schema import DDL as DDL
|
||||||
from sqlalchemy.schema import CheckConstraint as CheckConstraint
|
from sqlalchemy.schema import CheckConstraint as CheckConstraint
|
||||||
from sqlalchemy.schema import Column as Column
|
from sqlalchemy.schema import Column as Column
|
||||||
from sqlalchemy.schema import ColumnDefault as ColumnDefault
|
from sqlalchemy.schema import ColumnDefault as ColumnDefault
|
||||||
from sqlalchemy.schema import Computed as Computed
|
from sqlalchemy.schema import Computed as Computed
|
||||||
from sqlalchemy.schema import Constraint as Constraint
|
from sqlalchemy.schema import Constraint as Constraint
|
||||||
from sqlalchemy.schema import DDL as DDL
|
|
||||||
from sqlalchemy.schema import DefaultClause as DefaultClause
|
from sqlalchemy.schema import DefaultClause as DefaultClause
|
||||||
from sqlalchemy.schema import FetchedValue as FetchedValue
|
from sqlalchemy.schema import FetchedValue as FetchedValue
|
||||||
from sqlalchemy.schema import ForeignKey as ForeignKey
|
from sqlalchemy.schema import ForeignKey as ForeignKey
|
||||||
@ -23,6 +23,14 @@ from sqlalchemy.schema import Sequence as Sequence
|
|||||||
from sqlalchemy.schema import Table as Table
|
from sqlalchemy.schema import Table as Table
|
||||||
from sqlalchemy.schema import ThreadLocalMetaData as ThreadLocalMetaData
|
from sqlalchemy.schema import ThreadLocalMetaData as ThreadLocalMetaData
|
||||||
from sqlalchemy.schema import UniqueConstraint as UniqueConstraint
|
from sqlalchemy.schema import UniqueConstraint as UniqueConstraint
|
||||||
|
from sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
|
||||||
|
from sqlalchemy.sql import (
|
||||||
|
LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,
|
||||||
|
)
|
||||||
|
from sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE
|
||||||
|
from sqlalchemy.sql import (
|
||||||
|
LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
|
||||||
|
)
|
||||||
from sqlalchemy.sql import alias as alias
|
from sqlalchemy.sql import alias as alias
|
||||||
from sqlalchemy.sql import all_ as all_
|
from sqlalchemy.sql import all_ as all_
|
||||||
from sqlalchemy.sql import and_ as and_
|
from sqlalchemy.sql import and_ as and_
|
||||||
@ -48,14 +56,6 @@ from sqlalchemy.sql import insert as insert
|
|||||||
from sqlalchemy.sql import intersect as intersect
|
from sqlalchemy.sql import intersect as intersect
|
||||||
from sqlalchemy.sql import intersect_all as intersect_all
|
from sqlalchemy.sql import intersect_all as intersect_all
|
||||||
from sqlalchemy.sql import join as join
|
from sqlalchemy.sql import join as join
|
||||||
from sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
|
|
||||||
from sqlalchemy.sql import (
|
|
||||||
LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,
|
|
||||||
)
|
|
||||||
from sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE
|
|
||||||
from sqlalchemy.sql import (
|
|
||||||
LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
|
|
||||||
)
|
|
||||||
from sqlalchemy.sql import lambda_stmt as lambda_stmt
|
from sqlalchemy.sql import lambda_stmt as lambda_stmt
|
||||||
from sqlalchemy.sql import lateral as lateral
|
from sqlalchemy.sql import lateral as lateral
|
||||||
from sqlalchemy.sql import literal as literal
|
from sqlalchemy.sql import literal as literal
|
||||||
@ -85,55 +85,53 @@ from sqlalchemy.sql import values as values
|
|||||||
from sqlalchemy.sql import within_group as within_group
|
from sqlalchemy.sql import within_group as within_group
|
||||||
from sqlalchemy.types import ARRAY as ARRAY
|
from sqlalchemy.types import ARRAY as ARRAY
|
||||||
from sqlalchemy.types import BIGINT as BIGINT
|
from sqlalchemy.types import BIGINT as BIGINT
|
||||||
from sqlalchemy.types import BigInteger as BigInteger
|
|
||||||
from sqlalchemy.types import BINARY as BINARY
|
from sqlalchemy.types import BINARY as BINARY
|
||||||
from sqlalchemy.types import BLOB as BLOB
|
from sqlalchemy.types import BLOB as BLOB
|
||||||
from sqlalchemy.types import BOOLEAN as BOOLEAN
|
from sqlalchemy.types import BOOLEAN as BOOLEAN
|
||||||
from sqlalchemy.types import Boolean as Boolean
|
|
||||||
from sqlalchemy.types import CHAR as CHAR
|
from sqlalchemy.types import CHAR as CHAR
|
||||||
from sqlalchemy.types import CLOB as CLOB
|
from sqlalchemy.types import CLOB as CLOB
|
||||||
from sqlalchemy.types import DATE as DATE
|
from sqlalchemy.types import DATE as DATE
|
||||||
from sqlalchemy.types import Date as Date
|
|
||||||
from sqlalchemy.types import DATETIME as DATETIME
|
from sqlalchemy.types import DATETIME as DATETIME
|
||||||
from sqlalchemy.types import DateTime as DateTime
|
|
||||||
from sqlalchemy.types import DECIMAL as DECIMAL
|
from sqlalchemy.types import DECIMAL as DECIMAL
|
||||||
from sqlalchemy.types import Enum as Enum
|
|
||||||
from sqlalchemy.types import FLOAT as FLOAT
|
from sqlalchemy.types import FLOAT as FLOAT
|
||||||
from sqlalchemy.types import Float as Float
|
|
||||||
from sqlalchemy.types import INT as INT
|
from sqlalchemy.types import INT as INT
|
||||||
from sqlalchemy.types import INTEGER as INTEGER
|
from sqlalchemy.types import INTEGER as INTEGER
|
||||||
from sqlalchemy.types import Integer as Integer
|
|
||||||
from sqlalchemy.types import Interval as Interval
|
|
||||||
from sqlalchemy.types import JSON as JSON
|
from sqlalchemy.types import JSON as JSON
|
||||||
from sqlalchemy.types import LargeBinary as LargeBinary
|
|
||||||
from sqlalchemy.types import NCHAR as NCHAR
|
from sqlalchemy.types import NCHAR as NCHAR
|
||||||
from sqlalchemy.types import NUMERIC as NUMERIC
|
from sqlalchemy.types import NUMERIC as NUMERIC
|
||||||
from sqlalchemy.types import Numeric as Numeric
|
|
||||||
from sqlalchemy.types import NVARCHAR as NVARCHAR
|
from sqlalchemy.types import NVARCHAR as NVARCHAR
|
||||||
from sqlalchemy.types import PickleType as PickleType
|
|
||||||
from sqlalchemy.types import REAL as REAL
|
from sqlalchemy.types import REAL as REAL
|
||||||
from sqlalchemy.types import SMALLINT as SMALLINT
|
from sqlalchemy.types import SMALLINT as SMALLINT
|
||||||
|
from sqlalchemy.types import TEXT as TEXT
|
||||||
|
from sqlalchemy.types import TIME as TIME
|
||||||
|
from sqlalchemy.types import TIMESTAMP as TIMESTAMP
|
||||||
|
from sqlalchemy.types import VARBINARY as VARBINARY
|
||||||
|
from sqlalchemy.types import VARCHAR as VARCHAR
|
||||||
|
from sqlalchemy.types import BigInteger as BigInteger
|
||||||
|
from sqlalchemy.types import Boolean as Boolean
|
||||||
|
from sqlalchemy.types import Date as Date
|
||||||
|
from sqlalchemy.types import DateTime as DateTime
|
||||||
|
from sqlalchemy.types import Enum as Enum
|
||||||
|
from sqlalchemy.types import Float as Float
|
||||||
|
from sqlalchemy.types import Integer as Integer
|
||||||
|
from sqlalchemy.types import Interval as Interval
|
||||||
|
from sqlalchemy.types import LargeBinary as LargeBinary
|
||||||
|
from sqlalchemy.types import Numeric as Numeric
|
||||||
|
from sqlalchemy.types import PickleType as PickleType
|
||||||
from sqlalchemy.types import SmallInteger as SmallInteger
|
from sqlalchemy.types import SmallInteger as SmallInteger
|
||||||
from sqlalchemy.types import String as String
|
from sqlalchemy.types import String as String
|
||||||
from sqlalchemy.types import TEXT as TEXT
|
|
||||||
from sqlalchemy.types import Text as Text
|
from sqlalchemy.types import Text as Text
|
||||||
from sqlalchemy.types import TIME as TIME
|
|
||||||
from sqlalchemy.types import Time as Time
|
from sqlalchemy.types import Time as Time
|
||||||
from sqlalchemy.types import TIMESTAMP as TIMESTAMP
|
|
||||||
from sqlalchemy.types import TypeDecorator as TypeDecorator
|
from sqlalchemy.types import TypeDecorator as TypeDecorator
|
||||||
from sqlalchemy.types import Unicode as Unicode
|
from sqlalchemy.types import Unicode as Unicode
|
||||||
from sqlalchemy.types import UnicodeText as UnicodeText
|
from sqlalchemy.types import UnicodeText as UnicodeText
|
||||||
from sqlalchemy.types import VARBINARY as VARBINARY
|
|
||||||
from sqlalchemy.types import VARCHAR as VARCHAR
|
|
||||||
|
|
||||||
# Extensions and modifications of SQLAlchemy in SQLModel
|
# From SQLModel, modifications of SQLAlchemy or equivalents of Pydantic
|
||||||
from .engine.create import create_engine as create_engine
|
from .engine.create import create_engine as create_engine
|
||||||
from .orm.session import Session as Session
|
|
||||||
from .sql.expression import select as select
|
|
||||||
from .sql.expression import col as col
|
|
||||||
from .sql.sqltypes import AutoString as AutoString
|
|
||||||
|
|
||||||
# Export SQLModel specifics (equivalent to Pydantic)
|
|
||||||
from .main import SQLModel as SQLModel
|
|
||||||
from .main import Field as Field
|
from .main import Field as Field
|
||||||
from .main import Relationship as Relationship
|
from .main import Relationship as Relationship
|
||||||
|
from .main import SQLModel as SQLModel
|
||||||
|
from .orm.session import Session as Session
|
||||||
|
from .sql.expression import col as col
|
||||||
|
from .sql.expression import select as select
|
||||||
|
from .sql.sqltypes import AutoString as AutoString
|
||||||
|
@ -26,15 +26,24 @@ from typing import (
|
|||||||
|
|
||||||
from pydantic import BaseConfig, BaseModel
|
from pydantic import BaseConfig, BaseModel
|
||||||
from pydantic.errors import ConfigError, DictError
|
from pydantic.errors import ConfigError, DictError
|
||||||
from pydantic.fields import SHAPE_SINGLETON
|
from pydantic.fields import SHAPE_SINGLETON, ModelField, Undefined, UndefinedType
|
||||||
from pydantic.fields import FieldInfo as PydanticFieldInfo
|
from pydantic.fields import FieldInfo as PydanticFieldInfo
|
||||||
from pydantic.fields import ModelField, Undefined, UndefinedType
|
|
||||||
from pydantic.main import ModelMetaclass, validate_model
|
from pydantic.main import ModelMetaclass, validate_model
|
||||||
from pydantic.typing import NoArgAnyCallable, resolve_annotations
|
from pydantic.typing import NoArgAnyCallable, resolve_annotations
|
||||||
from pydantic.utils import ROOT_KEY, Representation
|
from pydantic.utils import ROOT_KEY, Representation
|
||||||
from sqlalchemy import Boolean, Column, Date, DateTime
|
from sqlalchemy import (
|
||||||
|
Boolean,
|
||||||
|
Column,
|
||||||
|
Date,
|
||||||
|
DateTime,
|
||||||
|
Float,
|
||||||
|
ForeignKey,
|
||||||
|
Integer,
|
||||||
|
Interval,
|
||||||
|
Numeric,
|
||||||
|
inspect,
|
||||||
|
)
|
||||||
from sqlalchemy import Enum as sa_Enum
|
from sqlalchemy import Enum as sa_Enum
|
||||||
from sqlalchemy import Float, ForeignKey, Integer, Interval, Numeric, inspect
|
|
||||||
from sqlalchemy.orm import RelationshipProperty, declared_attr, registry, relationship
|
from sqlalchemy.orm import RelationshipProperty, declared_attr, registry, relationship
|
||||||
from sqlalchemy.orm.attributes import set_attribute
|
from sqlalchemy.orm.attributes import set_attribute
|
||||||
from sqlalchemy.orm.decl_api import DeclarativeMeta
|
from sqlalchemy.orm.decl_api import DeclarativeMeta
|
||||||
@ -305,9 +314,9 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta):
|
|||||||
config_registry = cast(registry, config_registry)
|
config_registry = cast(registry, config_registry)
|
||||||
# If it was passed by kwargs, ensure it's also set in config
|
# If it was passed by kwargs, ensure it's also set in config
|
||||||
new_cls.__config__.registry = config_table
|
new_cls.__config__.registry = config_table
|
||||||
setattr(new_cls, "_sa_registry", config_registry)
|
setattr(new_cls, "_sa_registry", config_registry) # noqa: B010
|
||||||
setattr(new_cls, "metadata", config_registry.metadata)
|
setattr(new_cls, "metadata", config_registry.metadata) # noqa: B010
|
||||||
setattr(new_cls, "__abstract__", True)
|
setattr(new_cls, "__abstract__", True) # noqa: B010
|
||||||
return new_cls
|
return new_cls
|
||||||
|
|
||||||
# Override SQLAlchemy, allow both SQLAlchemy and plain Pydantic models
|
# Override SQLAlchemy, allow both SQLAlchemy and plain Pydantic models
|
||||||
@ -320,7 +329,7 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta):
|
|||||||
# triggers an error
|
# triggers an error
|
||||||
base_is_table = False
|
base_is_table = False
|
||||||
for base in bases:
|
for base in bases:
|
||||||
config = getattr(base, "__config__")
|
config = getattr(base, "__config__") # noqa: B009
|
||||||
if config and getattr(config, "table", False):
|
if config and getattr(config, "table", False):
|
||||||
base_is_table = True
|
base_is_table = True
|
||||||
break
|
break
|
||||||
@ -351,7 +360,7 @@ class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta):
|
|||||||
rel_kwargs["back_populates"] = rel_info.back_populates
|
rel_kwargs["back_populates"] = rel_info.back_populates
|
||||||
if rel_info.link_model:
|
if rel_info.link_model:
|
||||||
ins = inspect(rel_info.link_model)
|
ins = inspect(rel_info.link_model)
|
||||||
local_table = getattr(ins, "local_table")
|
local_table = getattr(ins, "local_table") # noqa: B009
|
||||||
if local_table is None:
|
if local_table is None:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Couldn't find the secondary table for "
|
"Couldn't find the secondary table for "
|
||||||
@ -430,7 +439,7 @@ def get_column_from_field(field: ModelField) -> Column: # type: ignore
|
|||||||
# Override derived nullability if the nullable property is set explicitly
|
# Override derived nullability if the nullable property is set explicitly
|
||||||
# on the field
|
# on the field
|
||||||
if hasattr(field.field_info, "nullable"):
|
if hasattr(field.field_info, "nullable"):
|
||||||
field_nullable = getattr(field.field_info, "nullable")
|
field_nullable = getattr(field.field_info, "nullable") # noqa: B009
|
||||||
if field_nullable != Undefined:
|
if field_nullable != Undefined:
|
||||||
nullable = field_nullable
|
nullable = field_nullable
|
||||||
args = []
|
args = []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user