Skip to content

Commit 8c07754

Browse files
rchen152meta-codesync[bot]
authored andcommitted
Move sqlalchemy and sqlmodel stubs to a real test stubs package
Summary: test/sqlalchemy.rs had accumulated 100+ lines of in-line stubs. Now the stubs are split out into a test-only stubs package. ___ landed-with-radar-review Differential Revision: D128988125 fbshipit-source-id: 825731796af1cb2d947b82fd176310c5a3fb7229
1 parent 292d912 commit 8c07754

16 files changed

Lines changed: 122 additions & 207 deletions

File tree

‎.cargo/config.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CINDERX_FIXTURES_PATH = { value = "pyrefly/lib/test/cinderx/fixtures", relative
1111
MARSHMALLOW_TEST_PATH = { value = "pyrefly/lib/test/marshmallow/third-party", relative = true }
1212
POLARS_TEST_PATH = { value = "pyrefly/lib/test/polars/third-party", relative = true }
1313
NARWHALS_TEST_PATH = { value = "pyrefly/lib/test/narwhals/third-party", relative = true }
14+
SQLALCHEMY_TEST_PATH = { value = "pyrefly/lib/test/sqlalchemy/third-party", relative = true }
1415
GLEAN_SNAPSHOTS_PATH = { value = "pyrefly/lib/report/glean/snapshots", relative = true }
1516
COVERAGE_TEST_PATH = { value = "pyrefly/lib/test/coverage/test_files", relative = true }
1617
STUBGEN_TEST_PATH = { value = "pyrefly/lib/test/stubgen", relative = true }

‎pyrefly/lib/test/sqlalchemy.rs‎

Lines changed: 9 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -5,191 +5,14 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
use std::env;
9+
810
use crate::test::util::TestEnv;
911
use crate::testcase;
1012

1113
fn sqlalchemy_env() -> TestEnv {
12-
let mut env = TestEnv::new();
13-
env.add_with_path(
14-
"sqlalchemy",
15-
"sqlalchemy/__init__.py",
16-
r#"
17-
from . import orm
18-
from .sql.dml import Update as Update
19-
from .sql.elements import ColumnElement as ColumnElement
20-
from .sql.selectable import Select as Select
21-
def select(*entities: object) -> Select: ...
22-
def update(table: object) -> Update: ...
23-
"#,
24-
);
25-
env.add_with_path(
26-
"sqlalchemy.sql",
27-
"sqlalchemy/sql/__init__.py",
28-
"from . import sqltypes\nfrom . import type_api\n",
29-
);
30-
env.add_with_path(
31-
"sqlalchemy.sql.elements",
32-
"sqlalchemy/sql/elements.py",
33-
r#"
34-
class ColumnElement[T]: ...
35-
"#,
36-
);
37-
env.add_with_path(
38-
"sqlalchemy.sql.dml",
39-
"sqlalchemy/sql/dml.py",
40-
r#"
41-
class Update:
42-
def where(self, *criteria: object) -> Update: ...
43-
def values(self, **kwargs: object) -> Update: ...
44-
"#,
45-
);
46-
env.add_with_path(
47-
"sqlalchemy.sql.selectable",
48-
"sqlalchemy/sql/selectable.py",
49-
r#"
50-
class Select:
51-
def where(self, *criteria: object) -> Select: ...
52-
def filter_by(self, **kwargs: object) -> Select: ...
53-
def join(self, target: object) -> Select: ...
54-
"#,
55-
);
56-
env.add_with_path(
57-
"sqlalchemy.sql.type_api",
58-
"sqlalchemy/sql/type_api.py",
59-
r#"
60-
from typing import Generic, TypeVar
61-
62-
_T = TypeVar("_T")
63-
64-
class TypeEngine(Generic[_T]):
65-
...
66-
67-
class TypeDecorator(TypeEngine[_T], Generic[_T]):
68-
...
69-
"#,
70-
);
71-
env.add_with_path(
72-
"sqlalchemy.sql.sqltypes",
73-
"sqlalchemy/sql/sqltypes.py",
74-
r#"
75-
from enum import Enum as PythonEnum
76-
from typing import Generic, TypeVar
77-
from .type_api import TypeEngine
78-
79-
_T = TypeVar("_T")
80-
81-
class String(TypeEngine[str]):
82-
...
83-
84-
class Integer(TypeEngine[int]):
85-
...
86-
87-
class Float(TypeEngine[float]):
88-
...
89-
90-
class GenericType(TypeEngine[_T], Generic[_T]):
91-
...
92-
93-
# SQLAlchemy itself inherits these conflicting TypeEngine arguments.
94-
class Enum(String, TypeEngine[str | PythonEnum]): # E: Class `Enum` has inconsistent type arguments
95-
def __init__(self, *enums: str | type[PythonEnum]) -> None:
96-
...
97-
"#,
98-
);
99-
env.add_with_path(
100-
"sqlalchemy.orm.attributes",
101-
"sqlalchemy/orm/attributes.py",
102-
r#"
103-
class InstrumentedAttribute[T]: ...
104-
"#,
105-
);
106-
env.add_with_path(
107-
"sqlalchemy.orm.base",
108-
"sqlalchemy/orm/base.py",
109-
r#"
110-
from typing import Any, Generic, TypeVar, overload
111-
from .attributes import InstrumentedAttribute
112-
113-
_T = TypeVar("_T")
114-
115-
class _MappedAnnotationBase(Generic[_T]): ...
116-
117-
class Mapped(_MappedAnnotationBase[_T]):
118-
@overload
119-
def __get__(self, instance: None, owner: Any) -> InstrumentedAttribute[_T]: ...
120-
@overload
121-
def __get__(self, instance: object, owner: Any) -> _T: ...
122-
def __get__(self, instance: object | None, owner: Any) -> InstrumentedAttribute[_T] | _T: ...
123-
def __set__(self, instance: object, value: _T) -> None: ...
124-
125-
class _DeclarativeMapped(Mapped[_T]): ...
126-
"#,
127-
);
128-
env.add_with_path(
129-
"sqlalchemy.orm.properties",
130-
"sqlalchemy/orm/properties.py",
131-
r#"
132-
from typing import Generic, TypeVar
133-
from .base import _DeclarativeMapped
134-
135-
_T = TypeVar("_T")
136-
137-
class MappedColumn(_DeclarativeMapped[_T]):
138-
column: object
139-
140-
def __init__(self) -> None:
141-
...
142-
"#,
143-
);
144-
env.add_with_path(
145-
"sqlalchemy.orm._orm_constructors",
146-
"sqlalchemy/orm/_orm_constructors.py",
147-
r#"
148-
from typing import Any
149-
from sqlalchemy.sql.type_api import TypeEngine
150-
from .properties import MappedColumn
151-
152-
def mapped_column(
153-
__name_pos: str | TypeEngine[Any] | type[TypeEngine[Any]] | None = None,
154-
__type_pos: TypeEngine[Any] | type[TypeEngine[Any]] | None = None,
155-
*args: Any,
156-
type_: TypeEngine[Any] | type[TypeEngine[Any]] | None = None,
157-
nullable: bool | None = None,
158-
primary_key: bool | None = False,
159-
**kw: Any,
160-
) -> MappedColumn[Any]:
161-
return MappedColumn()
162-
"#,
163-
);
164-
env.add_with_path(
165-
"sqlalchemy.orm.decl_api",
166-
"sqlalchemy/orm/decl_api.py",
167-
r#"
168-
from typing import dataclass_transform
169-
170-
from ._orm_constructors import mapped_column
171-
172-
class DeclarativeBase: ...
173-
174-
@dataclass_transform(field_specifiers=(mapped_column,))
175-
class DCTransformDeclarative(type): ...
176-
177-
class MappedAsDataclass(metaclass=DCTransformDeclarative): ...
178-
"#,
179-
);
180-
env.add_with_path(
181-
"sqlalchemy.orm",
182-
"sqlalchemy/orm/__init__.py",
183-
r#"
184-
from ._orm_constructors import mapped_column as mapped_column
185-
from .attributes import InstrumentedAttribute as InstrumentedAttribute
186-
from .base import Mapped as Mapped
187-
from .decl_api import DeclarativeBase as DeclarativeBase
188-
from .decl_api import MappedAsDataclass as MappedAsDataclass
189-
from .properties import MappedColumn as MappedColumn
190-
"#,
191-
);
192-
env
14+
let path = env::var("SQLALCHEMY_TEST_PATH").expect("SQLALCHEMY_TEST_PATH must be set");
15+
TestEnv::new_with_site_package_paths(&[&path])
19316
}
19417

19518
testcase!(
@@ -531,30 +354,9 @@ select_custom(User).filter_by(nam="alice")
531354
"#,
532355
);
533356

534-
fn sqlmodel_env() -> TestEnv {
535-
let mut env = sqlalchemy_env();
536-
env.add_with_path(
537-
"sqlmodel",
538-
"sqlmodel/__init__.py",
539-
r#"
540-
from typing import Any
541-
542-
class SQLModel:
543-
...
544-
545-
def Field(*args, **kwargs) -> Any:
546-
...
547-
548-
def Relationship(*args, **kwargs) -> Any:
549-
...
550-
"#,
551-
);
552-
env
553-
}
554-
555357
testcase!(
556358
test_sqlalchemy_update_values_checks_sqlmodel_fields,
557-
sqlmodel_env(),
359+
sqlalchemy_env(),
558360
r#"
559361
from uuid import UUID
560362
@@ -576,7 +378,7 @@ update(Node).values(nope="a") # E: Unexpected SQLAlchemy update field `nope`
576378

577379
testcase!(
578380
test_sqlalchemy_update_values_checks_sqlmodel_fields_no_mapped,
579-
sqlmodel_env(),
381+
sqlalchemy_env(),
580382
r#"
581383
from sqlalchemy import update
582384
from sqlmodel import Field, SQLModel
@@ -596,7 +398,7 @@ update(Hero).values(nope="a") # E: Unexpected SQLAlchemy update field `nope`
596398

597399
testcase!(
598400
test_sqlalchemy_update_values_checks_sqlmodel_fields_without_mapped,
599-
sqlmodel_env(),
401+
sqlalchemy_env(),
600402
r#"
601403
from uuid import UUID
602404
@@ -614,7 +416,7 @@ update(Node).values(nope="a") # E: Unexpected SQLAlchemy update field `nope`
614416

615417
testcase!(
616418
test_sqlalchemy_update_values_checks_sqlmodel_fields_inherited_fields,
617-
sqlmodel_env(),
419+
sqlalchemy_env(),
618420
r#"
619421
from sqlalchemy import update
620422
from sqlmodel import Field, SQLModel
@@ -634,7 +436,7 @@ update(Hero).values(nope="a") # E: Unexpected SQLAlchemy update field `nope`
634436

635437
testcase!(
636438
test_sqlalchemy_update_values_checks_sqlmodel_ignores_fields_past_table,
637-
sqlmodel_env(),
439+
sqlalchemy_env(),
638440
r#"
639441
from sqlalchemy import update
640442
from sqlmodel import Field, SQLModel
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from . import orm
2+
from .sql.dml import Update as Update
3+
from .sql.elements import ColumnElement as ColumnElement
4+
from .sql.selectable import Select as Select
5+
def select(*entities: object) -> Select: ...
6+
def update(table: object) -> Update: ...
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from ._orm_constructors import mapped_column as mapped_column
2+
from .attributes import InstrumentedAttribute as InstrumentedAttribute
3+
from .base import Mapped as Mapped
4+
from .decl_api import DeclarativeBase as DeclarativeBase
5+
from .decl_api import MappedAsDataclass as MappedAsDataclass
6+
from .properties import MappedColumn as MappedColumn
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from typing import Any
2+
from sqlalchemy.sql.type_api import TypeEngine
3+
from .properties import MappedColumn
4+
5+
def mapped_column(
6+
__name_pos: str | TypeEngine[Any] | type[TypeEngine[Any]] | None = None,
7+
__type_pos: TypeEngine[Any] | type[TypeEngine[Any]] | None = None,
8+
*args: Any,
9+
type_: TypeEngine[Any] | type[TypeEngine[Any]] | None = None,
10+
nullable: bool | None = None,
11+
primary_key: bool | None = False,
12+
**kw: Any,
13+
) -> MappedColumn[Any]: ...
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class InstrumentedAttribute[T]: ...
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import Any, Generic, TypeVar, overload
2+
from .attributes import InstrumentedAttribute
3+
4+
_T = TypeVar("_T")
5+
6+
class _MappedAnnotationBase(Generic[_T]): ...
7+
8+
class Mapped(_MappedAnnotationBase[_T]):
9+
@overload
10+
def __get__(self, instance: None, owner: Any) -> InstrumentedAttribute[_T]: ...
11+
@overload
12+
def __get__(self, instance: object, owner: Any) -> _T: ...
13+
def __set__(self, instance: object, value: _T) -> None: ...
14+
15+
class _DeclarativeMapped(Mapped[_T]): ...
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from typing import dataclass_transform
2+
3+
from ._orm_constructors import mapped_column
4+
5+
class DeclarativeBase: ...
6+
7+
@dataclass_transform(field_specifiers=(mapped_column,))
8+
class DCTransformDeclarative(type): ...
9+
10+
class MappedAsDataclass(metaclass=DCTransformDeclarative): ...
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from typing import Generic, TypeVar
2+
from .base import _DeclarativeMapped
3+
4+
_T = TypeVar("_T")
5+
6+
class MappedColumn(_DeclarativeMapped[_T]):
7+
column: object
8+
9+
def __init__(self) -> None:
10+
...
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import sqltypes
2+
from . import type_api

0 commit comments

Comments
 (0)