Skip to content

Commit

Permalink
[typing] add typing to web.api and dependent functions
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasjuhrich committed Sep 4, 2023
1 parent 2e4e5be commit 579e2b0
Show file tree
Hide file tree
Showing 17 changed files with 286 additions and 52 deletions.
6 changes: 4 additions & 2 deletions pycroft/lib/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from difflib import SequenceMatcher
from typing import Iterable

from sqlalchemy import func, select, Boolean, String
from sqlalchemy import func, select, Boolean, String, ColumnElement

from pycroft import config, property
from pycroft.helpers import user as user_helper, utc
Expand Down Expand Up @@ -681,7 +681,9 @@ def edit_address(


def traffic_history(
user_id: int, start: DateTimeTz, end: DateTimeTz
user_id: int,
start: DateTimeTz | ColumnElement[DateTimeTz],
end: DateTimeTz | ColumnElement[DateTimeTz],
) -> list[TrafficHistoryEntry]:
result = session.session.execute(
select("*")
Expand Down
12 changes: 7 additions & 5 deletions pycroft/model/finance.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import datetime
import typing as t
from datetime import timedelta, date
from decimal import Decimal
from math import fabs

from sqlalchemy import ForeignKey, event, func, select, Enum, ColumnElement
from sqlalchemy import ForeignKey, event, func, select, Enum, ColumnElement, Select
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship, object_session, Mapped, mapped_column
from sqlalchemy.schema import CheckConstraint, ForeignKeyConstraint, UniqueConstraint
Expand All @@ -25,6 +26,7 @@
from .exc import PycroftModelException
from .type_aliases import str127, str255, datetime_tz_onupdate
from ..helpers import utc
from ..helpers.utc import DateTimeTz

manager = ddl.DDLManager()

Expand Down Expand Up @@ -361,22 +363,22 @@ class BankAccount(IntegerIdModel):
# /backrefs

@hybrid_property
def balance(self):
def _balance(self) -> Decimal:
return object_session(self).execute(
select(func.coalesce(func.sum(BankAccountActivity.amount), 0))
.where(BankAccountActivity.bank_account_id == self.id)
).scalar()

@balance.expression
def balance(cls):
@_balance.expression
def balance(cls) -> Select[tuple[Decimal]]:
return select(
[func.coalesce(func.sum(BankAccountActivity.amount), 0)]
).where(
BankAccountActivity.bank_account_id == cls.id
).label("balance")

@hybrid_property
def last_imported_at(self):
def last_imported_at(self) -> DateTimeTz:
return object_session(self).execute(
select(func.max(BankAccountActivity.imported_at))
.where(BankAccountActivity.bank_account_id == self.id)
Expand Down
6 changes: 5 additions & 1 deletion pycroft/model/traffic.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
select,
cast,
TEXT,
ColumnElement,
)
from sqlalchemy.orm import relationship, Query, Mapped, mapped_column
from sqlalchemy.sql.selectable import TableValuedAlias
Expand Down Expand Up @@ -224,7 +225,10 @@ def traffic_history_query():


def traffic_history(
user_id: int, start: utc.DateTimeTz, end: utc.DateTimeTz, name='traffic_history'
user_id: int,
start: utc.DateTimeTz | ColumnElement[utc.DateTimeTz],
end: utc.DateTimeTz | ColumnElement[utc.DateTimeTz],
name="traffic_history",
) -> TableValuedAlias:
"""A sqlalchemy `func` wrapper for the `evaluate_properties` PSQL function.
Expand Down
54 changes: 54 additions & 0 deletions stubs/flask_restful/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from _typeshed import Incomplete

from flask import Response
from flask.views import MethodView

def abort(http_status_code, **kwargs) -> None: ...

class Api:
representations: Incomplete
urls: Incomplete
prefix: Incomplete
default_mediatype: Incomplete
decorators: Incomplete
catch_all_404s: Incomplete
serve_challenge_on_401: Incomplete
url_part_order: Incomplete
errors: Incomplete
blueprint_setup: Incomplete
endpoints: Incomplete
resources: Incomplete
app: Incomplete
blueprint: Incomplete
def __init__(self, app: Incomplete | None = ..., prefix: str = ..., default_mediatype: str = ..., decorators: Incomplete | None = ..., catch_all_404s: bool = ..., serve_challenge_on_401: bool = ..., url_part_order: str = ..., errors: Incomplete | None = ...) -> None: ...
def init_app(self, app) -> None: ...
def owns_endpoint(self, endpoint): ...
def error_router(self, original_handler, e): ...
def handle_error(self, e: Exception) -> Response: ...
def mediatypes_method(self): ...
def add_resource(self, resource, *urls, **kwargs) -> None: ...
def resource(self, *urls, **kwargs): ...
def output(self, resource): ...
def url_for(self, resource, **values): ...
def make_response(self, data, *args, **kwargs): ...
def mediatypes(self): ...
def representation(self, mediatype): ...
def unauthorized(self, response): ...

class Resource(MethodView):
representations: Incomplete
method_decorators: Incomplete
def dispatch_request(self, *args, **kwargs): ...

def marshal(data, fields, envelope: Incomplete | None = ...): ...

class marshal_with:
fields: Incomplete
envelope: Incomplete
def __init__(self, fields, envelope: Incomplete | None = ...) -> None: ...
def __call__(self, f): ...

class marshal_with_field:
field: Incomplete
def __init__(self, field) -> None: ...
def __call__(self, f): ...
Empty file.
62 changes: 62 additions & 0 deletions stubs/flask_restful/fields.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from _typeshed import Incomplete

class MarshallingException(Exception):
def __init__(self, underlying_exception) -> None: ...

class Raw:
attribute: Incomplete
default: Incomplete
def __init__(self, default: Incomplete | None = ..., attribute: Incomplete | None = ...) -> None: ...
def format(self, value): ...
def output(self, key, obj): ...

class Nested(Raw):
nested: Incomplete
allow_null: Incomplete
def __init__(self, nested, allow_null: bool = ..., **kwargs) -> None: ...
def output(self, key, obj): ...

class List(Raw):
container: Incomplete
def __init__(self, cls_or_instance, **kwargs) -> None: ...
def format(self, value): ...
def output(self, key, data): ...

class String(Raw):
def format(self, value): ...

class Integer(Raw):
def __init__(self, default: int = ..., **kwargs) -> None: ...
def format(self, value): ...

class Boolean(Raw):
def format(self, value): ...

class FormattedString(Raw):
src_str: Incomplete
def __init__(self, src_str) -> None: ...
def output(self, key, obj): ...

class Url(Raw):
endpoint: Incomplete
absolute: Incomplete
scheme: Incomplete
def __init__(self, endpoint: Incomplete | None = ..., absolute: bool = ..., scheme: Incomplete | None = ..., **kwargs) -> None: ...
def output(self, key, obj): ...

class Float(Raw):
def format(self, value): ...

class Arbitrary(Raw):
def format(self, value): ...

class DateTime(Raw):
dt_format: Incomplete
def __init__(self, dt_format: str = ..., **kwargs) -> None: ...
def format(self, value): ...

class Fixed(Raw):
precision: Incomplete
def __init__(self, decimals: int = ..., **kwargs) -> None: ...
def format(self, value): ...
Price = Fixed
31 changes: 31 additions & 0 deletions stubs/flask_restful/inputs.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from _typeshed import Incomplete
from calendar import timegm as timegm

START_OF_DAY: Incomplete
END_OF_DAY: Incomplete
url_regex: Incomplete

def url(value): ...

class regex:
pattern: Incomplete
re: Incomplete
def __init__(self, pattern, flags: int = ...) -> None: ...
def __call__(self, value): ...
def __deepcopy__(self, memo): ...

def iso8601interval(value, argument: str = ...): ...
def date(value): ...
def natural(value, argument: str = ...): ...
def positive(value, argument: str = ...): ...

class int_range:
low: Incomplete
high: Incomplete
argument: Incomplete
def __init__(self, low, high, argument: str = ...) -> None: ...
def __call__(self, value): ...

def boolean(value): ...
def datetime_from_rfc822(datetime_str): ...
def datetime_from_iso8601(datetime_str): ...
Empty file.
4 changes: 4 additions & 0 deletions stubs/flask_restful/representations/json.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from _typeshed import Incomplete
from flask_restful.utils import PY3 as PY3

def output_json(data, code, headers: Incomplete | None = ...): ...
42 changes: 42 additions & 0 deletions stubs/flask_restful/reqparse.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from _typeshed import Incomplete

class Namespace(dict):
def __getattr__(self, name): ...
def __setattr__(self, name, value) -> None: ...

text_type: Incomplete

class Argument:
name: Incomplete
default: Incomplete
dest: Incomplete
required: Incomplete
ignore: Incomplete
location: Incomplete
type: Incomplete
choices: Incomplete
action: Incomplete
help: Incomplete
case_sensitive: Incomplete
operators: Incomplete
store_missing: Incomplete
trim: Incomplete
nullable: Incomplete
def __init__(self, name, default: Incomplete | None = ..., dest: Incomplete | None = ..., required: bool = ..., ignore: bool = ..., type=..., location=..., choices=..., action: str = ..., help: Incomplete | None = ..., operators=..., case_sensitive: bool = ..., store_missing: bool = ..., trim: bool = ..., nullable: bool = ...) -> None: ...
def source(self, request): ...
def convert(self, value, op): ...
def handle_validation_error(self, error, bundle_errors): ...
def parse(self, request, bundle_errors: bool = ...): ...

class RequestParser:
args: Incomplete
argument_class: Incomplete
namespace_class: Incomplete
trim: Incomplete
bundle_errors: Incomplete
def __init__(self, argument_class=..., namespace_class=..., trim: bool = ..., bundle_errors: bool = ...) -> None: ...
def add_argument(self, *args, **kwargs): ...
def parse_args(self, req: Incomplete | None = ..., strict: bool = ..., http_error_code: int = ...): ...
def copy(self): ...
def replace_argument(self, name, *args, **kwargs): ...
def remove_argument(self, name): ...
6 changes: 6 additions & 0 deletions stubs/flask_restful/utils/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from _typeshed import Incomplete

PY3: Incomplete

def http_status_message(code): ...
def unpack(value): ...
3 changes: 3 additions & 0 deletions stubs/flask_restful/utils/cors.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from _typeshed import Incomplete

def crossdomain(origin: Incomplete | None = ..., methods: Incomplete | None = ..., headers: Incomplete | None = ..., expose_headers: Incomplete | None = ..., max_age: int = ..., attach_to_all: bool = ..., automatic_options: bool = ..., credentials: bool = ...): ...
2 changes: 2 additions & 0 deletions stubs/flask_restful/utils/crypto.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def encrypt(plaintext_data, key, seed): ...
def decrypt(encrypted_data, key, seed): ...
4 changes: 3 additions & 1 deletion web/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from flask import Blueprint, Flask
from flask.typing import ResponseReturnValue

from . import v0

Expand All @@ -8,5 +9,6 @@
app_for_sphinx = Flask(__name__)
app_for_sphinx.register_blueprint(bp, url_prefix="/api/v0")

def errorpage(e):

def errorpage(e: Exception) -> ResponseReturnValue:
return v0.api.handle_error(e)
Loading

0 comments on commit 579e2b0

Please sign in to comment.