Skip to content

Commit 0a9dde1

Browse files
authored
Update install instructions (#52)
(plus two tiny fixes)
1 parent daf6637 commit 0a9dde1

File tree

2 files changed

+43
-14
lines changed

2 files changed

+43
-14
lines changed

README.md

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ Mypy plugin and stubs for SQLAlchemy
66
[![Build Status](https://travis-ci.org/dropbox/sqlalchemy-stubs.svg?branch=master)](https://travis-ci.org/dropbox/sqlalchemy-stubs)
77
[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
88

9-
This package contains [type stubs](https://www.python.org/dev/peps/pep-0561/) and soon a
10-
mypy plugin to provide more precise static types
11-
and type inference for [SQLAlchemy framework](http://docs.sqlalchemy.org/en/latest/).
12-
SQLAlchemy uses some Python "magic" that
13-
makes having precise types for some code patterns problematic. This is why we need to
14-
accompany the stubs with mypy plugins. The final goal is to be able to get precise types
15-
for most common patterns. A simple example:
16-
9+
This package contains [type stubs](https://www.python.org/dev/peps/pep-0561/) and a
10+
[mypy plugin](https://mypy.readthedocs.io/en/latest/extending_mypy.html#extending-mypy-using-plugins)
11+
to provide more precise static types and type inference for
12+
[SQLAlchemy framework](http://docs.sqlalchemy.org/en/latest/). SQLAlchemy uses some
13+
Python "magic" that makes having precise types for some code patterns problematic.
14+
This is why we need to accompany the stubs with mypy plugins. The final goal is to
15+
be able to get precise types for most common patterns. Currently, basic operations
16+
with models are supported. A simple example:
1717
```python
1818
from sqlalchemy.ext.declarative import declarative_base
1919
from sqlalchemy import Column, Integer, String
@@ -25,11 +25,33 @@ class User(Base):
2525
id = Column(Integer, primary_key=True)
2626
name = Column(String)
2727

28-
user: User
28+
user = User(id=42, name=42) # Error: Incompatible type for "name" of "User"
29+
# (got "int", expected "Optional[str]"
2930
user.id # Inferred type is "int"
30-
User.name # Inferred type is "Column[str]"
31+
User.name # Inferred type is "Column[Optional[str]]"
32+
```
33+
34+
Some auto-generated attributes are added to models. Simple relationships
35+
are supported but require models to be imported:
36+
```python
37+
from typing import TYPE_CHECKING
38+
if TYPE_CHECKING:
39+
from models.address import Address
40+
41+
...
42+
43+
class User(Base):
44+
__tablename__ = 'users'
45+
id = Column(Integer, primary_key=True)
46+
name = Column(String)
47+
address = relationship('Address') # OK, mypy understands string references.
3148
```
3249

50+
The next step is to support precise types for table definitions (e.g.
51+
inferring `Column[Optional[str]]` for `users.c.name`, currently it is just
52+
`Column[Any]`), and precise types for results of queries made using `query()`
53+
and `select()`.
54+
3355
## Installation
3456

3557
To install the latest version of the package:
@@ -45,6 +67,12 @@ stable version as:
4567
pip install -U sqlalchemy-stubs
4668
```
4769

70+
*Important*: you need to enable the plugin in your mypy config file:
71+
```
72+
[mypy]
73+
plugins = sqlmypy
74+
```
75+
4876
## Development Setup
4977

5078
First, clone the repo and cd into it, like in _Installation_, then:

sqlmypy.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ def add_model_init_hook(ctx: ClassDefContext) -> None:
9292
if '__init__' in ctx.cls.info.names:
9393
# Don't override existing definition.
9494
return
95-
typ = AnyType(TypeOfAny.special_form)
96-
var = Var('kwargs', typ)
97-
kw_arg = Argument(variable=var, type_annotation=typ, initializer=None, kind=ARG_STAR2)
95+
any = AnyType(TypeOfAny.special_form)
96+
var = Var('kwargs', any)
97+
kw_arg = Argument(variable=var, type_annotation=any, initializer=None, kind=ARG_STAR2)
9898
add_method(ctx, '__init__', [kw_arg], NoneTyp())
9999
ctx.cls.info.metadata.setdefault('sqlalchemy', {})['generated_init'] = True
100100

@@ -300,7 +300,8 @@ class User(Base):
300300
new_arg = fill_typevars_with_any(sym.node)
301301
else:
302302
ctx.api.fail('Cannot find model "{}"'.format(name), ctx.context)
303-
ctx.api.note('Only imported models can be found; use "if TYPE_CHECKING: ..." to avoid import cycles', ctx.context)
303+
ctx.api.note('Only imported models can be found; use "if TYPE_CHECKING: ..." to avoid import cycles',
304+
ctx.context)
304305
new_arg = AnyType(TypeOfAny.from_error)
305306
else:
306307
if isinstance(arg_type, CallableType) and arg_type.is_type_obj():

0 commit comments

Comments
 (0)