Repository: linkml/linkml

Issue:
rdflib v7 introduces breaking changes
When we migrated from v5 to v6 (https://github.com/linkml/linkml/issues/291) we left the `.decode()`s in place; while no longer necessary, they worked in both 5 and 6.

v7 seems to drop support for this altogether, which introduces breaking changes in owlgen

`AttributeError: 'str' object has no attribute 'decode'. Did you mean: 'encode'?`

The quick fix is for schema repos to pin to 6. but we should change the code to remove the decodes - we have already dropped support for rdflib v5 anyway

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`598376c`)](https://app.codecov.io/gh/linkml/linkml/commit/598376ce7f8c11bd3cf31f0ca7e3d5c34770021a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml) 79.86% compared to head [(`8ac9cfd`)](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml) 79.82%.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1714      +/-   ##
==========================================
- Coverage   79.86%   79.82%   -0.05%     
==========================================
  Files          98       98              
  Lines       11185    11185              
  Branches     2865     2865              
==========================================
- Hits         8933     8928       -5     
- Misses       1716     1718       +2     
- Partials      536      539       +3     
```


| [Files](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml) | Coverage Δ | |
|---|---|---|
| [linkml/generators/rdfgen.py](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml#diff-bGlua21sL2dlbmVyYXRvcnMvcmRmZ2VuLnB5) | `100.00% <100.00%> (ø)` | |
| [linkml/generators/shaclgen.py](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml#diff-bGlua21sL2dlbmVyYXRvcnMvc2hhY2xnZW4ucHk=) | `79.01% <100.00%> (ø)` | |
| [linkml/generators/shexgen.py](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml#diff-bGlua21sL2dlbmVyYXRvcnMvc2hleGdlbi5weQ==) | `91.40% <100.00%> (ø)` | |

... and [2 files with indirect coverage changes](https://app.codecov.io/gh/linkml/linkml/pull/1714/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml)


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/linkml/linkml/pull/1714?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=linkml).


Patch:
diff --git a/linkml/generators/docgen.py b/linkml/generators/docgen.py
index c7d04a89..0dee9da8 100644
--- a/linkml/generators/docgen.py
+++ b/linkml/generators/docgen.py
@@ -130,6 +130,9 @@ class DocGenerator(Generator):
     directory: str = None
     """directory in which to write documents"""
 
+    index_name: str = "index"
+    """name of the index document"""
+
     template_directory: str = None
     """directory for custom templates"""
 
@@ -188,7 +191,7 @@ class DocGenerator(Generator):
         }
         template = self._get_template("index")
         out_str = template.render(gen=self, schema=sv.schema, schemaview=sv, **template_vars)
-        self._write(out_str, directory, "index")  # TODO: make configurable
+        self._write(out_str, directory, self.index_name)
         if self._is_single_file_format(self.format):
             logging.info(f"{self.format} is a single-page format, skipping non-index elements")
             return
@@ -844,6 +847,7 @@ class DocGenerator(Generator):
     required=True,
     help="Folder to which document files are written",
 )
+@click.option("--index-name", default="index", show_default=True, help="Name of the index document.")
 @click.option("--dialect", help="Dialect or 'flavor' of Markdown used.")
 @click.option(
     "--diagram-type",
@@ -885,7 +889,7 @@ class DocGenerator(Generator):
 )
 @click.version_option(__version__, "-V", "--version")
 @click.command()
-def cli(yamlfile, directory, dialect, template_directory, use_slot_uris, hierarchical_class_view, **args):
+def cli(yamlfile, directory, index_name, dialect, template_directory, use_slot_uris, hierarchical_class_view, **args):
     """Generate documentation folder from a LinkML YAML schema
 
     Currently a default set of templates for markdown is provided (see the
@@ -912,6 +916,7 @@ def cli(yamlfile, directory, dialect, template_directory, use_slot_uris, hierarc
         template_directory=template_directory,
         use_slot_uris=use_slot_uris,
         hierarchical_class_view=hierarchical_class_view,
+        index_name=index_name,
         **args,
     )
     print(gen.serialize())
diff --git a/linkml/generators/docgen/class.md.jinja2 b/linkml/generators/docgen/class.md.jinja2
index 390f5923..52a33d49 100644
--- a/linkml/generators/docgen/class.md.jinja2
+++ b/linkml/generators/docgen/class.md.jinja2
@@ -1,4 +1,10 @@
-# Class: {{ gen.name(element) }}
+{%- if element.title -%}
+    {%- set title = element.title ~ ' (' ~ gen.name(element) ~ ')' -%}
+{%- else -%}
+    {%- set title = gen.name(element) -%}
+{%- endif -%}
+
+# Class: {{ title }}
 
 {%- if header -%}
 {{header}}
diff --git a/linkml/generators/docgen/slot.md.jinja2 b/linkml/generators/docgen/slot.md.jinja2
index 8bd9890d..fb4731e6 100644
--- a/linkml/generators/docgen/slot.md.jinja2
+++ b/linkml/generators/docgen/slot.md.jinja2
@@ -1,4 +1,10 @@
-# Slot: {{ gen.name(element) }}
+{%- if element.title %}
+    {%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
+{%- else %}
+    {%- set title = gen.name(element) -%}
+{%- endif -%}
+
+# Slot: {{ title }}
 
 {%- if header -%}
 {{header}}
diff --git a/linkml/generators/rdfgen.py b/linkml/generators/rdfgen.py
index acf2f592..06423ca9 100644
--- a/linkml/generators/rdfgen.py
+++ b/linkml/generators/rdfgen.py
@@ -36,7 +36,7 @@ class RDFGenerator(Generator):
     context: List[str] = None
 
     def _data(self, g: Graph) -> str:
-        return g.serialize(format="turtle" if self.format == "ttl" else self.format).decode()
+        return g.serialize(format="turtle" if self.format == "ttl" else self.format)
 
     def end_schema(self, output: Optional[str] = None, context: str = None, **_) -> None:
         gen = JSONLDGenerator(
diff --git a/linkml/generators/shaclgen.py b/linkml/generators/shaclgen.py
index 90dcf2ba..928e2f59 100644
--- a/linkml/generators/shaclgen.py
+++ b/linkml/generators/shaclgen.py
@@ -53,7 +53,7 @@ class ShaclGenerator(Generator):
 
     def serialize(self, **args) -> None:
         g = self.as_graph()
-        data = g.serialize(format="turtle" if self.format in ["owl", "ttl"] else self.format).decode()
+        data = g.serialize(format="turtle" if self.format in ["owl", "ttl"] else self.format)
         return data
 
     def as_graph(self) -> None:
diff --git a/linkml/generators/shexgen.py b/linkml/generators/shexgen.py
index 796926fd..fb41cc93 100644
--- a/linkml/generators/shexgen.py
+++ b/linkml/generators/shexgen.py
@@ -148,7 +148,7 @@ class ShExGenerator(Generator):
             g = Graph()
             g.parse(data=shex, format="json-ld")
             g.bind("owl", OWL)
-            shex = g.serialize(format="turtle").decode()
+            shex = g.serialize(format="turtle")
         elif self.format == "shex":
             g = Graph()
             self.namespaces.load_graph(g)
diff --git a/poetry.lock b/poetry.lock
index fab50573..4231056b 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,10 +1,9 @@
-# This file is automatically @generated by Poetry 1.4.0 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 = [
@@ -1290,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 = [
@@ -1305,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 = [
@@ -1325,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 = [
@@ -1337,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 = [
@@ -1349,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 = [
@@ -1376,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 = [
@@ -1386,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"
 
@@ -1399,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 = [
@@ -1438,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 = [
@@ -1460,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 = [
@@ -1472,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 = [
@@ -1487,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 = [
@@ -1499,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 = [
@@ -1511,7 +1436,6 @@ files = [
 name = "parse"
 version = "1.19.1"
 description = "parse() is the opposite of format()"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1523,7 +1447,6 @@ files = [
 name = "parso"
 version = "0.8.3"
 description = "A Python Parser"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1539,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 = [
@@ -1554,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 = [
@@ -1566,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 = [
@@ -1578,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 = [
@@ -1594,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 = [
@@ -1610,7 +1528,6 @@ testing = ["pytest", "pytest-benchmark"]
 name = "ply"
 version = "3.11"
 description = "Python Lex & Yacc"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -1622,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 = [
@@ -1640,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 = [
@@ -1663,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 = [
@@ -1678,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 = [
@@ -1705,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 = [
@@ -1717,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 = [
@@ -1729,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 = [
@@ -1782,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 = [
@@ -1797,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 = [
@@ -1813,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 = [
@@ -1828,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 = [
@@ -1848,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 = [
@@ -1885,7 +1790,6 @@ files = [
 name = "pyshex"
 version = "0.8.1"
 description = "Python ShEx Implementation"
-category = "main"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -1908,7 +1812,6 @@ urllib3 = "*"
 name = "pyshexc"
 version = "0.9.1"
 description = "PyShExC - Python ShEx compiler"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -1928,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 = [
@@ -1951,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 = [
@@ -1965,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 = [
@@ -1981,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 = [
@@ -1996,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 = [
@@ -2010,7 +1908,6 @@ sortedcontainers = "*"
 name = "pytz"
 version = "2023.3.post1"
 description = "World timezone definitions, modern and historical"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2022,7 +1919,6 @@ files = [
 name = "pywin32"
 version = "306"
 description = "Python for Window Extensions"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -2046,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 = [
@@ -2096,7 +1991,6 @@ files = [
 name = "pyzmq"
 version = "25.1.1"
 description = "Python bindings for 0MQ"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -2200,34 +2094,29 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""}
 
 [[package]]
 name = "rdflib"
-version = "6.2.0"
+version = "7.0.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"
+python-versions = ">=3.8.1,<4.0.0"
 files = [
-    {file = "rdflib-6.2.0-py3-none-any.whl", hash = "sha256:85c34a86dfc517a41e5f2425a41a0aceacc23983462b32e68610b9fad1383bca"},
-    {file = "rdflib-6.2.0.tar.gz", hash = "sha256:62dc3c86d1712db0f55785baf8047f63731fa59b2682be03219cb89262065942"},
+    {file = "rdflib-7.0.0-py3-none-any.whl", hash = "sha256:0438920912a642c866a513de6fe8a0001bd86ef975057d6962c79ce4771687cd"},
+    {file = "rdflib-7.0.0.tar.gz", hash = "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae"},
 ]
 
 [package.dependencies]
-isodate = "*"
-pyparsing = "*"
-setuptools = "*"
+isodate = ">=0.6.0,<0.7.0"
+pyparsing = ">=2.1.0,<4"
 
 [package.extras]
-berkeleydb = ["berkeleydb"]
-dev = ["black (==22.6.0)", "flake8", "flakeheaven", "isort", "mypy", "pep8-naming", "types-setuptools"]
-docs = ["myst-parser", "sphinx (<6)", "sphinx-autodoc-typehints", "sphinxcontrib-apidoc", "sphinxcontrib-kroki"]
-html = ["html5lib"]
-networkx = ["networkx"]
-tests = ["html5lib", "pytest", "pytest-cov"]
+berkeleydb = ["berkeleydb (>=18.1.0,<19.0.0)"]
+html = ["html5lib (>=1.0,<2.0)"]
+lxml = ["lxml (>=4.3.0,<5.0.0)"]
+networkx = ["networkx (>=2.0.0,<3.0.0)"]
 
 [[package]]
 name = "rdflib-jsonld"
 version = "0.6.1"
 description = "rdflib extension adding JSON-LD parser and serializer"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2242,7 +2131,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 = [
@@ -2258,7 +2146,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 = [
@@ -2280,7 +2167,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 = [
@@ -2295,7 +2181,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 = [
@@ -2307,7 +2192,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 = [
@@ -2326,7 +2210,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 = [
@@ -2337,8 +2220,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"},
@@ -2373,7 +2255,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 = [
@@ -2390,7 +2271,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 = [
@@ -2405,7 +2285,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 = [
@@ -2417,7 +2296,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 = [
@@ -2429,7 +2307,6 @@ files = [
 name = "sortedcontainers"
 version = "2.4.0"
 description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
-category = "main"
 optional = false
 python-versions = "*"
 files = [
@@ -2441,7 +2318,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 = [
@@ -2453,7 +2329,6 @@ files = [
 name = "sparqlslurper"
 version = "0.5.1"
 description = "SPARQL Slurper for rdflib"
-category = "main"
 optional = false
 python-versions = ">=3.7.4"
 files = [
@@ -2470,7 +2345,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 = [
@@ -2491,7 +2365,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 = [
@@ -2527,7 +2400,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 = [
@@ -2545,7 +2417,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 = [
@@ -2562,7 +2433,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 = [
@@ -2580,7 +2450,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 = [
@@ -2596,7 +2465,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 = [
@@ -2612,7 +2480,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 = [
@@ -2628,7 +2495,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 = [
@@ -2643,7 +2509,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 = [
@@ -2655,7 +2520,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 = [
@@ -2671,7 +2535,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 = [
@@ -2687,7 +2550,6 @@ test = ["pytest"]
 name = "sqlalchemy"
 version = "2.0.21"
 description = "Database Abstraction Library"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2707,14 +2569,6 @@ files = [
     {file = "SQLAlchemy-2.0.21-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b69f1f754d92eb1cc6b50938359dead36b96a1dcf11a8670bff65fd9b21a4b09"},
     {file = "SQLAlchemy-2.0.21-cp311-cp311-win32.whl", hash = "sha256:af520a730d523eab77d754f5cf44cc7dd7ad2d54907adeb3233177eeb22f271b"},
     {file = "SQLAlchemy-2.0.21-cp311-cp311-win_amd64.whl", hash = "sha256:141675dae56522126986fa4ca713739d00ed3a6f08f3c2eb92c39c6dfec463ce"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:56628ca27aa17b5890391ded4e385bf0480209726f198799b7e980c6bd473bd7"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db726be58837fe5ac39859e0fa40baafe54c6d54c02aba1d47d25536170b690f"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7421c1bfdbb7214313919472307be650bd45c4dc2fcb317d64d078993de045b"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:632784f7a6f12cfa0e84bf2a5003b07660addccf5563c132cd23b7cc1d7371a9"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f6f7276cf26145a888f2182a98f204541b519d9ea358a65d82095d9c9e22f917"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2a1f7ffac934bc0ea717fa1596f938483fb8c402233f9b26679b4f7b38d6ab6e"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-win32.whl", hash = "sha256:bfece2f7cec502ec5f759bbc09ce711445372deeac3628f6fa1c16b7fb45b682"},
-    {file = "SQLAlchemy-2.0.21-cp312-cp312-win_amd64.whl", hash = "sha256:526b869a0f4f000d8d8ee3409d0becca30ae73f494cbb48801da0129601f72c6"},
     {file = "SQLAlchemy-2.0.21-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7614f1eab4336df7dd6bee05bc974f2b02c38d3d0c78060c5faa4cd1ca2af3b8"},
     {file = "SQLAlchemy-2.0.21-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d59cb9e20d79686aa473e0302e4a82882d7118744d30bb1dfb62d3c47141b3ec"},
     {file = "SQLAlchemy-2.0.21-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a95aa0672e3065d43c8aa80080cdd5cc40fe92dc873749e6c1cf23914c4b83af"},
@@ -2743,7 +2597,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]
@@ -2774,7 +2628,6 @@ sqlcipher = ["sqlcipher3-binary"]
 name = "tinycss2"
 version = "1.2.1"
 description = "A tiny CSS parser"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2793,7 +2646,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 = [
@@ -2805,7 +2657,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 = [
@@ -2826,7 +2677,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 = [
@@ -2854,7 +2704,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 = [
@@ -2870,7 +2719,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 = [
@@ -2882,7 +2730,6 @@ files = [
 name = "uri-template"
 version = "1.3.0"
 description = "RFC 6570 URI Template Processor"
-category = "main"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -2897,7 +2744,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 = [
@@ -2915,7 +2761,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 = [
@@ -2936,7 +2781,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 = [
@@ -2976,7 +2820,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 = [
@@ -2988,7 +2831,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 = [
@@ -3004,7 +2846,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 = [
@@ -3016,7 +2857,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 = [
@@ -3101,7 +2941,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 = [
@@ -3118,5 +2957,5 @@ docs = []
 
 [metadata]
 lock-version = "2.0"
-python-versions = "^3.8"
-content-hash = "d56d10ab69335c3a5439d1fe631b193c78094ef5527d2558b2e2a86f884bd41a"
+python-versions = "^3.8.1"
+content-hash = "7d0f8f7c25b9fd8aeb9fb565a92b7246b373d0f46aceadfbec6652f441d800bb"
diff --git a/pyproject.toml b/pyproject.toml
index e43f5e75..6b8891bc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -97,7 +97,7 @@ gen-linkml = "linkml.generators.linkmlgen:cli"
 linkml-schema-fixer = "linkml.utils.schema_fixer:main"
 
 [tool.poetry.dependencies]
-python = "^3.8"
+python = "^3.8.1"
 antlr4-python3-runtime = "<4.10,==4.*,>=4.9.0"
 click = ">=7.0"
 graphviz = ">=0.10.1"


Test patch:
diff --git a/tests/test_compliance/test_jsonpointer_compliance.py b/tests/test_compliance/test_jsonpointer_compliance.py
new file mode 100644
index 00000000..d35e56ed
--- /dev/null
+++ b/tests/test_compliance/test_jsonpointer_compliance.py
@@ -0,0 +1,141 @@
+import pytest
+
+from tests.test_compliance.helper import (
+    ValidationBehavior,
+    check_data,
+    validated_schema,
+)
+from tests.test_compliance.test_compliance import CLASS_C, CORE_FRAMEWORKS, SLOT_ID
+
+
+@pytest.mark.parametrize(
+    "data_name,data,invalid_reason",
+    [
+        (
+            "simple",
+            {
+                "id": "object1234",
+                "source": [
+                    {"property": "#/height", "provenance": "fooSource"},
+                    {"property": "#/width", "provenance": "barSource"},
+                    {"property": "#/address[0]", "provenance": "fizzSource"},
+                    {"property": "#/address[1]", "provenance": "bazSource"},
+                ],
+                "height": 10.0,
+                "width": 20.0,
+                "address": ["120 Main St", "100 Second St"],
+            },
+            None,
+        ),
+        (
+            "invalid_jsonpointer",
+            {
+                "id": "object1234",
+                "source": [
+                    {"property": "#/height", "provenance": "fooSource"},
+                    {"property": "#/width", "provenance": "barSource"},
+                    {"property": "#/address[0]", "provenance": "fizzSource"},
+                    {"property": "#/address[1]", "provenance": "bazSource"},
+                ],
+                "height": 10.0,
+                "width": 20.0,
+                "address": ["120 Main St", "100 Second St"],
+            },
+            "pointer to a non-existent property",
+        ),
+        (
+            "invalid_array_element",
+            {
+                "id": "object1234",
+                "source": [
+                    {"property": "#/height", "provenance": "fooSource"},
+                    {"property": "#/width", "provenance": "barSource"},
+                    {"property": "#/address[0]", "provenance": "fizzSource"},
+                    {"property": "#/address[99]", "provenance": "bazSource"},
+                ],
+                "height": 10.0,
+                "width": 20.0,
+                "address": ["120 Main St", "100 Second St"],
+            },
+            "array out of bounds",
+        ),
+    ],
+)
+@pytest.mark.parametrize("framework", CORE_FRAMEWORKS)
+def test_jsonpointer(framework, data_name, data, invalid_reason):
+    """
+    Tests behavior of json pointers.
+
+    Note: this feature is under discussion
+    and incompletely implemented. See:
+
+    https://github.com/linkml/linkml/issues/1469
+
+    :param framework: all should support built-in types
+    :param data_name: id for data instance
+    :param data: value to check
+    :param invalid_reason: reason for invalidity (valid if None)
+    :return:
+    """
+    CLASS_SOURCE = "Source"
+    classes = {
+        CLASS_SOURCE: {
+            "attributes": {
+                "property": {
+                    "range": "jsonpointer",
+                },
+                "provenance": {
+                    "description": "Provenance of the assignment property points at",
+                },
+            }
+        },
+        CLASS_C: {
+            "attributes": {
+                SLOT_ID: {
+                    "identifier": True,
+                },
+                "height": {
+                    "range": "float",
+                },
+                "width": {
+                    "range": "float",
+                },
+                "address": {
+                    "multivalued": True,
+                },
+                "source": {
+                    "description": "Key value to lookup source of S1/S2 assignment",
+                    "range": CLASS_SOURCE,
+                    "multivalued": True,
+                },
+            }
+        },
+    }
+    schema = validated_schema(
+        test_jsonpointer,
+        "default",
+        framework,
+        classes=classes,
+        core_elements=["jsonpointer"],
+    )
+    expected_behavior = ValidationBehavior.IMPLEMENTS
+    is_valid = invalid_reason is None
+    if not is_valid:
+        # validation behavior is not yet implemented for ANY framework.
+        # precise behavior is yet to be defined, but at a minimum
+        # any jsonpointer should be valid syntax and should resolve
+        # to a valid object within the json/tree form of the document.
+        # TODO decide:
+        #   - do we want to allow dangling pointers to reference a None assignment?
+        #   - should only inlined references be traversed?
+        expected_behavior = ValidationBehavior.INCOMPLETE
+    check_data(
+        schema,
+        data_name,
+        framework,
+        data,
+        is_valid,
+        expected_behavior=expected_behavior,
+        target_class=CLASS_C,
+        description=data_name,
+    )
diff --git a/tests/test_generators/test_docgen.py b/tests/test_generators/test_docgen.py
index 01037a12..18b8e71d 100644
--- a/tests/test_generators/test_docgen.py
+++ b/tests/test_generators/test_docgen.py
@@ -4,6 +4,7 @@ Tests generation of markdown and similar documents
 Note that docgen replaces markdowngen
 """
 import logging
+import os
 from collections import Counter
 from copy import copy
 from typing import List
@@ -426,6 +427,15 @@ def test_custom_directory(kitchen_sink_path, input_path, tmp_path):
     assert_mdfile_contains(tmp_path / "Organization.md", "FAKE TEMPLATE")
 
 
+def test_gen_custom_named_index(kitchen_sink_path, tmp_path):
+    """Tests that the name of the index page can be customized"""
+    gen = DocGenerator(kitchen_sink_path, index_name="custom-index")
+    gen.serialize(directory=str(tmp_path))
+    assert_mdfile_contains(tmp_path / "custom-index.md", "# Kitchen Sink Schema")
+    # Additionally test that the default index.md has NOT been created
+    assert not os.path.exists(tmp_path / "index.md")
+
+
 def test_html(kitchen_sink_path, input_path, tmp_path):
     """
     Tests ability to specify a complete new set of templates in a different format
diff --git a/tests/test_generators/test_rdfgen.py b/tests/test_generators/test_rdfgen.py
index 7b2ea859..41c135bc 100644
--- a/tests/test_generators/test_rdfgen.py
+++ b/tests/test_generators/test_rdfgen.py
@@ -35,5 +35,5 @@ def test_rdfgen(kitchen_sink_path):
 def test_rdf_type_in_jsonld(self):
     graph = Graph()
     graph.parse(data=JSONLD, format="json-ld", prefix=True)
-    ttl_str = graph.serialize(format="turtle").decode()
+    ttl_str = graph.serialize(format="turtle")
     graph.parse(data=ttl_str, format="turtle")
diff --git a/tests/test_issues/test_issue_103.py b/tests/test_issues/test_issue_103.py
index e006ef9f..4ae714af 100644
--- a/tests/test_issues/test_issue_103.py
+++ b/tests/test_issues/test_issue_103.py
@@ -18,9 +18,9 @@ def test_jsonld_prefix():
     """
 
     g = Graph().parse(data=test_json, format="json-ld", prefix=True)
-    rdfstr = g.serialize(format="turtle").decode()
+    rdfstr = g.serialize(format="turtle")
     assert "@prefix CHEBI: <http://purl.obolibrary.org/obo/CHEBI_>" in rdfstr
 
     g = Graph().parse(data=test_json, format="json-ld", prefix=False)
-    rdfstr = g.serialize(format="turtle").decode()
+    rdfstr = g.serialize(format="turtle")
     assert "@prefix CHEBI: <http://purl.obolibrary.org/obo/CHEBI_>" not in rdfstr
diff --git a/tests/test_issues/test_issue_80.py b/tests/test_issues/test_issue_80.py
index 9d8878ea..e2658748 100644
--- a/tests/test_issues/test_issue_80.py
+++ b/tests/test_issues/test_issue_80.py
@@ -20,5 +20,5 @@ def test_issue_80(input_path, snapshot):
     jsonld_context_output = ContextGenerator(input_path("issue_80.yaml")).serialize()
     assert jsonld_context_output == snapshot("issue_80.context.jsonld")
 
-    rdf_output = as_rdf(example, contexts=jsonld_context_output).serialize(format="turtle").decode()
+    rdf_output = as_rdf(example, contexts=jsonld_context_output).serialize(format="turtle")
     assert rdf_output == snapshot("issue_80.ttl")
diff --git a/tests/test_notebooks/input/examples.py b/tests/test_notebooks/input/examples.py
index 179caea7..60576d0c 100644
--- a/tests/test_notebooks/input/examples.py
+++ b/tests/test_notebooks/input/examples.py
@@ -108,7 +108,7 @@ jsonld = json_dumper.dumps(joe_smith, cntxt)
 print(jsonld)
 g = Graph()
 g.parse(data=jsonld, format="json-ld")
-print(g.serialize(format="turtle").decode())
+print(g.serialize(format="turtle"))
 
 
 shex = ShExGenerator(yaml).serialize(collections=False)
diff --git a/tests/test_notebooks/input/inheritance.py b/tests/test_notebooks/input/inheritance.py
index 5ee0565f..0cee7b98 100644
--- a/tests/test_notebooks/input/inheritance.py
+++ b/tests/test_notebooks/input/inheritance.py
@@ -88,7 +88,7 @@ print(shex)
 # print(jsonld)
 # g = Graph()
 # g.parse(data=jsonld, format="json-ld")
-# print(g.serialize(format="turtle").decode())
+# print(g.serialize(format="turtle"))
 #
 # from pyshex.evaluate import evaluate
 #
diff --git a/tests/test_scripts/test_gen_jsonld.py b/tests/test_scripts/test_gen_jsonld.py
index 9c0a9093..b91f7653 100644
--- a/tests/test_scripts/test_gen_jsonld.py
+++ b/tests/test_scripts/test_gen_jsonld.py
@@ -156,7 +156,7 @@ class GenJSONLDTestCase(ClickTestCase):
         g.load(tmp_jsonld_path, format="json-ld")
         g.serialize(tmp_rdf_path, format="ttl")
         g.bind("meta", METAMODEL_NAMESPACE)
-        new_ttl = g.serialize(format="turtle").decode()
+        new_ttl = g.serialize(format="turtle")
 
         # Make sure that the generated TTL matches the JSON-LD (probably not really needed, as this is more of a test
         # of rdflib than our tooling but it doesn't hurt
diff --git a/tests/test_utils/test_metamodelcore.py b/tests/test_utils/test_metamodelcore.py
index 6d3ff304..1507cec6 100644
--- a/tests/test_utils/test_metamodelcore.py
+++ b/tests/test_utils/test_metamodelcore.py
@@ -250,7 +250,7 @@ class MetamodelCoreTest(unittest.TestCase):
     rdfs:subject "http://example.org/tests/descendant1" .
 
 """,
-            as_rdf(y, context).serialize(format="turtle").decode(),
+            as_rdf(y, context).serialize(format="turtle"),
         )
         with self.assertRaises(ValueError):
             y = Pair(s, s)
diff --git a/tests/test_utils/test_uri_and_curie.py b/tests/test_utils/test_uri_and_curie.py
index 0395a3b2..5704047d 100644
--- a/tests/test_utils/test_uri_and_curie.py
+++ b/tests/test_utils/test_uri_and_curie.py
@@ -58,7 +58,7 @@ class URIAndCurieTestCase(GeneratorTestCase):
         )
         env.eval_single_file(
             env.expected_path("uriandcurie.ttl"),
-            g.serialize(format="ttl").decode(),
+            g.serialize(format="ttl"),
             lambda s: s,
             compare_rdf,
         )
diff --git a/tests/utils/compare_rdf.py b/tests/utils/compare_rdf.py
index 636011c0..db842a7b 100644
--- a/tests/utils/compare_rdf.py
+++ b/tests/utils/compare_rdf.py
@@ -38,7 +38,7 @@ def print_triples(g: Graph) -> None:
     Print the contents of g into stdout
     :param g: graph to print
     """
-    g_text = re.sub(r"@prefix.*\n", "", g.serialize(format="turtle").decode())
+    g_text = re.sub(r"@prefix.*\n", "", g.serialize(format="turtle"))
     print(g_text)
 
 
diff --git a/tests/utils/generatortestcase.py b/tests/utils/generatortestcase.py
index 4378aebb..d9f619c7 100644
--- a/tests/utils/generatortestcase.py
+++ b/tests/utils/generatortestcase.py
@@ -20,7 +20,7 @@ class GeneratorTestCase(TestEnvironmentTestCase):
         g.bind("BIOLINK", BIOLINK_NS)
         g.bind("meta", METAMODEL_NAMESPACE)
         g.bind("owl", OWL)
-        g_text = re.sub(r"@prefix.*\n", "", g.serialize(format="turtle").decode())
+        g_text = re.sub(r"@prefix.*\n", "", g.serialize(format="turtle"))
         print(g_text)
 
     def single_file_generator(