Repository: RDFLib/rdflib

Issue:
Polar-integer datatypes not verifying polarity of lexical value
I recently encountered an issue using pySHACL to validate a `xsd:positiveInteger` and found it was accepting `"0"^^xsd:positiveInteger`.

From review of today's `term.py` and the influence of the members of `_NUMERIC_LITERAL_TYPES`, and from a test-patch (linking in a few moments, I need this Issue number first), this is currently an acceptable rdflib statement:

```python
value = Literal("-1", datatype=XSD.positiveInteger)
```

What should this behavior be instead?  A runtime error (something like `raise ValueError`) would be correct to me, but I appreciate it'd potentially be a jarring change for many applications.

Discussion:

Patch:
diff --git a/pyproject.toml b/pyproject.toml
index a1feb7dd..8341c9c6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,6 +19,7 @@ exclude = '''
     | htmlcov
     | benchmarks
     | examples       # No need to Black examples
+    | test           # Tests are a mess, don't black them
     | test_reports
     | rdflib.egg-info
     | buck-out
diff --git a/rdflib/term.py b/rdflib/term.py
index b53d9287..2e577f4d 100644
--- a/rdflib/term.py
+++ b/rdflib/term.py
@@ -564,7 +564,8 @@ class Literal(Identifier):
     _language: Optional[str]
     # NOTE: _datatype should maybe be of type URIRef, and not optional.
     _datatype: Optional[str]
-    __slots__ = ("_language", "_datatype", "_value")
+    _ill_formed: Optional[bool]
+    __slots__ = ("_language", "_datatype", "_value", "_ill_formed")
 
     def __new__(
         cls,
@@ -586,12 +587,13 @@ class Literal(Identifier):
             )
 
         if lang is not None and not _is_valid_langtag(lang):
-            raise ValueError("'%s' is not a valid language tag!" % lang)
+            raise ValueError(f"'{str(lang)}' is not a valid language tag!")
 
         if datatype:
             datatype = URIRef(datatype)
 
         value = None
+        ill_formed: Optional[bool] = None
         if isinstance(lexical_or_value, Literal):
             # create from another Literal instance
 
@@ -607,7 +609,13 @@ class Literal(Identifier):
             # passed a string
             # try parsing lexical form of datatyped literal
             value = _castLexicalToPython(lexical_or_value, datatype)
-
+            if datatype and datatype in _toPythonMapping:
+                # datatype is a recognized datatype IRI:
+                # https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris
+                dt_uri: URIRef = URIRef(datatype)
+                checker = _check_well_formed_types.get(dt_uri, _well_formed_by_value)
+                well_formed = checker(lexical_or_value, value)
+                ill_formed = ill_formed or (not well_formed)
             if value is not None and normalize:
                 _value, _datatype = _castPythonToLiteral(value, datatype)
                 if _value is not None and _is_valid_unicode(_value):
@@ -641,6 +649,7 @@ class Literal(Identifier):
         inst._language = lang
         inst._datatype = datatype
         inst._value = value
+        inst._ill_formed = ill_formed
 
         return inst
 
@@ -663,6 +672,19 @@ class Literal(Identifier):
         else:
             return self
 
+    @property
+    def ill_formed(self) -> Optional[bool]:
+        """
+        For `recognized datatype IRIs
+        <https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris>`_,
+        this value will be `True` if the literal is ill formed, otherwise it
+        will be `False`. `Literal.value` (i.e. the `literal value <https://www.w3.org/TR/rdf11-concepts/#dfn-literal-value>`_) should always be defined if this property is `False`, but should not be considered reliable if this property is `True`.
+
+        If the literal's datatype is `None` or not in the set of `recognized datatype IRIs
+        <https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris>`_ this value will be `None`.
+        """
+        return self._ill_formed
+
     @property
     def value(self) -> Any:
         return self._value
@@ -1471,9 +1493,14 @@ def _unhexlify(value: Union[str, bytes, Literal]) -> bytes:
     return unhexlify(value)
 
 
-def _parseBoolean(value: str) -> bool:
-    true_accepted_values = ["1", "true"]
-    false_accepted_values = ["0", "false"]
+def _parseBoolean(value: Union[str, bytes]) -> bool:
+    """
+    Boolean is a datatype with value space {true,false},
+    lexical space {"true", "false","1","0"} and
+    lexical-to-value mapping {"true"→true, "false"→false, "1"→true, "0"→false}.
+    """
+    true_accepted_values = ["1", "true", b"1", b"true"]
+    false_accepted_values = ["0", "false", b"0", b"false"]
     new_value = value.lower()
     if new_value in true_accepted_values:
         return True
@@ -1485,6 +1512,102 @@ def _parseBoolean(value: str) -> bool:
     return False
 
 
+def _well_formed_by_value(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    This function is used as the fallback for detecting ill-typed/ill-formed
+    literals and operates on the asumption that if a value (i.e.
+    `Literal.value`) could be determined for a Literal then it is not
+    ill-typed/ill-formed.
+
+    This function will be called with `Literal.lexical` and `Literal.value` as arguments.
+    """
+    return value is not None
+
+
+def _well_formed_unsignedlong(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    xsd:unsignedInteger and xsd:unsignedLong must not be negative
+    """
+    return len(lexical) > 0 and isinstance(value, long_type) and value >= 0
+
+
+def _well_formed_boolean(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    Boolean is a datatype with value space {true,false},
+    lexical space {"true", "false","1","0"} and
+    lexical-to-value mapping {"true"→true, "false"→false, "1"→true, "0"→false}.
+    """
+    return lexical in ("true", b"true", "false", b"false", "1", b"1", "0", b"0")
+
+
+def _well_formed_int(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    The value space of xs:int is the set of common single size integers (32 bits),
+    i.e., the integers between -2147483648 and 2147483647,
+    its lexical space allows any number of insignificant leading zeros.
+    """
+    return (
+        len(lexical) > 0
+        and isinstance(value, int)
+        and (-2147483648 <= value <= 2147483647)
+    )
+
+
+def _well_formed_unsignedint(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    xsd:unsignedInt has a 32bit value of between 0 and 4294967295
+    """
+    return len(lexical) > 0 and isinstance(value, int) and (0 <= value <= 4294967295)
+
+
+def _well_formed_short(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    The value space of xs:short is the set of common short integers (16 bits),
+    i.e., the integers between -32768 and 32767,
+    its lexical space allows any number of insignificant leading zeros.
+    """
+    return len(lexical) > 0 and isinstance(value, int) and (-32768 <= value <= 32767)
+
+
+def _well_formed_unsignedshort(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    xsd:unsignedShort has a 16bit value of between 0 and 65535
+    """
+    return len(lexical) > 0 and isinstance(value, int) and (0 <= value <= 65535)
+
+
+def _well_formed_byte(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    The value space of xs:byte is the set of common single byte integers (8 bits),
+    i.e., the integers between -128 and 127,
+    its lexical space allows any number of insignificant leading zeros.
+    """
+    return len(lexical) > 0 and isinstance(value, int) and (-128 <= value <= 127)
+
+
+def _well_formed_unsignedbyte(lexical: Union[str, bytes], value: Any) -> bool:
+    """
+    xsd:unsignedByte has a 8bit value of between 0 and 255
+    """
+    return len(lexical) > 0 and isinstance(value, int) and (0 <= value <= 255)
+
+
+def _well_formed_non_negative_integer(lexical: Union[str, bytes], value: Any) -> bool:
+    return isinstance(value, int) and value >= 0
+
+
+def _well_formed_positive_integer(lexical: Union[str, bytes], value: Any) -> bool:
+    return isinstance(value, int) and value > 0
+
+
+def _well_formed_non_positive_integer(lexical: Union[str, bytes], value: Any) -> bool:
+    return isinstance(value, int) and value <= 0
+
+
+def _well_formed_negative_integer(lexical: Union[str, bytes], value: Any) -> bool:
+    return isinstance(value, int) and value < 0
+
+
 # Cannot import Namespace/XSD because of circular dependencies
 _XSD_PFX = "http://www.w3.org/2001/XMLSchema#"
 _RDF_PFX = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
@@ -1674,15 +1797,15 @@ XSDToPython: Dict[Optional[str], Optional[Callable[[str], Any]]] = {
     URIRef(_XSD_PFX + "boolean"): _parseBoolean,
     URIRef(_XSD_PFX + "decimal"): Decimal,
     URIRef(_XSD_PFX + "integer"): long_type,
-    URIRef(_XSD_PFX + "nonPositiveInteger"): int,
+    URIRef(_XSD_PFX + "nonPositiveInteger"): long_type,
     URIRef(_XSD_PFX + "long"): long_type,
-    URIRef(_XSD_PFX + "nonNegativeInteger"): int,
-    URIRef(_XSD_PFX + "negativeInteger"): int,
-    URIRef(_XSD_PFX + "int"): long_type,
+    URIRef(_XSD_PFX + "nonNegativeInteger"): long_type,
+    URIRef(_XSD_PFX + "negativeInteger"): long_type,
+    URIRef(_XSD_PFX + "int"): int,
     URIRef(_XSD_PFX + "unsignedLong"): long_type,
-    URIRef(_XSD_PFX + "positiveInteger"): int,
+    URIRef(_XSD_PFX + "positiveInteger"): long_type,
     URIRef(_XSD_PFX + "short"): int,
-    URIRef(_XSD_PFX + "unsignedInt"): long_type,
+    URIRef(_XSD_PFX + "unsignedInt"): int,
     URIRef(_XSD_PFX + "byte"): int,
     URIRef(_XSD_PFX + "unsignedShort"): int,
     URIRef(_XSD_PFX + "unsignedByte"): int,
@@ -1694,6 +1817,21 @@ XSDToPython: Dict[Optional[str], Optional[Callable[[str], Any]]] = {
     _RDF_HTMLLITERAL: _parseHTML,
 }
 
+_check_well_formed_types: Dict[URIRef, Callable[[Union[str, bytes], Any], bool]] = {
+    URIRef(_XSD_PFX + "boolean"): _well_formed_boolean,
+    URIRef(_XSD_PFX + "nonPositiveInteger"): _well_formed_non_positive_integer,
+    URIRef(_XSD_PFX + "nonNegativeInteger"): _well_formed_non_negative_integer,
+    URIRef(_XSD_PFX + "negativeInteger"): _well_formed_negative_integer,
+    URIRef(_XSD_PFX + "positiveInteger"): _well_formed_positive_integer,
+    URIRef(_XSD_PFX + "int"): _well_formed_int,
+    URIRef(_XSD_PFX + "short"): _well_formed_short,
+    URIRef(_XSD_PFX + "byte"): _well_formed_byte,
+    URIRef(_XSD_PFX + "unsignedInt"): _well_formed_unsignedint,
+    URIRef(_XSD_PFX + "unsignedLong"): _well_formed_unsignedlong,
+    URIRef(_XSD_PFX + "unsignedShort"): _well_formed_unsignedshort,
+    URIRef(_XSD_PFX + "unsignedByte"): _well_formed_unsignedbyte,
+}
+
 _toPythonMapping: Dict[Optional[str], Optional[Callable[[str], Any]]] = {}
 
 _toPythonMapping.update(XSDToPython)


Test patch:
diff --git a/test/helper.py b/test/helper.py
index ef4a2314..21c61bbe 100644
--- a/test/helper.py
+++ b/test/helper.py
@@ -47,7 +47,7 @@ def query_with_retry(graph: rdflib.Graph, query: str, **kwargs) -> rdflib.query.
             if i == MAX_RETRY - 1:
                 raise e
 
-            backoff_s = (BACKOFF_FACTOR**backoff) / 10
+            backoff_s = (BACKOFF_FACTOR ** backoff) / 10
             print(
                 f"Network error {e} during query, waiting for {backoff_s:.2f}s and retrying"
             )
diff --git a/test/jsonld/runner.py b/test/jsonld/runner.py
index 1f84f7fe..651e6e73 100644
--- a/test/jsonld/runner.py
+++ b/test/jsonld/runner.py
@@ -18,6 +18,8 @@ def _preserving_nodeid(self, bnode_context=None):
     return bNode(self.eat(r_nodeid).group(1))
 
 
+
+
 DEFAULT_PARSER_VERSION = 1.0
 
 
@@ -44,9 +46,7 @@ def make_fake_urlinputsource(input_uri, format=None, suite_base=None, options={}
             source.content_type = options['contentType']
         if "redirectTo" in options:
             redir = suite_base + options['redirectTo']
-            local_redirect = redir.replace(
-                "https://w3c.github.io/json-ld-api/tests/", "./"
-            )
+            local_redirect = redir.replace("https://w3c.github.io/json-ld-api/tests/", "./")
             if f:
                 f.close()
             try:
@@ -59,22 +59,13 @@ def make_fake_urlinputsource(input_uri, format=None, suite_base=None, options={}
             source.setSystemId(redir)
     return source
 
-
 def do_test_json(suite_base, cat, num, inputpath, expectedpath, context, options):
     input_uri = suite_base + inputpath
     input_graph = ConjunctiveGraph()
     if cat == "remote-doc":
-        input_src = make_fake_urlinputsource(
-            input_uri, format="json-ld", suite_base=suite_base, options=options
-        )
+        input_src = make_fake_urlinputsource(input_uri, format="json-ld", suite_base=suite_base, options=options)
         p = JsonLDParser()
-        p.parse(
-            input_src,
-            input_graph,
-            base=input_src.getPublicId(),
-            context_data=context,
-            generalized_rdf=True,
-        )
+        p.parse(input_src, input_graph, base=input_src.getPublicId(), context_data=context, generalized_rdf=True)
     else:
         input_obj = _load_json(inputpath)
         to_rdf(
@@ -127,17 +118,9 @@ def do_test_parser(suite_base, cat, num, inputpath, expectedpath, context, optio
         elif requested_version == "json-ld-1.0":
             version = 1.0
     if cat == "remote-doc":
-        input_src = make_fake_urlinputsource(
-            input_uri, format="json-ld", options=options
-        )
+        input_src = make_fake_urlinputsource(input_uri, format="json-ld", options=options)
         p = JsonLDParser()
-        p.parse(
-            input_src,
-            result_graph,
-            base=input_uri,
-            context_data=context,
-            generalized_rdf=True,
-        )
+        p.parse(input_src, result_graph, base=input_uri, context_data=context, generalized_rdf=True)
     else:
         to_rdf(
             input_obj,
diff --git a/test/jsonld/test_localsuite.py b/test/jsonld/test_localsuite.py
index 820b44f9..fd51586a 100644
--- a/test/jsonld/test_localsuite.py
+++ b/test/jsonld/test_localsuite.py
@@ -37,7 +37,9 @@ def get_test_suite_cases():
                 func = runner.do_test_parser
         else:  # fromRdf
             func = runner.do_test_serializer
-        rdf_test_uri = URIRef("{0}{1}-manifest.jsonld#t{2}".format(TC_BASE, cat, num))
+        rdf_test_uri = URIRef("{0}{1}-manifest.jsonld#t{2}".format(
+            TC_BASE, cat, num
+        ))
         yield rdf_test_uri, func, TC_BASE, cat, num, inputpath, expectedpath, context, options
 
 
@@ -53,15 +55,5 @@ def testsuide_dir():
     "rdf_test_uri, func, suite_base, cat, num, inputpath, expectedpath, context, options",
     get_test_suite_cases(),
 )
-def test_suite(
-    rdf_test_uri: URIRef,
-    func,
-    suite_base,
-    cat,
-    num,
-    inputpath,
-    expectedpath,
-    context,
-    options,
-):
+def test_suite(rdf_test_uri: URIRef, func, suite_base, cat, num, inputpath, expectedpath, context, options):
     func(suite_base, cat, num, inputpath, expectedpath, context, options)
diff --git a/test/jsonld/test_onedotone.py b/test/jsonld/test_onedotone.py
index 698c65ee..0fb21e73 100644
--- a/test/jsonld/test_onedotone.py
+++ b/test/jsonld/test_onedotone.py
@@ -147,7 +147,7 @@ known_bugs: Tuple[str, ...] = (
 
 if os.name == "nt":
     # nquad parser does not correctly handle unnormalized unicode on windows.
-    known_bugs += ("toRdf/js11-in",)
+    known_bugs += ("toRdf/js11-in", )
 
 TC_BASE = "https://w3c.github.io/json-ld-api/tests/"
 allow_lists_of_lists = True
@@ -203,7 +203,9 @@ def get_test_suite_cases():
     if SKIP_KNOWN_BUGS:
         skiptests += known_bugs
 
-    for cat, num, inputpath, expectedpath, context, options in read_manifest(skiptests):
+    for cat, num, inputpath, expectedpath, context, options in read_manifest(
+        skiptests
+    ):
         if options:
             if (
                 SKIP_1_0_TESTS
@@ -219,7 +221,9 @@ def get_test_suite_cases():
                 func = runner.do_test_parser
         else:  # fromRdf
             func = runner.do_test_serializer
-        rdf_test_uri = URIRef("{0}{1}-manifest#t{2}".format(TC_BASE, cat, num))
+        rdf_test_uri = URIRef("{0}{1}-manifest#t{2}".format(
+            TC_BASE, cat, num
+        ))
         yield rdf_test_uri, func, TC_BASE, cat, num, inputpath, expectedpath, context, options
 
 
@@ -235,15 +239,5 @@ def global_state():
     "rdf_test_uri, func, suite_base, cat, num, inputpath, expectedpath, context, options",
     get_test_suite_cases(),
 )
-def test_suite(
-    rdf_test_uri: URIRef,
-    func,
-    suite_base,
-    cat,
-    num,
-    inputpath,
-    expectedpath,
-    context,
-    options,
-):
+def test_suite(rdf_test_uri: URIRef, func, suite_base, cat, num, inputpath, expectedpath, context, options):
     func(suite_base, cat, num, inputpath, expectedpath, context, options)
diff --git a/test/jsonld/test_testsuite.py b/test/jsonld/test_testsuite.py
index d64711a3..200db054 100644
--- a/test/jsonld/test_testsuite.py
+++ b/test/jsonld/test_testsuite.py
@@ -82,7 +82,9 @@ def get_test_suite_cases(skip_known_bugs=True):
     skiptests = unsupported_tests
     if skip_known_bugs:
         skiptests += known_bugs
-    for cat, num, inputpath, expectedpath, context, options in read_manifest(skiptests):
+    for cat, num, inputpath, expectedpath, context, options in read_manifest(
+        skiptests
+    ):
         if inputpath.endswith(".jsonld"):  # toRdf
             if expectedpath.endswith(".jsonld"):  # compact/expand/flatten
                 func = runner.do_test_json
@@ -91,7 +93,9 @@ def get_test_suite_cases(skip_known_bugs=True):
         else:  # fromRdf
             func = runner.do_test_serializer
         # func.description = "%s-%s-%s" % (group, case)
-        rdf_test_uri = URIRef("{0}{1}-manifest.jsonld#t{2}".format(TC_BASE, cat, num))
+        rdf_test_uri = URIRef("{0}{1}-manifest.jsonld#t{2}".format(
+            TC_BASE, cat, num
+        ))
         yield rdf_test_uri, func, TC_BASE, cat, num, inputpath, expectedpath, context, options
 
 
@@ -113,15 +117,5 @@ def global_state():
     "rdf_test_uri, func, suite_base, cat, num, inputpath, expectedpath, context, options",
     get_test_suite_cases(),
 )
-def test_suite(
-    rdf_test_uri: URIRef,
-    func,
-    suite_base,
-    cat,
-    num,
-    inputpath,
-    expectedpath,
-    context,
-    options,
-):
+def test_suite(rdf_test_uri: URIRef, func, suite_base, cat, num, inputpath, expectedpath, context, options):
     func(suite_base, cat, num, inputpath, expectedpath, context, options)
diff --git a/test/plugins/parser/example/rdflib/plugin/parser/__init__.py b/test/plugins/parser/example/rdflib/plugin/parser/__init__.py
index d2df6d26..8554ceed 100644
--- a/test/plugins/parser/example/rdflib/plugin/parser/__init__.py
+++ b/test/plugins/parser/example/rdflib/plugin/parser/__init__.py
@@ -25,5 +25,4 @@ class ExampleParser(Parser):
     def constant_output(cls) -> Set[Tuple["Identifier", "Identifier", "Identifier"]]:
         return {(cls.namespace().subj, cls.namespace().pred, cls.namespace().obj)}
 
-
 from rdflib.namespace import Namespace
diff --git a/test/test_conjunctivegraph/test_conjunctivegraph_generators.py b/test/test_conjunctivegraph/test_conjunctivegraph_generators.py
index 339e93f8..7642c236 100644
--- a/test/test_conjunctivegraph/test_conjunctivegraph_generators.py
+++ b/test/test_conjunctivegraph/test_conjunctivegraph_generators.py
@@ -3,9 +3,7 @@ from rdflib import ConjunctiveGraph, URIRef
 
 
 timblcardn3 = open(
-    os.path.join(
-        os.path.dirname(__file__), "..", "consistent_test_data", "timbl-card.n3"
-    )
+    os.path.join(os.path.dirname(__file__), "..", "consistent_test_data", "timbl-card.n3")
 ).read()
 
 
diff --git a/test/test_conjunctivegraph/test_conjunctivegraph_operator_combinations.py b/test/test_conjunctivegraph/test_conjunctivegraph_operator_combinations.py
index aa371c9a..13d20421 100644
--- a/test/test_conjunctivegraph/test_conjunctivegraph_operator_combinations.py
+++ b/test/test_conjunctivegraph/test_conjunctivegraph_operator_combinations.py
@@ -18,9 +18,7 @@ c1 = URIRef("urn:example:context-1")
 c2 = URIRef("urn:example:context-2")
 
 sportquadstrig = open(
-    os.path.join(
-        os.path.dirname(__file__), "..", "consistent_test_data", "sportquads.trig"
-    )
+    os.path.join(os.path.dirname(__file__), "..", "consistent_test_data", "sportquads.trig")
 ).read()
 
 
diff --git a/test/test_definednamespace.py b/test/test_definednamespace.py
index 126fa5a6..3bf33575 100644
--- a/test/test_definednamespace.py
+++ b/test/test_definednamespace.py
@@ -10,12 +10,7 @@ def test_definednamespace_creator_qb():
     Tests basic use of DefinedNamespace creator script using QB
     """
 
-    definednamespace_script = (
-        Path(__file__).parent.parent
-        / "rdflib"
-        / "tools"
-        / "defined_namespace_creator.py"
-    )
+    definednamespace_script = Path(__file__).parent.parent / "rdflib" / "tools" / "defined_namespace_creator.py"
     qb_data_file = Path(__file__).parent / "defined_namespaces" / "qb.ttl"
     print("\n")
     print(f"Using {definednamespace_script}...")
@@ -40,10 +35,7 @@ def test_definednamespace_creator_qb():
         for line in f.readlines():
             if '_NS = Namespace("http://purl.org/linked-data/cube#")' in line:
                 has_ns = True
-            if (
-                'Attachable: URIRef  # Abstract superclass for everything that can have attributes and dimensions'
-                in line
-            ):
+            if 'Attachable: URIRef  # Abstract superclass for everything that can have attributes and dimensions' in line:
                 has_test_class = True
     assert has_ns, "_QB.py does not contain _NS"
     assert has_test_class, "_QB.py does not class Attachable"
@@ -58,12 +50,7 @@ def test_definednamespace_creator_fake():
     RDF file of unknonwn type
     """
 
-    definednamespace_script = (
-        Path(__file__).parent.parent
-        / "rdflib"
-        / "tools"
-        / "defined_namespace_creator.py"
-    )
+    definednamespace_script = Path(__file__).parent.parent / "rdflib" / "tools" / "defined_namespace_creator.py"
     qb_data_file = Path(__file__).parent / "defined_namespaces" / "fake.xxx"
     print("\n")
     print(f"Using {definednamespace_script}...")
@@ -89,12 +76,7 @@ def test_definednamespace_creator_bad_ns():
     supplied namespace doesn't end in # or /
     """
 
-    definednamespace_script = (
-        Path(__file__).parent.parent
-        / "rdflib"
-        / "tools"
-        / "defined_namespace_creator.py"
-    )
+    definednamespace_script = Path(__file__).parent.parent / "rdflib" / "tools" / "defined_namespace_creator.py"
     qb_data_file = Path(__file__).parent / "defined_namespaces" / "fake.xxx"
     print("\n")
     print(f"Using {definednamespace_script}...")
@@ -183,7 +165,7 @@ def test_definednamespace_jsonld_context():
             "Collection": "skos:Collection",
             "Concept": "skos:Concept",
             "ConceptScheme": "skos:ConceptScheme",
-            "OrderedCollection": "skos:OrderedCollection",
+            "OrderedCollection": "skos:OrderedCollection"
         }
     }
     actual = SKOS.as_jsonld_context("skos")
diff --git a/test/test_extras_external_graph_libs.py b/test/test_extras_external_graph_libs.py
index 89248060..6b1c942a 100644
--- a/test/test_extras_external_graph_libs.py
+++ b/test/test_extras_external_graph_libs.py
@@ -1,7 +1,6 @@
 from rdflib import Graph, URIRef, Literal
 import pytest
 
-
 def test_rdflib_to_networkx():
     try:
         import networkx
diff --git a/test/test_graph/test_graph_context.py b/test/test_graph/test_graph_context.py
index 489702d6..ab4df544 100644
--- a/test/test_graph/test_graph_context.py
+++ b/test/test_graph/test_graph_context.py
@@ -8,7 +8,6 @@ import shutil
 import pytest
 from rdflib import Graph, ConjunctiveGraph, URIRef, BNode, plugin
 
-
 class ContextTestCase(unittest.TestCase):
     store = "default"
     slow = True
diff --git a/test/test_graph/test_graph_formula.py b/test/test_graph/test_graph_formula.py
index d901771b..c8ee9d89 100644
--- a/test/test_graph/test_graph_formula.py
+++ b/test/test_graph/test_graph_formula.py
@@ -140,7 +140,6 @@ def get_formula_stores_tests():
             continue
         yield checkFormulaStore, s.name
 
-
 @pytest.mark.parametrize("checker, name", get_formula_stores_tests())
 def test_formula_stores(checker, name) -> None:
     checker(name)
diff --git a/test/test_graph/test_graph_generators.py b/test/test_graph/test_graph_generators.py
index 288bb2fc..b0b0077d 100644
--- a/test/test_graph/test_graph_generators.py
+++ b/test/test_graph/test_graph_generators.py
@@ -12,7 +12,9 @@ from test.data import (
 )
 
 
-timblcardn3 = open(os.path.join(CONSISTENT_DATA_DIR, "timbl-card.n3")).read()
+timblcardn3 = open(
+    os.path.join(CONSISTENT_DATA_DIR, "timbl-card.n3")
+).read()
 
 
 def add_stuff(graph):
diff --git a/test/test_graph/test_graph_http.py b/test/test_graph/test_graph_http.py
index 4bfe6f27..f9e1b170 100644
--- a/test/test_graph/test_graph_http.py
+++ b/test/test_graph/test_graph_http.py
@@ -2,12 +2,7 @@ from rdflib import Graph, Namespace
 
 from http.server import BaseHTTPRequestHandler
 from urllib.error import HTTPError
-from test.testutils import (
-    SimpleHTTPMock,
-    MockHTTPResponse,
-    ctx_http_server,
-    GraphHelper,
-)
+from test.testutils import SimpleHTTPMock, MockHTTPResponse, ctx_http_server, GraphHelper
 import unittest
 
 
diff --git a/test/test_graph/test_slice.py b/test/test_graph/test_slice.py
index 7e3cae8e..845c658b 100644
--- a/test/test_graph/test_slice.py
+++ b/test/test_graph/test_slice.py
@@ -2,7 +2,7 @@ from rdflib import Graph, URIRef
 from test.data import tarek, likes, pizza, cheese, michel, bob, hates
 
 
-class TestGraphSlice:
+class TestGraphSlice():
     def test_slice(self):
         """
         We pervert the slice object,
@@ -34,19 +34,19 @@ class TestGraphSlice:
 
         # single slice slices by s,p,o, with : used to split
         # tell me everything about "tarek" (same as above)
-        sl(g[tarek::], 2)
+        sl(g[tarek : :], 2)
 
         # give me every "likes" relationship
-        sl(g[:likes:], 5)
+        sl(g[: likes :], 5)
 
         # give me every relationship to pizza
-        sl(g[::pizza], 3)
+        sl(g[:: pizza], 3)
 
         # give me everyone who likes pizza
-        sl(g[:likes:pizza], 2)
+        sl(g[: likes : pizza], 2)
 
         # does tarek like pizza?
-        assert g[tarek:likes:pizza] is True
+        assert g[tarek : likes : pizza] is True
 
         # More intesting is using paths
 
diff --git a/test/test_graph/test_variants.py b/test/test_graph/test_variants.py
index dd0f02b2..57221d5b 100644
--- a/test/test_graph/test_variants.py
+++ b/test/test_graph/test_variants.py
@@ -48,9 +48,7 @@ class GraphAsserts:
     quad_count: Optional[int] = None
     exact_match: bool = False
 
-    def check(
-        self, first_graph: Optional[ConjunctiveGraph], graph: ConjunctiveGraph
-    ) -> None:
+    def check(self, first_graph: Optional[ConjunctiveGraph], graph: ConjunctiveGraph) -> None:
         if self.quad_count is not None:
             assert self.quad_count == len(list(graph.quads()))
         if first_graph is not None and self.exact_match:
@@ -211,8 +209,4 @@ def test_variants(graph_variant: GraphVariants) -> None:
             first_path = variant_path
         else:
             assert first_path is not None
-            GraphHelper.assert_isomorphic(
-                first_graph,
-                graph,
-                f"checking {variant_path.relative_to(VARIANTS_DIR)} against {first_path.relative_to(VARIANTS_DIR)}",
-            )
+            GraphHelper.assert_isomorphic(first_graph, graph, f"checking {variant_path.relative_to(VARIANTS_DIR)} against {first_path.relative_to(VARIANTS_DIR)}")
diff --git a/test/test_infixowl.py b/test/test_infixowl.py
index 96ed8d37..80f956a7 100644
--- a/test/test_infixowl.py
+++ b/test/test_infixowl.py
@@ -51,7 +51,8 @@ def test_infix_owl_example1():
     namespace_manager.bind("owl", OWL, override=False)
     owlGraph.namespace_manager = namespace_manager
     assert (
-        str(list(Class(OWL.Class, graph=owlGraph).subClassOf)) == "[Class: rdfs:Class ]"
+        str(list(Class(OWL.Class, graph=owlGraph).subClassOf))
+        == "[Class: rdfs:Class ]"
     )
 
     # Operators are also available. For instance we can add ex:Opera to the extension
diff --git a/test/test_issues/test_issue1404.py b/test/test_issues/test_issue1404.py
index 2d40204a..469f713e 100644
--- a/test/test_issues/test_issue1404.py
+++ b/test/test_issues/test_issue1404.py
@@ -20,10 +20,7 @@ def test_skolem_de_skolem_roundtrip():
     graph = Graph()
     graph.parse(data=ttl, format='turtle')
 
-    query = {
-        "subject": URIRef("http://www.wikidata.org/entity/Q1203"),
-        "predicate": FOAF.knows,
-    }
+    query = {"subject": URIRef("http://www.wikidata.org/entity/Q1203"), "predicate": FOAF.knows}
 
     # Save the original bnode id.
     bnode_id = graph.value(**query)
diff --git a/test/test_issues/test_issue1484.py b/test/test_issues/test_issue1484.py
index c86702bb..edccca12 100644
--- a/test/test_issues/test_issue1484.py
+++ b/test/test_issues/test_issue1484.py
@@ -57,8 +57,8 @@ class TestIssue1484_str(unittest.TestCase):
         g.bind("rdfs", RDFS)
         g.parse(data=jsonstr, publicID=b, format="json-ld")
 
-        assert (n.s, RDF.type, n.t) in g
-        assert (n.s, n.p, n.o) in g
+        assert((n.s, RDF.type, n.t) in g)
+        assert((n.s, n.p, n.o) in g)
 
 
 if __name__ == "__main__":
diff --git a/test/test_literal/test_literal.py b/test/test_literal/test_literal.py
index 990e8464..44c3e25c 100644
--- a/test/test_literal/test_literal.py
+++ b/test/test_literal/test_literal.py
@@ -8,16 +8,19 @@
 # mypy: warn_return_any, no_implicit_reexport, strict_equality
 
 from decimal import Decimal
-from typing import Any, Optional, Sequence, Tuple, Type
+from typing import Any, Optional, Sequence, Tuple, Type, Union
 import unittest
 import datetime
 
 import rdflib  # needed for eval(repr(...)) below
 from rdflib.term import Literal, URIRef, _XSD_DOUBLE, bind, _XSD_BOOLEAN
 from rdflib import XSD
+from rdflib.namespace import RDF, Namespace
 
 import pytest
 
+EGNS = Namespace("http://example.com/")
+
 
 class TestLiteral(unittest.TestCase):
     def setUp(self) -> None:
@@ -80,6 +83,62 @@ class TestNewPT:
         with pytest.raises(exception_type):
             Literal("foo", lang=lang)
 
+    @pytest.mark.parametrize(
+        "lexical, datatype, is_ill_formed",
+        [
+            ("true", XSD.boolean, False),
+            ("1", XSD.boolean, False),
+            (b"false", XSD.boolean, False),
+            (b"0", XSD.boolean, False),
+            ("yes", XSD.boolean, True),
+            ("200", XSD.byte, True),
+            (b"-128", XSD.byte, False),
+            ("127", XSD.byte, False),
+            ("255", XSD.unsignedByte, False),
+            ("-100", XSD.unsignedByte, True),
+            (b"200", XSD.unsignedByte, False),
+            (b"64300", XSD.short, True),
+            ("-6000", XSD.short, False),
+            ("1000000", XSD.nonNegativeInteger, False),
+            ("-100", XSD.nonNegativeInteger, True),
+            ("a", XSD.double, True),
+            ("0", XSD.double, False),
+            ("0.1", XSD.double, False),
+            ("0.1", XSD.decimal, False),
+            ("0.g", XSD.decimal, True),
+            ("b", XSD.integer, True),
+            ("2147483647", XSD.int, False),
+            ("2147483648", XSD.int, True),
+            ("2147483648", XSD.integer, False),
+            ("valid ASCII", XSD.string, False),
+            pytest.param("هذا رجل ثلج⛄", XSD.string, False, id="snowman-ar"),
+            ("More ASCII", None, None),
+            ("Not a valid time", XSD.time, True),
+            ("Not a valid date", XSD.date, True),
+            ("7264666c6962", XSD.hexBinary, False),
+
+            # RDF.langString is not a recognized datatype IRI as we assign no literal value to it, though this should likely change.
+            ("English string", RDF.langString, None),
+
+            # The datatypes IRIs below should never be recognized.
+            ("[p]", EGNS.unrecognized, None),
+        ],
+    )
+    def test_ill_formed_literals(
+        self,
+        lexical: Union[bytes, str],
+        datatype: Optional[URIRef],
+        is_ill_formed: Optional[bool],
+    ) -> None:
+        """
+        ill_formed has the correct value.
+        """
+        lit = Literal(lexical, datatype=datatype)
+        assert lit.ill_formed is is_ill_formed
+        if is_ill_formed is False:
+            # If the literal is not ill formed it should have a value associated with it.
+            assert lit.value is not None
+
 
 class TestNew(unittest.TestCase):
     # NOTE: Please use TestNewPT for new tests instead of this which is written
diff --git a/test/test_literal/test_normalized_string.py b/test/test_literal/test_normalized_string.py
index 73519191..4aa979f0 100644
--- a/test/test_literal/test_normalized_string.py
+++ b/test/test_literal/test_normalized_string.py
@@ -26,3 +26,4 @@ class TestNormalizedString:
         )
         expected = Literal("""hey there a tab carriage return""", datatype=XSD.string)
         assert str(lit) == str(expected)
+
diff --git a/test/test_literal/test_term.py b/test/test_literal/test_term.py
index e70fb591..6e0db827 100644
--- a/test/test_literal/test_term.py
+++ b/test/test_literal/test_term.py
@@ -43,7 +43,6 @@ class TestBNodeRepr:
         x = MyBNode()
         assert repr(x).startswith("MyBNode(")
 
-
 class TestLiteral:
     def test_base64_values(self):
         b64msg = "cmRmbGliIGlzIGNvb2whIGFsc28gaGVyZSdzIHNvbWUgYmluYXJ5IAAR83UC"
diff --git a/test/test_literal/test_tokendatatype.py b/test/test_literal/test_tokendatatype.py
index 13e4b360..83fe339e 100644
--- a/test/test_literal/test_tokendatatype.py
+++ b/test/test_literal/test_tokendatatype.py
@@ -32,3 +32,4 @@ class TestTokenDatatype:
             datatype=XSD.string,
         )
         assert str(lit) == str(expected)
+
diff --git a/test/test_misc/test_b64_binary.py b/test/test_misc/test_b64_binary.py
index a64a7674..c4fe1b6e 100644
--- a/test/test_misc/test_b64_binary.py
+++ b/test/test_misc/test_b64_binary.py
@@ -21,3 +21,4 @@ class TestB64Binary:
         assert b_str1 == b_str1b
         assert b_str1b.decode("utf-8") == str1
         assert str(l1b) == b64_str1
+
diff --git a/test/test_misc/test_create_input_source.py b/test/test_misc/test_create_input_source.py
index 86bd214e..501e9d31 100644
--- a/test/test_misc/test_create_input_source.py
+++ b/test/test_misc/test_create_input_source.py
@@ -12,3 +12,4 @@ class TestParser:
         """create_input_source() function has a few conflicting arguments."""
         with pytest.raises(ValueError):
             create_input_source(source="a", location="b")
+
diff --git a/test/test_misc/test_parse_file_guess_format.py b/test/test_misc/test_parse_file_guess_format.py
index c1c3ec04..147a357a 100644
--- a/test/test_misc/test_parse_file_guess_format.py
+++ b/test/test_misc/test_parse_file_guess_format.py
@@ -63,3 +63,4 @@ class TestFileParserGuessFormat:
                     match="does not look like a valid URI, trying to serialize this will break.",
                 ) as logwarning:
                     g.parse(str(newpath))
+
diff --git a/test/test_misc/test_prefix_types.py b/test/test_misc/test_prefix_types.py
index b168eef8..42bd7282 100644
--- a/test/test_misc/test_prefix_types.py
+++ b/test/test_misc/test_prefix_types.py
@@ -21,8 +21,7 @@ class TestPrefixTypes:
     This is issue 161
     http://code.google.com/p/rdflib/issues/detail?id=161
     """
-
     def test(self):
-        s = graph.serialize(format="n3")
-        assert "foaf:Document" in s
-        assert "xsd:date" in s
+	    s = graph.serialize(format="n3")
+	    assert "foaf:Document" in s
+	    assert "xsd:date" in s
diff --git a/test/test_namespace/test_definednamespace_creator.py b/test/test_namespace/test_definednamespace_creator.py
index 70293c9a..6d857154 100644
--- a/test/test_namespace/test_definednamespace_creator.py
+++ b/test/test_namespace/test_definednamespace_creator.py
@@ -8,12 +8,7 @@ def test_definednamespace_creator_qb():
     Tests basic use of DefinedNamespace creator script using QB
     """
 
-    definednamespace_script = (
-        Path(__file__).parent.parent.parent
-        / "rdflib"
-        / "tools"
-        / "defined_namespace_creator.py"
-    )
+    definednamespace_script = Path(__file__).parent.parent.parent / "rdflib" / "tools" / "defined_namespace_creator.py"
     qb_data_file = Path(__file__).parent.parent / "defined_namespaces" / "qb.ttl"
     print("\n")
     print(f"Using {definednamespace_script}...")
@@ -38,10 +33,7 @@ def test_definednamespace_creator_qb():
         for line in f.readlines():
             if '_NS = Namespace("http://purl.org/linked-data/cube#")' in line:
                 has_ns = True
-            if (
-                'Attachable: URIRef  # Abstract superclass for everything that can have attributes and dimensions'
-                in line
-            ):
+            if 'Attachable: URIRef  # Abstract superclass for everything that can have attributes and dimensions' in line:
                 has_test_class = True
     assert has_ns, "_QB.py does not contain _NS"
     assert has_test_class, "_QB.py does not class Attachable"
@@ -56,12 +48,7 @@ def test_definednamespace_creator_fake():
     RDF file of unknonwn type
     """
 
-    definednamespace_script = (
-        Path(__file__).parent.parent.parent
-        / "rdflib"
-        / "tools"
-        / "defined_namespace_creator.py"
-    )
+    definednamespace_script = Path(__file__).parent.parent.parent / "rdflib" / "tools" / "defined_namespace_creator.py"
     qb_data_file = Path(__file__).parent.parent / "defined_namespaces" / "fake.xxx"
     print("\n")
     print(f"Using {definednamespace_script}...")
@@ -87,12 +74,7 @@ def test_definednamespace_creator_bad_ns():
     supplied namespace doesn't end in # or /
     """
 
-    definednamespace_script = (
-        Path(__file__).parent.parent.parent
-        / "rdflib"
-        / "tools"
-        / "defined_namespace_creator.py"
-    )
+    definednamespace_script = Path(__file__).parent.parent.parent / "rdflib" / "tools" / "defined_namespace_creator.py"
     qb_data_file = Path(__file__).parent.parent / "defined_namespaces" / "fake.xxx"
     print("\n")
     print(f"Using {definednamespace_script}...")
diff --git a/test/test_parsers/test_empty_xml_base.py b/test/test_parsers/test_empty_xml_base.py
index 1c245b3e..38abbbe2 100644
--- a/test/test_parsers/test_empty_xml_base.py
+++ b/test/test_parsers/test_empty_xml_base.py
@@ -33,14 +33,11 @@ test_data2 = """
 baseUri = URIRef("http://example.com/")
 baseUri2 = URIRef("http://example.com/foo/bar")
 
-
 class TestEmptyBase:
     def test_empty_base_ref(self):
         self.graph = ConjunctiveGraph()
         self.graph.parse(data=test_data, publicID=baseUri, format="xml")
-        assert (
-            len(list(self.graph)) > 0
-        ), "There should be at least one statement in the graph"
+        assert len(list(self.graph)) > 0, "There should be at least one statement in the graph"
         assert (
             baseUri,
             RDF.type,
@@ -52,9 +49,7 @@ class TestRelativeBase:
     def test_relative_base_ref(self):
         self.graph = ConjunctiveGraph()
         self.graph.parse(data=test_data2, publicID=baseUri2, format="xml")
-        assert (
-            len(self.graph) > 0
-        ), "There should be at least one statement in the graph"
+        assert len(self.graph) > 0, "There should be at least one statement in the graph"
         resolvedBase = URIRef("http://example.com/baz")
         assert (
             resolvedBase,
diff --git a/test/test_parsers/test_parser_hext.py b/test/test_parsers/test_parser_hext.py
index 4af94c79..d4b595c1 100644
--- a/test/test_parsers/test_parser_hext.py
+++ b/test/test_parsers/test_parser_hext.py
@@ -1,6 +1,5 @@
 import sys
 from pathlib import Path
-
 sys.path.append(str(Path(__file__).parent.parent.absolute()))
 from rdflib import Dataset, ConjunctiveGraph, Literal
 from rdflib.namespace import XSD
@@ -41,11 +40,7 @@ def test_small_string_cg():
 
 
 def test_small_file_singlegraph():
-    d = Dataset().parse(
-        Path(__file__).parent.parent
-        / "consistent_test_data/test_parser_hext_singlegraph.ndjson",
-        format="hext",
-    )
+    d = Dataset().parse(Path(__file__).parent.parent / "consistent_test_data/test_parser_hext_singlegraph.ndjson", format="hext")
     assert len(d) == 10
 
 
@@ -53,10 +48,9 @@ def test_small_file_multigraph():
     d = Dataset()
     assert len(d) == 0
     d.parse(
-        Path(__file__).parent.parent
-        / "consistent_test_data/test_parser_hext_multigraph.ndjson",
+        Path(__file__).parent.parent / "consistent_test_data/test_parser_hext_multigraph.ndjson",
         format="hext",
-        publicID=d.default_context.identifier,
+        publicID=d.default_context.identifier
     )
 
     """There are 22 lines in the file test_parser_hext_multigraph.ndjson. When loaded
@@ -74,10 +68,9 @@ def test_small_file_multigraph_cg():
     d = ConjunctiveGraph()
     assert len(d) == 0
     d.parse(
-        Path(__file__).parent.parent
-        / "consistent_test_data/test_parser_hext_multigraph.ndjson",
+        Path(__file__).parent.parent / "consistent_test_data/test_parser_hext_multigraph.ndjson",
         format="hext",
-        publicID=d.default_context.identifier,
+        publicID=d.default_context.identifier
     )
 
     """There are 22 lines in the file test_parser_hext_multigraph.ndjson. When loaded
@@ -128,7 +121,7 @@ def test_roundtrip():
                 cg2.parse(
                     data=cg.serialize(format="hext"),
                     format="hext",
-                    publicID=cg2.default_context.identifier,
+                    publicID=cg2.default_context.identifier
                 )
                 if cg2.context_aware:
                     for context in cg2.contexts():
@@ -136,9 +129,7 @@ def test_roundtrip():
                             if type(triple[2]) == Literal:
                                 if triple[2].datatype == XSD.string:
                                     context.remove((triple[0], triple[1], triple[2]))
-                                    context.add(
-                                        (triple[0], triple[1], Literal(str(triple[2])))
-                                    )
+                                    context.add((triple[0], triple[1], Literal(str(triple[2]))))
                 else:
                     for triple in cg2.triples((None, None, None)):
                         if type(triple[2]) == Literal:
diff --git a/test/test_rdfxml.py b/test/test_rdfxml.py
index 4e53c3c7..697fc336 100644
--- a/test/test_rdfxml.py
+++ b/test/test_rdfxml.py
@@ -85,7 +85,7 @@ RDFCOREBASE = "http://www.w3.org/2000/10/rdf-tests/rdfcore/"
 
 
 def relative(url):
-    return url[len(RDFCOREBASE) :]
+    return url[len(RDFCOREBASE):]
 
 
 def resolve(rel):
diff --git a/test/test_serializers/test_serializer_hext.py b/test/test_serializers/test_serializer_hext.py
index f2c7867f..dfba2533 100644
--- a/test/test_serializers/test_serializer_hext.py
+++ b/test/test_serializers/test_serializer_hext.py
@@ -1,6 +1,5 @@
 import sys
 from pathlib import Path
-
 sys.path.append(str(Path(__file__).parent.parent.absolute()))
 from rdflib import Dataset, Graph, ConjunctiveGraph
 import json
@@ -34,51 +33,18 @@ def test_hext_graph():
     out = g.serialize(format="hext")
     # note: can't test for BNs in result as they will be different every time
     testing_lines = [
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p3", "Object 3", "http://www.w3.org/2001/XMLSchema#string", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p3", "Object 4 - English", "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", "en", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p4", "2021-12-03", "http://www.w3.org/2001/XMLSchema#date", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p6", "42", "http://www.w3.org/2001/XMLSchema#string", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p7", "true", "http://www.w3.org/2001/XMLSchema#boolean", "", ""]',
-        ],
-        [
-            False,
-            '"http://www.w3.org/1999/02/22-rdf-syntax-ns#value", "thingy", "http://www.w3.org/2001/XMLSchema#string", "", ""]',
-        ],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p3", "Object 3", "http://www.w3.org/2001/XMLSchema#string", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p3", "Object 4 - English", "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", "en", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p4", "2021-12-03", "http://www.w3.org/2001/XMLSchema#date", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p6", "42", "http://www.w3.org/2001/XMLSchema#string", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p7", "true", "http://www.w3.org/2001/XMLSchema#boolean", "", ""]'],
+        [False, '"http://www.w3.org/1999/02/22-rdf-syntax-ns#value", "thingy", "http://www.w3.org/2001/XMLSchema#string", "", ""]'],
         [False, '["http://example.com/s1", "http://example.com/p2"'],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p5", "42", "http://www.w3.org/2001/XMLSchema#integer", "", ""]',
-        ],
-        [
-            False,
-            '"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2002/07/owl#Thing", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p8", "false", "http://www.w3.org/2001/XMLSchema#boolean", "", ""]',
-        ],
+        [False, '["http://example.com/s1", "http://example.com/p5", "42", "http://www.w3.org/2001/XMLSchema#integer", "", ""]'],
+        [False, '"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2002/07/owl#Thing", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p8", "false", "http://www.w3.org/2001/XMLSchema#boolean", "", ""]'],
     ]
     for line in out.splitlines():
         for test in testing_lines:
@@ -131,75 +97,24 @@ def test_hext_cg():
     out = d.serialize(format="hext")
     # note: cant' test for BNs in result as they will be different ever time
     testing_lines = [
-        [
-            False,
-            '["http://example.com/s21", "http://example.com/p21", "http://example.com/o21", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s21", "http://example.com/p21", "http://example.com/o22", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s11", "http://example.com/p11", "http://example.com/o12", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s11", "http://example.com/p11", "http://example.com/o11", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g1"]',
-        ],
+        [False, '["http://example.com/s21", "http://example.com/p21", "http://example.com/o21", "globalId", "", ""]'],
+        [False, '["http://example.com/s21", "http://example.com/p21", "http://example.com/o22", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", ""]'],
+        [False, '["http://example.com/s11", "http://example.com/p11", "http://example.com/o12", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s11", "http://example.com/p11", "http://example.com/o11", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g1"]'],
         [False, '["http://example.com/s1", "http://example.com/p2"'],
-        [
-            False,
-            '"http://www.w3.org/1999/02/22-rdf-syntax-ns#value", "thingy", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2002/07/owl#Thing", "globalId", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p3", "Object 4 - English", "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", "en", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p6", "42", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p4", "2021-12-03", "http://www.w3.org/2001/XMLSchema#date", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p5", "42", "http://www.w3.org/2001/XMLSchema#integer", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p3", "Object 3", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]',
-        ],
+        [False, '"http://www.w3.org/1999/02/22-rdf-syntax-ns#value", "thingy", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]'],
+        [False, '"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2002/07/owl#Thing", "globalId", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p3", "Object 4 - English", "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", "en", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p6", "42", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p4", "2021-12-03", "http://www.w3.org/2001/XMLSchema#date", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p5", "42", "http://www.w3.org/2001/XMLSchema#integer", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p3", "Object 3", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]'],
     ]
     for line in out.splitlines():
         for test in testing_lines:
@@ -247,75 +162,24 @@ def test_hext_dataset():
     out = d.serialize(format="hext")
     # note: cant' test for BNs in result as they will be different ever time
     testing_lines = [
-        [
-            False,
-            '["http://example.com/s21", "http://example.com/p21", "http://example.com/o21", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s21", "http://example.com/p21", "http://example.com/o22", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", ""]',
-        ],
-        [
-            False,
-            '["http://example.com/s11", "http://example.com/p11", "http://example.com/o12", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s11", "http://example.com/p11", "http://example.com/o11", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g2"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g1"]',
-        ],
+        [False, '["http://example.com/s21", "http://example.com/p21", "http://example.com/o21", "globalId", "", ""]'],
+        [False, '["http://example.com/s21", "http://example.com/p21", "http://example.com/o22", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", ""]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", ""]'],
+        [False, '["http://example.com/s11", "http://example.com/p11", "http://example.com/o12", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s11", "http://example.com/p11", "http://example.com/o11", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g2"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o2", "globalId", "", "http://example.com/g1"]'],
         [False, '["http://example.com/s1", "http://example.com/p2"'],
-        [
-            False,
-            '"http://www.w3.org/1999/02/22-rdf-syntax-ns#value", "thingy", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2002/07/owl#Thing", "globalId", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p3", "Object 4 - English", "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", "en", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p6", "42", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p4", "2021-12-03", "http://www.w3.org/2001/XMLSchema#date", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p5", "42", "http://www.w3.org/2001/XMLSchema#integer", "", "http://example.com/g1"]',
-        ],
-        [
-            False,
-            '["http://example.com/s1", "http://example.com/p3", "Object 3", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]',
-        ],
+        [False, '"http://www.w3.org/1999/02/22-rdf-syntax-ns#value", "thingy", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]'],
+        [False, '"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://www.w3.org/2002/07/owl#Thing", "globalId", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p3", "Object 4 - English", "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString", "en", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p6", "42", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p4", "2021-12-03", "http://www.w3.org/2001/XMLSchema#date", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p1", "http://example.com/o1", "globalId", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p5", "42", "http://www.w3.org/2001/XMLSchema#integer", "", "http://example.com/g1"]'],
+        [False, '["http://example.com/s1", "http://example.com/p3", "Object 3", "http://www.w3.org/2001/XMLSchema#string", "", "http://example.com/g1"]'],
     ]
     for line in out.splitlines():
         for test in testing_lines:
@@ -370,10 +234,9 @@ def test_hext_dataset_linecount():
     d = Dataset()
     assert len(d) == 0
     d.parse(
-        Path(__file__).parent.parent
-        / "consistent_test_data/test_parser_hext_multigraph.ndjson",
+        Path(__file__).parent.parent / "consistent_test_data/test_parser_hext_multigraph.ndjson",
         format="hext",
-        publicID=d.default_context.identifier,
+        publicID=d.default_context.identifier
     )
     total_triples = 0
     # count all the triples in the Dataset
@@ -390,18 +253,12 @@ def test_hext_dataset_linecount():
 def test_roundtrip():
     d = Dataset()
     d.parse(
-        Path(__file__).parent.parent
-        / "consistent_test_data/test_parser_hext_multigraph.ndjson",
+        Path(__file__).parent.parent / "consistent_test_data/test_parser_hext_multigraph.ndjson",
         format="hext",
-        publicID=d.default_context.identifier,
+        publicID=d.default_context.identifier
     )
     d.default_union = True
-    with open(
-        str(
-            Path(__file__).parent.parent
-            / "consistent_test_data/test_parser_hext_multigraph.ndjson"
-        )
-    ) as i:
+    with open(str(Path(__file__).parent.parent / "consistent_test_data/test_parser_hext_multigraph.ndjson")) as i:
         ordered_input = "".join(sorted(i.readlines())).strip()
 
     ordered_output = "\n".join(sorted(d.serialize(format="hext").split("\n"))).strip()
diff --git a/test/test_sparql/test_construct_bindings.py b/test/test_sparql/test_construct_bindings.py
index 3b21e87d..bf62d11d 100644
--- a/test/test_sparql/test_construct_bindings.py
+++ b/test/test_sparql/test_construct_bindings.py
@@ -5,7 +5,6 @@ from rdflib.compare import isomorphic
 import unittest
 from test.testutils import eq_
 
-
 class TestConstructInitBindings(unittest.TestCase):
     def test_construct_init_bindings(self):
         """
diff --git a/test/test_sparql/test_evaluate_bind.py b/test/test_sparql/test_evaluate_bind.py
index 91f704a3..928acbb3 100644
--- a/test/test_sparql/test_evaluate_bind.py
+++ b/test/test_sparql/test_evaluate_bind.py
@@ -37,7 +37,6 @@ def get_bind_tests():
         URIRef("http://example.org/ns#Thing"),
     )
 
-
 @pytest.mark.parametrize("checker, expr, var, obj", get_bind_tests())
 def test_bind(checker, expr, var, obj) -> None:
     checker(expr, var, obj)
diff --git a/test/test_sparql/test_operators.py b/test/test_sparql/test_operators.py
index 80a5aaf0..2c122eb4 100644
--- a/test/test_sparql/test_operators.py
+++ b/test/test_sparql/test_operators.py
@@ -5,7 +5,6 @@ from rdflib.plugins.sparql import operators
 from rdflib.plugins.sparql import sparql
 import pytest
 
-
 def test_date_cast():
     now = datetime.datetime.now()
     today = now.date()
diff --git a/test/test_sparql/test_prepare.py b/test/test_sparql/test_prepare.py
index ae1496d4..89edf2c2 100644
--- a/test/test_sparql/test_prepare.py
+++ b/test/test_sparql/test_prepare.py
@@ -34,9 +34,7 @@ def test_prepare_query():
 
     g = Graph()
     g.parse(
-        location=os.path.join(
-            os.path.dirname(__file__), "..", "..", "examples", "foaf.n3"
-        ),
+        location=os.path.join(os.path.dirname(__file__), "..", "..", "examples", "foaf.n3"),
         format="n3",
     )
 
diff --git a/test/test_sparql/test_sparql.py b/test/test_sparql/test_sparql.py
index 3c90da9d..09a0ab24 100644
--- a/test/test_sparql/test_sparql.py
+++ b/test/test_sparql/test_sparql.py
@@ -164,42 +164,60 @@ def test_named_filter_graph_query():
     """,
     )
 
-    assert list(
-        g.query(
-            "SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } ?a a ?type }",
-            initNs={"ex": ex},
+    assert (
+        list(
+            g.query(
+                "SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } ?a a ?type }",
+                initNs={"ex": ex},
+            )
         )
-    ) == [(Literal("Boris"),)]
-    assert list(
-        g.query(
-            "SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } FILTER EXISTS { ?a a ?type }}",
-            initNs={"ex": ex},
+        == [(Literal("Boris"),)]
+    )
+    assert (
+        list(
+            g.query(
+                "SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } FILTER EXISTS { ?a a ?type }}",
+                initNs={"ex": ex},
+            )
         )
-    ) == [(Literal("Boris"),)]
-    assert list(
-        g.query(
-            "SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } FILTER NOT EXISTS { ?a a ?type }}",
-            initNs={"ex": ex},
+        == [(Literal("Boris"),)]
+    )
+    assert (
+        list(
+            g.query(
+                "SELECT ?l WHERE { GRAPH ex:g1 { ?a rdfs:label ?l } FILTER NOT EXISTS { ?a a ?type }}",
+                initNs={"ex": ex},
+            )
         )
-    ) == [(Literal("Susan"),)]
-    assert list(
-        g.query(
-            "SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } ?a a ?type }",
-            initNs={"ex": ex},
+        == [(Literal("Susan"),)]
+    )
+    assert (
+        list(
+            g.query(
+                "SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } ?a a ?type }",
+                initNs={"ex": ex},
+            )
         )
-    ) == [(Literal("Boris"),)]
-    assert list(
-        g.query(
-            "SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } FILTER EXISTS { ?a a ?type }}",
-            initNs={"ex": ex},
+        == [(Literal("Boris"),)]
+    )
+    assert (
+        list(
+            g.query(
+                "SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } FILTER EXISTS { ?a a ?type }}",
+                initNs={"ex": ex},
+            )
         )
-    ) == [(Literal("Boris"),)]
-    assert list(
-        g.query(
-            "SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } FILTER NOT EXISTS { ?a a ?type }}",
-            initNs={"ex": ex},
+        == [(Literal("Boris"),)]
+    )
+    assert (
+        list(
+            g.query(
+                "SELECT ?l WHERE { GRAPH ?g { ?a rdfs:label ?l } FILTER NOT EXISTS { ?a a ?type }}",
+                initNs={"ex": ex},
+            )
         )
-    ) == [(Literal("Susan"),)]
+        == [(Literal("Susan"),)]
+    )
 
 
 def test_txtresult():
diff --git a/test/test_tools/test_csv2rdf.py b/test/test_tools/test_csv2rdf.py
index e98e71ed..504cf44f 100644
--- a/test/test_tools/test_csv2rdf.py
+++ b/test/test_tools/test_csv2rdf.py
@@ -7,7 +7,6 @@ from test.data import CONSISTENT_DATA_DIR
 
 REALESTATE_FILE_PATH = os.path.join(CONSISTENT_DATA_DIR, "csv", "realestate.csv")
 
-
 class TestCSV2RDF:
     def test_csv2rdf_cli(self):
         completed = subprocess.run(
diff --git a/test/test_typing.py b/test/test_typing.py
index 5a1695bc..c3295ed4 100644
--- a/test/test_typing.py
+++ b/test/test_typing.py
@@ -56,7 +56,9 @@ def test_rdflib_query_exercise() -> None:
     graph.add((kb_https_uriref, predicate_q, literal_two))
     graph.add((kb_bnode, predicate_p, literal_one))
 
-    expected_nodes_using_predicate_q: Set[rdflib.IdentifiedNode] = {kb_https_uriref}
+    expected_nodes_using_predicate_q: Set[rdflib.IdentifiedNode] = {
+        kb_https_uriref
+    }
     computed_nodes_using_predicate_q: Set[rdflib.IdentifiedNode] = set()
     for triple in graph.triples((None, predicate_q, None)):
         computed_nodes_using_predicate_q.add(triple[0])
diff --git a/test/testutils.py b/test/testutils.py
index 93e20851..ec832412 100644
--- a/test/testutils.py
+++ b/test/testutils.py
@@ -191,10 +191,7 @@ class GraphHelper:
 
     @classmethod
     def format_set(
-        cls,
-        item_set: Union[IdentifierQuadSet, IdentifierTripleSet],
-        prefix: str = "  ",
-        sort: bool = False,
+        cls, item_set: Union[IdentifierQuadSet, IdentifierTripleSet], prefix: str = "  ", sort: bool = False
     ) -> str:
         items = []
         use_item_set = sorted(item_set) if sort else item_set
@@ -203,15 +200,11 @@ class GraphHelper:
         return "\n".join(items)
 
     @classmethod
-    def format_graph_set(
-        cls, graph: Graph, prefix: str = "  ", sort: bool = False
-    ) -> str:
+    def format_graph_set(cls, graph: Graph, prefix: str = "  ", sort: bool = False) -> str:
         return cls.format_set(cls.triple_or_quad_set(graph), prefix, sort)
 
     @classmethod
-    def assert_isomorphic(
-        cls, lhs: Graph, rhs: Graph, message: Optional[str] = None
-    ) -> None:
+    def assert_isomorphic(cls, lhs: Graph, rhs: Graph, message: Optional[str] = None) -> None:
         """
         This asserts that the two graphs are isomorphic, providing a nicely
         formatted error message if they are not.