tools4rdf#

tools4RDF is a Python toolkit designed to simplify working with RDF data, ontologies, and knowledge graphs. It provides user-friendly utilities for creating, manipulating, querying, and visualizing RDF data, making it easier to integrate semantic web technologies into research and applications, particularly for domain scientists and developers without deep RDF expertise.

It is built on top of rdflib, and a primary function is the automated creation of SPARQL queries through an autocompleted programmatic interface.

Explore the examples below to get started with tools4rdf and see how it can accelerate your semantic data workflows!

A small example#

from tools4rdf import OntologyNetwork

Read in the FOAF ontology

onto = OntologyNetwork('http://purl.org/spar/foaf')

Explore terms, autocompletion works!

onto.terms.foaf.Person
foaf:Person
onto.terms.foaf.Person.uri, onto.terms.foaf.Person.description
('http://xmlns.com/foaf/0.1/Person',
 rdflib.term.Literal('A person.', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#string')))

Another term

onto.terms.foaf.name
foaf:name

Find domain and range of the term

onto.terms.foaf.name.domain, onto.terms.foaf.name.range
(['foaf:Agent',
  'foaf:Project',
  'foaf:Document',
  'foaf:Person',
  'foaf:Group',
  'foaf:Organization',
  'foaf:Image',
  'foaf:PersonalProfileDocument'],
 [])

Build SPARQL queries automatically, and execute them on endpoints

df = onto.query(
    'https://dbpedia.org/sparql',
    onto.terms.foaf.Person,
    onto.terms.foaf.name,
    limit=10,
)
df
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[7], line 1
----> 1 df = onto.query(
      2     'https://dbpedia.org/sparql',
      3     onto.terms.foaf.Person,
      4     onto.terms.foaf.name,
      5     limit=10,
      6 )
      7 df

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/checkouts/stable/tools4rdf/network/network.py:963, in Network.query(self, kg, source, destinations, return_df, num_paths, limit)
    961 res = []
    962 for query_string in query_strings:
--> 963     r = self._query(kg, query_string, return_df=return_df)
    964     if r is not None:
    965         res.append(r)

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/checkouts/stable/tools4rdf/network/network.py:1009, in Network._query(self, kg, query_string, return_df)
   1007                 break
   1008         labels = [x[1:] for x in line.split()[2:]]
-> 1009         return pd.DataFrame(res, columns=labels)
   1011 return res

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/site-packages/pandas/core/frame.py:829, in DataFrame.__init__(self, data, index, columns, dtype, copy)
    827         data = np.asarray(data)
    828     else:
--> 829         data = list(data)
    830 if len(data) > 0:
    831     if is_dataclass(data[0]):

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/site-packages/rdflib/query.py:346, in Result.__len__(self)
    344     return 1
    345 elif self.type == "SELECT":
--> 346     return len(self.bindings)
    347 else:
    348     # type error: Argument 1 to "len" has incompatible type "Optional[Graph]"; expected "Sized"
    349     return len(self.graph)

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/site-packages/rdflib/query.py:232, in Result.bindings(self)
    228 """
    229 a list of variable bindings as dicts
    230 """
    231 if self._genbindings:
--> 232     self._bindings += list(self._genbindings)
    233     self._genbindings = None
    235 return self._bindings

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py:565, in evalDistinct(ctx, part)
    562 res = evalPart(ctx, part.p)
    564 done = set()
--> 565 for x in res:
    566     if x not in done:
    567         yield x

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py:573, in <genexpr>(.0)
    571 def evalProject(ctx: QueryContext, project: CompValue):
    572     res = evalPart(ctx, project.p)
--> 573     return (row.project(project.PV) for row in res)

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/site-packages/rdflib/plugins/sparql/evaluate.py:378, in evalServiceQuery(ctx, part)
    376     json_dict = orjson.loads(response.read())
    377 else:
--> 378     json_dict = json.loads(response.read())
    379 variables = res["vars_"] = json_dict["head"]["vars"]
    380 # or just return the bindings?

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/http/client.py:489, in HTTPResponse.read(self, amt)
    487 else:
    488     try:
--> 489         s = self._safe_read(self.length)
    490     except IncompleteRead:
    491         self._close_conn()

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/http/client.py:638, in HTTPResponse._safe_read(self, amt)
    631 def _safe_read(self, amt):
    632     """Read the number of bytes requested.
    633 
    634     This function should be used when <amt> bytes "should" be present for
    635     reading. If the bytes are truly not available (due to EOF), then the
    636     IncompleteRead exception can be used to detect the problem.
    637     """
--> 638     data = self.fp.read(amt)
    639     if len(data) < amt:
    640         raise IncompleteRead(data, amt-len(data))

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/socket.py:718, in SocketIO.readinto(self, b)
    716 while True:
    717     try:
--> 718         return self._sock.recv_into(b)
    719     except timeout:
    720         self._timeout_occurred = True

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/ssl.py:1314, in SSLSocket.recv_into(self, buffer, nbytes, flags)
   1310     if flags != 0:
   1311         raise ValueError(
   1312           "non-zero flags not allowed in calls to recv_into() on %s" %
   1313           self.__class__)
-> 1314     return self.read(nbytes, buffer)
   1315 else:
   1316     return super().recv_into(buffer, nbytes, flags)

File ~/checkouts/readthedocs.org/user_builds/tools4rdf/conda/stable/lib/python3.11/ssl.py:1166, in SSLSocket.read(self, len, buffer)
   1164 try:
   1165     if buffer is not None:
-> 1166         return self._sslobj.read(len, buffer)
   1167     else:
   1168         return self._sslobj.read(len)

KeyboardInterrupt: 

We can take a look at the SPARQL query that was executed:

q = onto.create_query(
    onto.terms.foaf.Person,
    onto.terms.foaf.name,
    limit=10,
)
print(q)
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT DISTINCT ?Person ?namevalue
WHERE {
    ?Person foaf:name ?namevalue .
     ?Person rdf:type foaf:Person . 
}
LIMIT 10

Other features include:

  • Automated SPARQL query of both local knowledge graphs and remote endpoints

  • Read and parse ontologies

  • Combine ontologies programatically and connect them

For more examples, please check here

Supported SPARQL keywords#

The queries automatically generated by tools4RDF incorporates the following SPARQL features:

  • PREFIX declarations: Automatically generated from the ontologies and namespaces in use

  • SELECT DISTINCT: All queries use SELECT DISTINCT to retrieve unique results

  • WHERE clause: Triple patterns are constructed based on the paths between source and destination terms

  • LIMIT: The number of results can be restricted using the limit parameter

  • Type assertions: Automatic generation of rdf:type statements for classes

  • Subclass support: When subclasses are included, UNION clauses are generated to match any subclass

  • Comparison operators: <, >, <=, >=, ==, !=

  • Logical operators: &&, || for combining conditions

  • XSD datatype support: Filters are generated with appropriate XSD datatypes

  • Remote endpoints: Pass a SPARQL endpoint to the query