This post was updated on .
I am running into the following issue when using owlready2 to define and instantiate my ontology classes.
- The scenario is that I have 1 class that is defined at run time, that inherits from a class that is defined based on a type: MasterData or Transaction, which on its turn, inherits from the BusinessDocument. - The BusinessDocument class needs to inherit from the Thing module that is imported in my package. The following code has been implemented to create all the classes in the chain: from owlready2 import * with onto: class BusinessDocument(Thing): @staticmethod def get_class(doc_type): switch = { 'MasterData': MasterData, 'Transactional': Transactional } cls = switch.get(doc_type, lambda: "Invalid Noun Type") return cls def __init__(self, doc_id, location, doc_type, color, size): self.doc_id = doc_id self.location = location self.doc_type = doc_type self.color = color self.size = size @property def get_location(self): return self.location @property def get_doc_id(self): return self.doc_id with onto: class MasterData(BusinessDocument): def __init__(self, doc_id, location, color, size): BusinessDocument.__init__(self, doc_id, location, color, size, 'MasterData') with onto: class Transactional(BusinessDocument): def __init__(self, doc_id, location, color, size): BusinessDocument.__init__(self, doc_id, location, color, size, 'Transactional') with onto: class NounClass(): @staticmethod def get_class(doc_name, doc_type): return type(doc_name, (BusinessDocument.get_class(doc_type), BusinessDocument, ),dict.fromkeys(['doc_id', 'location', 'color', 'size',])) At run time when I get the doc_name and I get a new class, but when I try to instantiate. ``` invoice_cls = NounClass.get_class('Invoice', 'Transactional') my_invoice = invoice_cls('IN-1234', 'New York', 'blue', 'big') ``` Calls to the type() and __mro__() methods for the invoice_cls gives me the following information: DEBUG:app.__main__:Type of from_noun is [(bod_ontology.Invoice, bod_ontology.MasterData, bod_ontology.BusinessDocument, owl.Thing, <class 'object'>)] DEBUG:app.__main__:Class type is [<class 'owlready2.entity.ThingClass'>] But then I get an exception thrown related to the `__new__()` method: DEBUG:app.__main__:Type of from_noun is [(bod_ontology.BillFromPartyMaster, bod_ontology.MasterData, bod_ontology.BusinessObjectDocument, owl.Thing, <class 'object'>)] DEBUG:app.__main__:Class type is [<class 'owlready2.entity.ThingClass'>] File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 167, in parse_xml my_invoice = invoice_cls('IN-1234', 'New York', 'blue', 'big') --- Logging error --- Traceback (most recent call last): File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 167, in parse_xml my_invoice = invoice_cls('IN-1234', 'New York', 'blue', 'big') TypeError: __new__() takes from 1 to 3 positional arguments but 5 were given During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 1081, in emit msg = self.format(record) File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 925, in format return fmt.format(record) File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 664, in format record.message = record.getMessage() File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 369, in getMessage msg = msg % self.args TypeError: must be real number, not TypeError Call stack: File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1758, in <module> main() File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1752, in main globals = debugger.run(setup['file'], None, None, is_module) File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1147, in run pydev_imports.execfile(file, globals, locals) # execute the script File "/Applications/PyCharm.app/Contents/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 520, in <module> exit(main()) File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 515, in main query_database() File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 103, in query_database csv_record = parse_xml(bod_type, date_time, from_lid, tenant, xml_string) File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 174, in parse_xml log.debug("Got an error [%e]", e) Arguments: (TypeError('__new__() takes from 1 to 3 positional arguments but 5 were given'),) ``` Then if I try to make the instantiation call without the arguments, I get a different exception related to the `__init__()` method, and here is the full : ``` DEBUG:app.__main__:Type of from_noun is [(bod_ontology.BillFromPartyMaster, bod_ontology.MasterData, bod_ontology.BusinessObjectDocument, owl.Thing, <class 'object'>)] DEBUG:app.__main__:Class type is [<class 'owlready2.entity.ThingClass'>] File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 167, in parse_xml my_invoice = invoice_cls() --- Logging error --- Traceback (most recent call last): File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 167, in parse_xml my_obj = MyCls() TypeError: __init__() missing 4 required positional arguments: 'doc_id', 'location', 'color', and 'size' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 1081, in emit msg = self.format(record) File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 925, in format return fmt.format(record) File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 664, in format record.message = record.getMessage() File "/Users/cracoras/.pyenv/versions/3.8.1/lib/python3.8/logging/__init__.py", line 369, in getMessage msg = msg % self.args TypeError: must be real number, not TypeError Call stack: File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1758, in <module> main() File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1752, in main globals = debugger.run(setup['file'], None, None, is_module) File "/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py", line 1147, in run pydev_imports.execfile(file, globals, locals) # execute the script File "/Applications/PyCharm.app/Contents/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 520, in <module> exit(main()) File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 515, in main query_database() File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 103, in query_database csv_record = parse_xml(bod_type, date_time, from_lid, tenant, xml_string) File "/Users/cracoras/PycharmProjects/bod2owl/app/convert_data.py", line 174, in parse_xml log.debug("Got an error [%e]", e) Arguments: (TypeError("__init__() missing 4 required positional arguments: 'doc_id', 'location', 'color', and 'size'"),) ``` This only happens when I inherit from the 'Thing' class. If I remove the inheritance the code runs just fine. It looks like I am messing up with the instantiation sequence in the class hierarchy. I tried also using the types() function in the format NewClass = types.new_class(noun, (BusinessObjectDocument.get_class(noun_type), BusinessObjectDocument, )) and at the end I get the same errors. |
Administrator
|
Hi,
Owlready uses the __new__() special method for initializing object. The default __new__() handles keyword arguments, but not non-keyword arguments as you are using. There are 2 solutions : 1) you can use keyword arguments, for example: my_invoice = invoice_cls(doc_id = 'IN-1234', location = 'New York', color = 'blue', size = 'big') 2) you can override __new__(), as following: class BusinessDocument(Thing): def __new__(Class, doc_id, location, doc_type, color, size): Thing.__new__(Class) def __init__(self, doc_id, location, doc_type, color, size): self.doc_id = doc_id self.location = location self.doc_type = doc_type self.color = color self.size = size And the same for the other classes. Jiba |
This post was updated on .
Hi Jiba.
I figured out the 1st solution and was able to move forward it, but I like the second one better as it makes the instantiation of the subclasses simpler. So I made the following changes in my code. from owlready2 import * onto = get_ontology('http://test.org/onto.owl') with onto: class BusinessDocument(Thing): @staticmethod def get_class(doc_type): switch = { 'MasterData': MasterData, 'Transactional': Transactional } cls = switch.get(doc_type, lambda: "Invalid Noun Type") return cls def __new__ (cls, doc_id, location, color, size, doc_type): Thing.__new__(cls) def __init__ (self, doc_id, location, color, size, doc_type): self.doc_id = doc_id, self.location = location self.color = color self.size = size self.doc_type = doc_type def get_type(self): return self.doc_type class MasterData(BusinessDocument): def __new__ (cls, doc_id, location, color, size): BusinessDocument.__new__(cls, doc_id, location, color, size, 'MasterData') def __init__ (self, doc_id, location, color, size): BusinessDocument.__init__(doc_id, location, color, size, 'MasterData') class Transactional(BusinessDocument): def __new__ (cls, doc_id, location, color, size): BusinessDocument.__new__(cls, doc_id, location, color, size, 'Transactional') def __init__ (self, doc_id, location, color, size): BusinessDocument.__init__(doc_id, location, color, size, 'Transactional') class NounClass(): @staticmethod def get_class(doc_name, doc_type): return type(doc_name, (BusinessDocument.get_class(doc_type), ),dict()) def __new__ (cls, doc_id, location, color, size): super().__new__(cls, doc_id, location, color, size) def __init__(self, doc_id, location, color, size): super().__init__(doc_id, location, color, size) I am able to successfully get the new class type in the following line: invoice_class = NounClass.get_class('Invoice', 'Transactional') When I print the mro for it I get what seems to be the correct inheritance chain. print(invoice_class.__mro__) (onto.Invoice, onto.Transactional, onto.BusinessDocument, owl.Thing, <class 'object'>) Then I try to create the new invoice object: my_obj = invoice_class('IN-001', 'London', "Red", "Small") But it sees like that object is None, but I get the following error when I call the type or __mro__ property for it. print(my_obj.__mro__) AttributeError Traceback (most recent call last) <ipython-input-80-e4b41e54bf70> in <module> 60 print(invoice_class.__mro__) 61 my_obj = invoice_class('IN-001', 'London', "Red", "Small") ---> 62 print(my_obj.__mro__) 63 AttributeError: 'NoneType' object has no attribute '__mro__' Thank you in advance for any help. MD. |
Free forum by Nabble | Edit this page |