Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User defined constraints #996

Open
wants to merge 80 commits into
base: devel
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
782b645
added annotation class
Hemant27031999 Jun 4, 2020
9709974
made some modifications
Hemant27031999 Jun 4, 2020
a7af772
made the complete metadata package
Hemant27031999 Jun 9, 2020
a191413
modified meta_data classes
Hemant27031999 Jun 10, 2020
4ea5b3e
modified classes to look exactly like dictionaries and lists
Hemant27031999 Jun 11, 2020
7795ea6
modified imports and incorporated SBO term in metadata
Hemant27031999 Jun 11, 2020
02345bb
made the classed to inherit from MutableSequence and MutableMapping
Hemant27031999 Jun 13, 2020
4c6c1ca
adding backward compatibility
Hemant27031999 Jun 15, 2020
ff72c55
added instance
Hemant27031999 Jun 15, 2020
989ffe4
work on annotation structure
matthiaskoenig Jun 15, 2020
a4eb840
adding json example
matthiaskoenig Jun 15, 2020
cf38e02
fixed instance2
Hemant27031999 Jun 15, 2020
7d490a4
work on cvterms
matthiaskoenig Jun 15, 2020
024c980
made backward compatible
Hemant27031999 Jun 18, 2020
ff440fb
code review metadata
matthiaskoenig Jun 18, 2020
e4ad484
cleaned the metadata class by putting code in respective classes
Hemant27031999 Jun 21, 2020
2508ac3
new annotation format supported for SBML to cobra model
Hemant27031999 Jun 23, 2020
d5fc54c
added io for json and other formats
Hemant27031999 Jun 24, 2020
c9e904b
added tests for new annotation format
Hemant27031999 Jun 25, 2020
a6e2f8a
updated history
matthiaskoenig Jun 25, 2020
23f9699
fixing broken tests
Hemant27031999 Jun 28, 2020
2f55bbf
commented a few methods
Hemant27031999 Jun 28, 2020
5aae1b0
added equal method inisde metadata classes
Hemant27031999 Jun 29, 2020
d467a14
modified directories paths
Hemant27031999 Jun 30, 2020
e4cc72b
fixed imports and tox tests
Hemant27031999 Jun 30, 2020
32a81da
solved the problem of annotation copy
Hemant27031999 Jul 1, 2020
a07ccaf
new notes format
Hemant27031999 Jul 2, 2020
f69a55c
code refactoring
matthiaskoenig Jul 2, 2020
e4ab40b
modified history, keyvaluepair and notes
Hemant27031999 Jul 4, 2020
8dc96cf
modified tests and imports
Hemant27031999 Jul 5, 2020
a3685d4
modified cvterm class
Hemant27031999 Jul 6, 2020
991123b
small fixes
matthiaskoenig Jul 9, 2020
70b33db
refactored a few names
Hemant27031999 Jul 12, 2020
0e20a91
modified notes documentation
Hemant27031999 Jul 15, 2020
eeee56a
added user defined constraint class
Hemant27031999 Jul 16, 2020
f93723b
example test cases
matthiaskoenig Jul 16, 2020
efcf064
added tests for UserDefinedConstraints
Hemant27031999 Jul 23, 2020
3039344
modified tests
Hemant27031999 Jul 23, 2020
d5dedc9
small modifications
Hemant27031999 Jul 26, 2020
f839755
moved cobra directory to src directory
Hemant27031999 Jul 26, 2020
9704a4b
solved conflicts
Hemant27031999 Jul 26, 2020
211bf48
fixed some tests
Hemant27031999 Jul 26, 2020
1dba21e
fixed conflicts and tests
Hemant27031999 Jul 26, 2020
90c156f
fixed tests
Hemant27031999 Jul 27, 2020
91177cd
added support of group to JSON
Hemant27031999 Jul 27, 2020
1fc7ab2
added support for optional ids in UserDefinedConstraint class
Hemant27031999 Jul 28, 2020
de2398d
added test for json validation function
Hemant27031999 Jul 30, 2020
54809ad
added json schema import requirement
Hemant27031999 Jul 30, 2020
c758bc5
added helper function for UserDefinedConstraint
Hemant27031999 Jul 30, 2020
5c5e2c2
added validate function for json models
Hemant27031999 Jul 30, 2020
0884f4a
added ast tree for parsing constraint expression
Hemant27031999 Aug 5, 2020
0f93cdd
modified json validation function
Hemant27031999 Aug 6, 2020
3da58be
removed python 2 support
Hemant27031999 Aug 6, 2020
8ec5ef2
modified ids in json
Hemant27031999 Aug 6, 2020
d2d8ee9
code refactoring
matthiaskoenig Aug 6, 2020
14a68f5
reformatted code to python 3
Hemant27031999 Aug 9, 2020
80fdcaa
added datetime validation for py3.6
Hemant27031999 Aug 15, 2020
06cb989
modified dict.py
Hemant27031999 Aug 15, 2020
c10f3fa
modified xfail
Hemant27031999 Aug 15, 2020
1747a7b
removed .idea files
Hemant27031999 Aug 15, 2020
14a1415
removed .idea
Hemant27031999 Aug 15, 2020
ba2990c
merged with devel
Hemant27031999 Aug 16, 2020
b04b81a
removed idea
Hemant27031999 Aug 16, 2020
6bae4c0
modified notes string passing
Hemant27031999 Aug 21, 2020
66dd463
modified notes return type
Hemant27031999 Aug 26, 2020
479c2b2
adding dependency for json validation
matthiaskoenig Aug 26, 2020
543d1f8
added .idea files
matthiaskoenig Aug 26, 2020
65e48f1
merged latest devel
matthiaskoenig Aug 26, 2020
564a51a
refactored and cleanup of history
matthiaskoenig Aug 26, 2020
a6aefc5
Intermediate refactoring, breaking changes
matthiaskoenig Aug 26, 2020
42f4838
refactored keyvaluepairs
matthiaskoenig Aug 26, 2020
b3e26cc
cleanup of datetimes
matthiaskoenig Aug 26, 2020
ca9ef48
cleanup metadata
matthiaskoenig Aug 26, 2020
093f799
cleanup dict methods
matthiaskoenig Aug 26, 2020
b5f7516
added to_dict for CVTerm and fixed models
Hemant27031999 Aug 27, 2020
c8b850a
added metadata.ipynb
Hemant27031999 Aug 27, 2020
67d3af1
fixed imports
Hemant27031999 Aug 27, 2020
b951dbd
Merge branch 'devel' into metadata_fbc3_group
Hemant27031999 Aug 27, 2020
e5b3fba
smaller fix to_dict usage
matthiaskoenig Aug 27, 2020
8b2d6dc
modified to_dict for cvterms
Hemant27031999 Aug 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
made the classed to inherit from MutableSequence and MutableMapping
Hemant27031999 committed Jun 13, 2020
commit 02345bb487938c228096cfee791c02a289de9d30
2 changes: 1 addition & 1 deletion cobra/core/__init__.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
from cobra.core.dictlist import DictList
from cobra.core.gene import Gene
from cobra.core.group import Group
from cobra.core.meta_data import *
from cobra.core.metadata import *
from cobra.core.metabolite import Metabolite
from cobra.core.model import Model
from cobra.core.object import Object
8 changes: 0 additions & 8 deletions cobra/core/meta_data/__init__.py

This file was deleted.

8 changes: 8 additions & 0 deletions cobra/core/metadata/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@


from __future__ import absolute_import

from cobra.core.metadata.cvterm import CVTerm
from cobra.core.metadata.history import History
from cobra.core.metadata.keyvaluepair import ListOfKeyValue
from cobra.core.metadata.metadata import MetaData
142 changes: 95 additions & 47 deletions cobra/core/meta_data/cvTerm.py → cobra/core/metadata/cvterm.py
Original file line number Diff line number Diff line change
@@ -7,8 +7,10 @@

from __future__ import absolute_import

from collections.abc import MutableMapping, MutableSequence

class CVTerm(dict):

class CVTerm(MutableMapping):
"""
Class representation of Controlled Vocabulary term inside Annotation.
It will look similar to a dictionary, but will have restrictions on the
@@ -17,28 +19,35 @@ class CVTerm(dict):
Parameters
----------
cvterm : dict
A dictionary that maps the provider to its corresponding CVList
A dictionary type structure that maps the provider to its
corresponding CVList

Attributes
----------
The providers are set as keys for accessing their CVLists

"""

def __init__(self, cvterm={}):
def __init__(self, cvterm=None):
if cvterm is None:
cvterm = {}
self._mapping = dict()
if not isinstance(cvterm, dict):
raise TypeError("The annotation data must be in a dict form")
else:
for key, value in cvterm.items():
if not isinstance(key, str):
raise TypeError("the provider must be of type string")
if isinstance(value, list):
dict.__setitem__(self, key, self.CVList(value))
self._mapping[key] = self.CVList(value)
elif isinstance(value, self.CVList):
self._mapping[key] = value
else:
dict.__setitem__(self, key, value)
raise TypeError("the value passed for key '%s' "
"has invalid format" % key)

def __getitem__(self, key):
return dict.__getitem__(self, key)
return self._mapping[key]

def __setitem__(self, key, value):
"""Make sure that key passed is of type string and value
@@ -47,25 +56,28 @@ def __setitem__(self, key, value):
if not isinstance(key, str):
raise TypeError("The key passed must be a string")
if isinstance(value, list):
dict.__setitem__(self, key, self.CVList(value))
self._mapping[key] = self.CVList(value)
elif isinstance(value, self.CVList):
dict.__setitem__(self, key, value)
self._mapping[key] = key, value
else:
raise TypeError("The value passed does not confirm to CVList type")

def __delitem__(self, key):
dict.__delitem__(self, key)
del self._mapping[key]

def __iter__(self):
return dict.__iter__(self)
return iter(self._mapping)

def __len__(self):
return dict.__len__(self)
return len(self._mapping)

def __str__(self):
return str(self._mapping)

def __contains__(self, x):
return dict.__contains__(self, x)
def __repr__(self):
return '{}'.format(self._mapping)

class CVList(list):
class CVList(MutableSequence):
"""
Class representation of all sets of resources and their nested
annotation corresponding to a given qualifier. It have similar
@@ -79,37 +91,52 @@ class CVList(list):

"""

def __init__(self, cvlist=[]):
def __init__(self, cvlist=None):
if cvlist is None:
cvlist = []
self._sequence = list()
if not isinstance(cvlist, list):
raise TypeError("The resources passed must be inside a list")
for item in cvlist:
if isinstance(item, CVTerm.ExternalResources):
list.append(self, item)
self._sequence.append(item)
elif isinstance(item, dict):
list.append(self, CVTerm.ExternalResources(item))
self._sequence.append(CVTerm.ExternalResources(item))
else:
raise TypeError("All items must confirm to "
"ExternalResources structure")

def __len__(self):
return list.__len__(self)
return len(self._sequence)

def __delitem__(self, index):
list.__delitem__(self, index)
del self._sequence[index]

def insert(self, index, value):
list.insert(self, index, CVTerm.ExternalResources(value))
self._sequence.insert(index, CVTerm.ExternalResources(value))

def append(self, value):
list.append(self, CVTerm.ExternalResources(value))
if isinstance(value, CVTerm.ExternalResources):
self._sequence.append(value)
elif isinstance(value, dict):
self._sequence.append(CVTerm.ExternalResources(value))
else:
raise TypeError("The passed format for setting external"
" resources is invalid.")

def __setitem__(self, index, value):
list.__setitem__(self, index, CVTerm.ExternalResources(value))
self._sequence[index] = CVTerm.ExternalResources(value)

def __getitem__(self, index):
return list.__getitem__(self, index)
return self._sequence[index]

def __str__(self):
return str(self._sequence)

def __repr__(self):
return '{}'.format(self._sequence)

class ExternalResources(dict):
class ExternalResources(MutableMapping):
"""
Class representation of a single set of resources and its nested
annotation. Its a special type of dict with restricted keys and
@@ -133,66 +160,87 @@ class ExternalResources(dict):

"""

ANNOTATION_KEYS = ['resources', 'nested_data']
ANNOTATION_KEYS = ['resources', 'nested_data', 'qualifier_type']
QUALIFIER_RELATION = ['MODEL', 'BIOLOGICAL', 'UNKNOWN']

def __init__(self, data={}):
self._resources = []
self._nested_data = None
def __init__(self, data=None):
if data is None:
data = {}
self._mapping = dict()
if not isinstance(data, dict):
raise TypeError("The value passed must be of type dict.")
for key, value in data.items():
if key not in self.ANNOTATION_KEYS:
raise ValueError("Key '%s' is not allowed. Only "
"allowed keys are 'resource', "
"allowed keys are 'resources', "
"'nested_data'." % key)
if key == 'resources':
if not isinstance(value, list):
raise TypeError("Resources must be put in a list")
dict.__setitem__(self, key, value)
if key == 'nested_data':
self._mapping[key] = value
elif key == 'nested_data':
if isinstance(value, CVTerm):
dict.__setitem__(self, key, value)
self._mapping[key] = value
elif isinstance(value, dict):
dict.__setitem__(self, key, CVTerm(value))
self._mapping[key] = CVTerm(value)
else:
raise TypeError("The nested data structure does "
"not have valid CVTerm format")
elif key == "qualifier_type":
if not isinstance(value, int):
raise TypeError("The value passed for qualifier type "
"must be an integer")
if value == 0 or value == 1:
self._mapping[key] = self.QUALIFIER_RELATION[value]
else:
self._mapping[key] = self.QUALIFIER_RELATION[2]

def __getitem__(self, key):
if key not in self.ANNOTATION_KEYS:
raise ValueError("Key %s is not allowed. Only allowed keys are"
" 'resources', 'nested_data'." % key)
return dict.__getitem__(self, key)
raise ValueError("Key %s is not allowed. Only allowed "
"keys are : 'qualifier_type', 'resources', "
"'nested_data'" % key)
return self._mapping[key]

def __setitem__(self, key, value):
"""Restricting the keys and values that can be set.
Only allowed keys are 'resources' and 'nested_data'
"""
if key not in self.ANNOTATION_KEYS:
raise ValueError("Key %s is not allowed. Only allowed "
"keys are 'resources', 'nested_data'."
% key)
"keys are : 'qualifier_type', 'resources', "
"'nested_data'" % key)
if key == 'resources':
if not isinstance(value, list):
raise TypeError("Resources must be put in a list")
dict.__setitem__(self, key, value)
self._mapping[key] = value
elif key == 'nested_data':
if isinstance(value, CVTerm):
dict.__setitem__(self, key, value)
self._mapping[key] = value
elif isinstance(value, dict):
dict.__setitem__(self, key, CVTerm(value))
self._mapping[key] = CVTerm(value)
else:
raise TypeError("The value passed has invalid format.")
dict.__setitem__(self, key, value)
elif key == "qualifier_type":
if not isinstance(value, int):
raise TypeError("The value passed for qualifier type "
"must be an integer")
if value == 0 or value == 1:
self._mapping[key] = self.QUALIFIER_RELATION[value]
else:
self._mapping[key] = self.QUALIFIER_RELATION[2]

def __delitem__(self, key):
dict.__delitem__(self, key)
del self._mapping[key]

def __iter__(self):
return dict.__iter__(self)
return iter(self._mapping)

def __len__(self):
return dict.__len__(self)
return len(self._mapping)

def __str__(self):
return str(self._mapping)

def __contains__(self, x):
return dict.__contains__(self, x)
def __repr__(self):
return '{}'.format(self._mapping)
133 changes: 81 additions & 52 deletions cobra/core/meta_data/history.py → cobra/core/metadata/history.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
from __future__ import absolute_import

import datetime
from collections.abc import MutableMapping, MutableSequence


# The possible keys inside creator dict
@@ -18,7 +19,7 @@ def validateDate(date_text):
return True


class History(dict):
class History(MutableMapping):
"""
Class representation of history of a given component i.e. creator,
created date and modification dates. It is basically an extended
@@ -48,28 +49,29 @@ class History(dict):

VALID_KEYS = ["creators", "created", "modified"]

def __init__(self, creators=[], created=None, modified=[]):
def __init__(self, creators=None, created=None, modified=None):
if creators is None:
creators = []
dict.__setitem__(self, "creators", self.ListOfCreators(creators))
if modified is None:
modified = []
self._mapping = dict()
self._mapping["creators"] = self.ListOfCreators(creators)
if isinstance(created, str):
validateDate(created)
dict.__setitem__(self, "created", created)
self._mapping["created"] = created
elif created is None:
dict.__setitem__(self, "created", None)
self._mapping["created"] = None
else:
raise TypeError('Only None and string types are possible for '
'"created" date attribute')
if modified is None:
modified = []
dict.__setitem__(self, "modified", self.ModifiedHistory(modified))
self._mapping["modified"] = self.ModifiedHistory(modified)

def __getitem__(self, key):
if key not in self.VALID_KEYS:
raise ValueError("Key %s is not allowed. Only allowed "
"keys are : 'creators', 'created', 'modified'"
% key)
return dict.__getitem__(self, key)
return self._mapping[key]

def __setitem__(self, key, value):
"""Restricting the keys and values that can be set.
@@ -81,96 +83,108 @@ def __setitem__(self, key, value):
" 'value', 'uri'" % key)
if key == "creators":
if isinstance(value, self.ListOfCreators):
dict.__setitem__(self, key, value)
self._mapping[key] = value
elif isinstance(value, list):
dict.__setitem__(self, key, self.ListOfCreators(value))
self._mapping[key] = self.ListOfCreators(value)
else:
raise TypeError("The passed format for creators is invalid")
elif key == "created":
if not isinstance(value, str):
raise TypeError("The date passed must be a string")
else:
validateDate(value)
dict.__setitem__(self, key, value)
self._mapping[key] = value
elif key == "modified":
if isinstance(value, self.ModifiedHistory):
dict.__setitem__(self, key, value)
self._mapping[key] = value
elif isinstance(value, list):
dict.__setitem__(self, key, self.ModifiedHistory(value))
self._mapping[key] = self.ModifiedHistory(value)
else:
raise TypeError("The passed format for modification"
" history is invalid")

def __delitem__(self, key):
dict.__delitem__(self, key)
del self._mapping[key]

def __iter__(self):
return dict.__iter__(self)
return iter(self._mapping)

def __len__(self):
return dict.__len__(self)
return len(self._mapping)

def __str__(self):
return str(self._mapping)

def __contains__(self, x):
return dict.__contains__(self, x)
def __repr__(self):
return '{}'.format(self._mapping)

class ListOfCreators(list):
class ListOfCreators(MutableSequence):
"""A list extension to store each creator's info
Parameters
----------
creators : list containing info about creators
"""

def __init__(self, creators=[]):
def __init__(self, creators=None):
if creators is None:
creators = []
self._sequence = list()
if not isinstance(creators, list):
raise TypeError("The data passed for creators must be "
"inside a list")
else:
for item in creators:
if isinstance(item, History.Creator):
list.append(self, item)
self._sequence.append(item)
elif isinstance(item, dict):
list.append(self, History.Creator(item))
self._sequence.append(History.Creator(item))
else:
raise TypeError("The data passed for creator "
"indexed %s has invalid format"
% creators.index(item, 0,
len(creators)))

def __len__(self):
return list.__len__(self)
return len(self._sequence)

def __delitem__(self, index):
list.__delitem__(self, index)
del self._sequence[index]

def insert(self, index, value):
if isinstance(value, History.Creator):
list.insert(self, index, value)
self._sequence.insert(index, value)
elif isinstance(value, dict):
list.insert(self, index, History.Creator(value))
self._sequence.insert(index, History.Creator(value))
else:
raise TypeError("The data passed has invalid format")

def append(self, value):
if isinstance(value, History.Creator):
list.append(self, value)
self._sequence.append(value)
elif isinstance(value, dict):
list.append(self, History.Creator(value))
self._sequence.append(History.Creator(value))
else:
raise TypeError("The data passed has invalid format")

def __setitem__(self, index, value):
if isinstance(value, History.Creator):
list.__setitem__(self, index, value)
self._sequence[index] = value
elif isinstance(value, dict):
list.__setitem__(self, index, History.Creator(value))
self._sequence[index] = History.Creator(value)
else:
raise TypeError("The data passed has invalid format")

def __getitem__(self, index):
return list.__getitem__(self, index)
return self._sequence[index]

class Creator(dict):
def __str__(self):
return str(self._sequence)

def __repr__(self):
return '{}'.format(self._sequence)

class Creator(MutableMapping):
"""A dictionary extension to store basic info of this component
creator
@@ -185,26 +199,29 @@ class Creator(dict):
}
"""

def __init__(self, creator_dict={}):
def __init__(self, creator_dict=None):
if creator_dict is None:
creator_dict = {}
self._mapping = dict()
if not isinstance(creator_dict, dict):
raise TypeError("The value passed for creator must "
"be of type dict.")
for key in CREATOR_KEYS:
if key not in creator_dict:
dict.__setitem__(self, key, None)
self._mapping[key] = None
else:
if not isinstance(creator_dict[key], str):
raise TypeError("All the values passed must "
"be of type string.")
else:
dict.__setitem__(self, key, creator_dict[key])
self._mapping[key] = creator_dict[key]

def __getitem__(self, key):
if key not in CREATOR_KEYS:
raise ValueError("Key %s is not allowed. only allowed "
"keys are 'first_name', 'last_name', "
"'email', 'organization_name'." % key)
return dict.__getitem__(self, key)
return self._mapping[key]

def __setitem__(self, key, value):
if key not in CREATOR_KEYS:
@@ -213,21 +230,24 @@ def __setitem__(self, key, value):
"'email', 'organization_name'." % key)
if not isinstance(value, str):
raise TypeError("Value passed must be of type string.")
dict.__setitem__(self, key, value)
self._mapping[key] = value

def __delitem__(self, key):
dict.__delitem__(self, key)
del self._mapping[key]

def __iter__(self):
return dict.__iter__(self)
return iter(self._mapping)

def __len__(self):
return dict.__len__(self)
return len(self._mapping)

def __str__(self):
return str(self._mapping)

def __contains__(self, x):
return dict.__contains__(self, x)
def __repr__(self):
return '{}'.format(self._mapping)

class ModifiedHistory(list):
class ModifiedHistory(MutableSequence):
"""A list extension to store modification dates. Only Restricted
type of entries are possible.
@@ -237,32 +257,41 @@ class ModifiedHistory(list):
8601 format
"""

def __init__(self, modifiedList=[]):
def __init__(self, modifiedList=None):
if modifiedList is None:
modifiedList = []
self._sequence = list()
if not isinstance(modifiedList, list):
raise TypeError("The dates passed must be inside a list")
for item in modifiedList:
if not isinstance(item, str):
raise ValueError("Each date must be of type string")
validateDate(item)
list.append(self, item)
self._sequence.append(item)

def __len__(self):
return list.__len__(self)
return len(self._sequence)

def __delitem__(self, index):
list.__delitem__(self, index)
del self._sequence[index]

def insert(self, index, value):
validateDate(value)
list.insert(self, index, value)
self._sequence.insert(index, value)

def append(self, value):
validateDate(value)
list.append(self, value)
self._sequence.append(value)

def __setitem__(self, index, value):
validateDate(value)
list.__setitem__(self, index, value)
self._sequence[index] = value

def __getitem__(self, index):
return list.__getitem__(self, index)
return self._sequence[index]

def __str__(self):
return str(self._sequence)

def __repr__(self):
return '{}'.format(self._sequence)
Original file line number Diff line number Diff line change
@@ -2,68 +2,79 @@

from __future__ import absolute_import

from collections.abc import MutableMapping, MutableSequence

class ListOfKeyValue(list):

class ListOfKeyValue(MutableSequence):
"""A list extension to store key-value pairs
Parameters
----------
creators : list key-value pair data
"""

def __init__(self, keyvaluelist=[]):
def __init__(self, keyvaluelist=None):
if keyvaluelist is None:
keyvaluelist = []
self._sequence = list()
if not isinstance(keyvaluelist, list):
raise TypeError("The data passed for ListOfKeyValue "
"must be inside a list")
else:
for item in keyvaluelist:
if isinstance(item, self.KeyValuePair):
list.append(self, item)
self._sequence.append(item)
elif isinstance(item, dict):
list.append(self, self.KeyValuePair(item))
self._sequence.append(self.KeyValuePair(item))
else:
raise TypeError("The data passed for KeyValuepair "
"indexed %s has invalid format"
% keyvaluelist.index(item, 0,
len(keyvaluelist)))

def __len__(self):
return list.__len__(self)
return len(self._sequence)

def __delitem__(self, index):
list.__delitem__(self, index)
del self._sequence[index]

def insert(self, index, value):
if isinstance(value, self.KeyValuePair):
list.insert(self, index, value)
self._sequence.insert(index, value)
elif isinstance(value, dict):
list.insert(self, index, self.KeyValuePair(value))
self._sequence.insert(index, self.KeyValuePair(value))
else:
raise TypeError("The data passed for KeyValuePair "
"has invalid format")

def append(self, value):
if isinstance(value, self.KeyValuePair):
list.append(self, value)
self._sequence.append(value)
elif isinstance(value, dict):
list.append(self, self.KeyValuePair(value))
self._sequence.append(self.KeyValuePair(value))
else:
raise TypeError("The data passed for KeyValuePair "
"has invalid format")

def __setitem__(self, index, value):
if isinstance(value, self.KeyValuePair):
list.__setitem__(self, index, value)
self._sequence[index] = value
elif isinstance(value, dict):
list.__setitem__(self, index, self.KeyValuePair(value))
self._sequence[index] = self.KeyValuePair(value)
else:
raise TypeError("The data passed for KeyValuePair "
"has invalid format")

def __getitem__(self, index):
return list.__getitem__(self, index)
return self._sequence[index]

def __str__(self):
return str(self._sequence)

class KeyValuePair(dict):
def __repr__(self):
return '{}'.format(self._sequence)

class KeyValuePair(MutableMapping):
"""
Class representation of key-value pairs supported in fba-v3
@@ -83,7 +94,10 @@ class KeyValuePair(dict):

VALID_KEYS = ["id", "name", "key", "value", "uri"]

def __init__(self, data={}):
def __init__(self, data=None):
if data is None:
data = {}
self._mapping = dict()
for key, value in data.items():
if key not in self.VALID_KEYS:
raise ValueError("'%s' is not allowed. Only possible "
@@ -93,17 +107,17 @@ def __init__(self, data={}):
raise TypeError("All keys must be of type string")
if not isinstance(value, str):
raise TypeError("All values must be of type string")
dict.__setitem__(self, key, value)
self._mapping[key] = value
for key in self.VALID_KEYS:
if key not in data:
dict.__setitem__(self, key, None)
self._mapping[key] = None

def __getitem__(self, key):
if key not in self.VALID_KEYS:
raise ValueError("Key %s is not allowed. Only allowed "
"keys are : 'id', 'name', 'key',"
" 'value', 'uri'" % key)
return dict.__getitem__(self, key)
return self._mapping[key]

def __setitem__(self, key, value):
"""Restricting the keys and values that can be set.
@@ -115,16 +129,19 @@ def __setitem__(self, key, value):
" 'value', 'uri'" % key)
if not isinstance(value, str):
raise TypeError("The value must be of type string")
dict.__setitem__(self, key, value)
self._mapping[key] = value

def __delitem__(self, key):
dict.__delitem__(self, key)
del self._mapping[key]

def __iter__(self):
return dict.__iter__(self)
return iter(self._mapping)

def __len__(self):
return dict.__len__(self)
return len(self._mapping)

def __str__(self):
return str(self._mapping)

def __contains__(self, x):
return dict.__contains__(self, x)
def __repr__(self):
return '{}'.format(self._mapping)
Original file line number Diff line number Diff line change
@@ -2,12 +2,14 @@

from __future__ import absolute_import

from cobra.core.meta_data.cvTerm import CVTerm
from cobra.core.meta_data.history import History
from cobra.core.meta_data.keyValuePair import ListOfKeyValue
from collections.abc import MutableMapping

from cobra.core.metadata.cvterm import CVTerm
from cobra.core.metadata.history import History
from cobra.core.metadata.keyvaluepair import ListOfKeyValue

class MetaData(dict):

class MetaData(MutableMapping):
"""Class representation of the meta-data of the component.
It is a combination of three classes i.e CVTerm, History
and KeyValuePair class.
@@ -28,50 +30,50 @@ class MetaData(dict):
VALID_KEYS = ["sbo", "cvTerms", "history", "listofKeyValue"]

def __init__(self, cvterm=None, history=None, listofKeyValue=None):
self._mapping = dict()
# setting the cvterm
if cvterm is None:
dict.__setitem__(self, "cvTerms", CVTerm())
self._mapping["cvTerms"] = CVTerm()
elif isinstance(cvterm, CVTerm):
dict.__setitem__(self, "cvTerms", cvterm)
self._mapping["cvTerms"] = cvterm
elif isinstance(cvterm, dict):
dict.__setitem__(self, "cvTerms", CVTerm(cvterm))
self._mapping["cvTerms"] = CVTerm(cvterm)
else:
raise TypeError("Invalid format passed for cvterm")
# setting the history of the component
if history is None:
dict.__setitem__(self, "history", History())
self._mapping["history"] = History()
elif isinstance(history, History):
dict.__setitem__(self, "history", history)
self._mapping["history"] = history
elif isinstance(history, dict):
if "creators" not in history:
history["creators"] = []
if "created" not in history:
history["created"] = None
if "modified" not in history:
history["modified"] = []
dict.__setitem__(self, "history", History(history["creators"],
history["created"],
history["modified"]))
self._mapping["history"] = History(history["creators"],
history["created"],
history["modified"])
else:
raise TypeError("Invalid format passed for history")
# setting the list of key-value pair
if listofKeyValue is not None:
if isinstance(listofKeyValue, ListOfKeyValue):
dict.__setitem__(self, "listofKeyValue", listofKeyValue)
self._mapping["listofKeyValue"] = listofKeyValue
elif isinstance(listofKeyValue, list):
dict.__setitem__(self, "listofKeyValue",
ListOfKeyValue(listofKeyValue))
self._mapping["listofKeyValue"] = ListOfKeyValue(listofKeyValue)
else:
raise TypeError("Key value pairs must be passed in a list")
else:
dict.__setitem__(self, "listofKeyValue", ListOfKeyValue())
self._mapping["listofKeyValue"] = ListOfKeyValue()

def __getitem__(self, key):
if key not in self.VALID_KEYS:
raise ValueError("Key %s is not allowed. Only allowed "
"keys are : 'sbo', 'cvTerms', 'history', "
"'listofKeyValue'" % key)
return dict.__getitem__(self, key)
return self._mapping[key]

def __setitem__(self, key, value):
"""Restricting the keys and values that can be set.
@@ -84,43 +86,45 @@ def __setitem__(self, key, value):
"'listofKeyValue'" % key)
if key == "cvTerms":
if isinstance(value, CVTerm):
dict.__setitem__(self, "cvTerms", value)
self._mapping["cvTerms"] = value
elif isinstance(value, dict):
dict.__setitem__(self, "cvTerms", CVTerm(value))
self._mapping["cvTerms"] = CVTerm(value)
else:
raise TypeError("This passed format for cvterm is invalid")
elif key == "history":
if isinstance(history, History):
dict.__setitem__(self, "history", history)
self._mapping["history"] = history
elif isinstance(history, dict):
if "creators" not in history:
history["creators"] = []
if "created" not in history:
history["created"] = None
if "modified" not in history:
history["modified"] = []
dict.__setitem__(self, "history", History(history["creators"],
history["created"],
history["modified"]))
self._mapping["history"] = History(history["creators"],
history["created"],
history["modified"])
elif key == "listofKeyValue":
if isinstance(listofKeyValue, ListOfKeyValue):
dict.__setitem__(self, "listofKeyValue", listofKeyValue)
self._mapping["listofKeyValue"] = listofKeyValue
elif isinstance(listofKeyValue, list):
dict.__setitem__(self, "listofKeyValue",
ListOfKeyValue(listofKeyValue))
self._mapping["listofKeyValue"] = ListOfKeyValue(listofKeyValue)
else:
raise TypeError("Key value pairs must be passed in a list")
elif key == "sbo":
dict.__setitem__(self, "sbo", value)
self._mapping["sbo"] = value

def __delitem__(self, key):
dict.__delitem__(self, key)
del self._mapping[key]

def __iter__(self):
return dict.__iter__(self)
return iter(self._mapping)

def __len__(self):
return dict.__len__(self)
return len(self._mapping)

def __str__(self):
return str(self._mapping)

def __contains__(self, x):
return dict.__contains__(self, x)
def __repr__(self):
return '{}'.format(self._mapping)
2 changes: 1 addition & 1 deletion cobra/core/object.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

from six import string_types

from cobra.core.meta_data import MetaData
from cobra.core.metadata import MetaData


class Object(object):