diff --git a/.drone.yml b/.drone.yml index 7a46aea6a..8a02ce450 100644 --- a/.drone.yml +++ b/.drone.yml @@ -28,7 +28,7 @@ steps: - python setup.py install - black --config black.toml --check ./rdflib || true - flake8 --exit-zero rdflib - - mypy --show-error-context --show-error-codes rdflib + - mypy --show-error-context --show-error-codes - ./with-fuseki.sh pytest -ra --cov - coveralls diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index b36db7652..5e231f642 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -73,7 +73,7 @@ jobs: run: | black --config black.toml --check ./rdflib || true flake8 --exit-zero rdflib - mypy --show-error-context --show-error-codes rdflib + mypy --show-error-context --show-error-codes if [ "${{ matrix.os }}" == "windows-latest" ] then pytest -ra --cov diff --git a/docker-compose.tests.yml b/docker-compose.tests.yml index f433c70f4..b8c24a78e 100644 --- a/docker-compose.tests.yml +++ b/docker-compose.tests.yml @@ -24,4 +24,4 @@ services: volumes: - .:/rdflib working_dir: /rdflib - command: ["python", "-m", "mypy", "--show-error-context", "--show-error-codes" ,"rdflib"] + command: ["python", "-m", "mypy", "--show-error-context", "--show-error-codes"] diff --git a/rdflib/graph.py b/rdflib/graph.py index 8f5b05442..75291f1d2 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -1002,7 +1002,7 @@ def qname(self, uri): def compute_qname(self, uri, generate=True): return self.namespace_manager.compute_qname(uri, generate) - def bind(self, prefix, namespace, override=True, replace=False): + def bind(self, prefix, namespace, override=True, replace=False) -> None: """Bind prefix to namespace If override is True will bind namespace to given prefix even diff --git a/rdflib/namespace/__init__.py b/rdflib/namespace/__init__.py index e1f0b52b0..80ede21e6 100644 --- a/rdflib/namespace/__init__.py +++ b/rdflib/namespace/__init__.py @@ -1,6 +1,6 @@ import logging import warnings -from typing import List +from typing import TYPE_CHECKING, List, Union from unicodedata import category from pathlib import Path @@ -101,11 +101,11 @@ class Namespace(str): False """ - def __new__(cls, value): + def __new__(cls, value: Union[str, bytes]) -> "Namespace": try: rt = str.__new__(cls, value) except UnicodeDecodeError: - rt = str.__new__(cls, value, "utf-8") + rt = str.__new__(cls, value, "utf-8") # type: ignore[arg-type] return rt @property @@ -521,7 +521,7 @@ def compute_qname_strict(self, uri, generate=True): return self.__cache_strict[uri] - def bind(self, prefix, namespace, override=True, replace=False): + def bind(self, prefix, namespace, override=True, replace=False) -> None: """bind a given namespace to the prefix if override, rebind, even if the given namespace is already diff --git a/rdflib/plugins/sparql/processor.py b/rdflib/plugins/sparql/processor.py index 84e8c8231..9f463a779 100644 --- a/rdflib/plugins/sparql/processor.py +++ b/rdflib/plugins/sparql/processor.py @@ -17,7 +17,7 @@ from rdflib.plugins.sparql.update import evalUpdate -def prepareQuery(queryString, initNs={}, base=None): +def prepareQuery(queryString, initNs={}, base=None) -> Query: """ Parse and translate a SPARQL Query """ diff --git a/rdflib/term.py b/rdflib/term.py index 181824f6d..1182ecb8f 100644 --- a/rdflib/term.py +++ b/rdflib/term.py @@ -125,7 +125,7 @@ class Identifier(Node, str): # allow Identifiers to be Nodes in the Graph __slots__ = () - def __new__(cls, value): + def __new__(cls, value: str) -> "Identifier": return str.__new__(cls, value) def eq(self, other): @@ -250,7 +250,7 @@ def __new__(cls, value: str, base: Optional[str] = None): rt = str.__new__(cls, value, "utf-8") # type: ignore[call-overload] return rt - def toPython(self): + def toPython(self) -> str: return str(self) def n3(self, namespace_manager=None) -> str: @@ -395,8 +395,11 @@ class BNode(Identifier): __slots__ = () def __new__( - cls, value=None, _sn_gen=_serial_number_generator(), _prefix=_unique_id() - ): + cls, + value: Optional[str] = None, + _sn_gen: Callable[[], str] = _serial_number_generator(), + _prefix: str = _unique_id(), + ) -> "BNode": """ # only store implementations should pass in a value """ @@ -413,9 +416,9 @@ def __new__( pass # assert is_ncname(str(value)), "BNode identifiers # must be valid NCNames" _:[A-Za-z][A-Za-z0-9]* # http://www.w3.org/TR/2004/REC-rdf-testcases-20040210/#nodeID - return Identifier.__new__(cls, value) + return Identifier.__new__(cls, value) # type: ignore[return-value] - def toPython(self): + def toPython(self) -> str: return str(self) def n3(self, namespace_manager=None): @@ -1227,7 +1230,7 @@ def n3(self, namespace_manager=None): else: return self._literal_n3() - def _literal_n3(self, use_plain=False, qname_callback=None): + def _literal_n3(self, use_plain=False, qname_callback=None) -> str: """ Using plain literal (shorthand) output:: >>> from rdflib.namespace import XSD @@ -1369,7 +1372,7 @@ def __repr__(self): clsName = self.__class__.__name__ return """%s(%s)""" % (clsName, ", ".join(args)) - def toPython(self): + def toPython(self) -> Any: """ Returns an appropriate python datatype derived from this RDF Literal """ @@ -1683,7 +1686,7 @@ def _strip_and_collapse_whitespace(lexical_or_value): def bind( datatype, pythontype, constructor=None, lexicalizer=None, datatype_specific=False -): +) -> None: """ register a new datatype<->pythontype binding @@ -1736,7 +1739,7 @@ def __repr__(self): return """%s(%s)""" % (clsName, super(Variable, self).__repr__()) - def toPython(self): + def toPython(self) -> str: return "?%s" % self def n3(self, namespace_manager=None): diff --git a/rdflib/util.py b/rdflib/util.py index 182c1fe3e..7318dcc36 100644 --- a/rdflib/util.py +++ b/rdflib/util.py @@ -31,6 +31,7 @@ from calendar import timegm from time import altzone +from typing import Optional # from time import daylight from time import gmtime @@ -370,7 +371,7 @@ def parse_date_time(val): } -def guess_format(fpath, fmap=None): +def guess_format(fpath, fmap=None) -> Optional[str]: """ Guess RDF serialization based on file suffix. Uses ``SUFFIX_FORMAT_MAP`` unless ``fmap`` is provided. Examples: diff --git a/requirements.dev.txt b/requirements.dev.txt index a42f20e33..a0d867468 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -12,3 +12,4 @@ pytest-subtests sphinx sphinxcontrib-apidoc types-setuptools +types-tabulate diff --git a/setup.cfg b/setup.cfg index 5a0defdae..9cba6e1ca 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,12 +22,21 @@ exclude_lines = if __name__==.__main__.: [mypy] +files = rdflib,test +# NOTE: There are some errrors coming from test/translate_algebra directory and +# should be fixed so this exclude can be removed. +exclude = test/translate_algebra/ python_version = 3.7 warn_unused_configs = True ignore_missing_imports = True disallow_subclassing_any = False warn_unreachable = True +[mypy-test.*] +# NOTE: Currently there are many type errors in tests, these should be fixed but +# until they are fixed errors are ignored. +ignore_errors = True + [tool:pytest] addopts = --doctest-modules diff --git a/test/test_issue_git_336.py b/test/test_issue_git_336.py index 1f312fbdd..e0301e581 100644 --- a/test/test_issue_git_336.py +++ b/test/test_issue_git_336.py @@ -1,3 +1,12 @@ +# NOTE: The config below enables strict mode for mypy. +# mypy: no_ignore_errors +# mypy: warn_unused_configs, disallow_any_generics +# mypy: disallow_subclassing_any, disallow_untyped_calls +# mypy: disallow_untyped_defs, disallow_incomplete_defs +# mypy: check_untyped_defs, disallow_untyped_decorators +# mypy: no_implicit_optional, warn_redundant_casts, warn_unused_ignores +# mypy: warn_return_any, no_implicit_reexport, strict_equality + import rdflib from rdflib.plugins.parsers.notation3 import BadSyntax @@ -18,7 +27,7 @@ """ -def test_ns_localname_roundtrip(): +def test_ns_localname_roundtrip() -> None: XNS = rdflib.Namespace("http://example.net/fs") diff --git a/test/test_literal.py b/test/test_literal.py index e71799b89..990e84645 100644 --- a/test/test_literal.py +++ b/test/test_literal.py @@ -1,30 +1,39 @@ +# NOTE: The config below enables strict mode for mypy. +# mypy: no_ignore_errors +# mypy: warn_unused_configs, disallow_any_generics +# mypy: disallow_subclassing_any, disallow_untyped_calls +# mypy: disallow_untyped_defs, disallow_incomplete_defs +# mypy: check_untyped_defs, disallow_untyped_decorators +# mypy: no_implicit_optional, warn_redundant_casts, warn_unused_ignores +# mypy: warn_return_any, no_implicit_reexport, strict_equality + from decimal import Decimal -from typing import Any, Optional, Type +from typing import Any, Optional, Sequence, Tuple, Type import unittest import datetime import rdflib # needed for eval(repr(...)) below from rdflib.term import Literal, URIRef, _XSD_DOUBLE, bind, _XSD_BOOLEAN -from rdflib.namespace import XSD +from rdflib import XSD import pytest class TestLiteral(unittest.TestCase): - def setUp(self): + def setUp(self) -> None: pass - def test_repr_apostrophe(self): + def test_repr_apostrophe(self) -> None: a = rdflib.Literal("'") b = eval(repr(a)) self.assertEqual(a, b) - def test_repr_quote(self): + def test_repr_quote(self) -> None: a = rdflib.Literal('"') b = eval(repr(a)) self.assertEqual(a, b) - def test_backslash(self): + def test_backslash(self) -> None: d = r""" None: l = rdflib.Literal(True) self.assertEqual(l.datatype, rdflib.XSD["boolean"]) @@ -64,7 +73,7 @@ def test_cant_pass_invalid_lang( self, lang: Any, exception_type: Type[Exception], - ): + ) -> None: """ Construction of Literal fails if the language tag is invalid. """ @@ -75,12 +84,15 @@ def test_cant_pass_invalid_lang( class TestNew(unittest.TestCase): # NOTE: Please use TestNewPT for new tests instead of this which is written # for unittest. - def testCantPassLangAndDatatype(self): + def testCantPassLangAndDatatype(self) -> None: self.assertRaises( TypeError, Literal, "foo", lang="en", datatype=URIRef("http://example.com/") ) - def testFromOtherLiteral(self): + def testCantPassInvalidLang(self) -> None: + self.assertRaises(ValueError, Literal, "foo", lang="999") + + def testFromOtherLiteral(self) -> None: l = Literal(1) l2 = Literal(l) self.assertTrue(isinstance(l.value, int)) @@ -91,7 +103,7 @@ def testFromOtherLiteral(self): l2 = Literal(l, datatype=rdflib.XSD.integer) self.assertTrue(isinstance(l2.value, int)) - def testDatatypeGetsAutoURIRefConversion(self): + def testDatatypeGetsAutoURIRefConversion(self) -> None: # drewp disapproves of this behavior, but it should be # represented in the tests x = Literal("foo", datatype="http://example.com/") @@ -102,22 +114,22 @@ def testDatatypeGetsAutoURIRefConversion(self): class TestRepr(unittest.TestCase): - def testOmitsMissingDatatypeAndLang(self): + def testOmitsMissingDatatypeAndLang(self) -> None: self.assertEqual(repr(Literal("foo")), "rdflib.term.Literal('foo')") - def testOmitsMissingDatatype(self): + def testOmitsMissingDatatype(self) -> None: self.assertEqual( repr(Literal("foo", lang="en")), "rdflib.term.Literal('foo', lang='en')", ) - def testOmitsMissingLang(self): + def testOmitsMissingLang(self) -> None: self.assertEqual( repr(Literal("foo", datatype=URIRef("http://example.com/"))), "rdflib.term.Literal('foo', datatype=rdflib.term.URIRef('http://example.com/'))", ) - def testSubclassNameAppearsInRepr(self): + def testSubclassNameAppearsInRepr(self) -> None: class MyLiteral(Literal): pass @@ -126,7 +138,7 @@ class MyLiteral(Literal): class TestDoubleOutput(unittest.TestCase): - def testNoDanglingPoint(self): + def testNoDanglingPoint(self) -> None: """confirms the fix for https://github.com/RDFLib/rdflib/issues/237""" vv = Literal("0.88", datatype=_XSD_DOUBLE) out = vv._literal_n3(use_plain=True) @@ -136,19 +148,19 @@ def testNoDanglingPoint(self): class TestParseBoolean(unittest.TestCase): """confirms the fix for https://github.com/RDFLib/rdflib/issues/913""" - def testTrueBoolean(self): + def testTrueBoolean(self) -> None: test_value = Literal("tRue", datatype=_XSD_BOOLEAN) self.assertTrue(test_value.value) test_value = Literal("1", datatype=_XSD_BOOLEAN) self.assertTrue(test_value.value) - def testFalseBoolean(self): + def testFalseBoolean(self) -> None: test_value = Literal("falsE", datatype=_XSD_BOOLEAN) self.assertFalse(test_value.value) test_value = Literal("0", datatype=_XSD_BOOLEAN) self.assertFalse(test_value.value) - def testNonFalseBoolean(self): + def testNonFalseBoolean(self) -> None: test_value = Literal("abcd", datatype=_XSD_BOOLEAN) self.assertRaises(UserWarning) self.assertFalse(test_value.value) @@ -158,12 +170,12 @@ def testNonFalseBoolean(self): class TestBindings(unittest.TestCase): - def testBinding(self): + def testBinding(self) -> None: class a: - def __init__(self, v): + def __init__(self, v: str) -> None: self.v = v[3:-3] - def __str__(self): + def __str__(self) -> str: return "<<<%s>>>" % self.v dtA = rdflib.URIRef("urn:dt:a") @@ -179,10 +191,10 @@ def __str__(self): self.assertEqual(la2.value.v, va.v) class b: - def __init__(self, v): + def __init__(self, v: str) -> None: self.v = v[3:-3] - def __str__(self): + def __str__(self) -> str: return "B%s" % self.v dtB = rdflib.URIRef("urn:dt:b") @@ -193,11 +205,11 @@ def __str__(self): self.assertEqual(lb.value, vb) self.assertEqual(lb.datatype, dtB) - def testSpecificBinding(self): - def lexify(s): + def testSpecificBinding(self) -> None: + def lexify(s: str) -> str: return "--%s--" % s - def unlexify(s): + def unlexify(s: str) -> str: return s[2:-2] datatype = rdflib.URIRef("urn:dt:mystring") @@ -218,7 +230,7 @@ def unlexify(s): class TestXsdLiterals(unittest.TestCase): - def test_make_literals(self): + def test_make_literals(self) -> None: """ Tests literal construction. """ @@ -254,6 +266,7 @@ def test_make_literals(self): ("2002", XSD.gYear, datetime.date), ("1921-05-01T00:00:00+00:30", XSD.dateTime, datetime.datetime), ("1921-05-01T00:00:00-00:30", XSD.dateTime, datetime.datetime), + ("true", XSD.boolean, bool), ("abcdef0123", XSD.hexBinary, bytes), ("", XSD.hexBinary, bytes), ("UkRGTGli", XSD.base64Binary, bytes), @@ -265,7 +278,7 @@ def test_make_literals(self): self.check_make_literals(inputs) @unittest.expectedFailure - def test_make_literals_ki(self): + def test_make_literals_ki(self) -> None: """ Known issues with literal construction. """ @@ -283,11 +296,13 @@ def test_make_literals_ki(self): ] self.check_make_literals(inputs) - def check_make_literals(self, inputs): + def check_make_literals( + self, inputs: Sequence[Tuple[str, URIRef, Optional[type]]] + ) -> None: for literal_pair in inputs: - (lexical, type, value_cls) = literal_pair + (lexical, _type, value_cls) = literal_pair with self.subTest(f"testing {literal_pair}"): - literal = Literal(lexical, datatype=type) + literal = Literal(lexical, datatype=_type) if value_cls is not None: self.assertIsInstance(literal.value, value_cls) else: diff --git a/test/test_parse_file_guess_format.py b/test/test_parse_file_guess_format.py index 081255e84..1195aef8a 100644 --- a/test/test_parse_file_guess_format.py +++ b/test/test_parse_file_guess_format.py @@ -1,3 +1,12 @@ +# NOTE: The config below enables strict mode for mypy. +# mypy: no_ignore_errors +# mypy: warn_unused_configs, disallow_any_generics +# mypy: disallow_subclassing_any, disallow_untyped_calls +# mypy: disallow_untyped_defs, disallow_incomplete_defs +# mypy: check_untyped_defs, disallow_untyped_decorators +# mypy: no_implicit_optional, warn_redundant_casts, warn_unused_ignores +# mypy: warn_return_any, no_implicit_reexport, strict_equality + import unittest import logging from pathlib import Path @@ -7,25 +16,33 @@ from rdflib.exceptions import ParserError from rdflib import Graph +from rdflib.util import guess_format class FileParserGuessFormatTest(unittest.TestCase): - def test_jsonld(self): + def test_guess_format(self) -> None: + self.assertEqual(guess_format("example.trix"), "trix") + self.assertEqual(guess_format("local-file.jsonld"), "json-ld") + self.assertEqual(guess_format("local-file.json-ld"), "json-ld") + self.assertEqual(guess_format("/some/place/on/disk/example.json"), "json-ld") + self.assertEqual(guess_format("../../relative/place/on/disk/example.json"), "json-ld") + + def test_jsonld(self) -> None: g = Graph() self.assertIsInstance(g.parse("test/jsonld/1.1/manifest.jsonld"), Graph) self.assertIsInstance(g.parse("test/jsonld/file_ending_test_01.json"), Graph) self.assertIsInstance(g.parse("test/jsonld/file_ending_test_01.json-ld"), Graph) self.assertIsInstance(g.parse("test/jsonld/file_ending_test_01.jsonld"), Graph) - def test_ttl(self): + def test_ttl(self) -> None: g = Graph() self.assertIsInstance(g.parse("test/w3c/turtle/IRI_subject.ttl"), Graph) - def test_n3(self): + def test_n3(self) -> None: g = Graph() self.assertIsInstance(g.parse("test/n3/example-lots_of_graphs.n3"), Graph) - def test_warning(self): + def test_warning(self) -> None: g = Graph() graph_logger = logging.getLogger("rdflib") diff --git a/test/test_typing.py b/test/test_typing.py new file mode 100644 index 000000000..2696e5937 --- /dev/null +++ b/test/test_typing.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +# This software was developed at the National Institute of Standards +# and Technology by employees of the Federal Government in the course +# of their official duties. Pursuant to title 17 Section 105 of the +# United States Code this software is not subject to copyright +# protection and is in the public domain. NIST assumes no +# responsibility whatsoever for its use by other parties, and makes +# no guarantees, expressed or implied, about its quality, +# reliability, or any other characteristic. +# +# We would appreciate acknowledgement if the software is used. + +# NOTE: The config below enables strict mode for mypy. +# mypy: no_ignore_errors +# mypy: warn_unused_configs, disallow_any_generics +# mypy: disallow_subclassing_any, disallow_untyped_calls +# mypy: disallow_untyped_defs, disallow_incomplete_defs +# mypy: check_untyped_defs, disallow_untyped_decorators +# mypy: no_implicit_optional, warn_redundant_casts, warn_unused_ignores +# mypy: warn_return_any, no_implicit_reexport, strict_equality + +from typing import Set, Tuple, Union + +# TODO Bug - rdflib.plugins.sparql.prepareQuery() will run fine if this +# test is run, but mypy can't tell the symbol is exposed. +import rdflib.plugins.sparql.processor + + +# TODO Question - is there a usable type name or class name for +# 'typing.Union[rdflib.BNode, rdflib.URIRef]'? +# Conversation to resolve: +# https://github.com/RDFLib/rdflib/issues/1526 +example_BlankNodeOrIRI = Union[rdflib.BNode, rdflib.URIRef] + + +def test_rdflib_query_exercise() -> None: + """ + The purpose of this test is to exercise a selection of rdflib features under "mypy --strict" review. + """ + + graph = rdflib.Graph() + + literal_one = rdflib.Literal("1", datatype=rdflib.XSD.integer) + literal_two = rdflib.Literal(2) + literal_true = rdflib.Literal(True) + + # Set up predicate nodes, using hash IRI pattern. + predicate_p = rdflib.URIRef("http://example.org/predicates#p") + predicate_q = rdflib.URIRef("http://example.org/predicates#q") + predicate_r = rdflib.URIRef("http://example.org/predicates#r") + + # Set up knowledge base nodes, using URN namespace, slash IRI pattern, and/or blank node. + kb_bnode = rdflib.BNode() + kb_http_uriref = rdflib.URIRef("http://example.org/kb/x") + kb_https_uriref = rdflib.URIRef("https://example.org/kb/y") + kb_urn_uriref = rdflib.URIRef("urn:example:kb:z") + + graph.add((kb_urn_uriref, predicate_p, literal_one)) + graph.add((kb_http_uriref, predicate_p, literal_one)) + graph.add((kb_https_uriref, predicate_p, literal_one)) + graph.add((kb_https_uriref, predicate_p, literal_two)) + graph.add((kb_https_uriref, predicate_q, literal_two)) + graph.add((kb_bnode, predicate_p, literal_one)) + + expected_nodes_using_predicate_q: Set[example_BlankNodeOrIRI] = { + kb_https_uriref + } + computed_nodes_using_predicate_q: Set[example_BlankNodeOrIRI] = set() + for triple in graph.triples((None, predicate_q, None)): + computed_nodes_using_predicate_q.add(triple[0]) + assert expected_nodes_using_predicate_q == computed_nodes_using_predicate_q + + one_usage_query = """\ +SELECT ?resource +WHERE { + ?resource 1 . +} +""" + + expected_one_usage: Set[example_BlankNodeOrIRI] = { + kb_bnode, + kb_http_uriref, + kb_https_uriref, + kb_urn_uriref, + } + computed_one_usage: Set[example_BlankNodeOrIRI] = set() + for one_usage_result in graph.query(one_usage_query): + computed_one_usage.add(one_usage_result[0]) + assert expected_one_usage == computed_one_usage + + # The purpose of this query is confirming the believed return + # signature of graph.query() is determined at *each* call of + # graph.query(), rather than the first. I.e. there should not be a + # type error when the first call returns a length-one result tuple, + # and the second a length-two result tuple. + two_usage_query = """\ +SELECT ?resource ?predicate +WHERE { + ?resource ?predicate "2"^^xsd:integer . +} +""" + + expected_two_usage: Set[ + Tuple[ + example_BlankNodeOrIRI, + example_BlankNodeOrIRI, + ] + ] = {(kb_https_uriref, predicate_p), (kb_https_uriref, predicate_q)} + computed_two_usage: Set[ + Tuple[ + example_BlankNodeOrIRI, + example_BlankNodeOrIRI, + ] + ] = set() + for two_usage_result in graph.query(two_usage_query): + computed_two_usage.add(two_usage_result) + assert expected_two_usage == computed_two_usage + + nsdict = {k: v for (k, v) in graph.namespace_manager.namespaces()} + + prepared_one_usage_query = rdflib.plugins.sparql.processor.prepareQuery( + one_usage_query, initNs=nsdict + ) + computed_one_usage_from_prepared_query: Set[example_BlankNodeOrIRI] = set() + for prepared_one_usage_result in graph.query(prepared_one_usage_query): + computed_one_usage_from_prepared_query.add(prepared_one_usage_result[0]) + assert expected_one_usage == computed_one_usage_from_prepared_query + + for node_using_one in sorted(computed_one_usage): + graph.add((node_using_one, predicate_r, literal_true)) + + python_one: int = literal_one.toPython() + assert python_one == 1 + + python_two: int = literal_two.toPython() + assert python_two == 2 + + python_true: bool = literal_true.toPython() + assert python_true == True + + python_iri: str = kb_https_uriref.toPython() + assert python_iri == "https://example.org/kb/y" diff --git a/tox.ini b/tox.ini index 7982bc239..b3076fcc9 100644 --- a/tox.ini +++ b/tox.ini @@ -29,7 +29,7 @@ deps = [testenv:py3{7,8,9,10}-mypy] commands = - {envpython} -m mypy rdflib --show-error-context --show-error-codes + {envpython} -m mypy --show-error-context --show-error-codes deps = -rrequirements.txt -rrequirements.dev.txt