Accessing Annotation of an Entity of ontology using owlready - python-3.x

I want to access the annotation properties of an entity from an ontology using owlready library. In the screenshot below I want to access the definition of the selected Entity i.e. impulse control disorder.
from owlready2 import *
onto = get_ontology("./HumanDO.owl").load()
for subclass_of_mental_health in list(onto.search(label ="disease of mental health")[0].subclasses()):
print(subclass_of_mental_health.id, subclass_of_mental_health.label) # This gives outputs (see below)
print(subclass_of_mental_health.definition) # This results in error
Above is the code to access the impulse control disorder entity. I was able to access id by simply using dot notation (<entity>.id) but when i try to <entity.definition> getting
['DOID:10937'] ['impulse control disorder']
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_14348\3127299132.py in <module>
1 for subclass_of_mental_health in list(onto.search(label ="disease of mental health")[0].subclasses()):
2 print(subclass_of_mental_health.id, subclass_of_mental_health.label)
----> 3 print(subclass_of_mental_health.definition)
E:\Python\PythonInstall\envs\new\lib\site-packages\owlready2\entity.py in __getattr__(Class, attr)
592 else:
593 Prop = Class.namespace.world._props.get(attr)
--> 594 if not Prop: raise AttributeError("'%s' property is not defined." % attr)
595 if issubclass_python(Prop, AnnotationProperty):
596 attr = "__%s" % attr # Do NOT cache as such in __dict__, to avoid inheriting annotations
AttributeError: 'definition' property is not defined.
The ontology look like this and you can download the actual file from here Github link
My final goal is to read some annotations and store them but stuck at just reading them. To make it clear, I am not able to access any property other than id and label

Related

Error when validating impact assessment method data and issues with regional characterization factors

This question is somewhat related to this one.
I am attempting to validate the data for a new impact assessment method, prior to writing the method. The method data contains characterization factors for both global and regional interventions. I created a small toy example here.
I am trying to validate the data as follows:
my_method = Method(('my method', 'a method', 'oh what a method'))
method_data = [
(('biosphere', 'global intervention'),1, u'GLO'),
(('biosphere', 'regional intervention'),1, u'REG')
]
my_method.validate(method_data)
The following error occurs:
MultipleInvalid: expected a list # data[0]
No errors occur when attempting the write the method without validation. The error can be avoided by storing data in lists rather than tuples.
Is this a bug in the package or am I doing something wrong?
Furthermore, I am testing specifying regional identifiers for each characterization factors (as shown in the data above). This does not seem required, but when specifying an identifier other than u'GLO' the impacts are not accounted for in subsequent lca calculations. I test this in my example notebook.
Should one avoid specifying regional identifiers for characterization factors?
Validating your new method
What happens is that you need to "organize" your CFs as a list of lists, instead of a list of tuples:
my_method = Method(('my method', 'a method', 'oh what a method'))
method_data = [
[('biosphere', 'global intervention'),1, u'GLO'],
[('biosphere', 'regional intervention'),1, u'REG']
]
my_method.validate(method_data)
Validating an existing method
Suppose you want to copy an existing method, and update some CFs (or add a location or uncertainty data). You would be tempted to use the method data from the load() function of the Method class, but this data is not in "valid" format.
method_data = Method(('CML 2001 (obsolete)',
'acidification potential', 'generic')).load()
...
# modify the `method_data`
my_new_method = Method(('my method', 'a method', 'oh what a method'))
my_new_method.validate(method_data)
that would yield the following error:
MultipleInvalid Traceback (most recent call last)
<ipython-input-27-2fa012f6d12b> in <module>
2 my_method = Method(('my method', 'a method', 'oh what a method'))
3 my_method.validate([list(item) for item in method_data])
----> 4 my_method.validate(method_data)
/opt/conda/lib/python3.9/site-packages/bw2data/data_store.py in validate(self, data)
277 def validate(self, data):
278 """Validate data. Must be called manually."""
--> 279 self.validator(data)
280 return True
/opt/conda/lib/python3.9/site-packages/voluptuous/schema_builder.py in __call__(self, data)
270 """Validate data against this schema."""
271 try:
--> 272 return self._compiled([], data)
273 except er.MultipleInvalid:
274 raise
/opt/conda/lib/python3.9/site-packages/voluptuous/schema_builder.py in validate_sequence(path, data)
644 errors.append(invalid)
645 if errors:
--> 646 raise er.MultipleInvalid(errors)
647
648 if _isnamedtuple(data):
MultipleInvalid: expected a list # data[0]
You must transform it into a list of lists first:
my_method.validate([list(item) for item in method_data])

Is this example of model object property usage unique to a logged-in session in django?

I know django optimises with some model instance re-use. So - the question is really - is the value of 'imprints' shown below always unique to a logged-in session in django?
Lets say I have a django deployment in which, with this model.
Class Thing(models.Model):
example_field = models.UUIDField(default=uuid.uuid4, editable=False)
imprints = None # placeholder for imprints to be added dynamically
def add_imprints(self, cc):
"""
Adds an imprints object associated with this instance for passed cc to this
instance.
"""
self.imprints = cc.imprint_set.get(entity=self)
using the ORM, an instance of this Thing model in the db is pulled up in a view, say with.
object = Thing.objects.get(pk=thing_id)
a value is then assigned to the imprints field which is intended just as an addition to the instance so that when it is passed to another function that added information is there - like this
object.add_imprints(cc)
To emphasise - the imprints value is only used to pass information with the instance of Thing during the processing of a view and through some related functions, there is no need for further persistence and it must be unique to the session.
Normally there is no problem with this kind of practice - however there may be a security issue here. I need to know if django would ever use the same instance for another logged-in user - along with the value of imprints, with a different session if they do
object = Thing.objects.get(pk=thing_id)
with the same thing_id, while the other instance is still in use.
Django creates a new instance of the model when you retrieve a concrete object of the query.
You can be pretty confident that temporary variables will be only in that object
You can check it:
In [13]: from django.contrib.auth.models import User
In [14]: users = User.objects.all()
In [15]: u = users.first()
In [16]: u
Out[16]: <User: super>
In [17]: u.tmp = 123
In [18]: u.tmp
Out[18]: 123
In [19]: u2 = users.first()
In [20]: u2.tmp
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-20-f4c979d08460> in <module>
----> 1 u2.tmp
AttributeError: 'User' object has no attribute 'tmp'

AttributeError: object has no attribute - although class method exists

I have a class consisting of 14 methods. Here is the skeleton:
class Field
def __init__():
...
return
def ...():
country = Field()
country.re_fitness_population()
It's a large class, so here is the full pastebin.
Running this code results in:
----> 1 country.re_fitness_population()
AttributeError: 'Field' object has no attribute 're_fitness_population'
Running dir() on this class doesn't show the method as available, and I've tried fixing any spacing issues, but running python3 -tt also doesn't show anything. I've tried renaming the method, also doesn't help.
I clearly have written the function as one of the methods of the class. I feel like there is something big I'm missing.

hasattr telling lies? (AttributeError: 'method' object has no attribute '__annotations__')

The following code
class Foo:
def bar(self) -> None:
pass
foo = Foo()
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__ = 'hi'
crashes with
AttributeError: 'method' object has no attribute '__annotations__'
How can this happen?
The attribute error here is raised because you can't set any attribute on a method object:
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
The exception here is perhaps confusing because method objects wrap a function object and proxy attribute read access to that underlying function object. So when attributes on the function exist, then hasattr() on the method will return True:
>>> hasattr(foo.bar, 'baz')
False
>>> foo.bar.__func__.baz = 42
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz
42
However, you still can't set those attributes via the method, regardless:
>>> hasattr(foo.bar, 'baz')
True
>>> foo.bar.baz = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'baz'
So, just because the attribute can be read doesn't mean you can set it. hasattr() is speaking the truth, you just interpreted it to mean something different.
Now, if you tried to set the __annotations__ attribute directly on the underlying function object you'd get another error message:
>>> foo.bar.__func__.__annotations__ = 'hi'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __annotations__ must be set to a dict object
You would want to use a dictionary object here:
>>> foo.bar.__func__.__annotations__ = {'return': 'hi'}
>>> foo.bar.__annotations__
{'return': 'hi'}
However, because __annotations__ is a mutable dictionary, it is just easier to directly manipulate the keys and values to that object, which is perfectly feasible to do via the method wrapper:
>>> foo.bar.__annotations__['return'] = 'int'
>>> foo.bar.__annotations__
{'return': 'int'}
Now, if you were hoping to set per instance annotations, you can't get away with setting attributes on method objects, because method objects are ephemeral, they are created just for the call, then usually discarded right after.
You would have to use custom method descriptor objects via a metaclass and re-create the __annotations__ attribute for those each time, or you could instead pre-bind methods with a new function object that would be given their own attributes. You then have to pay a larger memory price:
import functools
foo.bar = lambda *args, **kwargs: Foo.bar(foo, *args, **kwargs)
functools.update_wrapper(foo.bar, Foo.bar) # copy everything over to the new wrapper
foo.bar.__annotations__['return'] = 'hi'
Either way you completely kill important speed optimisations made in Python 3.7 this way.
And tools that operate on the most important use case for __annatotions__, type hints, do not actually execute code, they read code statically and would completely miss these runtime alterations.
You're getting an error. because __annotations__ is a dictionary. If you want to change values you'll have to do it like this:
if hasattr(foo.bar, '__annotations__'):
foo.bar.__annotations__['return'] = 'hi'
This will make the return value of your foo.bar be hi instead of None. The only thing I'm not sure about is how the __annotations__ are protected, not allowing you to change them from a dict to string, but I suppose it's some internal check in the source.
UPDATE
For more control over the signature you can use the inspect module and get the Signature object of your class(or method) and edit it from there. For example
import inspect
sig = inspect.signature(foo.bar)
sig.return_annotation # prints None (before modifying)
sig.replace(return_annotation="anything you want")
More on that here

Django __call__() missing 1 required keyword-only argument: 'manager'

I have two models:
class Someinfo(models.Model):
name = models.CharField(max_length=200)
#something else
class OtherInfo(models.Model):
name2 = models.CharField(max_lenth=200)
related_someinfo = models.ManyToManyField(Someinfo)
#something else
Now I have created CBV views to create and view them. The CreateView works fine and saves info that can be reviewed in admin, but I cannot get the template to display the data on any other view be it FormView, DetailView or any other, because I get this error:
__call__() missing 1 required keyword-only argument: 'manager'
Request Method: GET
Request URL: http://something
Django Version: 2.0.3
Exception Type: TypeError
Exception Value:
__call__() missing 1 required keyword-only argument: 'manager'
Exception Location: /usr/local/lib/python3.5/dist-packages/django/forms/forms.py in get_initial_for_field, line 494
Python Executable: /usr/bin/python3
Python Version: 3.5.3
Checking the line in forms.py it shows that the function that is not working is:
def get_initial_for_field(self, field, field_name):
"""
Return initial data for field on form. Use initial data from the form
or the field, in that order. Evaluate callable values.
"""
value = self.initial.get(field_name, field.initial)
if callable(value):
value = value() # line 494
return value
Any suggestions? I can query the linked objects via shell and they are saved in the database, so I have no idea how to proceed.
Here is my case, I am using django shell:
python manage.py shell
There are two models: Topic and Entry. I tried to get all entries from Topic which id is 1.
>>> Topic.objects.get(id=1)
<Topic: Chess>
>>> t = Topic.objects.get(id=1)
>>> t.entry_set().all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __call__() missing 1 required keyword-only argument: 'manager'
>>> t.entry_set.all()
<QuerySet [<Entry: Ah okey, so when testing for a console.log (or oth...>]>
>>>
The correct command is: t.entry_set.all(), not t.entry_set().all()
use entry_set instead of entry_set()(wihout brackets )

Resources