Skip to content

Commit

Permalink
Add support for pydantic v2 (#795)
Browse files Browse the repository at this point in the history
**Pull Request Checklist**
- [x] Fixes #713
- [ ] Tests added
- [ ] Documentation/examples added
- [x] [Good commit messages](https://cbea.ms/git-commit/) and/or PR
title

**Description of PR**
WIP, but wanted to get the bulk of it up for any feedback while I:
- add a test run in CI with pydantic v1 installed (to ensure existing
users are covered - they passed manually)
- add a couple more tests and try to support serializing v1 *and* v2
user-defined models (not just the v1 models from either version - I
think this should be possible).
- update the model generation to update the Field import

---

This PR updates hera to support use with either pydantic v1 or v2
installed. All hera internal code now imports pydantic objects from
`hera.shared._pydantic` (extended and renamed from `_base_model`). This
module ensures that we're always using v1 compatible objects, which
allows us to support codebases installing either pydantic v1 or v2
(although the models passed to Hera must be v1 for pydantic v1 and v2
for pydantic v2).

---------

Signed-off-by: Jacob Hayes <[email protected]>
Signed-off-by: Matt Rose <[email protected]>
Signed-off-by: Sambhav Kothari <[email protected]>
Co-authored-by: Matt Rose <[email protected]>
Co-authored-by: Sambhav Kothari <[email protected]>
  • Loading branch information
3 people authored Dec 8, 2023
1 parent 826cebb commit f0279c8
Show file tree
Hide file tree
Showing 73 changed files with 439 additions and 643 deletions.
40 changes: 39 additions & 1 deletion .github/workflows/cicd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:

- name: Install dependencies
run: poetry install

- name: run ci checks
run: make ci

Expand All @@ -53,6 +53,44 @@ jobs:
with:
path: dist/*.whl

# Run tests against pydantic v1 until we drop support.
test-pydantic-v1:
name: test py${{ matrix.python-version }} (pydantic v1) on ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.8", "3.9", "3.10", "3.11"]

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

steps:
- name: checkout
uses: actions/checkout@v3

- name: Install poetry
run: pipx install poetry

- name: setup python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "poetry"

- name: Install dependencies
run: |
poetry install
poetry run pip install "pydantic<2"
- name: run ci checks
run: make ci

- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml

concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ workflows-models: ## Generate the Workflows models portion of Argo Workflows
--snake-case-field \
--target-python-version 3.8 \
--output src/hera/workflows/models \
--base-class hera.shared._base_model.BaseModel \
--output-model-type pydantic.BaseModel \
--base-class hera.shared._pydantic.BaseModel \
--input-file-type jsonschema \
--wrap-string-literal \
--disable-appending-item-suffix \
--disable-timestamp \
--use-default-kwarg
@find src/hera/workflows/models/ -name '*.py' -exec sed -i.bak 's/from pydantic import Field/from hera.shared._pydantic import Field/' {} +
@find src/hera/workflows/models/ -name '*.bak' -delete
@poetry run python scripts/models.py $(OPENAPI_SPEC_URL) workflows
@poetry run stubgen -o src -p hera.workflows.models && find src/hera/workflows/models -name '__init__.pyi' -delete
@rm $(SPEC_PATH)
Expand All @@ -74,11 +78,15 @@ events-models: ## Generate the Events models portion of Argo Workflows
--snake-case-field \
--target-python-version 3.8 \
--output src/hera/events/models \
--base-class hera.shared._base_model.BaseModel \
--output-model-type pydantic.BaseModel \
--base-class hera.shared._pydantic.BaseModel \
--input-file-type jsonschema \
--wrap-string-literal \
--disable-appending-item-suffix \
--disable-timestamp \
--use-default-kwarg
@find src/hera/events/models/ -name '*.py' -exec sed -i.bak 's/from pydantic import Field/from hera.shared._pydantic import Field/' {} +
@find src/hera/events/models/ -name '*.bak' -delete
@poetry run python scripts/models.py $(OPENAPI_SPEC_URL) events
@poetry run stubgen -o src -p hera.events.models && find src/hera/events/models -name '__init__.pyi' -delete
@rm $(SPEC_PATH)
Expand Down
4 changes: 3 additions & 1 deletion docs/examples/workflows/scripts/callable_script.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
```python linenums="1"
from typing import List, Union

from hera.shared.serialization import serialize

try:
from typing import Annotated # type: ignore
except ImportError:
Expand Down Expand Up @@ -99,7 +101,7 @@
with Workflow(name="my-workflow") as w:
with Steps(name="my-steps") as s:
my_function(arguments={"input": Input(a=2, b="bar", c=42)})
str_function(arguments={"input": Input(a=2, b="bar", c=42).json()})
str_function(arguments={"input": serialize(Input(a=2, b="bar", c=42))})
another_function(arguments={"inputs": [Input(a=2, b="bar", c=42), Input(a=2, b="bar", c=42.0)]})
function_kebab(arguments={"a-but-kebab": 3, "b-but-kebab": "bar"})
function_kebab_object(arguments={"input-value": Input(a=3, b="bar", c="42")})
Expand Down
4 changes: 3 additions & 1 deletion examples/workflows/scripts/callable_script.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import List, Union

from hera.shared.serialization import serialize

try:
from typing import Annotated # type: ignore
except ImportError:
Expand Down Expand Up @@ -89,7 +91,7 @@ def function_kebab_object(annotated_input_value: Annotated[Input, Parameter(name
with Workflow(name="my-workflow") as w:
with Steps(name="my-steps") as s:
my_function(arguments={"input": Input(a=2, b="bar", c=42)})
str_function(arguments={"input": Input(a=2, b="bar", c=42).json()})
str_function(arguments={"input": serialize(Input(a=2, b="bar", c=42))})
another_function(arguments={"inputs": [Input(a=2, b="bar", c=42), Input(a=2, b="bar", c=42.0)]})
function_kebab(arguments={"a-but-kebab": 3, "b-but-kebab": "bar"})
function_kebab_object(arguments={"input-value": Input(a=3, b="bar", c="42")})
Loading

0 comments on commit f0279c8

Please sign in to comment.