Skip to content

Commit

Permalink
Merge pull request #150 from python-odin/development
Browse files Browse the repository at this point in the history
Release 2.8
  • Loading branch information
timsavage authored May 30, 2023
2 parents 278c5da + 6037fda commit 6e115c7
Show file tree
Hide file tree
Showing 88 changed files with 1,174 additions and 897 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
python-version: [3.8, 3.9, "3.10", "3.11"]
experimental: [false]
include:
- python-version: "3.11-dev"
- python-version: "3.12-dev"
experimental: true

steps:
Expand Down
44 changes: 44 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_language_version:
python: python3.10
repos:
#- repo: https://github.com/pre-commit/pre-commit-hooks
# rev: v4.4.0
# hooks:
# - id: check-added-large-files
# - id: check-toml
# - id: check-yaml
# args:
# - --unsafe
# - id: end-of-file-fixer
# - id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args:
- --py38-plus
- --keep-runtime-typing
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.270
hooks:
- id: ruff
args:
- --fix
- --exit-non-zero-on-fix
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
name: isort (python)
- id: isort
name: isort (cython)
types: [cython]
- id: isort
name: isort (pyi)
types: [pyi]
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
24 changes: 24 additions & 0 deletions HISTORY
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
2.8
===

Changes
-------

- Change behaviour of create_resource_from_dict to not raise Validation errors
from ``field.to_python`` when ``full_clean`` is ``False``.

Allows for invalid documents to still be loaded with invalid data to allow
for correction of data and to prevent data loss.

- Introduce Pre-commit, PyUpgrade, isort, ruff and black.


2.7
===

Bug fixes
---------

- TypedDictField now includes a prepare method to ensure types are cast correctly for serailisation.


2.6
===

Expand Down
15 changes: 7 additions & 8 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Odin documentation build configuration file, created by
# sphinx-quickstart on Tue Aug 20 18:57:24 2013.
Expand All @@ -11,8 +10,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
import sys

HERE = os.path.dirname(__file__)

Expand Down Expand Up @@ -53,8 +52,8 @@
master_doc = "contents"

# General information about the project.
project = u"Odin"
copyright = u"2023, Tim Savage"
project = "Odin"
copyright = "2023, Tim Savage"
author = "Tim Savage <[email protected]>"

# The version info for the project you're documenting, acts as replacement for
Expand Down Expand Up @@ -205,8 +204,8 @@
(
"index",
"Odin.tex",
u"Odin Documentation",
u"Tim Savage \\textless{}[email protected]\\textgreater{}",
"Odin Documentation",
"Tim Savage \\textless{}[email protected]\\textgreater{}",
"manual",
),
]
Expand Down Expand Up @@ -236,7 +235,7 @@

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [("index", "odin", u"Odin Documentation", [author], 1)]
man_pages = [("index", "odin", "Odin Documentation", [author], 1)]

# If true, show URL addresses after external links.
# man_show_urls = False
Expand All @@ -251,7 +250,7 @@
(
"index",
"Odin",
u"Odin Documentation",
"Odin Documentation",
author,
"Odin",
"One line description of project.",
Expand Down
370 changes: 186 additions & 184 deletions poetry.lock

Large diffs are not rendered by default.

32 changes: 30 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "odin"
version = "2.6"
version = "2.8"
description = "Data-structure definition/validation/traversal, mapping and serialisation toolkit for Python"
authors = ["Tim Savage <[email protected]>"]
license = "BSD-3-Clause"
Expand Down Expand Up @@ -53,4 +53,32 @@ msgpack = ["msgpack"]
toml = ["toml"]
pint = ["pint"]
arrow = ["arrow"]
rich = ["rich"]
rich = ["rich"]

[tool.isort]
profile = "black"

[tool.ruff]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
# "I", # isort
"C", # flake8-comprehensions
"B", # flake8-bugbear
]
ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
"C901", # too complex
]

# Assume Python 3.8.
target-version = "py38"

[tool.ruff.per-file-ignores]
"tests/test_adapters.py" = ["F403", "F405"]
"tests/test_codec*.py" = ["F403", "F405"]
"tests/test_fields.py" = ["F403", "F405"]
"tests/test_kitchensink.py" = ["F403", "F405"]
"tests/test_mapping.py" = ["F403", "F405"]
10 changes: 5 additions & 5 deletions src/odin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
logging.getLogger("odin.registration").addHandler(logging.NullHandler())

from odin import exceptions # noqa
from odin.adapters import ResourceAdapter # noqa
from odin.annotated_resource import * # noqa
from odin.annotated_resource import type_aliases as types # noqa
from odin.fields import * # noqa
from odin.fields.composite import * # noqa
from odin.fields.virtual import * # noqa
from odin.helpers import * # noqa
from odin.mapping import * # noqa
from odin.resources import Resource # noqa
from odin.adapters import ResourceAdapter # noqa
from odin.proxy import ResourceProxy # noqa
from odin.annotated_resource import * # noqa
from odin.annotated_resource import type_aliases as types # noqa
from odin.helpers import * # noqa
from odin.resources import Resource # noqa

__authors__ = "Tim Savage <[email protected]>"
__copyright__ = "Copyright (C) 2021 Tim Savage"
1 change: 1 addition & 0 deletions src/odin/adapters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import cached_property

from odin.utils import field_iter_items, getmeta

__all__ = ("ResourceAdapter",)
Expand Down
9 changes: 5 additions & 4 deletions src/odin/annotated_resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@
"""
import copy
from typing import Any, Dict, Tuple, Type, Optional, TypeVar, Iterable
from typing import Any, Dict, Iterable, Optional, Tuple, Type, TypeVar

from odin import registration
from odin.fields import BaseField
from odin.resources import (
ResourceBase,
ResourceOptions,
DEFAULT_TYPE_FIELD,
NotProvided,
ResourceBase,
ResourceOptions,
)
from .type_resolution import process_attribute, Options

from ..exceptions import ResourceDefError
from .type_resolution import Options, process_attribute

__all__ = (
"Options",
Expand Down
2 changes: 1 addition & 1 deletion src/odin/annotated_resource/type_aliases.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Type aliases for string formatted types."""
from typing import Callable, Union, Any, Sequence, Tuple
from typing import Any, Callable, Sequence, Tuple, Union

__all__ = (
"Email",
Expand Down
72 changes: 44 additions & 28 deletions src/odin/annotated_resource/type_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,48 @@
import pathlib
import re
import uuid
from typing import Any, Sequence, Dict, Type, Union, get_origin, List, Final
from typing import Any, Dict, Final, List, Sequence, Type, Union, get_origin

try:
# Handle the change in typing between 3.8 and later releases
from typing import T, KT, VT
from typing import KT, VT, T
except ImportError:
T = None
KT = None
VT = None

import odin
from .special_fields import AnyField
from .type_aliases import Validator, Choices, Email, IPv4, IPv6, IPv46, Url
from .. import ListOf, DictOf

from ..exceptions import ResourceDefError
from ..fields import (
BaseField,
BooleanField,
DateField,
DateTimeField,
DictField,
EmailField,
Field,
FloatField,
IntegerField,
IPv4Field,
IPv6Field,
IPv46Field,
ListField,
NotProvided,
TypedListField,
PathField,
RegexField,
StringField,
TimeField,
TypedDictField,
ListField,
DictField,
TypedListField,
UrlField,
UUIDField,
)
from ..fields.composite import DictOf, ListOf
from ..fields.virtual import ConstantField
from ..resources import ResourceBase
from .special_fields import AnyField
from .type_aliases import Choices, Email, IPv4, IPv6, IPv46, Url, Validator


class Options:
Expand All @@ -44,8 +60,8 @@ class Options:

def __init__(
self,
default: Any = odin.NotProvided,
field_type: Type[odin.BaseField] = None,
default: Any = NotProvided,
field_type: Type[BaseField] = None,
*,
verbose_name: str = None,
verbose_name_plural: str = None,
Expand Down Expand Up @@ -112,23 +128,23 @@ def init_field(self):


SIMPLE_TYPE_MAP = {
bool: odin.BooleanField,
datetime.date: odin.DateField,
datetime.datetime: odin.DateTimeField,
dict: odin.DictField,
Email: odin.EmailField,
float: odin.FloatField,
int: odin.IntegerField,
IPv4: odin.IPv4Field,
IPv6: odin.IPv6Field,
IPv46: odin.IPv46Field,
list: odin.ListField,
pathlib.Path: odin.PathField,
re.Pattern: odin.RegexField,
str: odin.StringField,
datetime.time: odin.TimeField,
Url: odin.UrlField,
uuid.UUID: odin.UUIDField,
bool: BooleanField,
datetime.date: DateField,
datetime.datetime: DateTimeField,
dict: DictField,
Email: EmailField,
float: FloatField,
int: IntegerField,
IPv4: IPv4Field,
IPv6: IPv6Field,
IPv46: IPv46Field,
list: ListField,
pathlib.Path: PathField,
re.Pattern: RegexField,
str: StringField,
datetime.time: TimeField,
Url: UrlField,
uuid.UUID: UUIDField,
Any: AnyField, # For Python 3.11
}

Expand Down Expand Up @@ -223,7 +239,7 @@ def _resolve_field_from_sub_scripted_type(origin: Type, options: Options, type_)
options.field_type = ConstantField
value = options.field_args["default"]
if value is NotProvided:
raise ResourceDefError(f"Final fields require a value")
raise ResourceDefError("Final fields require a value")
options.base_args["value"] = value
return

Expand Down
4 changes: 2 additions & 2 deletions src/odin/codecs/csv_codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

from odin import bases
from odin.datastructures import CaseLessStringList
from odin.exceptions import CodecDecodeError, ValidationError
from odin.fields import NotProvided
from odin.resources import create_resource_from_iter
from odin.utils import getmeta, lazy_property
from odin.exceptions import CodecDecodeError, ValidationError

CONTENT_TYPE = "text/csv"

Expand Down Expand Up @@ -101,7 +101,7 @@ def __init__(
# Handle strict fields
if self.strict_fields and self.extra_field_names:
raise CodecDecodeError(
"Extra unknown fields: {0}".format(",".join(self.extra_field_names))
"Extra unknown fields: {}".format(",".join(self.extra_field_names))
)

# Built in counters
Expand Down
4 changes: 1 addition & 3 deletions src/odin/codecs/dict_codec.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from odin import bases
from odin import resources, ResourceAdapter
from odin import ResourceAdapter, bases, resources
from odin.utils import getmeta


TYPE_SERIALIZERS = {}


Expand Down
Loading

0 comments on commit 6e115c7

Please sign in to comment.