def validate(self, obj, value): """ Determine if :obj:`value` is a valid value Args: obj (:obj:`Model`): class being validated value (:obj:`numpy.array`): value of attribute to validate Returns: :obj:`core.InvalidAttribute` or None: None if attribute is valid, other return list of errors as an instance of :obj:`core.InvalidAttribute` """ errors = [] if value is not None and not isinstance( value, Bio.SeqFeature.FeatureLocation): errors.append( 'Value must be an instance of `Bio.SeqFeature.FeatureLocation`' ) if self.primary and value is None: errors.append( '{} value for primary attribute cannot be empty'.format( self.__class__.__name__)) if errors: return core.InvalidAttribute(self, errors) return None
def deserialize(self, value): """ Deserialize value Args: value (:obj:`str`): semantically equivalent representation Returns: :obj:`tuple` of :obj:`numpy.array`, :obj:`core.InvalidAttribute` or :obj:`None`: tuple of cleaned value and cleaning error """ if value is None or value == '': value = None error = None elif isinstance(value, str): start, end, strand = map(int, value.split(',')) value = Bio.SeqFeature.FeatureLocation(start, end, strand) error = None elif isinstance(value, (list, tuple)): stand, end, strand = value value = Bio.SeqFeature.FeatureLocation(stand, end, strand) error = None elif isinstance(value, Bio.SeqFeature.FeatureLocation): error = None else: value = None error = core.InvalidAttribute(self, [( 'FeatureLocAttribute must be None, an empty string, ' 'a comma-separated string representation of a tuple, a tuple, a list, ' 'or a Bio.SeqFeature.FeatureLocation')]) return (value, error)
def test_SymbolicBasicAttribute(self): class Node(core.Model): value = obj_tables.math.symbolic.SymbolicBasicAttribute() attr = Node.Meta.attributes['value'] # constructor attr2 = obj_tables.math.symbolic.SymbolicBasicAttribute(default=None) self.assertEqual(attr2.get_default(), None) attr2 = obj_tables.math.symbolic.SymbolicBasicAttribute(default=sympy.Basic('x')) self.assertEqual(attr2.get_default(), sympy.Basic('x')) with self.assertRaisesRegex(ValueError, 'Default must be a '): obj_tables.math.symbolic.SymbolicBasicAttribute(default='x') # deserialize self.assertEqual(attr.deserialize(''), (None, None)) self.assertEqual(attr.deserialize(None), (None, None)) self.assertEqual(attr.deserialize('x'), (sympy.Basic('x'), None)) # serialize self.assertEqual(attr.serialize(''), '') self.assertEqual(attr.serialize(None), '') self.assertEqual(attr.serialize(sympy.Basic('x')), 'x') # deserialize + serialize self.assertEqual(attr.serialize(attr.deserialize('')[0]), '') self.assertEqual(attr.serialize(attr.deserialize(None)[0]), '') self.assertEqual(attr.serialize(attr.deserialize('x')[0]), 'x') # validate node = Node() self.assertEqual(attr.validate(node, ''), None) self.assertEqual(attr.validate(node, None), None) self.assertEqual(attr.validate(node, sympy.Basic('x')), None) self.assertNotEqual(attr.validate(node, 'x'), None) with mock.patch.object(core.Attribute, 'validate', return_value=core.InvalidAttribute(None, [])): obj = None attr2 = obj_tables.math.symbolic.SymbolicBasicAttribute() self.assertEqual(attr2.validate(obj, None), None) attr2 = obj_tables.math.symbolic.SymbolicBasicAttribute(primary=True) self.assertNotEqual(attr2.validate(node, ''), None) self.assertNotEqual(attr2.validate(node, None), None) # validate_unique nodes = [Node(), Node()] self.assertEqual(attr.validate_unique(nodes, [sympy.Basic('x'), sympy.Basic('y')]), None) self.assertNotEqual(attr.validate_unique(nodes, [sympy.Basic('x'), sympy.Basic('x')]), None) # to/from JSON self.assertEqual(attr.to_builtin(None), None) self.assertEqual(attr.to_builtin(sympy.Basic('x')), 'x') self.assertEqual(attr.from_builtin(None), None) self.assertEqual(attr.from_builtin('x'), sympy.Basic('x')) self.assertEqual(attr.from_builtin(attr.to_builtin(sympy.Basic('x'))), sympy.Basic('x'))
def validate(self, obj, value): """ Determine if :obj:`value` is a valid value Args: obj (:obj:`Model`): class being validated value (:obj:`Bio.motifs.matrix.FrequencyPositionMatrix`): value of attribute to validate Returns: :obj:`core.InvalidAttribute` or :obj:`None`: None if attribute is valid, otherwise return list of errors as an instance of :obj:`core.InvalidAttribute` """ if value is not None and not isinstance( value, Bio.motifs.matrix.FrequencyPositionMatrix): return core.InvalidAttribute(self, [ 'Value must be an instance of `Bio.motifs.matrix.FrequencyPositionMatrix`' ]) return None
def validate(self, obj, value): """ Determine if :obj:`value` is a valid value Args: obj (:obj:`Model`): class being validated value (:obj:`Bio.Seq.Seq`): value of attribute to validate Returns: :obj:`core.InvalidAttribute` or None: None if attribute is valid, other return list of errors as an instance of :obj:`core.InvalidAttribute` """ errors = [] if value is not None: if not isinstance(value, Bio.Seq.Seq): errors.append('Value must be an instance of `Bio.Seq.Seq`') elif self.alphabet and ( value.alphabet.__class__ != self.alphabet.__class__ or value.alphabet.letters != self.alphabet.letters or value.alphabet.size != self.alphabet.size): errors.append( 'The alphabet of value must be an instance of `{}`'.format( self.alphabet.__class__.__name__)) if self.min_length and (not value or len(value) < self.min_length): errors.append('Value must be at least {:d} characters'.format( self.min_length)) if self.max_length and value and len(value) > self.max_length: errors.append('Value must be less than {:d} characters'.format( self.max_length)) if self.primary and (not value or len(value) == 0): errors.append( '{} value for primary attribute cannot be empty'.format( self.__class__.__name__)) if errors: return core.InvalidAttribute(self, errors) return None
def deserialize(self, values, objects, decoded=None): """ Deserialize value Args: values (:obj:`object`): String representation of related objects objects (:obj:`dict`): dictionary of objects, grouped by model decoded (:obj:`dict`, optional): dictionary of objects that have already been decoded Returns: :obj:`tuple` of :obj:`object`, :obj:`core.InvalidAttribute` or :obj:`None`: tuple of cleaned value and cleaning error """ if values in [None, '']: return ([], None) try: tree = self.parser.parse(values) self.Transformer = self.Transformer or self.gen_transformer(self.related_class) transformer = self.Transformer(objects) result = transformer.transform(tree) return (result, None) except lark.exceptions.LarkError as err: return (None, core.InvalidAttribute(self, [str(err)]))
def deserialize(self, value): """ Deserialize value Args: value (:obj:`str`): string representation Returns: :obj:`tuple` of :obj:`Bio.motifs.matrix.FrequencyPositionMatrix`, :obj:`core.InvalidAttribute` or :obj:`None`: tuple of cleaned value and cleaning error """ if value: try: dict_value = json.loads(value) alphabet = dict_value['_alphabet'] dict_value.pop('_alphabet') return (Bio.motifs.matrix.FrequencyPositionMatrix( alphabet, dict_value), None) except Exception as error: return (None, core.InvalidAttribute(self, [str(error)])) else: return (None, None)
def test(self): # constructor attr = obj_tables.math.numeric.ArrayAttribute() self.assertEqual(attr.get_default(), None) attr = obj_tables.math.numeric.ArrayAttribute( default=numpy.array([1, 2])) numpy.testing.assert_equal(attr.get_default(), numpy.array([1, 2])) with self.assertRaisesRegex( ValueError, '`default` must be a `numpy.array` or `None`'): obj_tables.math.numeric.ArrayAttribute(default=[1, 2]) with self.assertRaisesRegex( ValueError, '`min_length` must be a non-negative integer'): obj_tables.math.numeric.ArrayAttribute(min_length=-1) with self.assertRaisesRegex( ValueError, '`max_length` must be an integer greater than or equal to `min_length`' ): obj_tables.math.numeric.ArrayAttribute(min_length=10, max_length=5) # deserialize attr = obj_tables.math.numeric.ArrayAttribute() self.assertEqual(attr.deserialize(None), (None, None)) self.assertEqual(attr.deserialize(''), (None, None)) numpy.testing.assert_equal(attr.deserialize('[1, 2, 3]'), (numpy.array([1, 2, 3]), None)) numpy.testing.assert_equal(attr.deserialize((1, 2, 3)), (numpy.array([1, 2, 3]), None)) numpy.testing.assert_equal(attr.deserialize([1., 2., 3.]), (numpy.array([1., 2., 3.]), None)) numpy.testing.assert_equal(attr.deserialize(numpy.array([1., 2., 3.])), (numpy.array([1., 2., 3.]), None)) attr = obj_tables.math.numeric.ArrayAttribute(default=numpy.ones((1, 1))) self.assertEqual(attr.deserialize(None), (None, None)) self.assertEqual(attr.deserialize(''), (None, None)) numpy.testing.assert_equal( attr.deserialize('[1, 2, 3]'), (numpy.array([1, 2, 3], numpy.float64), None)) numpy.testing.assert_equal(attr.deserialize( (1, 2, 3)), (numpy.array([1, 2, 3], numpy.float64), None)) numpy.testing.assert_equal(attr.deserialize( [1, 2, 3]), (numpy.array([1, 2, 3], numpy.float64), None)) numpy.testing.assert_equal(attr.deserialize(numpy.array( [1, 2, 3])), (numpy.array([1., 2., 3.], numpy.float64), None)) self.assertNotEqual(attr.deserialize('x')[1], None) self.assertNotEqual(attr.deserialize(1.)[1], None) # validate attr = obj_tables.math.numeric.ArrayAttribute() self.assertEqual(attr.validate(None, None), None) self.assertNotEqual(attr.validate(None, []), None) attr = obj_tables.math.numeric.ArrayAttribute( default=numpy.array([1., 2.], numpy.float64)) self.assertNotEqual( attr.validate(None, numpy.array([1, 2], numpy.int64)), None) attr = obj_tables.math.numeric.ArrayAttribute(min_length=2, max_length=5) self.assertEqual(attr.validate(None, numpy.array([1, 2])), None) self.assertNotEqual(attr.validate(None, numpy.array([1])), None) self.assertNotEqual( attr.validate(None, numpy.array([1, 2, 3, 4, 5, 6])), None) attr = obj_tables.math.numeric.ArrayAttribute(primary=True) self.assertNotEqual(attr.validate(None, None), None) with mock.patch.object(core.Attribute, 'validate', return_value=core.InvalidAttribute(None, [])): obj = None attr = obj_tables.math.numeric.ArrayAttribute() self.assertEqual(attr.validate(obj, None), None) # validate unique attr = obj_tables.math.numeric.ArrayAttribute() self.assertEqual( attr.validate_unique( [], [numpy.array([1, 2]), numpy.array([2, 3])]), None) self.assertEqual(attr.validate_unique([], [numpy.array([1, 2]), None]), None) self.assertNotEqual( attr.validate_unique( [], [numpy.array([1, 2]), numpy.array([1, 2])]), None) self.assertNotEqual(attr.validate_unique([], [None, None]), None) # serialize attr = obj_tables.math.numeric.ArrayAttribute() numpy.testing.assert_equal( attr.deserialize(attr.serialize(numpy.array([1, 2])))[0], numpy.array([1, 2])) numpy.testing.assert_equal( attr.deserialize(attr.serialize(numpy.array([1., 2.])))[0], numpy.array([1., 2.])) # to/from JSON self.assertEqual(attr.to_builtin(None), None) self.assertEqual(attr.to_builtin(numpy.array([1, 2])), [1, 2]) self.assertEqual(attr.from_builtin(None), None) numpy.testing.assert_equal(attr.from_builtin([1, 2]), numpy.array([1, 2])) numpy.testing.assert_equal( attr.from_builtin(attr.to_builtin(numpy.array([1, 2]))), numpy.array([1, 2])) attr = obj_tables.math.numeric.ArrayAttribute(primary=True, default=numpy.array( [1.1, 2.2])) numpy.testing.assert_equal(attr.from_builtin([1, 2]), numpy.array([1, 2]))
def test_FeatureLocAttribute(self): # construction attr = obj_tables.bio.seq.FeatureLocAttribute() self.assertEqual(attr.get_default(), None) attr = obj_tables.bio.seq.FeatureLocAttribute( default=Bio.SeqFeature.FeatureLocation(10, 10, 1)) self.assertEqual(attr.get_default(), Bio.SeqFeature.FeatureLocation(10, 10, 1)) with self.assertRaisesRegex( ValueError, '`default` must be a `Bio.SeqFeature.FeatureLocation`'): obj_tables.bio.seq.FeatureLocAttribute(default='') # deserialize attr = obj_tables.bio.seq.FeatureLocAttribute() self.assertEqual(attr.deserialize(None), (None, None)) self.assertEqual(attr.deserialize(''), (None, None)) self.assertEqual(attr.deserialize('10,10,1'), (Bio.SeqFeature.FeatureLocation(10, 10, 1), None)) self.assertEqual(attr.deserialize((10, 10, 1)), (Bio.SeqFeature.FeatureLocation(10, 10, 1), None)) self.assertEqual(attr.deserialize([10, 10, 1]), (Bio.SeqFeature.FeatureLocation(10, 10, 1), None)) self.assertEqual( attr.deserialize(Bio.SeqFeature.FeatureLocation(10, 10, 1)), (Bio.SeqFeature.FeatureLocation(10, 10, 1), None)) self.assertEqual(attr.deserialize(1)[0], None) self.assertNotEqual(attr.deserialize(1)[1], None) # validate obj = None attr = obj_tables.bio.seq.FeatureLocAttribute() self.assertEqual(attr.validate(obj, None), None) self.assertEqual( attr.validate(obj, Bio.SeqFeature.FeatureLocation(10, 10, 1)), None) self.assertNotEqual(attr.validate(obj, 1), None) attr = obj_tables.bio.seq.FeatureLocAttribute(primary=True) self.assertNotEqual(attr.validate(obj, None), None) with mock.patch.object(core.Attribute, 'validate', return_value=core.InvalidAttribute(None, [])): obj = None attr = obj_tables.bio.seq.FeatureLocAttribute() self.assertEqual(attr.validate(obj, None), None) # validate unique attr = obj_tables.bio.seq.FeatureLocAttribute() self.assertEqual( attr.validate_unique([], [ Bio.SeqFeature.FeatureLocation(10, 10, 1), None, ]), None) self.assertEqual( attr.validate_unique([], [ Bio.SeqFeature.FeatureLocation(10, 10, 1), Bio.SeqFeature.FeatureLocation(1, 10, 1), ]), None) self.assertNotEqual( attr.validate_unique([], [ Bio.SeqFeature.FeatureLocation(10, 10, 1), Bio.SeqFeature.FeatureLocation(10, 10, 1), ]), None) self.assertNotEqual(attr.validate_unique([], [ None, None, ]), None) # serialize attr = obj_tables.bio.seq.FeatureLocAttribute() self.assertEqual(attr.serialize(None), '') self.assertEqual( attr.serialize(Bio.SeqFeature.FeatureLocation(10, 10, 1)), '10,10,1') self.assertEqual(attr.serialize(attr.deserialize('10,10,1')[0]), '10,10,1') self.assertEqual(attr.serialize(attr.deserialize('')[0]), '') # to/from JSON ft = Bio.SeqFeature.FeatureLocation(100, 200, 1) ft2 = { 'start': 100, 'end': 200, 'strand': 1, } self.assertEqual(attr.to_builtin(None), None) self.assertEqual(attr.to_builtin(ft), ft2) self.assertEqual(attr.from_builtin(None), None) self.assertEqual(attr.from_builtin(ft2), ft) self.assertEqual(attr.from_builtin(attr.to_builtin(ft)), ft)
def test_SeqAttribute(self): class Node(core.Model): value = obj_tables.bio.seq.SeqAttribute() attr = Node.Meta.attributes['value'] # constructor attr2 = obj_tables.bio.seq.SeqAttribute(default=None) self.assertEqual(attr2.get_default(), None) attr2 = obj_tables.bio.seq.SeqAttribute(default=Bio.Seq.Seq('acgt')) self.assertEqual(attr2.get_default(), Bio.Seq.Seq('acgt')) with self.assertRaisesRegex( ValueError, '`default` must be a `Bio.Seq.Seq` or `None`'): obj_tables.bio.seq.SeqAttribute(default='acgt') with self.assertRaisesRegex( ValueError, '`min_length` must be a non-negative integer'): obj_tables.bio.seq.SeqAttribute(min_length=-1) with self.assertRaisesRegex( ValueError, '`max_length` must be an integer greater than or equal to `min_length`' ): obj_tables.bio.seq.SeqAttribute(min_length=10, max_length=5) # deserialize self.assertEqual(attr.deserialize(''), (None, None)) self.assertEqual(attr.deserialize(None), (None, None)) alphabet = Bio.Alphabet.Alphabet() alphabet.letters = None alphabet.size = None self.assertEqual( attr.deserialize( '{"seq": "ATCG", "alphabet": {"type": "Alphabet", "letters": "", "size": ""}}' ), (Bio.Seq.Seq('ATCG', alphabet), None)) alphabet = Bio.Alphabet.Alphabet() alphabet.letters = 'ACGT' alphabet.size = 1 self.assertEqual( attr.deserialize( '{"seq": "ATCG", "alphabet": {"type": "Alphabet", "letters": "ACGT", "size": 1}}' ), (Bio.Seq.Seq('ATCG', alphabet), None)) alphabet = Bio.Alphabet.Alphabet() alphabet.letters = ['AC', 'GT'] alphabet.size = 2 self.assertEqual( attr.deserialize( '{"seq": "ATCG", "alphabet": {"type": "Alphabet", "letters": ["AC", "GT"], "size": 2}}' ), (Bio.Seq.Seq('ATCG', alphabet), None)) alphabet = Bio.Alphabet.ProteinAlphabet() alphabet.letters = None alphabet.size = 1 self.assertEqual( attr.deserialize( '{"seq": "ATCG", "alphabet": {"type": "ProteinAlphabet", "letters": "", "size": 1}}' ), (Bio.Seq.Seq('ATCG', alphabet), None)) alphabet = Bio.Alphabet.ProteinAlphabet() alphabet.letters = 'ARG' alphabet.size = 1 self.assertEqual( attr.deserialize( '{"seq": "ATCG", "alphabet": {"type": "ProteinAlphabet", "letters": "ARG", "size": 1}}' ), (Bio.Seq.Seq('ATCG', alphabet), None)) # serialize self.assertEqual(attr.serialize(None), '') self.assertEqual( json.loads(attr.serialize(Bio.Seq.Seq(''))), { "seq": "", "alphabet": { "type": "Alphabet", "letters": None, "size": None } }) self.assertEqual( json.loads(attr.serialize(Bio.Seq.Seq('ACGT'))), { "seq": "ACGT", "alphabet": { "type": "Alphabet", "letters": None, "size": None } }) alphabet = Bio.Alphabet.Alphabet() alphabet.letters = 'ACGT' alphabet.size = 1 self.assertEqual( json.loads(attr.serialize(Bio.Seq.Seq('ACGT', alphabet))), { "seq": "ACGT", "alphabet": { "type": "Alphabet", "letters": "ACGT", "size": 1 } }) alphabet = Bio.Alphabet.Alphabet() alphabet.letters = ['AC', 'GT'] alphabet.size = 2 self.assertEqual( json.loads(attr.serialize(Bio.Seq.Seq('ACGT', alphabet))), { "seq": "ACGT", "alphabet": { "type": "Alphabet", "letters": ["AC", "GT"], "size": 2 } }) alphabet = Bio.Alphabet.ProteinAlphabet() alphabet.letters = ['AC', 'GT'] alphabet.size = 2 self.assertEqual( json.loads(attr.serialize(Bio.Seq.Seq('ACGT', alphabet))), { "seq": "ACGT", "alphabet": { "type": "ProteinAlphabet", "letters": ["AC", "GT"], "size": 2 } }) # validate node = Node() self.assertEqual(attr.validate(node, None), None) self.assertNotEqual(attr.validate(node, ''), None) self.assertEqual(attr.validate(node, Bio.Seq.Seq('')), None) self.assertEqual(attr.validate(node, Bio.Seq.Seq('acgt')), None) attr.min_length = 2 attr.max_length = 4 self.assertNotEqual(attr.validate(node, Bio.Seq.Seq('A')), None) self.assertEqual(attr.validate(node, Bio.Seq.Seq('ACG')), None) self.assertNotEqual(attr.validate(node, Bio.Seq.Seq('ACGTA')), None) with mock.patch.object(core.Attribute, 'validate', return_value=core.InvalidAttribute(None, [])): self.assertEqual(attr.validate(node, Bio.Seq.Seq('acgt')), None) attr2 = obj_tables.bio.seq.SeqAttribute(primary=True) self.assertNotEqual(attr2.validate(None, None), None) # validate_unique nodes = [Node(), Node()] values = [Bio.Seq.Seq('AA'), Bio.Seq.Seq('CC')] self.assertEqual(attr.validate_unique(nodes, values), None) nodes = [Node(), Node()] values = [Bio.Seq.Seq('AA'), Bio.Seq.Seq('AA')] self.assertNotEqual(attr.validate_unique(nodes, values), None) # to/from JSON seq = Bio.Seq.Seq('AA') seq2 = { 'seq': 'AA', 'alphabet': { 'type': 'Alphabet', 'letters': None, 'size': None, } } self.assertEqual(attr.to_builtin(None), None) self.assertEqual(attr.to_builtin(seq), seq2) self.assertEqual(attr.from_builtin(None), None) self.assertEqual(attr.from_builtin(seq2), seq) self.assertEqual(attr.from_builtin(attr.to_builtin(seq)), seq)