Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for pydantic v2 and fixed build issues, building packages with yaml files. #86

Merged
1 change: 1 addition & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
uses: abatilo/actions-poetry@v2
- name: Install dependencies
run: |
find -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;
poetry build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
3 changes: 2 additions & 1 deletion .github/workflows/unittest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ on:
pull_request:
branches:
- main
- dev

jobs:
test:
runs-on: ubuntu-latest

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

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion focus_validator/config_objects/override.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List

import yaml
from pydantic import BaseModel
from pydantic.v1 import BaseModel


class Override(BaseModel):
Expand Down
18 changes: 10 additions & 8 deletions focus_validator/config_objects/rule.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Optional, Union

import yaml
from pydantic import BaseModel, root_validator
from pydantic import BaseModel, model_validator, ConfigDict
from pydantic_core.core_schema import ValidationInfo

from focus_validator.config_objects.common import (
SIMPLE_CHECKS,
Expand Down Expand Up @@ -34,13 +35,14 @@ class Rule(BaseModel):
] = None # auto generated or else can be overwritten
check_type_friendly_name: Optional[str] = None

class Config:
extra = "forbid" # prevents config from containing any undesirable keys
frozen = (
True # prevents any modification to any attribute onces loaded from config
)
model_config = ConfigDict(
extra="forbid", # prevents config from containing any undesirable keys
frozen=True, # prevents any modification to any attribute onces loaded from config
)

@root_validator
# @root_validator
@model_validator(mode="before")
@classmethod
def root_val(cls, values):
"""
Root validator that checks for all options passed in the config and generate missing options.
Expand Down Expand Up @@ -80,7 +82,7 @@ def load_yaml(
):
rule_obj["column"] = f"{column_namespace}:{rule_obj['column']}"

return Rule.parse_obj(rule_obj)
return Rule.model_validate(rule_obj)
except Exception as e:
return InvalidRule(
rule_path=rule_path, error=str(e), error_type=e.__class__.__name__
Expand Down
2 changes: 1 addition & 1 deletion focus_validator/outputter/outputter_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __restructure_check_list__(result_set: ValidationResult):
else:
check_type = "ERRORED"

row_obj = value.dict()
row_obj = value.model_dump()
row_obj.update(
{
"check_type": check_type,
Expand Down
2 changes: 1 addition & 1 deletion focus_validator/outputter/outputter_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def write(self, result_set):
)

# format the results for processing
rows = [v.dict() for v in result_set.checklist.values()]
rows = [v.model_dump() for v in result_set.checklist.values()]

# Setup a Formatter and initiate with result totals
formatter = UnittestFormatter(
Expand Down
14 changes: 12 additions & 2 deletions focus_validator/validator.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
from pkg_resources import resource_filename
import importlib.resources

from focus_validator.data_loaders import data_loader
from focus_validator.outputter.outputter import Outputter
from focus_validator.rules.spec_rules import SpecRules

DEFAULT_VERSION_SETS_PATH = resource_filename("focus_validator.rules", "version_sets")
try:
DEFAULT_VERSION_SETS_PATH = str(
importlib.resources.files("focus_validator.rules").joinpath("version_sets")
)
except AttributeError:
# for compatibility with python 3.8, which does not support files api in importlib
from pkg_resources import resource_filename

DEFAULT_VERSION_SETS_PATH = resource_filename(
"focus_validator.rules", "version_sets"
)


class Validator:
Expand Down
25 changes: 18 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,31 @@ version = "0.5.0"
description = "FOCUS spec validator."
authors = []
readme = "README.md"
packages = [{include = "focus_validator"}]
packages = [{ include = "focus_validator" }]
include = [
{ path = "focus_validator/rules/version_sets/0.5/*", format = ["sdist", "wheel"] }
]

[tool.poetry.dependencies]
python = "^3.8.1"
pandas = "^1"
python = "^3.8.3 || 3.12"
pandas = "^2"
tabulate = "*"
pyarrow = "*"
pydantic = "^1"
pydantic = "^2"
python-magic = "*"
pyyaml = "*"
requests = "*"
pandera = "^0.16"
# pandera next release supports pydantic, need to revert back to once available
pandera = { git = "https://github.com/unionai-oss/pandera", branch = "main" }

# for Python 3.12, force higher version of numpy
numpy = [
{version = "~1.24", python = "~3.8"},
{version = "~1.26", python = "~3.12"}
]

[tool.poetry.group.dev.dependencies]
black = {extras = ["d"], version = "^23.7.0"}
black = { extras = ["d"], version = "^23.7.0" }
polyfactory = "^2.7.0"
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
Expand All @@ -28,7 +38,8 @@ types-tabulate = "^0.9.0.3"
pandas-stubs = "^2.0.2.230605"
types-pyyaml = "^6.0.12.11"
types-requests = "^2.31.0.2"
pandera = {extras = ["mypy"], version = "^0.16.1"}
# pandera next release supports pydantic, need to revert back to once available
pandera = { extras = ["mypy"], git = "https://github.com/unionai-oss/pandera", branch = "main" }
isort = "^5.12.0"
flake8 = "^6.1.0"
pre-commit = "^3.3.3"
Expand Down
7 changes: 4 additions & 3 deletions tests/config_objects/test_check_type_friendly_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ def test_check_type_config_deny_update(self):
model_factory = ModelFactory.create_factory(model=Rule)

sample_data_type = model_factory.build()
with self.assertRaises(TypeError) as cm:
with self.assertRaises(ValidationError) as cm:
sample_data_type.check_type_friendly_name = "new_value"
self.assertIn(
'"Rule" is immutable and does not support item assignment',
"Instance is frozen",
str(cm.exception),
)

Expand All @@ -69,5 +69,6 @@ def test_assign_bad_type(self):
)
self.assertEqual(len(cm.exception.errors()), 1)
self.assertIn(
"value is not a valid enumeration member; permitted:", str(cm.exception)
"Input should be 'string', 'decimal', 'datetime' or 'currency-code'",
str(cm.exception),
)