0

This is a follow-up question to a problem I previously posted that was partially resolved with the answer I received.

  • 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 a class Thing which is available through an external module.

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.

Cracoras
  • 347
  • 3
  • 16
  • 3
    Please update your question with the full tracebacks. I see no code which calls new()). – quamrana Feb 18 '20 at 21:48
  • 1
    In `MasterData.__init__` (and `Transactional.__init__`) you don't ever define `color` or `size`, so I'm not surprised you're getting errors related to those names when you try to pass them to `BusinessDocument`. I have no idea what you're actually trying to do here, it seems very confusing, and I can't tell if it's because of good reasons (related to the library you're using) or if it's just messed up code. As quamrana said, giving the full tracebacks of the errors you're experiencing would help us understand what's happening. – Blckknght Feb 18 '20 at 21:55
  • @quamrana added the tracebacks. – Cracoras Feb 18 '20 at 23:24
  • @Blckknght sorry, I added the missing arguments in the call, the actual code has another 4 arguments and I was making it short here. All I am trying to do is to be able to instantiate the class that was defined dynamically. Like I mentioned, when I remove the inheritance from Thing, the instantiation works fine, but unfortunately I need that class :-) Thanks for your help. – Cracoras Feb 18 '20 at 23:25
  • Yes, your problem is with `Thing`. I have now tried your code with a dummy `Thing` and everything works ok. There seems to be a problem with the way that `__new__()` creates `Thing`. – quamrana Feb 19 '20 at 11:59

1 Answers1

0

The problem seems to be caused by the Thing class as I suspected and also confirmed by @quamrana.

Cracoras
  • 347
  • 3
  • 16