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
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ["3.9", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "pypy3.9", "pypy3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "pypy3.9", "pypy3.10"]

steps:
- uses: actions/checkout@v5
Expand Down Expand Up @@ -53,7 +53,6 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- run: pip install mypy
- run: |
pip install
pip install mypy
mypy .
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
exclude: '.git'
default_stages: [commit]
default_stages: [pre-commit]
fail_fast: false

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
files: "pypika.*"
Expand All @@ -20,6 +20,6 @@ repos:
- id: debug-statements

- repo: https://github.com/psf/black
rev: 23.9.1
rev: 25.9.0
hooks:
- id: black
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ install: ## Install development dependencies
pre-commit install

test: ## Run tests
tox
coverage run -m pytest
coverage report -m

docs.build: ## Build the documentation
$(SPHINXBUILD) $(SOURCEDIR) $(BUILDDIR) -b html -E
Expand Down
10 changes: 8 additions & 2 deletions pypika/queries.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
from copy import copy
from functools import reduce
from typing import Any, Generic, List, Optional, Sequence, Tuple as TypedTuple, Type, TypeVar, Union
from typing_extensions import Self, Type
from typing import TYPE_CHECKING, Any, Generic, List, Optional, Sequence, Tuple as TypedTuple, Type, TypeVar, Union

from pypika.enums import Dialects, JoinType, ReferenceOption, SetOperation
from pypika.terms import (
Expand Down Expand Up @@ -30,6 +30,12 @@
ignore_copy,
)

if TYPE_CHECKING:
if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self

__author__ = "Timothy Heys"
__email__ = "[email protected]"

Expand Down
39 changes: 27 additions & 12 deletions pypika/terms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from __future__ import annotations

import inspect
import re
import sys
import uuid
from datetime import (
date,
Expand All @@ -21,6 +24,7 @@
Type,
TypeVar,
Union,
overload,
)

from pypika.enums import Arithmetic, Boolean, Comparator, Dialects, Equality, JSONOperators, Matching, Order
Expand All @@ -35,6 +39,10 @@
)

if TYPE_CHECKING:
if sys.version_info < (3, 11):
from typing_extensions import Self
else:
from typing import Self
from pypika.queries import QueryBuilder, Selectable, Table


Expand Down Expand Up @@ -593,23 +601,30 @@ def __init__(self, alias: Optional[str] = None) -> None:


class Criterion(Term):
def __and__(self, other: Any) -> "ComplexCriterion":
if isinstance(other, EmptyCriterion):
return self
return ComplexCriterion(Boolean.and_, self, other)
@overload
def _compare(self, comparator: Comparator, other: EmptyCriterion) -> "Self":
...

def __or__(self, other: Any) -> "ComplexCriterion":
if isinstance(other, EmptyCriterion):
return self
return ComplexCriterion(Boolean.or_, self, other)
@overload
def _compare(self, comparator: Comparator, other: Any) -> "ComplexCriterion":
...

def __xor__(self, other: Any) -> "ComplexCriterion":
def _compare(self, comparator: Comparator, other: Any) -> "Self | ComplexCriterion":
if isinstance(other, EmptyCriterion):
return self
return ComplexCriterion(Boolean.xor_, self, other)
return ComplexCriterion(comparator, self, other)

def __and__(self, other: Any) -> "Self | ComplexCriterion":
return self._compare(Boolean.and_, other)

def __or__(self, other: Any) -> "Self | ComplexCriterion":
return self._compare(Boolean.or_, other)

def __xor__(self, other: Any) -> "Self | ComplexCriterion":
return self._compare(Boolean.xor_, other)

@staticmethod
def any(terms: Iterable[Term] = ()) -> "EmptyCriterion":
def any(terms: Iterable[Term] = ()) -> "EmptyCriterion | Term | ComplexCriterion":
crit = EmptyCriterion()

for term in terms:
Expand All @@ -618,7 +633,7 @@ def any(terms: Iterable[Term] = ()) -> "EmptyCriterion":
return crit

@staticmethod
def all(terms: Iterable[Any] = ()) -> "EmptyCriterion":
def all(terms: Iterable[Any] = ()) -> "EmptyCriterion | Any | ComplexCriterion":
crit = EmptyCriterion()

for term in terms:
Expand Down
15 changes: 9 additions & 6 deletions pypika/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import sys
from functools import wraps
from typing import Any, Callable, List, Optional, Type, TypeVar, Union, overload
from typing_extensions import Concatenate, ParamSpec

if sys.version_info >= (3, 10):
from typing import Concatenate, ParamSpec
else:
from typing_extensions import Concatenate, ParamSpec


__author__ = "Timothy Heys"
Expand Down Expand Up @@ -45,13 +50,11 @@ class FunctionException(Exception):


@overload
def builder(func: Callable[Concatenate[_Self, P], None]) -> Callable[Concatenate[_Self, P], _Self]:
...
def builder(func: Callable[Concatenate[_Self, P], None]) -> Callable[Concatenate[_Self, P], _Self]: ...


@overload
def builder(func: Callable[Concatenate[_Self, P], R]) -> Callable[Concatenate[_Self, P], R]:
...
def builder(func: Callable[Concatenate[_Self, P], R]) -> Callable[Concatenate[_Self, P], R]: ...


def builder(func: Callable[Concatenate[_Self, P], Optional[R]]) -> Callable[Concatenate[_Self, P], Union[_Self, R]]:
Expand Down Expand Up @@ -121,7 +124,7 @@ def resolve_is_aggregate(values: List[Optional[bool]]) -> Optional[bool]:

def format_quotes(value: Any, quote_char: Optional[str]) -> str:
if quote_char:
value = value.replace(quote_char, quote_char * 2)
value = str(value).replace(quote_char, quote_char * 2)

return "{quote}{value}{quote}".format(value=value, quote=quote_char or "")

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
typing_extensions>=4.5.0
typing_extensions>=4.5.0; python_version<'3.11'
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def version():
package_data={"pypika": ["py.typed"]},
include_package_data=True,

install_requires=["typing_extensions>=4.5.0"],
install_requires=["typing_extensions>=4.5.0; python_version<'3.11'"],

# Details
url="https://github.com/kayak/pypika",
Expand Down
Loading