Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F86469716
class_spec.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Oct 6, 16:36
Size
11 KB
Mime Type
text/x-python
Expires
Tue, Oct 8, 16:36 (2 d)
Engine
blob
Format
Raw Data
Handle
21428589
Attached To
rNIETZSCHEPYTHON nietzsche-python
class_spec.py
View Options
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" This is an abstract class for all classes that are semantically relevant.
"""
# Copyright (C) University of Basel 2019 {{{1
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/> 1}}}
__author__
=
"Christian Steiner"
__maintainer__
=
__author__
__copyright__
=
'University of Basel'
__email__
=
"christian.steiner@unibas.ch"
__status__
=
"Development"
__license__
=
"GPL v3"
__version__
=
"0.0.1"
import
abc
import
inspect
import
warnings
class
UnSemanticClass
:
"""
Subclasses of this class are not semantically relevant, even if their superclasses are.
"""
pass
class
SemanticClass
(
metaclass
=
abc
.
ABCMeta
):
"""
This is an abstract class for all classes that are semantically relevant.
"""
HAS_PART
=
'has_part'
HAS_SEQNUM
=
'has_seqnum'
SINGLE_VALUE
=
1
LIST
=
-
99
CLASS_KEY
=
'class'
CARDINALITY
=
"cardinality"
CARDINALITY_RESTRICTION
=
"cardinality_restriction"
HAS_HOMOTYPIC_PARTS_URL_STRING
=
'http://www.nie.org/ontology/homotypic#hasHomotypicParts'
HOMOTYPIC_HAS_TEXT_URL_STRING
=
'http://www.nie.org/ontology/homotypic#hasText'
STOFF_STYLE_HAS_CSS_URL_STRING
=
'http://www.nie.org/ontology/standoff#styleHasCSS'
PROPERTY_NAME
=
"name"
PROPERTY_LABEL
=
"label"
PROPERTY_COMMENT
=
"comment"
PROPERTIES_KEY
=
"properties"
SUBCLASS_OF
=
"rdfs:subClassOf"
SUBPROPERTYOF
=
"subPropertyOf"
SUPER_CLASSES_DICT
=
{
'http://www.nie.org/ontology/homotypic'
:
'HomotypicEntity'
,
'http://www.nie.org/ontology/standoff'
:
'Style'
}
SUPER_PROPERTY
=
"super_property"
THIS
=
"this"
TYPE
=
"type"
@classmethod
def
create_semantic_property_dictionary
(
cls
,
property_key
,
class_type
,
cardinality
=
0
,
cardinality_restriction
=
'cardinality'
,
name
=
''
,
label
=
''
,
comment
=
''
,
subPropertyOf
=
''
)
->
dict
:
"""Create a semantic property dicitonary.
Here is how to make a subproperty:
Pass the IRI of the super property as subPropertyOf=IRI,
be sure that base_uri of IRI (as key) and Class identifier of super class (as value) are in cls.SUPER_CLASSES_DICT,
then call cls.return_dictionary_after_updating_super_classes -> it will subclass the class that owns the subproperty
to the super class.
:return: semantic property dicitonary (dict)
"""
property_content
=
{
SemanticClass
.
CLASS_KEY
:
class_type
}
if
cardinality
>
0
:
property_content
.
update
({
SemanticClass
.
CARDINALITY
:
cardinality
})
property_content
.
update
({
SemanticClass
.
CARDINALITY_RESTRICTION
:
cardinality_restriction
})
if
name
!=
''
:
property_content
.
update
({
SemanticClass
.
PROPERTY_NAME
:
name
})
if
label
!=
''
:
property_content
.
update
({
SemanticClass
.
PROPERTY_LABEL
:
label
})
if
comment
!=
''
:
property_content
.
update
({
SemanticClass
.
PROPERTY_COMMENT
:
comment
})
if
subPropertyOf
!=
''
:
property_content
.
update
({
SemanticClass
.
SUBPROPERTYOF
:
subPropertyOf
})
return
{
property_key
:
property_content
}
@classmethod
def
get_class_dictionary
(
cls
):
"""Creates and returns a class_dictionary with the keys cls.THIS [, cls.SUBCLASS_OF, cls.TYPE].
"""
class_dict
=
{
cls
.
THIS
:
cls
}
if
cls
.
__dict__
.
get
(
'OWL_EQUIVALENTCLASSES'
)
and
len
(
cls
.
OWL_EQUIVALENTCLASSES
)
>
0
:
class_dict
.
update
({
'owl:equivalentClass'
:
cls
.
OWL_EQUIVALENTCLASSES
})
if
cls
.
__dict__
.
get
(
'RDFS_SUBCLASSOF_LIST'
)
and
len
(
cls
.
RDFS_SUBCLASSOF_LIST
)
>
0
:
class_dict
.
update
({
cls
.
SUBCLASS_OF
:
cls
.
RDFS_SUBCLASSOF_LIST
})
else
:
direct_super_class
=
inspect
.
getclasstree
([
cls
],
unique
=
True
)[
0
][
0
]
if
issubclass
(
direct_super_class
,
SemanticClass
)
and
direct_super_class
!=
SemanticClass
:
class_dict
.
update
({
cls
.
TYPE
:
direct_super_class
})
return
class_dict
def
get_name_and_id
(
self
):
"""Return an identification for object as 2-tuple.
"""
id
=
0
if
'id'
in
self
.
__dict__
.
keys
():
id
=
self
.
id
elif
'number'
in
self
.
__dict__
.
keys
():
id
=
self
.
number
elif
'title'
in
self
.
__dict__
.
keys
():
id
=
self
.
title
.
replace
(
' '
,
'_'
)
return
type
(
self
)
.
__name__
,
id
def
_get_list_of_type
(
self
,
list_type
):
"""Return list of type == list_type if list is not empty.
"""
list_of_type
=
[]
for
object_list
in
[
list_obj
for
list_obj
in
self
.
__dict__
.
values
()
\
if
type
(
list_obj
)
==
list
]:
if
len
(
object_list
)
>
0
and
type
(
object_list
[
0
])
==
list_type
:
return
object_list
return
list_of_type
def
get_object_from_list_with_id
(
self
,
object_type
,
object_id
):
"""Return object from list if object has id == object_id,
None if not found.
"""
list_with_object
=
[
item
for
item
in
self
.
_get_list_of_type
(
object_type
)
\
if
item
.
id
==
object_id
]
if
len
(
list_with_object
)
>
0
:
return
list_with_object
[
0
]
return
None
@classmethod
def
get_cls_hasPart_objectCls_dictionaries
(
cls
,
object_cls
,
xpath
,
object_seqnum_xpath
=
None
,
cardinality
=
0
,
cardinality_restriction
=
'minCardinality'
):
"""Return a dictionary containing the information for creating a class that can act
as an intermediary between cls and a number of object_cls if object_cls has
a position in a sequence of object_classes that belong to cls.
"""
part_name
=
object_cls
.
__name__
+
'Part'
has_part_name
=
object_cls
.
__name__
.
lower
()
+
'PartHas'
+
object_cls
.
__name__
has_seqnum_name
=
object_cls
.
__name__
.
lower
()
+
'HasSeqNum'
if
object_seqnum_xpath
is
None
:
object_seqnum_xpath
=
xpath
+
'/@id'
object_part_dictionary
=
{
'class'
:
object_cls
,
'cardinality'
:
1
,
'xpath'
:
xpath
,
\
'name'
:
has_part_name
,
'label'
:
'{0} has a {1}'
.
format
(
part_name
,
object_cls
.
__name__
),
\
'comment'
:
'{0} has a part, that is a {1}'
.
format
(
part_name
,
object_cls
.
__name__
)}
object_seqnum_dictionary
=
{
'class'
:
int
,
'cardinality'
:
1
,
'xpath'
:
object_seqnum_xpath
,
\
'name'
:
has_seqnum_name
,
'label'
:
'{0} has a sequence number'
.
format
(
part_name
),
\
'comment'
:
'{0} has a part, that stands in a sequence with this number'
.
format
(
part_name
,
object_cls
.
__name__
)}
object_dictionary
=
{
'class_name'
:
part_name
,
SemanticClass
.
HAS_PART
:
object_part_dictionary
,
SemanticClass
.
HAS_SEQNUM
:
object_seqnum_dictionary
,
\
'label'
:
'{0} part'
.
format
(
object_cls
.
__name__
.
lower
()),
\
'comment'
:
'This class servers as a intermediary between {0} and {1}. {0} has some {1} in a specific sequence.'
.
format
(
cls
.
__name__
,
object_cls
.
__name__
)}
dictionary
=
{
'flag'
:
'ordered_list'
,
'class'
:
object_dictionary
,
'cardinality'
:
cardinality
,
'cardinality_restriction'
:
cardinality_restriction
,
'xpath'
:
xpath
,
\
'name'
:
cls
.
__name__
.
lower
()
+
'Has'
+
part_name
,
'label'
:
'{0} has a part that connects it with a {1}'
.
format
(
cls
.
__name__
,
object_cls
.
__name__
),
\
'comment'
:
'{0} has a part that connects it with a {1}, that has a position in a sequence of {1}'
.
format
(
cls
.
__name__
,
object_cls
.
__name__
)}
return
dictionary
@classmethod
@abc.abstractmethod
def
get_semantic_dictionary
(
cls
):
"""Creates a semantic dictionary with cls.CLASS_KEY and cls.PROPERTIES_KEY as its keys.
The class-key points to a class_dictionary with the keys: cls.THIS [, cls.SUBCLASS_OF, cls.TYPE].
Create initial dictionary using cls.get_class_dictionary():
dictionary = { cls.CLASS_KEY: cls.get_class_dictionary(), cls.PROPERTIES_KEY: {} }
The properties_key points to a properties_dictionary with semantically relevant keys
of self.__dict__ as keys. Use cls.create_semantic_property_dictionary(...) in order to
add a property dictionary for each property as follows:
dictionary[cls.PROPERTIES_KEY].update(cls.create_semantic_property_dictionary(property_key, ...))
Return dictionary by using:
cls.return_dictionary_after_updating_super_classes(dictionary)
"""
pass
@classmethod
def
return_dictionary_after_updating_super_classes
(
cls
,
dictionary
):
"""Return semantic dictionary after updating super classes if necessary.
"""
if
cls
.
PROPERTIES_KEY
not
in
dictionary
.
keys
():
return
dictionary
subproperty_base_uri_set
=
set
(
value
.
get
(
cls
.
SUBPROPERTYOF
)
.
split
(
'#'
)[
0
]
\
for
value
in
dictionary
[
cls
.
PROPERTIES_KEY
]
.
values
()
\
if
bool
(
value
.
get
(
cls
.
SUBPROPERTYOF
))
)
for
sub_property_base
in
subproperty_base_uri_set
:
if
bool
(
cls
.
SUPER_CLASSES_DICT
.
get
(
sub_property_base
))
\
and
(
\
cls
.
SUBCLASS_OF
not
in
dictionary
[
cls
.
CLASS_KEY
]
.
keys
()
\
or
len
(
dictionary
[
cls
.
CLASS_KEY
][
cls
.
SUBCLASS_OF
])
==
0
\
or
sub_property_base
+
'#'
+
cls
.
SUPER_CLASSES_DICT
.
get
(
sub_property_base
)
not
in
dictionary
[
cls
.
CLASS_KEY
][
cls
.
SUBCLASS_OF
]
\
):
subclass_list
=
dictionary
[
cls
.
CLASS_KEY
][
cls
.
SUBCLASS_OF
]
\
if
cls
.
SUBCLASS_OF
in
dictionary
[
cls
.
CLASS_KEY
]
.
keys
()
\
and
len
(
dictionary
[
cls
.
CLASS_KEY
]
.
get
(
cls
.
SUBCLASS_OF
))
>
0
\
else
[]
subclass_list
.
append
(
sub_property_base
+
'#'
+
cls
.
SUPER_CLASSES_DICT
.
get
(
sub_property_base
))
dictionary
[
cls
.
CLASS_KEY
]
.
update
({
cls
.
SUBCLASS_OF
:
subclass_list
})
return
dictionary
def
__repr__
(
self
)
->
str
:
"""Return a representation of all semantically relevant properties.
"""
data_string
=
self
.
__str__
()
return
f
'<{data_string}>'
def
__str__
(
self
)
->
str
:
"""Return a str of all semantically relevant properties.
"""
name
=
type
(
self
)
.
__name__
data
=
[]
for
key
in
self
.
get_semantic_dictionary
()[
self
.
PROPERTIES_KEY
]
.
keys
():
if
key
in
self
.
__dict__
.
keys
()
and
\
(
self
.
__dict__
[
key
]
!=
None
or
(
type
(
self
.
__dict__
[
key
])
==
list
and
len
(
self
.
__dict__
[
key
])
>
0
)):
data
.
append
(
f
'{key}: {self.__dict__[key]}'
)
data_string
=
', '
.
join
(
data
)
return
f
'{name} {data_string}'
Event Timeline
Log In to Comment