Skip to content

Commit

Permalink
adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Dec 4, 2023
1 parent 455e39f commit 3f941d2
Show file tree
Hide file tree
Showing 12 changed files with 420 additions and 35 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,39 @@ jobs:
extra_args: --all-files
env:
SKIP: no-commit-to-branch
test:
name: test ${{ matrix.python-version }} on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos]
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

runs-on: ${{ matrix.os }}-latest

env:
PYTHON: ${{ matrix.python-version }}
OS: ${{ matrix.os }}

steps:
- uses: actions/checkout@v3

- name: set up python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- run: pip install -r src/python-fastui/requirements/test.txt
- run: pip install -r src/python-fastui/requirements/pyproject.txt

- run: make test

- run: coverage xml

- uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
env_vars: PYTHON,OS

packages-build:
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
/**/*.egg-info

node_modules
dist
Expand All @@ -31,3 +32,4 @@ __pycache__/
/frontend-dist/
/scratch/
/packages-dist/
/.coverage
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ install:
update-lockfiles:
@echo "Updating requirements files using pip-compile"
pip-compile -q --strip-extras -o $(path)/requirements/lint.txt $(path)/requirements/lint.in
pip-compile -q --strip-extras -o $(path)/requirements/pyproject.txt pyproject.toml --extra=fastapi
pip-compile -q --strip-extras -o $(path)/requirements/test.txt $(path)/requirements/test.in
pip-compile -q --strip-extras -o $(path)/requirements/pyproject.txt $(path)/pyproject.toml --extra=fastapi
pip install --dry-run -r $(path)/requirements/all.txt

.PHONY: format
Expand All @@ -30,7 +31,7 @@ typecheck:

.PHONY: test
test:
coverage run -m pytest tests
coverage run -m pytest

.PHONY: testcov
testcov: test
Expand Down
15 changes: 3 additions & 12 deletions demo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,19 @@ def form_content(kind: FormKind):
return [
c.Heading(text='Login Form', level=2),
c.Paragraph(text='Simple login form with email and password.'),
c.ModelForm[LoginForm](
submit_url='/api/forms/login',
success_event=PageEvent(name='form_success'),
),
c.ModelForm[LoginForm](submit_url='/api/forms/login'),
]
case 'select':
return [
c.Heading(text='Select Form', level=2),
c.Paragraph(text='Form showing different ways of doing select.'),
c.ModelForm[SelectForm](
submit_url='/api/forms/select',
success_event=PageEvent(name='form_success'),
),
c.ModelForm[SelectForm](submit_url='/api/forms/select'),
]
case 'big':
return [
c.Heading(text='Large Form', level=2),
c.Paragraph(text='Form with a lot of fields.'),
c.ModelForm[BigModel](
submit_url='/api/forms/big',
success_event=PageEvent(name='form_success'),
),
c.ModelForm[BigModel](submit_url='/api/forms/big'),
]
case _:
raise ValueError(f'Invalid kind {kind!r}')
Expand Down
4 changes: 3 additions & 1 deletion src/python-fastui/fastui/components/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class FormFieldSelectSearch(BaseFormField):
FormField = FormFieldInput | FormFieldCheckbox | FormFieldFile | FormFieldSelect | FormFieldSelectSearch


class BaseForm(pydantic.BaseModel, ABC, defer_build=True):
class BaseForm(pydantic.BaseModel, ABC, defer_build=True, extra='forbid'):
submit_url: str = pydantic.Field(serialization_alias='submitUrl')
initial: dict[str, typing.Any] | None = None
method: typing.Literal['POST', 'GOTO', 'GET'] = 'POST'
Expand All @@ -91,6 +91,8 @@ class Form(BaseForm):


class ModelForm(BaseForm, typing.Generic[FormFieldsModel]):
# TODO should we change this to simply have
# model: type[pydantic.BaseModel] = pydantic.Field(exclude=True)
type: typing.Literal['ModelForm'] = 'ModelForm'

@pydantic.computed_field(alias='formFields')
Expand Down
34 changes: 22 additions & 12 deletions src/python-fastui/fastui/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import json
import typing
from itertools import groupby
from mimetypes import MimeTypes
from operator import itemgetter

import pydantic
Expand All @@ -14,6 +15,7 @@

try:
import fastapi
from fastapi import params as fastapi_params
from starlette import datastructures as ds
except ImportError as e:
raise ImportError('fastui.dev requires fastapi to be installed, install with `pip install fastui[fastapi]`') from e
Expand All @@ -31,13 +33,11 @@ class FastUIForm(typing.Generic[FormModel]):
TODO mypy, pyright and pycharm don't understand the model type if this is used, is there a way to get it to work?
"""

def __class_getitem__(
cls, model: type[FormModel]
) -> typing.Callable[[fastapi.Request], typing.Awaitable[FormModel]]:
def __class_getitem__(cls, model: type[FormModel]) -> fastapi_params.Depends:
return fastui_form(model)


def fastui_form(model: type[FormModel]) -> typing.Callable[[fastapi.Request], typing.Awaitable[FormModel]]:
def fastui_form(model: type[FormModel]) -> fastapi_params.Depends:
async def run_fastui_form(request: fastapi.Request):
async with request.form() as form_data:
model_data = unflatten(form_data)
Expand Down Expand Up @@ -77,15 +77,15 @@ def validate_multiple(self, input_value: typing.Any) -> list[ds.UploadFile]:
def _validate_file(self, file: ds.UploadFile) -> None:
"""
See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers
for details on what's allowed
for details on what's allowed.
"""
if file.size == 0:
# FIXME is this right???
return

if self.max_size is not None and file.size is not None and file.size > self.max_size:
raise pydantic_core.PydanticCustomError(
'file_no_big',
'file_too_big',
'File size was {file_size}, exceeding maximum allowed size of {max_size}',
{
'file_size': pydantic.ByteSize(file.size).human_readable(),
Expand All @@ -104,13 +104,13 @@ def _validate_file(self, file: ds.UploadFile) -> None:
# this is a file extension
if file.filename and file.filename.endswith(accept):
return
elif file.content_type is None:
continue
elif accept.endswith('/*'):
if file.content_type.startswith(accept[:-1]):

if content_type := get_content_type(file):
if accept.endswith('/*'):
if content_type.startswith(accept[:-1]):
return
elif content_type == accept:
return
elif file.content_type == accept:
return

raise pydantic_core.PydanticCustomError(
'accept_mismatch',
Expand Down Expand Up @@ -147,6 +147,16 @@ def __repr__(self):
return f'FormFile(accept={self.accept!r})'


_mime_types = MimeTypes()


def get_content_type(file: ds.UploadFile) -> str | None:
if file.content_type:
return file.content_type
elif file.filename:
return _mime_types.guess_type(file.filename)[0]


class FormResponse(pydantic.BaseModel):
event: events.AnyEvent
type: typing.Literal['FormResponse'] = 'FormResponse'
Expand Down
1 change: 1 addition & 0 deletions src/python-fastui/requirements/all.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-r ./lint.txt
-r ./test.txt
-r ./pyproject.txt
uvicorn[standard]
6 changes: 3 additions & 3 deletions src/python-fastui/requirements/lint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --output-file=python/requirements/lint.txt --strip-extras python/requirements/lint.in
# pip-compile --output-file=src/python-fastui/requirements/lint.txt --strip-extras src/python-fastui/requirements/lint.in
#
nodeenv==1.8.0
# via pyright
pyright==1.1.335
# via -r python/requirements/lint.in
# via -r src/python-fastui/requirements/lint.in
ruff==0.1.5
# via -r python/requirements/lint.in
# via -r src/python-fastui/requirements/lint.in

# The following packages are considered to be unsafe in a requirements file:
# setuptools
10 changes: 5 additions & 5 deletions src/python-fastui/requirements/pyproject.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --extra=fastapi --output-file=python/requirements/pyproject.txt --strip-extras pyproject.toml
# pip-compile --extra=fastapi --output-file=src/python-fastui/requirements/pyproject.txt --strip-extras src/python-fastui/pyproject.toml
#
annotated-types==0.6.0
# via pydantic
Expand All @@ -15,20 +15,20 @@ dnspython==2.4.2
email-validator==2.1.0.post1
# via pydantic
fastapi==0.104.1
# via fastui (pyproject.toml)
idna==3.4
# via fastui (src/python-fastui/pyproject.toml)
idna==3.6
# via
# anyio
# email-validator
pydantic==2.5.2
# via
# fastapi
# fastui (pyproject.toml)
# fastui (src/python-fastui/pyproject.toml)
# pydantic
pydantic-core==2.14.5
# via pydantic
python-multipart==0.0.6
# via fastui (pyproject.toml)
# via fastui (src/python-fastui/pyproject.toml)
sniffio==1.3.0
# via anyio
starlette==0.27.0
Expand Down
4 changes: 4 additions & 0 deletions src/python-fastui/requirements/test.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
coverage
pytest
pytest-pretty
dirty-equals
32 changes: 32 additions & 0 deletions src/python-fastui/requirements/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --output-file=src/python-fastui/requirements/test.txt --strip-extras src/python-fastui/requirements/test.in
#
coverage==7.3.2
# via -r src/python-fastui/requirements/test.in
dirty-equals==0.7.1.post0
# via -r src/python-fastui/requirements/test.in
iniconfig==2.0.0
# via pytest
markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
packaging==23.2
# via pytest
pluggy==1.3.0
# via pytest
pygments==2.17.2
# via rich
pytest==7.4.3
# via
# -r src/python-fastui/requirements/test.in
# pytest-pretty
pytest-pretty==1.2.0
# via -r src/python-fastui/requirements/test.in
pytz==2023.3.post1
# via dirty-equals
rich==13.7.0
# via pytest-pretty
Loading

0 comments on commit 3f941d2

Please sign in to comment.