Skip to content

Commit

Permalink
add tests etc
Browse files Browse the repository at this point in the history
  • Loading branch information
snopoke committed Nov 9, 2023
1 parent b7e5e3e commit 76cbb04
Show file tree
Hide file tree
Showing 13 changed files with 349 additions and 26 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [snopoke]
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13-dev"]

steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- name: Install Poetry
uses: Gr1N/setup-poetry@v8
- uses: actions/cache@v3
with:
path: ~/.cache/pypoetry/virtualenvs
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
- name: Install dependencies
# Explicitly also install tox-gh-actions to prevent tests from using system interpreter
run: |
poetry install --no-interaction=
pip install tox-gh-actions
- name: Run tox
run: tox
39 changes: 39 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
on:
workflow_dispatch:
branches: [main]
release:
types:
- published

name: PyPI Publish

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Install Poetry
uses: Gr1N/setup-poetry@v8
- uses: actions/cache@v3
with:
path: ~/.cache/pypoetry/virtualenvs
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
- name: Checks
run: |
poetry --version
poetry check --no-interaction
- name: Install deps
run: poetry install --no-interaction
- name: Run tests
run: poetry run pytest -v
- name: Publish to PyPI
env:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
run: |
poetry config pypi-token.pypi $PYPI_TOKEN
poetry publish --build
64 changes: 64 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
on:
workflow_dispatch:
branches: [main]
push:
tags:
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10

name: Create Release
permissions:
contents: write

jobs:
autorelease:
name: Create Release
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Install Poetry
uses: Gr1N/setup-poetry@v8
- uses: actions/cache@v3
with:
path: ~/.cache/pypoetry/virtualenvs
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
- name: Checks
run: |
poetry --version
poetry check --no-interaction
- name: Add version to environment vars
run: |
PROJECT_VERSION=$(poetry version --short)
echo "PROJECT_VERSION=$PROJECT_VERSION" >> $GITHUB_ENV
- name: Check if tag version matches project version
run: |
TAG=$(git describe HEAD --tags --abbrev=0)
echo $TAG
echo $PROJECT_VERSION
if [[ "$TAG" != "v$PROJECT_VERSION" ]]; then exit 1; fi
- name: Checks
run: |
poetry --version
poetry check --no-interaction
- name: Install deps
run: poetry install --no-interaction
- name: Run tests
run: poetry run pytest -v
- name: Build
run: poetry build
- name: Create Release Draft
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: Release ${{ github.ref }}
draft: true
generate_release_notes: true
files: |
dist/taskbadger-${{env.PROJECT_VERSION}}-py3-none-any.whl
dist/taskbadger-${{env.PROJECT_VERSION}}.tar.gz
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
.idea/
.ruff_cache/
.pytest_cache/
.tox/
__pycache__
2 changes: 2 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ repos:
rev: v0.1.4
hooks:
- id: ruff
args:
- --fix
- id: ruff-format
File renamed without changes.
43 changes: 21 additions & 22 deletions django_dataclass_form/form.py → django_dataclass_forms/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def form_field_for_dataclass_field(dataclass_field):

def fields_for_dataclass(
dataclass_type,
fields=None,
field_names=None,
exclude=None,
widgets=None,
formfield_callback=None,
Expand All @@ -38,7 +38,7 @@ def fields_for_dataclass(
field_classes=None,
):
"""
Return a dictionary containing form fields for the given model.
Return a dictionary containing form fields for the given dataclass.
``fields`` is an optional list of field names. If provided, return only the
named fields.
Expand All @@ -47,30 +47,27 @@ def fields_for_dataclass(
named fields from the returned fields, even if they are listed in the
``fields`` argument.
``widgets`` is a dictionary of model field names mapped to a widget.
``widgets`` is a dictionary of dataclass field names mapped to a widget.
``formfield_callback`` is a callable that takes a model field and returns
``formfield_callback`` is a callable that takes a dataclass field and returns
a form field.
``labels`` is a dictionary of model field names mapped to a label.
``labels`` is a dictionary of dataclass field names mapped to a label.
``help_texts`` is a dictionary of model field names mapped to a help text.
``help_texts`` is a dictionary of dataclass field names mapped to a help text.
``error_messages`` is a dictionary of model field names mapped to a
``error_messages`` is a dictionary of dataclass field names mapped to a
dictionary of error messages.
``field_classes`` is a dictionary of model field names mapped to a form
``field_classes`` is a dictionary of dataclass field names mapped to a form
field class.
``apply_limit_choices_to`` is a boolean indicating if limit_choices_to
should be applied to a field's queryset.
"""
field_dict = {}
ignored = []

dataclass_fields = dataclasses.fields(dataclass_type)
for f in dataclass_fields:
if fields is not None and f.name not in fields:
if field_names is not None and f.name not in field_names:
continue
if exclude and f.name in exclude:
continue
Expand All @@ -84,10 +81,10 @@ def fields_for_dataclass(
kwargs["help_text"] = help_texts[f.name]
if error_messages and f.name in error_messages:
kwargs["error_messages"] = error_messages[f.name]
if field_classes and f.name in field_classes:
kwargs["form_class"] = field_classes[f.name]

if formfield_callback is None:
if field_classes and f.name in field_classes:
formfield = field_classes[f.name](**kwargs)
elif formfield_callback is None:
formfield = form_field_for_dataclass_field(f)(**kwargs)
elif not callable(formfield_callback):
raise TypeError("formfield_callback must be a function or callable")
Expand All @@ -98,8 +95,10 @@ def fields_for_dataclass(
field_dict[f.name] = formfield
else:
ignored.append(f.name)
if fields:
field_dict = {f: field_dict.get(f) for f in fields if (not exclude or f not in exclude) and f not in ignored}
if field_names:
field_dict = {
f: field_dict.get(f) for f in field_names if (not exclude or f not in exclude) and f not in ignored
}
return field_dict


Expand Down Expand Up @@ -144,7 +143,7 @@ def __new__(mcs, name, bases, attrs):
# fields from the model"
opts.fields = None

fields = fields_for_dataclass(
form_fields = fields_for_dataclass(
opts.model,
opts.fields,
opts.exclude,
Expand All @@ -157,19 +156,19 @@ def __new__(mcs, name, bases, attrs):
)

# make sure opts.fields doesn't specify an invalid field
none_fields = {k for k, v in fields.items() if not v}
none_fields = {k for k, v in form_fields.items() if not v}
missing_fields = none_fields.difference(new_class.declared_fields)
if missing_fields:
message = "Unknown field(s) (%s) specified for %s"
message %= (", ".join(missing_fields), opts.model.__name__)
raise FieldError(message)
# Override default model fields with any custom declared ones
# (plus, include all the other declared fields).
fields.update(new_class.declared_fields)
form_fields.update(new_class.declared_fields)
else:
fields = new_class.declared_fields
form_fields = new_class.declared_fields

new_class.base_fields = fields
new_class.base_fields = form_fields

return new_class

Expand Down
68 changes: 67 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 76cbb04

Please sign in to comment.