Request for details on the behaviour of get_ontology(), load(), the base_uri and save()

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Request for details on the behaviour of get_ontology(), load(), the base_uri and save()

tither
Hello Jiba! Thanks a lot for developing & maintaining Owlready2. It's been amazingly useful!

I'm a fairly new user and still find some concepts unclear, especially when reading and writing local files. My use of Owlready2 is purely from a Knowledge Graph perspective.

I'm initializing my ontology like so:
o2.default_world.set_backend(filename = "quadstore.sqlite3", exclusive=True)
onto = o2.get_ontology('reso.owl').load()
And tried different ways of saving it:

Exporting the world works

o2.default_world.save(path)

Specifying the output file works

onto.save(file='reso.owl', format='rdfxml')

Saving without arguments will not work

>>> onto.save()


---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
C:\(...)\Temp/ipykernel_23620/1481190103.py in <module>
----> 1 reso.db.onto.onto.save()

c:\Anaconda3\lib\site-packages\owlready2\namespace.py in save(self, file, format, **kargs)
   1168   def save(self, file = None, format = "rdfxml", **kargs):
   1169     if   file is None:
-> 1170       file = _open_onto_file(self._base_iri, self.name, "wb")
   1171       if _LOG_LEVEL: print("* Owlready2 * Saving ontology %s to %s..." % (self.name, getattr(file, "name", "???")), file = sys.stderr)
   1172       self.graph.save(file, format, **kargs)

c:\Anaconda3\lib\site-packages\owlready2\namespace.py in _open_onto_file(base_iri, name, mode, only_local)
   1447       if os.path.exists(filename) and os.path.isfile(filename): return open(filename, mode)
   1448   if (mode.startswith("r")) and not only_local: return urllib.request.urlopen(base_iri)
-> 1449   if (mode.startswith("w")): return open(os.path.join(onto_path[0], "%s.owl" % name), mode)
   1450   raise FileNotFoundError
   1451 

IndexError: list index out of range


However if I initialize the ontology differently, this behaviour can change. It is also conditional on many parameters. For instance, if entities are added with different base uri, the following can occur: (this is not my own traceback, I encountered a similar issue and expended too much time already trying to replicate the error - will document it if I find it again :
TypeError                                 Traceback (most recent call last)
<ipython-input-20-a50699e0134c> in <module>
     39     filename = "raw/"+DATASET+"_"+split+".owl"
     40     print(onto, len(list(onto.properties())), list(onto.properties()))
---> 41     onto.save(file = filename, format = "rdfxml")

d:\Programs\Anaconda3\envs\pytorch\lib\site-packages\owlready2\namespace.py in save(self, file, format, **kargs)
   1004       if _LOG_LEVEL: print("* Owlready2 * Saving ontology %s to %s..." % (self.name, file), file = sys.stderr)
   1005       file = open(file, "wb")
-> 1006       self.graph.save(file, format, **kargs)
   1007       file.close()
   1008     else:

d:\Programs\Anaconda3\envs\pytorch\lib\site-packages\owlready2\driver.py in save(self, f, format, commit, **kargs)
    223   def save(self, f, format = "rdfxml", commit = False, **kargs):
    224     if commit: self.parent.commit()
--> 225     _save(f, format, self, **kargs)
    226 
    227 

d:\Programs\Anaconda3\envs\pytorch\lib\site-packages\owlready2\driver.py in _save(f, format, graph, filter)
    500 
    501       else:
--> 502         o = _unabbreviate(o)
    503         s_lines.append("""  <%s rdf:resource="%s"/>""" % (p, o))
    504 

d:\Programs\Anaconda3\envs\pytorch\lib\site-packages\owlready2\driver.py in _unabbreviate(storid)
    290     @lru_cache(None)
    291     def _unabbreviate(storid):
--> 292       r = graph._unabbreviate(storid).replace("&", "&amp;")
    293       if r.startswith(base_iri):
    294         if base_iri.endswith("/"): return r[len(base_iri) :]

d:\Programs\Anaconda3\envs\pytorch\lib\site-packages\owlready2\triplelite.py in _unabbreviate(self, storid)
    489 
    490   def _unabbreviate(self, storid):
--> 491     return self.execute("SELECT iri FROM resources WHERE storid=? LIMIT 1", (storid,)).fetchone()[0]
    492 
    493   def get_storid_dict(self):

TypeError: 'NoneType' object is not subscriptable"


Could you provide a bit more insight into which parameters and process are best for handling local ontologies and load/save them to files? Specifically, here are a list of questions.
  • Why is load() required when creating an ontology?
  • How are the base URI and ontology name used in the saving process?
  • Are there principles, enforced by Owlready2 or not, that dictate how IRI or individual names should be written? (for instance, exporting to RDF yields many "XXX does not look like a valid URI, trying to serialize this will break." warnings, although I did not encounter any loss of functionality afterwards.)
  • What are the pros and cons of loading/saving ontologies VS worlds?

Thank you very much, and many cheers!
Reply | Threaded
Open this post in threaded view
|

Re: Request for details on the behaviour of get_ontology(), load(), the base_uri and save()

Jiba
Administrator
Hello,

* Saving without arguments will not work

Ontology.save() without arguments requires that you specify the onto_path variable (with onto_path.append("xxx_path")). It works like PYTHON_PATH and sys.path, but for ontologies and not for Python modules). Ontology.save() without arguments will save the ontology in the directory onto_path[0], and the filename is determined by the last part of the ontology's IRI.

* Why is load() required when creating an ontology?

load() is required when loading an ontology from Internet or from a local file. On the contrary, it should not be called when creating an ontology from scratch in Python.

 * How are the base URI and ontology name used in the saving process?

When saving an ontology, the IRI of the ontology is written inside the file (or the quadstore). As a consequence, you cannot just rename the OWL file to change the IRI of the ontology : the content of the file must also be changed.

 * Are there principles, enforced by Owlready2 or not, that dictate how IRI or individual names should be written?

IRI must starts with http:// or https:// (Owlready2 accepts file:// but many tools do not).

In addition, many special characters are not supported in IRI, but Owlready2 is actually quite tolerant and often accepts them.

My personal recommendation are to use IRI of the form "http://website.xxx/path/ontoname.owl#entity", but other forms are acceptable and fully supported, e.g. "http://website.xxx/path/ontoname/entity".

 * What are the pros and cons of loading/saving ontologies VS worlds?

Savings ontologies produces multiples OWL or RDF files, it is slower, but the files can be opened with other tools (like Protégé).

Saving world produces a single file, is faster, but the file can only be opened with Owlready2.

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: Request for details on the behaviour of get_ontology(), load(), the base_uri and save()

tither
Thank you very much for all these clear answers!

Now I have some code to re-work a bit in order to leverage this new knowledge ;)
Reply | Threaded
Open this post in threaded view
|

Re: Request for details on the behaviour of get_ontology(), load(), the base_uri and save()

tither
This post was updated on .
Hi again!
I've been reformatting my code to integrate these new recommendations. However, I run into errors for the two main options I've been trying, namely setting onto_path as relative or absolute.

Onto_path absolute path, saving with onto.save(path), with argument as built inside owlready2


>>> # Local onto_path example

>>> import owlready2 as o2

>>> o2.default_world.set_backend(filename = "quadstore.sqlite3", exclusive=True)
>>> onto = o2.get_ontology('http://reso.owl') 
>>> path = r'C:\Users\...\reso\'
>>> o2.onto_path.append(path)
>>> onto.name = 'reso'

>>> # Example of an individual IRI
>>> document_py_handle
'http://reso.owl#document'

>>> # Trying to save
>>> p = os.path.join('', "%s.owl" % name)
>>> onto.save(p)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
C:\...\Local\Temp/ipykernel_22096/1142227128.py in <module>
----> 1onto.save(p)

c:\Anaconda3\lib\site-packages\owlready2\namespace.py in save(self, file, format, **kargs)
   1175       if _LOG_LEVEL: print("* Owlready2 * Saving ontology %s to %s..." % (self.name, file), file = sys.stderr)
   1176       file = open(file, "wb")
-> 1177       self.graph.save(file, format, **kargs)
   1178       file.close()
   1179     else:

c:\Anaconda3\lib\site-packages\owlready2\driver.py in save(self, f, format, commit, **kargs)
    223   def save(self, f, format = "rdfxml", commit = False, **kargs):
    224     if commit: self.parent.commit()
--> 225     _save(f, format, self, **kargs)
    226 
    227 

c:\Anaconda3\lib\site-packages\owlready2\driver.py in _save(f, format, graph, filter)
    444 
    445       if (p == rdf_type) and (type == "rdf:Description") and (not o < 0):
--> 446         t = abbrev(o)
    447         if not t in bad_types:
    448           if t.startswith("#"): t = t[1:]
...
--> 505     return self.execute("SELECT iri FROM resources WHERE storid=? LIMIT 1", (storid,)).fetchone()[0]
    506 
    507   def get_storid_dict(self):

TypeError: 'NoneType' object is not subscriptable

Using an onto_path relative path with or witout arguments, and using an absolute path without arguments


These 3 methods will produce a permissionError I can't explain (I could manually read or write through the same python script using "with open(, 'w') as f: f.write(...)" without any problem).

>>> # Local onto_path example

>>> import owlready2 as o2

>>> o2.default_world.set_backend(filename = "quadstore.sqlite3", exclusive=True)
>>> onto = o2.get_ontology('http://reso.owl') 
>>> o2.onto_path.append('/')
>>> onto.name = 'reso'

>>> # Example of an individual IRI
>>> document_py_handle
'http://reso.owl#document'

>>> # Trying to save
>>> onto.save()

---------------------------------------------------------------------------
PermissionError                           Traceback (most recent call last)
C:\...\Temp/ipykernel_28748/1481190103.py in <module>
----> 1onto.save()

c:\Anaconda3\lib\site-packages\owlready2\namespace.py in save(self, file, format, **kargs)
   1168   def save(self, file = None, format = "rdfxml", **kargs):
   1169     if   file is None:
-> 1170       file = _open_onto_file(self._base_iri, self.name, "wb")
   1171       if _LOG_LEVEL: print("* Owlready2 * Saving ontology %s to %s..." % (self.name, getattr(file, "name", "???")), file = sys.stderr)
   1172       self.graph.save(file, format, **kargs)

c:\Anaconda3\lib\site-packages\owlready2\namespace.py in _open_onto_file(base_iri, name, mode, only_local)
   1447       if os.path.exists(filename) and os.path.isfile(filename): return open(filename, mode)
   1448   if (mode.startswith("r")) and not only_local: return urllib.request.urlopen(base_iri)
-> 1449   if (mode.startswith("w")): return open(os.path.join(onto_path[0], "%s.owl" % name), mode)
   1450   raise FileNotFoundError
   1451 

PermissionError: [Errno 13] Permission denied: '/reso.owl'


So I though I was following better guidelines but I instead encounter a loss of functionality, with the only saving mechanism working being to and from the sqlite database. However I'd need to make an actual, rdfxml, file saving work.
Have you any insight on what I am doing wrong?



---------------------------------------------------------------------------------------------------
EDIT:
Here is a longer traceback for easier tracking

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
C:\...\Temp/ipykernel_29208/2232994153.py in <module>
----> 1 reso.db.onto.save()

c:\...\onto.py in save()
    123     name = onto.name
    124     p = os.path.join('', "%s.owl" % name)
--> 125     onto.save(p)
    126 
    127 def world_to_rdf(path:str):

c:\Anaconda3\lib\site-packages\owlready2\namespace.py in save(self, file, format, **kargs)
   1175       if _LOG_LEVEL: print("* Owlready2 * Saving ontology %s to %s..." % (self.name, file), file = sys.stderr)
   1176       file = open(file, "wb")
-> 1177       self.graph.save(file, format, **kargs)
   1178       file.close()
   1179     else:

c:\Anaconda3\lib\site-packages\owlready2\driver.py in save(self, f, format, commit, **kargs)
    223   def save(self, f, format = "rdfxml", commit = False, **kargs):
    224     if commit: self.parent.commit()
--> 225     _save(f, format, self, **kargs)
    226 
    227 

c:\Anaconda3\lib\site-packages\owlready2\driver.py in _save(f, format, graph, filter)
    444 
    445       if (p == rdf_type) and (type == "rdf:Description") and (not o < 0):
--> 446         t = abbrev(o)
    447         if not t in bad_types:
    448           if t.startswith("#"): t = t[1:]

c:\Anaconda3\lib\site-packages\owlready2\driver.py in abbrev(storid)
    316     @lru_cache(None)
    317     def abbrev(storid):
--> 318       x = graph._unabbreviate(storid).replace("&", "&amp;")
    319 
    320       splitat = max(x.rfind("/"), x.rfind("#"), x.rfind(":"))

c:\Anaconda3\lib\site-packages\owlready2\triplelite.py in _unabbreviate(self, storid)
    503 
    504   def _unabbreviate(self, storid):
--> 505     return self.execute("SELECT iri FROM resources WHERE storid=? LIMIT 1", (storid,)).fetchone()[0]
    506 
    507   def get_storid_dict(self):

TypeError: 'NoneType' object is not subscriptable
Reply | Threaded
Open this post in threaded view
|

Re: Request for details on the behaviour of get_ontology(), load(), the base_uri and save()

Jiba
Administrator
Hi,

For the second problem, the cause is that you set "/" as the onto path. Thus, Owlready will try to save the ontology in the / directory. But either you are using Linux (or Mac) and / is only available for root user, or you are using Windows and / does not exist (it is more or less equivalent to C:/). You need to specify a writeable directory in onto_path if you want to save ontology.

For the first problem, the path is writeable (but notice that the path variable is actually not used, since it is not used in the construction of the p variable later). The problem seems related to the translation in RDF/XML ; Owlready encounter an entity for which it cannot find an IRI. If you send me the ontology, I can investigate it further.

Jiba