Repository: linkml/linkml

Issue:
Outdated lockfile hides test failures
**Describe the bug**
The CI installs the package using poetry, which respects the poetry lockfile.
not all installation methods respect the lockfile, and will install the most recent versions of packages that are allowed by the version pinning. This causes the tests to be overconfident. 

eg. Pydantic:

- lockfile pins 1.10.8: https://github.com/linkml/linkml/blob/0d2f3f0d5d65e619a00c81de81a5d1879e3c6830/poetry.lock#L1672
- dependency spec allows '*':  https://github.com/linkml/linkml/blob/0d2f3f0d5d65e619a00c81de81a5d1879e3c6830/pyproject.toml#L115

so a relock currently fetches 2.3.0 which causes the tests to fail because it doesn't allow keyword initialization in class MROs as used by `ConfiguredBaseModel` in the pydanticgen and tests. 

**To reproduce**
Steps to reproduce the behavior:

```
poetry lock
poetry install
pytest tests/test_generators/test_pydanticgen.py
```

**Expected behavior**
Should tighten up dependency specifiers or add versions to the test matrix

having a slow lockfile is good for keeping production systems stable but i don't think it's as good for in-use code in a language environment where lockfiles are not universally supported, unfortunately :(

Discussion:

Patch:
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index cdb7701d..c34a7a5e 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -20,9 +20,16 @@ jobs:
       matrix:
         os: [ubuntu-latest, windows-latest]
         python-version: ["3.8", "3.9", "3.10"]
+        pydantic-version: ["1", "2"]
         exclude:
           - os: windows-latest
             python-version: "3.8"
+          - os: windows-latest
+            pydantic-version: "2"
+          - python-version: "3.8"
+            pydantic-version: "2"
+          - python-version: "3.9"
+            pydantic-version: "2"
 
     # See https://github.com/snok/install-poetry#running-on-windows
     defaults:
@@ -70,6 +77,12 @@ jobs:
         if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
         run: poetry install --no-interaction --no-root
 
+      #----------------------------------------------
+      # install pydantic
+      #----------------------------------------------
+      - name: Install Pydantic
+        run: poetry add pydantic@^${{ matrix.pydantic-version }}
+
       #----------------------------------------------
       #         setup and install graphviz
       #----------------------------------------------
diff --git a/Dockerfile b/Dockerfile
index 08c6f1dc..e18dd8c2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,7 +7,7 @@ ENV PYTHONFAULTHANDLER=1 \
   PIP_NO_CACHE_DIR=off \
   PIP_DISABLE_PIP_VERSION_CHECK=on \
   PIP_DEFAULT_TIMEOUT=100 \
-  POETRY_VERSION=1.2.1
+  POETRY_VERSION=1.6.0
 
 # Install Poetry
 RUN pip install "poetry==$POETRY_VERSION"
@@ -19,11 +19,15 @@ WORKDIR /code
 COPY ./.git ./.git
 COPY pyproject.toml poetry.lock README.md .
 COPY linkml linkml/
-RUN poetry build 
+RUN poetry build
 
 #######################################
 FROM python:3.9-slim-bullseye as runner
 
+ENV DEBIAN_FRONTEND=noninteractive
+RUN apt update
+RUN apt update && apt install -y gcc musl-dev python3-dev && rm -rf /var/lib/apt/lists/*
+
 RUN useradd --create-home linkmluser
 WORKDIR /home/linkmluser
 USER linkmluser
diff --git a/docs/contributing/contributing.md b/docs/contributing/contributing.md
index 29f5d6cb..793795d9 100644
--- a/docs/contributing/contributing.md
+++ b/docs/contributing/contributing.md
@@ -120,6 +120,24 @@ New tests in any directory should be written using pytest.
 
   If you make a change that intentionally causes some output to not match the saved snapshot file(s), you should update the snapshots by running `pytest` with the `--generate-snapshots` flag. You should try to run only a single or small group of tests with this flag (as opposed to the entire test suite). The updated snapshot files should be checked in to Git alongside your other code changes.
 
+#### Testing multiple Pydantic versions
+
+LinkML both generates and depends on Pydantic. [Pydantic V2](https://docs.pydantic.dev/2.4/migration/) brought a number of breaking changes, but we intend to support both V1 and V2. By default, the `PydanticGenerator` class will generate code compatible with the version of Pydantic that is installed in your environment. This can be overridden by explicitly setting the `pydantic_version` field.
+
+As of October 2023, our default development environment still specifies Pydantic 1 (as determined by the `poetry.lock` file). But since we also support Pydantic 2 (as specified in `pyproject.toml`), it is important to test with Pydantic 2 in your environment. To facilitate that there is a `tox` environment called `pydantic2`. To run all tests with Pydantic 2 installed:
+
+```shell
+poetry run tox -e pydantic2
+```
+
+Additional arguments will be passed to `pytest`. For example, to run a specific test:
+
+```shell
+poetry run tox -e pydantic2 -- tests/test_compliance/test_core_compliance.py
+```
+
+Our main GitHub Actions testing workflow will also automatically perform one test run with Pydantic 2 in the environment.
+
 ### Code formatting and linting
 
 This repository is configured to use [Black](https://black.readthedocs.io/en/stable/index.html#) and [Ruff](https://beta.ruff.rs/docs/) to ensure good  formatting and code quality standards.
diff --git a/linkml/generators/pydanticgen.py b/linkml/generators/pydanticgen.py
index 3d82fa6f..e43746d3 100644
--- a/linkml/generators/pydanticgen.py
+++ b/linkml/generators/pydanticgen.py
@@ -20,6 +20,7 @@ from linkml_runtime.linkml_model.meta import (
 from linkml_runtime.utils.compile_python import compile_python
 from linkml_runtime.utils.formatutils import camelcase, underscore
 from linkml_runtime.utils.schemaview import SchemaView
+from pydantic.version import VERSION as PYDANTIC_VERSION
 
 from linkml._version import __version__
 from linkml.generators.common.type_designators import (
@@ -42,8 +43,15 @@ def default_template(pydantic_ver: str = "1") -> str:
 from __future__ import annotations
 from datetime import datetime, date
 from enum import Enum
-from typing import List, Dict, Optional, Any, Union
-from pydantic import BaseModel as BaseModel, Field
+from typing import List, Dict, Optional, Any, Union"""
+    if pydantic_ver == 1:
+        template += """
+from pydantic import BaseModel as BaseModel, Field"""
+    else:
+        template += """
+from pydantic import BaseModel as BaseModel, ConfigDict, Field"""
+
+    template += """
 import sys
 if sys.version_info >= (3, 8):
     from typing import Literal
@@ -71,13 +79,13 @@ class ConfiguredBaseModel(WeakRefShimBaseModel,
 """
     else:
         template += """
-class ConfiguredBaseModel(BaseModel,
-                validate_assignment = True,
-                validate_default = True,
-                extra = {% if allow_extra %}'allow'{% else %}'forbid'{% endif %},
-                arbitrary_types_allowed = True,
-                use_enum_values = True):
-    pass
+class ConfiguredBaseModel(BaseModel):
+    model_config = ConfigDict(
+        validate_assignment=True,
+        validate_default=True,
+        extra={% if allow_extra %}'allow'{% else %}'forbid'{% endif %},
+        arbitrary_types_allowed=True,
+        use_enum_values = True)
 """
     ### ENUMS ###
     template += """
@@ -148,7 +156,7 @@ class {{ c.name }}
 # see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model
 {% for c in schema.classes.values() -%}
 {{ c.name }}.model_rebuild()
-{% endfor %}    
+{% endfor %}
 """
     return template
 
@@ -183,7 +191,7 @@ class PydanticGenerator(OOCodeGenerator):
     file_extension = "py"
 
     # ObjectVars
-    pydantic_version: str = field(default_factory=lambda: "1")
+    pydantic_version: str = field(default_factory=lambda: PYDANTIC_VERSION[0])
     template_file: str = None
     allow_extra: bool = field(default_factory=lambda: False)
     gen_mixin_inheritance: bool = field(default_factory=lambda: True)
diff --git a/linkml/validator/report.py b/linkml/validator/report.py
index 81583ddc..b1d85fdc 100644
--- a/linkml/validator/report.py
+++ b/linkml/validator/report.py
@@ -25,9 +25,9 @@ class ValidationResult(BaseModel):
     type: str
     severity: Severity
     message: str
-    instance: Optional[Any]
-    instance_index: Optional[int]
-    instantiates: Optional[str]
+    instance: Optional[Any] = None
+    instance_index: Optional[int] = None
+    instantiates: Optional[str] = None
 
 
 class ValidationReport(BaseModel):
diff --git a/poetry.lock b/poetry.lock
index c1418a82..8cd8a02f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,10 +1,9 @@
-# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand.
 
 [[package]]
 name = "alabaster"
 version = "0.7.13"
 description = "A configurable sidebar-enabled Sphinx theme"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -16,7 +15,6 @@ files = [
 name = "antlr4-python3-runtime"
 version = "4.9.3"
 description = "ANTLR 4.9.3 runtime for Python 3.7"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -27,7 +25,6 @@ files = [
 name = "appnope"
 version = "0.1.3"
 description = "Disable App Nap on macOS >= 10.9"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -39,7 +36,6 @@ files = [
 name = "arrow"
 version = "1.2.3"
 description = "Better dates & times for Python"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -54,7 +50,6 @@ python-dateutil = ">=2.7.0"
 name = "attrs"
 version = "23.1.0"
 description = "Classes Without Boilerplate"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -73,7 +68,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte
 name = "babel"
 version = "2.12.1"
 description = "Internationalization utilities"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -88,7 +82,6 @@ pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""}
 name = "backcall"
 version = "0.2.0"
 description = "Specifications for callback functions passed in to an API"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -100,7 +93,6 @@ files = [
 name = "beautifulsoup4"
 version = "4.12.2"
 description = "Screen-scraping library"
-category = "dev"
 optional = false
 python-versions = ">=3.6.0"
 files = [
@@ -119,7 +111,6 @@ lxml = ["lxml"]
 name = "bleach"
 version = "6.0.0"
 description = "An easy safelist-based HTML-sanitizing tool."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -138,7 +129,6 @@ css = ["tinycss2 (>=1.1.0,<1.2)"]
 name = "cachetools"
 version = "5.3.1"
 description = "Extensible memoizing collections and decorators"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -150,7 +140,6 @@ files = [
 name = "certifi"
 version = "2023.7.22"
 description = "Python package for providing Mozilla's CA Bundle."
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -162,7 +151,6 @@ files = [
 name = "cffi"
 version = "1.15.1"
 description = "Foreign Function Interface for Python calling C code."
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -239,7 +227,6 @@ pycparser = "*"
 name = "cfgraph"
 version = "0.2.1"
 description = "rdflib collections flattening graph"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -253,7 +240,6 @@ rdflib = ">=0.4.2"
 name = "chardet"
 version = "5.2.0"
 description = "Universal encoding detector for Python 3"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -265,7 +251,6 @@ files = [
 name = "charset-normalizer"
 version = "3.2.0"
 description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "main"
 optional = false
 python-versions = ">=3.7.0"
 files = [
@@ -350,7 +335,6 @@ files = [
 name = "click"
 version = "8.1.7"
 description = "Composable command line interface toolkit"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -365,7 +349,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
 name = "colorama"
 version = "0.4.6"
 description = "Cross-platform colored terminal text."
-category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 files = [
@@ -377,7 +360,6 @@ files = [
 name = "coverage"
 version = "6.5.0"
 description = "Code coverage measurement for Python"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -440,7 +422,6 @@ toml = ["tomli"]
 name = "curies"
 version = "0.5.5"
 description = "Idiomatic conversion between URIs and compact URIs (CURIEs)."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -466,7 +447,6 @@ tests = ["coverage", "pytest"]
 name = "debugpy"
 version = "1.7.0"
 description = "An implementation of the Debug Adapter Protocol for Python"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -498,7 +478,6 @@ files = [
 name = "decorator"
 version = "5.1.1"
 description = "Decorators for Humans"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -510,7 +489,6 @@ files = [
 name = "defusedxml"
 version = "0.7.1"
 description = "XML bomb protection for Python stdlib modules"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 files = [
@@ -522,7 +500,6 @@ files = [
 name = "deprecated"
 version = "1.2.14"
 description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -540,7 +517,6 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"]
 name = "distlib"
 version = "0.3.7"
 description = "Distribution utilities"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -552,7 +528,6 @@ files = [
 name = "docutils"
 version = "0.19"
 description = "Docutils -- Python Documentation Utilities"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -564,7 +539,6 @@ files = [
 name = "entrypoints"
 version = "0.4"
 description = "Discover and load entry points from installed packages."
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -576,7 +550,6 @@ files = [
 name = "et-xmlfile"
 version = "1.1.0"
 description = "An implementation of lxml.xmlfile for the standard library"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -588,7 +561,6 @@ files = [
 name = "exceptiongroup"
 version = "1.1.3"
 description = "Backport of PEP 654 (exception groups)"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -603,7 +575,6 @@ test = ["pytest (>=6)"]
 name = "fastjsonschema"
 version = "2.18.0"
 description = "Fastest Python implementation of JSON schema"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -618,7 +589,6 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc
 name = "filelock"
 version = "3.12.2"
 description = "A platform independent file lock."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -634,7 +604,6 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p
 name = "fqdn"
 version = "1.5.1"
 description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4"
 files = [
@@ -646,7 +615,6 @@ files = [
 name = "furo"
 version = "2023.3.27"
 description = "A clean customisable Sphinx documentation theme."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -664,7 +632,6 @@ sphinx-basic-ng = "*"
 name = "graphviz"
 version = "0.20.1"
 description = "Simple Python interface for Graphviz"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -681,7 +648,6 @@ test = ["coverage", "mock (>=4)", "pytest (>=7)", "pytest-cov", "pytest-mock (>=
 name = "greenlet"
 version = "2.0.1"
 description = "Lightweight in-process concurrent programming"
-category = "main"
 optional = false
 python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
 files = [
@@ -755,7 +721,6 @@ test = ["faulthandler", "objgraph", "psutil"]
 name = "hbreader"
 version = "0.9.1"
 description = "Honey Badger reader - a generic file/url/string open and read tool"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -767,7 +732,6 @@ files = [
 name = "idna"
 version = "3.4"
 description = "Internationalized Domain Names in Applications (IDNA)"
-category = "main"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -779,7 +743,6 @@ files = [
 name = "imagesize"
 version = "1.4.1"
 description = "Getting image size from png/jpeg/jpeg2000/gif file"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -791,7 +754,6 @@ files = [
 name = "importlib-metadata"
 version = "6.7.0"
 description = "Read metadata from Python packages"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -811,7 +773,6 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs
 name = "importlib-resources"
 version = "5.12.0"
 description = "Read resources from Python packages"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -830,7 +791,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec
 name = "iniconfig"
 version = "2.0.0"
 description = "brain-dead simple config-ini parsing"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -842,7 +802,6 @@ files = [
 name = "ipykernel"
 version = "6.16.2"
 description = "IPython Kernel for Jupyter"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -871,7 +830,6 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-cov", "p
 name = "ipython"
 version = "7.34.0"
 description = "IPython: Productive Interactive Computing"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -908,7 +866,6 @@ test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments"
 name = "ipython-genutils"
 version = "0.2.0"
 description = "Vestigial utilities from IPython"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -920,7 +877,6 @@ files = [
 name = "isodate"
 version = "0.6.1"
 description = "An ISO 8601 date/time/duration parser and formatter"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -935,7 +891,6 @@ six = "*"
 name = "isoduration"
 version = "20.11.0"
 description = "Operations with ISO 8601 durations"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -950,7 +905,6 @@ arrow = ">=0.15.0"
 name = "jedi"
 version = "0.19.0"
 description = "An autocompletion tool for Python that can be used for text editors."
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -970,7 +924,6 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
 name = "jinja2"
 version = "3.1.2"
 description = "A very fast and expressive template engine."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -988,7 +941,6 @@ i18n = ["Babel (>=2.7)"]
 name = "json-flattener"
 version = "0.1.9"
 description = "Python library for denormalizing nested dicts or json objects to tables and back"
-category = "main"
 optional = false
 python-versions = ">=3.7.0"
 files = [
@@ -1004,7 +956,6 @@ pyyaml = "*"
 name = "jsonasobj"
 version = "1.3.1"
 description = "JSON as python objects"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1016,7 +967,6 @@ files = [
 name = "jsonasobj2"
 version = "1.0.4"
 description = "JSON as python objects - version 2"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1031,12 +981,10 @@ hbreader = "*"
 name = "jsonpatch"
 version = "1.33"
 description = "Apply JSON-Patches (RFC 6902)"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
 files = [
     {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"},
-    {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"},
 ]
 
 [package.dependencies]
@@ -1046,7 +994,6 @@ jsonpointer = ">=1.9"
 name = "jsonpath-ng"
 version = "1.6.0"
 description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1061,19 +1008,16 @@ ply = "*"
 name = "jsonpointer"
 version = "2.4"
 description = "Identify specific nodes in a JSON document (RFC 6901)"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
 files = [
     {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"},
-    {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"},
 ]
 
 [[package]]
 name = "jsonschema"
 version = "4.17.3"
 description = "An implementation of JSON Schema validation for Python"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1103,7 +1047,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-
 name = "jupyter-client"
 version = "7.4.9"
 description = "Jupyter protocol implementation and client libraries"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1128,7 +1071,6 @@ test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-com
 name = "jupyter-core"
 version = "4.12.0"
 description = "Jupyter core package. A base package on which Jupyter projects rely."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1147,7 +1089,6 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"]
 name = "jupyterlab-pygments"
 version = "0.2.2"
 description = "Pygments theme using JupyterLab CSS variables"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1159,7 +1100,6 @@ files = [
 name = "linkml-dataops"
 version = "0.1.0"
 description = "LinkML Data Operations API"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1178,7 +1118,6 @@ linkml-runtime = ">=1.1.6"
 name = "linkml-runtime"
 version = "1.6.0"
 description = "Runtime environment for LinkML, the Linked open data modeling language"
-category = "main"
 optional = false
 python-versions = ">=3.7.6,<4.0.0"
 files = [
@@ -1205,7 +1144,6 @@ requests = "*"
 name = "markdown-it-py"
 version = "2.2.0"
 description = "Python port of markdown-it. Markdown parsing, done right!"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1230,7 +1168,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
 name = "markupsafe"
 version = "2.1.3"
 description = "Safely add untrusted strings to HTML/XML markup."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1254,16 +1191,6 @@ files = [
     {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@@ -1300,7 +1227,6 @@ files = [
 name = "matplotlib-inline"
 version = "0.1.6"
 description = "Inline Matplotlib backend for Jupyter"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -1315,7 +1241,6 @@ traitlets = "*"
 name = "mdit-py-plugins"
 version = "0.3.5"
 description = "Collection of plugins for markdown-it-py"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1335,7 +1260,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
 name = "mdurl"
 version = "0.1.2"
 description = "Markdown URL utilities"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1347,7 +1271,6 @@ files = [
 name = "mistune"
 version = "3.0.1"
 description = "A sane and fast Markdown parser with useful plugins and renderers"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1359,7 +1282,6 @@ files = [
 name = "myst-parser"
 version = "1.0.0"
 description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser,"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1386,7 +1308,6 @@ testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,
 name = "nbclient"
 version = "0.7.4"
 description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
-category = "dev"
 optional = false
 python-versions = ">=3.7.0"
 files = [
@@ -1396,7 +1317,7 @@ files = [
 
 [package.dependencies]
 jupyter-client = ">=6.1.12"
-jupyter-core = ">=4.12,<5.0.0 || >=5.1.0"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
 nbformat = ">=5.1"
 traitlets = ">=5.3"
 
@@ -1409,7 +1330,6 @@ test = ["flaky", "ipykernel", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "p
 name = "nbconvert"
 version = "7.6.0"
 description = "Converting Jupyter Notebooks"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1448,7 +1368,6 @@ webpdf = ["pyppeteer (>=1,<1.1)"]
 name = "nbformat"
 version = "5.8.0"
 description = "The Jupyter Notebook format"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1470,7 +1389,6 @@ test = ["pep440", "pre-commit", "pytest", "testpath"]
 name = "nest-asyncio"
 version = "1.5.8"
 description = "Patch asyncio to allow nested event loops"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -1482,7 +1400,6 @@ files = [
 name = "openpyxl"
 version = "3.1.2"
 description = "A Python library to read/write Excel 2010 xlsx/xlsm files"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1497,7 +1414,6 @@ et-xmlfile = "*"
 name = "packaging"
 version = "23.1"
 description = "Core utilities for Python packages"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1509,7 +1425,6 @@ files = [
 name = "pandocfilters"
 version = "1.5.0"
 description = "Utilities for writing pandoc filters in python"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -1521,7 +1436,6 @@ files = [
 name = "parse"
 version = "1.19.1"
 description = "parse() is the opposite of format()"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1533,7 +1447,6 @@ files = [
 name = "parso"
 version = "0.8.3"
 description = "A Python Parser"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1549,7 +1462,6 @@ testing = ["docopt", "pytest (<6.0.0)"]
 name = "pexpect"
 version = "4.8.0"
 description = "Pexpect allows easy control of interactive console applications."
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -1564,7 +1476,6 @@ ptyprocess = ">=0.5"
 name = "pickleshare"
 version = "0.7.5"
 description = "Tiny 'shelve'-like database with concurrency support"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -1576,7 +1487,6 @@ files = [
 name = "pkgutil-resolve-name"
 version = "1.3.10"
 description = "Resolve a name to an object."
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1588,7 +1498,6 @@ files = [
 name = "platformdirs"
 version = "3.10.0"
 description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1604,7 +1513,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
 name = "pluggy"
 version = "1.2.0"
 description = "plugin and hook calling mechanisms for python"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1620,7 +1528,6 @@ testing = ["pytest", "pytest-benchmark"]
 name = "ply"
 version = "3.11"
 description = "Python Lex & Yacc"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1632,7 +1539,6 @@ files = [
 name = "prefixcommons"
 version = "0.1.12"
 description = "A python API for working with ID prefixes"
-category = "main"
 optional = false
 python-versions = ">=3.7,<4.0"
 files = [
@@ -1650,7 +1556,6 @@ requests = ">=2.28.1,<3.0.0"
 name = "prefixmaps"
 version = "0.1.5"
 description = "A python library for retrieving semantic prefix maps"
-category = "main"
 optional = false
 python-versions = ">=3.7.6,<4.0.0"
 files = [
@@ -1673,7 +1578,6 @@ refresh = ["bioregistry[refresh] (>=0.8.0,<0.9.0)", "rdflib[refresh] (>=6.2.0,<7
 name = "prompt-toolkit"
 version = "3.0.39"
 description = "Library for building powerful interactive command lines in Python"
-category = "dev"
 optional = false
 python-versions = ">=3.7.0"
 files = [
@@ -1688,7 +1592,6 @@ wcwidth = "*"
 name = "psutil"
 version = "5.9.5"
 description = "Cross-platform lib for process and system monitoring in Python."
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -1715,7 +1618,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
 name = "ptyprocess"
 version = "0.7.0"
 description = "Run a subprocess in a pseudo terminal"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -1727,7 +1629,6 @@ files = [
 name = "pycparser"
 version = "2.21"
 description = "C parser in Python"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -1739,7 +1640,6 @@ files = [
 name = "pydantic"
 version = "1.10.13"
 description = "Data validation and settings management using python type hints"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1792,7 +1692,6 @@ email = ["email-validator (>=1.0.3)"]
 name = "pygments"
 version = "2.16.1"
 description = "Pygments is a syntax highlighting package written in Python."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1807,7 +1706,6 @@ plugins = ["importlib-metadata"]
 name = "pyjsg"
 version = "0.11.10"
 description = "Python JSON Schema Grammar interpreter"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1823,7 +1721,6 @@ jsonasobj = ">=1.2.1"
 name = "pyparsing"
 version = "3.1.1"
 description = "pyparsing module - Classes and methods to define and execute parsing grammars"
-category = "main"
 optional = false
 python-versions = ">=3.6.8"
 files = [
@@ -1838,7 +1735,6 @@ diagrams = ["jinja2", "railroad-diagrams"]
 name = "pyproject-api"
 version = "1.5.3"
 description = "API to interact with the python pyproject.toml based projects"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1858,7 +1754,6 @@ testing = ["covdefaults (>=2.3)", "importlib-metadata (>=6.6)", "pytest (>=7.3.1
 name = "pyrsistent"
 version = "0.19.3"
 description = "Persistent/Functional/Immutable data structures"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1895,7 +1790,6 @@ files = [
 name = "pyshex"
 version = "0.8.1"
 description = "Python ShEx Implementation"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1918,7 +1812,6 @@ urllib3 = "*"
 name = "pyshexc"
 version = "0.9.1"
 description = "PyShExC - Python ShEx compiler"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1938,7 +1831,6 @@ shexjsg = ">=0.8.1"
 name = "pytest"
 version = "7.4.2"
 description = "pytest: simple powerful testing with Python"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1961,7 +1853,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no
 name = "pytest-logging"
 version = "2015.11.4"
 description = "Configures logging and allows tweaking the log level with a py.test flag"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1975,7 +1866,6 @@ pytest = ">=2.8.1"
 name = "pytest-subtests"
 version = "0.11.0"
 description = "unittest subTest() support and subtests fixture"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1991,7 +1881,6 @@ pytest = ">=7.0"
 name = "python-dateutil"
 version = "2.8.2"
 description = "Extensions to the standard Python datetime module"
-category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
 files = [
@@ -2006,7 +1895,6 @@ six = ">=1.5"
 name = "pytrie"
 version = "0.4.0"
 description = "A pure Python implementation of the trie data structure."
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2020,7 +1908,6 @@ sortedcontainers = "*"
 name = "pytz"
 version = "2023.3.post1"
 description = "World timezone definitions, modern and historical"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2032,7 +1919,6 @@ files = [
 name = "pywin32"
 version = "306"
 description = "Python for Window Extensions"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2056,7 +1942,6 @@ files = [
 name = "pyyaml"
 version = "6.0.1"
 description = "YAML parser and emitter for Python"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -2065,7 +1950,6 @@ files = [
     {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
     {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
     {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
-    {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
     {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
     {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
     {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
@@ -2073,15 +1957,8 @@ files = [
     {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
     {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
     {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
-    {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
     {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
     {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
-    {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
-    {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
-    {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
-    {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
-    {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
-    {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
     {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
     {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
     {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
@@ -2098,7 +1975,6 @@ files = [
     {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
     {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
     {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
-    {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
     {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
     {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
     {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
@@ -2106,7 +1982,6 @@ files = [
     {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
     {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
     {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
-    {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
     {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
     {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
     {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
@@ -2116,7 +1991,6 @@ files = [
 name = "pyzmq"
 version = "25.1.1"
 description = "Python bindings for 0MQ"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -2222,7 +2096,6 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""}
 name = "rdflib"
 version = "6.2.0"
 description = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2247,7 +2120,6 @@ tests = ["html5lib", "pytest", "pytest-cov"]
 name = "rdflib-jsonld"
 version = "0.6.1"
 description = "rdflib extension adding JSON-LD parser and serializer"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2262,7 +2134,6 @@ rdflib = ">=5.0.0"
 name = "rdflib-shim"
 version = "1.0.3"
 description = "Shim for rdflib 5 and 6 incompatibilities"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2278,7 +2149,6 @@ rdflib-jsonld = "0.6.1"
 name = "requests"
 version = "2.31.0"
 description = "Python HTTP for Humans."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2300,7 +2170,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
 name = "rfc3339-validator"
 version = "0.1.4"
 description = "A pure python RFC3339 validator"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 files = [
@@ -2315,7 +2184,6 @@ six = "*"
 name = "rfc3987"
 version = "1.3.8"
 description = "Parsing and validation of URIs (RFC 3986) and IRIs (RFC 3987)"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2327,7 +2195,6 @@ files = [
 name = "ruamel-yaml"
 version = "0.17.33"
 description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
-category = "main"
 optional = false
 python-versions = ">=3"
 files = [
@@ -2346,7 +2213,6 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
 name = "ruamel-yaml-clib"
 version = "0.2.7"
 description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
-category = "main"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -2357,8 +2223,7 @@ files = [
     {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"},
     {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"},
     {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"},
-    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"},
-    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"},
+    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"},
     {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"},
     {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"},
     {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"},
@@ -2393,7 +2258,6 @@ files = [
 name = "setuptools"
 version = "68.0.0"
 description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2410,7 +2274,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
 name = "shexjsg"
 version = "0.8.2"
 description = "ShExJSG - Astract Syntax Tree for the ShEx 2.0 language"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2425,7 +2288,6 @@ pyjsg = ">=0.11.10"
 name = "six"
 version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
 files = [
@@ -2437,7 +2299,6 @@ files = [
 name = "snowballstemmer"
 version = "2.2.0"
 description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2449,7 +2310,6 @@ files = [
 name = "sortedcontainers"
 version = "2.4.0"
 description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2461,7 +2321,6 @@ files = [
 name = "soupsieve"
 version = "2.4.1"
 description = "A modern CSS selector implementation for Beautiful Soup."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2473,7 +2332,6 @@ files = [
 name = "sparqlslurper"
 version = "0.5.1"
 description = "SPARQL Slurper for rdflib"
-category = "main"
 optional = false
 python-versions = ">=3.7.4"
 files = [
@@ -2490,7 +2348,6 @@ sparqlwrapper = ">=1.8.2"
 name = "sparqlwrapper"
 version = "2.0.0"
 description = "SPARQL Endpoint interface to Python"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2511,7 +2368,6 @@ pandas = ["pandas (>=1.3.5)"]
 name = "sphinx"
 version = "5.3.0"
 description = "Python documentation generator"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -2547,7 +2403,6 @@ test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"]
 name = "sphinx-basic-ng"
 version = "1.0.0b2"
 description = "A modern skeleton for Sphinx themes."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2565,7 +2420,6 @@ docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-ta
 name = "sphinx-click"
 version = "4.4.0"
 description = "Sphinx extension that automatically documents click applications"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2582,7 +2436,6 @@ sphinx = ">=2.0"
 name = "sphinx-rtd-theme"
 version = "0.5.1"
 description = "Read the Docs theme for Sphinx"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2600,7 +2453,6 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"]
 name = "sphinxcontrib-applehelp"
 version = "1.0.2"
 description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -2616,7 +2468,6 @@ test = ["pytest"]
 name = "sphinxcontrib-devhelp"
 version = "1.0.2"
 description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -2632,7 +2483,6 @@ test = ["pytest"]
 name = "sphinxcontrib-htmlhelp"
 version = "2.0.0"
 description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -2648,7 +2498,6 @@ test = ["html5lib", "pytest"]
 name = "sphinxcontrib-jsmath"
 version = "1.0.1"
 description = "A sphinx extension which renders display math in HTML via JavaScript"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -2663,7 +2512,6 @@ test = ["flake8", "mypy", "pytest"]
 name = "sphinxcontrib-mermaid"
 version = "0.7.1"
 description = "Mermaid diagrams in yours Sphinx powered docs"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2675,7 +2523,6 @@ files = [
 name = "sphinxcontrib-qthelp"
 version = "1.0.3"
 description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -2691,7 +2538,6 @@ test = ["pytest"]
 name = "sphinxcontrib-serializinghtml"
 version = "1.1.5"
 description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -2707,7 +2553,6 @@ test = ["pytest"]
 name = "sqlalchemy"
 version = "2.0.21"
 description = "Database Abstraction Library"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2755,7 +2600,7 @@ files = [
 ]
 
 [package.dependencies]
-greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""}
+greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""}
 typing-extensions = ">=4.2.0"
 
 [package.extras]
@@ -2786,7 +2631,6 @@ sqlcipher = ["sqlcipher3-binary"]
 name = "tinycss2"
 version = "1.2.1"
 description = "A tiny CSS parser"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2805,7 +2649,6 @@ test = ["flake8", "isort", "pytest"]
 name = "tomli"
 version = "2.0.1"
 description = "A lil' TOML parser"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2817,7 +2660,6 @@ files = [
 name = "tornado"
 version = "6.2"
 description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
-category = "dev"
 optional = false
 python-versions = ">= 3.7"
 files = [
@@ -2838,7 +2680,6 @@ files = [
 name = "tox"
 version = "4.8.0"
 description = "tox is a generic virtualenv management and test command line tool"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2866,7 +2707,6 @@ testing = ["build[virtualenv] (>=0.10)", "covdefaults (>=2.3)", "detect-test-pol
 name = "traitlets"
 version = "5.9.0"
 description = "Traitlets Python configuration system"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2882,7 +2722,6 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"]
 name = "typing-extensions"
 version = "4.7.1"
 description = "Backported and Experimental Type Hints for Python 3.7+"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2894,7 +2733,6 @@ files = [
 name = "uri-template"
 version = "1.3.0"
 description = "RFC 6570 URI Template Processor"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2909,7 +2747,6 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake
 name = "urllib3"
 version = "2.0.5"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2927,7 +2764,6 @@ zstd = ["zstandard (>=0.18.0)"]
 name = "virtualenv"
 version = "20.24.5"
 description = "Virtual Python Environment builder"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2948,7 +2784,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
 name = "watchdog"
 version = "3.0.0"
 description = "Filesystem events monitoring"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2988,7 +2823,6 @@ watchmedo = ["PyYAML (>=3.10)"]
 name = "wcwidth"
 version = "0.2.7"
 description = "Measures the displayed width of unicode strings in a terminal"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -3000,7 +2834,6 @@ files = [
 name = "webcolors"
 version = "1.13"
 description = "A library for working with the color formats defined by HTML and CSS."
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -3016,7 +2849,6 @@ tests = ["pytest", "pytest-cov"]
 name = "webencodings"
 version = "0.5.1"
 description = "Character encoding aliases for legacy web content"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -3028,7 +2860,6 @@ files = [
 name = "wrapt"
 version = "1.15.0"
 description = "Module for decorators, wrappers and monkey patching."
-category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 files = [
@@ -3113,7 +2944,6 @@ files = [
 name = "zipp"
 version = "3.15.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -3131,4 +2961,4 @@ docs = []
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "d7e2df4ba7895727f8f9dec650a725a0fc9a1e8dba9542ddb5ab67b4a28129a7"
+content-hash = "d56d10ab69335c3a5439d1fe631b193c78094ef5527d2558b2e2a86f884bd41a"
diff --git a/pyproject.toml b/pyproject.toml
index 0947c81d..57e97f73 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -112,7 +112,7 @@ openpyxl = "*"
 parse = "*"
 prefixcommons = ">=0.1.7"
 prefixmaps = ">=0.1.3"
-pydantic = "*"
+pydantic = ">=1.0.0,<3.0.0"
 pyjsg = ">=0.11.6"
 pyshex = ">=0.7.20"
 pyshexc = ">=0.8.3"
diff --git a/tox.ini b/tox.ini
index 11706e33..f3460a11 100644
--- a/tox.ini
+++ b/tox.ini
@@ -2,8 +2,9 @@
 requires =
     tox>=4
 envlist =
-     lint
-     py
+    lint
+    py{38,39,310,311}
+    pydantic2
 
 [testenv]
 # Running tests via poetry within the tox environment is not the ideal
@@ -20,6 +21,18 @@ commands =
     poetry install --no-root --sync
     poetry run pytest {posargs}
 
+[testenv:pydantic2]
+allowlist_externals = poetry
+commands_pre =
+    poetry install --no-root --sync
+    # This `pip` call looks weird but we want to avoid doing a `poetry add` or
+    # `poetry update` here because that will mess with the the pyproject.toml
+    # and poetry.lock. But we want this change to only to be ephemeral in the
+    # tox testenv.
+    poetry run pip install 'pydantic>=2,<3'
+commands =
+    poetry run pytest {posargs}
+
 [testenv:codespell]
 description = Run spell checker.
 skip_install = true


Test patch:
diff --git a/tests/test_data/test_sqlite_pydantic.py b/tests/test_data/test_sqlite_pydantic.py
index 9edddfc5..e6c31a15 100644
--- a/tests/test_data/test_sqlite_pydantic.py
+++ b/tests/test_data/test_sqlite_pydantic.py
@@ -5,15 +5,9 @@ import yaml
 from linkml_runtime.dumpers import yaml_dumper
 from sqlalchemy.orm import sessionmaker
 
-import tests.test_data.model.personinfo
+from linkml.generators.pydanticgen import PydanticGenerator
 from linkml.utils.sqlutils import SQLStore
 from tests.test_data.environment import env
-from tests.test_data.model.personinfo_pydantic import (
-    Container,
-    FamilialRelationship,
-    GenderType,
-    Person,
-)
 from tests.utils.dict_comparator import compare_yaml
 
 SCHEMA = env.input_path("personinfo.yaml")
@@ -34,15 +28,20 @@ class SQLiteStoreTest(unittest.TestCase):
     - :meth:`SQLStore.load`
     """
 
+    @classmethod
+    def setUpClass(cls) -> None:
+        cls.personinfo_module = PydanticGenerator(SCHEMA).compile_module()
+
     def test_enums(self):
         """
         Tests that enum objects can be constructed inlined.
 
         See https://github.com/linkml/linkml/issues/817
         """
-        FamilialRelationship(type="SIBLING_OF", related_to="x")
-        p = Person(id="x", gender=GenderType("cisgender_man"))
-        self.assertIsInstance(p.gender, GenderType)
+        mod = self.personinfo_module
+        mod.FamilialRelationship(type="SIBLING_OF", related_to="x")
+        p = mod.Person(id="x", gender=mod.GenderType("cisgender_man"))
+        self.assertIsInstance(p.gender, str)
 
     def test_sqlite_store(self):
         """
@@ -51,14 +50,15 @@ class SQLiteStoreTest(unittest.TestCase):
         # step 1: setup
         # TODO: currently it is necessary to pass the actual yaml rather than a schema object
         # endpoint = SQLiteEndpoint(sv.schema, database_path=DB, include_schema_in_database=False)
+        mod = self.personinfo_module
         endpoint = SQLStore(SCHEMA, database_path=DB, include_schema_in_database=False)
-        endpoint.native_module = tests.test_data.model.personinfo_pydantic
+        endpoint.native_module = mod
         endpoint.db_exists(force=True)
         # step 2: load data from file and store in SQLStore
         # TODO: use yaml_loader once this supports pydantic
         with open(DATA) as file:
             dict_obj = yaml.safe_load(file)
-        container = Container(**dict_obj)
+        container = mod.Container(**dict_obj)
         endpoint.dump(container)
         # step 3: test query using SQL Alchemy
         session_class = sessionmaker(bind=endpoint.engine)
@@ -69,7 +69,7 @@ class SQLiteStoreTest(unittest.TestCase):
         q = session.query(endpoint.module.FamilialRelationship)
         # step 4: test loading from SQLStore
         # 4a: first test load_all, diff to original data should be empty
-        [returned_container] = endpoint.load_all(target_class=Container)
+        [returned_container] = endpoint.load_all(target_class=mod.Container)
         # y = yaml_dumper.dumps(x[0])
         returned_dict = returned_container.dict(exclude_none=True)
         if False:
diff --git a/tests/test_issues/conftest.py b/tests/test_issues/conftest.py
index c6e1c855..a71a3330 100644
--- a/tests/test_issues/conftest.py
+++ b/tests/test_issues/conftest.py
@@ -119,13 +119,13 @@ def data_str():
 {
   "things": [
     {
-      "id": 1,
+      "id": "1",
       "thingtype": "x:Person",
       "full_name": "phoebe",
       "height": 10
     },
     {
-      "id": 2,
+      "id": "2",
       "thingtype": "x:Organisation",
       "full_name": "University of Earth",
       "number_of_employees": 2
diff --git a/tests/test_issues/test_pydantic_polymorphism.py b/tests/test_issues/test_pydantic_polymorphism.py
index 0284c923..0f722cce 100644
--- a/tests/test_issues/test_pydantic_polymorphism.py
+++ b/tests/test_issues/test_pydantic_polymorphism.py
@@ -3,6 +3,7 @@ import re
 import pytest
 from linkml_runtime.utils.compile_python import compile_python
 from pydantic import ValidationError
+from pydantic.version import VERSION as PYDANTIC_VERSION
 
 from linkml.generators.pydanticgen import PydanticGenerator
 
@@ -43,7 +44,10 @@ def test_pydantic_load_poly_data(schema_str, data_str):
     gen = PydanticGenerator(schema_str)
     output = gen.serialize()
     mod = compile_python(output, "testschema")
-    data = mod.Container.parse_raw(data_str)
+    if PYDANTIC_VERSION[0] == "1":
+        data = mod.Container.parse_raw(data_str)
+    else:
+        data = mod.Container.model_validate_json(data_str)
 
     assert len([x for x in data.things if isinstance(x, mod.Person)]) == 1
     assert len([x for x in data.things if isinstance(x, mod.Organisation)]) == 1
diff --git a/tests/test_validator/test_pydantic_validation_plugin.py b/tests/test_validator/test_pydantic_validation_plugin.py
index e4581ec4..4eb57eeb 100644
--- a/tests/test_validator/test_pydantic_validation_plugin.py
+++ b/tests/test_validator/test_pydantic_validation_plugin.py
@@ -1,18 +1,17 @@
-from pathlib import Path
-
 import pytest
 from linkml_runtime.linkml_model import SchemaDefinition
 from linkml_runtime.loaders import yaml_loader
+from pydantic.version import VERSION as PYDANTIC_VERSION
 
 from linkml.validator.plugins.pydantic_validation_plugin import PydanticValidationPlugin
 from linkml.validator.validation_context import ValidationContext
 
-PERSONINFO_SCHEMA = str(Path(__file__).parent / "input/personinfo.yaml")
+IS_PYDANTIC_V1 = PYDANTIC_VERSION[0] == "1"
 
 
 @pytest.fixture
-def validation_context():
-    schema = yaml_loader.load(PERSONINFO_SCHEMA, SchemaDefinition)
+def validation_context(input_path):
+    schema = yaml_loader.load(input_path("personinfo.yaml"), SchemaDefinition)
     return ValidationContext(schema, "Person")
 
 
@@ -29,7 +28,7 @@ def validation_context():
         ({"id": "1", "full_name": "Person One", "aliases": "Person 1"}, False, False),
         ({"id": "1", "full_name": ["Person One"]}, False, False),
         ({"id": ["1"], "full_name": "Person One"}, False, False),
-        ({"id": "1", "full_name": 1, "age": 100}, True, False),
+        ({"id": "1", "full_name": 1, "age": 100}, True if IS_PYDANTIC_V1 else False, False),
         ({"id": "1", "full_name": 1, "age": "one hundred"}, False, False),
         ({"full_name": "Person One"}, False, False),
         # TODO