-
Notifications
You must be signed in to change notification settings - Fork 572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPARQL results starting with RDFLib 6.3.0 induce new inlined type check needs with mypy --strict
#2283
Comments
What is happening here is:
Lines 1509 to 1518 in 334787b
Lines 358 to 360 in 334787b
This Union exists because depending on the type of the query, the result will be different. The problem is, there is not enough information available to the type checker to determine what kind of result is being returned, so users have to do this themselves. If you know you passed a for result in graph.query(...):
assert isinstance(result, tuple)
... for result in cast(Iterable[Tuple[URIRef, URIRef, URIRef]], graph.query(...)):
... I think the reason why From https://docs.python.org/3/library/typing.html#typing.TypeVar:
|
One way to make this less annoying is to add an enum valued for triple in graph.query(..., query_type=QueryType.CONSTRUCT):
... |
Thank you @aucampia , your first post addressed all of my questions. Your second post ... I get what the extra parameter would do, but I feel like that's breaking some obtrusiveness boundary of the type system. I'm not sure, just a gut response that will probably change on another day. |
I'm satisfied with this thread being closed, unless you think there's a graceful way to handle it. My best guess would be supplanting the first argument to |
Eh, pardon: s/graceful way to handle it/more graceful way to handle automatic type hinting/ s/best guess/reflexive guess/ |
The But definitely the current I will close this issue, but we should think of ways to make the interface friendlier to use with type checking than it is now. |
I caught another typo in my split-out suggestion: I'd confused |
This would be a cleaner and better solution. |
I'm now fine with leaving this Issue open, to relate to a PR implementing that. I can't start that PR today. |
Sounds good, the title should maybe be adjusted, but the interface should definitely be improved and best to track it. |
mypy --strict
now confused on RDFLib 6.3.0 SPARQL resultsmypy --strict
RDFLib 6.3.0, released today, included an update to type hints for the `Graph.query` function. Issue 2283 logs some of the new induced type hints required to get `mypy --strict` to pass. This patch is needed to respond to the newly induced type assertion requirements. It is intentionally based off of `main` in case a hotfix `case-utils` release is required. References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
This patch upgrades all scripts to pass static type review, including updates due to RDFLib 6.3.1. References: * RDFLib/rdflib#2283 * casework/CASE-Utilities-Python#62 Signed-off-by: Alex Nelson <[email protected]>
Due to a revision in RDFLib type signature requirements with 6.3.0, and an overlapping-in-maintenance-period break in a `pre-commit` package, this patch batches updates to fix two dependencies' issues at once. This patch is built off of `main` because this could potentially be part of a bugfix release. References: * RDFLib/rdflib#2283
Hi there, I am facing a similar issue in my code. I am doing a I would strongly support what you proposed in #2283 (comment). Let me know if I can be of any assistance. |
This patch is known to be an incomplete implementation. Running `mypy test/test_typing.py` before this patch raised 0 type errors. After just adding the two new tests, 3. After starting the subclasses of Query, 30. References: * RDFLib#2283 Signed-off-by: Alex Nelson <[email protected]>
Started PR 2320 to address this Issue. I started in "the middle" of the implementation, enacting the most obvious implementation steps I'd noted above and that @tobiasschweizer also pointed at. After doing so, I now think the challenge for the type reviewer is the simplest type interface, my_select_query = "SELECT ..."
my_query_object: SelectQuery = parseQuery(my_select_query) The string has to be parsed to satisfy that type designation. I know there's some things that can be done with expected string literal values and the type system, but I'm not so sure determining which SPARQL query form is in a string (especially with preceding My current thinking is that my_select_query = "SELECT ..."
my_query_object: SelectQuery = parseSelectQuery(my_select_query)
for result in graph.query(my_query_object): ...
That currently feels like the least intrusive type assertion framework to me. This feels like a good point to pause for sanity-checking. I'll need to come back to this in a few days. |
There sadly are not that many better options, and even if there were, they would not be that distinct in operation. I think maybe the right function may be rdflib/rdflib/plugins/sparql/processor.py Lines 21 to 29 in 0d07f9b
We would need to create different query types, though, so one option is to have: class SelectQuery
@classmethod
def prepare(cls, queryString: str, initNs: Mapping[str, Any] = {}, base: Optional[str] = None) -> SelectQuery:
... That would then still do the type-asserts internally, but really from a user point of view it is not that relevant, all they see is a function that either does not return, or returns a SelectQuery. Whether that is because it can't parse anything else, or because it parses other things and just raises exceptions for them, is essentially the same to users (given we ingore the compute cost of parsing) The benefit of having a method on each subclass is that it makes for maybe slightly more succinct code, and seems a bit more natural to than to have the different free functions. |
Just to confirm here, you are right, the type system can't really distinguish from the current arguments what is going on with the query. Our options are:
The differentiator works, but it makes for more complex type signatures also, and more complex documentation. Separate functions are better in that regard, but there are tradeoffs both ways. I somewhat prefer having class methods on the differentiated subclasses, this still comes down to separate functions, but places them in a bit more natural place from my point of view. |
This could actually go to the base class and be typed as returning Then as long as the subclass constructors validate the query (i.e. so long as So, a very rudimentary option is: class Query:
def __init__(self, prologue: Prologue, algebra: CompValue):
...
@classmethod
def prepare(cls, ...):
result = prepareQuery(...)
return cls(result.prologue, result.algebra)
class SelectQuery(Query):
def __init_(self, prologue: Prologue, algebra: CompValue):
# assert that prologue and/or algebra is for select, if not raise ValueError
# init super type It could be more sophisticated behind the scenes, but this should do everything we need and presents the right interface to users. Users can then do result = graph.query(SelectQuery.prepare(...)) And should get an appropriately typed result. The interface of |
Some of these issues are due to RDFLib Issue 2283. Some are due to symbol reuse. A follow-on patch will regenerate Make-managed files. References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
Some of these issues are due to RDFLib Issue 2283. Some are due to symbol reuse. A follow-on patch will regenerate Make-managed files. References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
No effects were observed on Make-managed files. References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
This patch handles a type review matter not yet automatically provided by `Graph.query`, though rdflib Issue 2283 is planned to provide a mechanism for this. References: * RDFLib/rdflib#2283 Signed-off-by: Alex Nelson <[email protected]>
Potentially, adding an assert() addresses the subclass type review, per `@classmethod` docs: > ... If a class method is called for a derived class, the derived class > object is passed as the implied first argument. This patch also reverts the first-draft change to `Graph.query`. References: * https://docs.python.org/3/library/functions.html#classmethod * RDFLib#2283 (comment) Suggested-by: Iwan Aucamp <[email protected]> Signed-off-by: Alex Nelson <[email protected]>
References: * RDFLib#2283 Signed-off-by: Alex Nelson <[email protected]>
I just hit an unpleasant surprise on running unit tests on a project that worked yesterday, but failed today. The issue I hit was in using
mypy --strict
on a SPARQLCONSTRUCT
query. A similar issue exists forSELECT
queries, but I've resolved that one.With RDFLib 6.2.0, this worked:
Those
assert
s are a pattern I've had to implement to convincemypy --strict
about types when I have later code assuming e.g.result[0]
(and[1]
) is aURIRef
.With 6.3.0 (released today), I get a complaint that I haven't guaranteed
result
is indexable. This is true forSELECT
andCONSTRUCT
queries.I can get by with the following extra bits for
SELECT
queries:That pretty much followed from the
mypy
complaint I excerpted above, and checking for whereResultRow
was defined. But, forCONSTRUCT
queries, theTuple
syntax doesn't quite work the same.mypy --strict
throws a different error on that:I don't see a unit test demonstrating how to get this to work. I also am not understanding how the return type of
rdflib.graph.Graph.query() -> rdflib.query.Result
eventually ties to thatUnion
that coversSELECT
,CONSTRUCT
andASK
return types.How should the results of
CONSTRUCT
queries interact withmypy --strict
? Is there a type alias I should use instead of thatTuple
? I thought there was an alias somewhere interm.py
to cover a general triple, but I'm having trouble finding the symbol now.The text was updated successfully, but these errors were encountered: