aboutsummaryrefslogtreecommitdiffstats
path: root/netmodel/model/attribute.py
diff options
context:
space:
mode:
Diffstat (limited to 'netmodel/model/attribute.py')
-rw-r--r--netmodel/model/attribute.py120
1 files changed, 45 insertions, 75 deletions
diff --git a/netmodel/model/attribute.py b/netmodel/model/attribute.py
index b69ee1bf..b2fa2331 100644
--- a/netmodel/model/attribute.py
+++ b/netmodel/model/attribute.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Cisco and/or its affiliates.
@@ -22,11 +22,10 @@ import logging
import operator
import types
-from netmodel.model.mapper import ObjectSpecification
-from netmodel.model.type import is_type
-from netmodel.util.meta import inheritors
-from netmodel.util.misc import is_iterable
-from vicn.core.sa_collections import InstrumentedList, _list_decorators
+from netmodel.model.mapper import ObjectSpecification
+from netmodel.model.type import Type, Self
+from netmodel.util.misc import is_iterable
+from netmodel.model.collection import Collection
log = logging.getLogger(__name__)
instance_dict = operator.attrgetter('__dict__')
@@ -38,26 +37,25 @@ class NEVER_SET: None
#------------------------------------------------------------------------------
class Multiplicity:
- _1_1 = '1_1'
- _1_N = '1_N'
- _N_1 = 'N_1'
- _N_N = 'N_N'
-
+ OneToOne = '1_1'
+ OneToMany = '1_N'
+ ManyToOne = 'N_1'
+ ManyToMany = 'N_N'
@staticmethod
def reverse(value):
reverse_map = {
- Multiplicity._1_1: Multiplicity._1_1,
- Multiplicity._1_N: Multiplicity._N_1,
- Multiplicity._N_1: Multiplicity._1_N,
- Multiplicity._N_N: Multiplicity._N_N,
+ Multiplicity.OneToOne: Multiplicity.OneToOne,
+ Multiplicity.OneToMany: Multiplicity.ManyToOne,
+ Multiplicity.ManyToOne: Multiplicity.OneToMany,
+ Multiplicity.ManyToMany: Multiplicity.ManyToMany,
}
return reverse_map[value]
# Default attribute properties values (default to None)
DEFAULT = {
- 'multiplicity' : Multiplicity._1_1,
+ 'multiplicity' : Multiplicity.OneToOne,
'mandatory' : False,
}
@@ -71,33 +69,36 @@ class Attribute(abc.ABC, ObjectSpecification):
'type',
'description',
'default',
- 'choices',
'mandatory',
'multiplicity',
'ro',
'auto',
'func',
- 'requirements',
'reverse_name',
'reverse_description',
'reverse_auto'
]
def __init__(self, *args, **kwargs):
- for key in Attribute.properties:
+ for key in kwargs.keys():
+ if not key in self.properties:
+ raise ValueError("Invalid attribute property {}".format(key))
+ for key in self.properties:
value = kwargs.pop(key, NEVER_SET)
setattr(self, key, value)
if len(args) == 1:
self.type, = args
- elif len(args) == 2:
- self.name, self.type = args
- assert is_type(self.type)
+ # self.type is optional since the type can be inherited. Although we
+ # will have to verify the attribute is complete at some point
+ if isinstance(self.type, str):
+ self.type = Type.from_string(self.type)
+ assert self.type is Self or Type.exists(self.type)
self.is_aggregate = False
self._reverse_attributes = list()
-
+
#--------------------------------------------------------------------------
# Display
#--------------------------------------------------------------------------
@@ -107,6 +108,15 @@ class Attribute(abc.ABC, ObjectSpecification):
__str__ = __repr__
+ # The following functions are required to allow comparing attributes, and
+ # using them as dict keys
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __hash__(self):
+ return hash(self.name)
+
#--------------------------------------------------------------------------
# Descriptor protocol
#
@@ -118,7 +128,7 @@ class Attribute(abc.ABC, ObjectSpecification):
return self
value = instance_dict(instance).get(self.name, NEVER_SET)
-
+
# Case : collection attribute
if self.is_collection:
if value is NEVER_SET:
@@ -126,12 +136,12 @@ class Attribute(abc.ABC, ObjectSpecification):
default = self.default(instance)
else:
default = self.default
- value = InstrumentedList(default)
+ value = Collection(default)
value._attribute = self
value._instance = instance
self.__set__(instance, value)
return value
- return value
+ return value
# Case : scalar attribute
@@ -159,8 +169,8 @@ class Attribute(abc.ABC, ObjectSpecification):
return
if self.is_collection:
- if not isinstance(value, InstrumentedList):
- value = InstrumentedList(value)
+ if not isinstance(value, Collection):
+ value = Collection(value)
value._attribute = self
value._instance = instance
@@ -172,6 +182,10 @@ class Attribute(abc.ABC, ObjectSpecification):
def __delete__(self, instance):
raise NotImplementedError
+ def __set_name__(self, owner, name):
+ self.name = name
+ self.owner = owner
+
#--------------------------------------------------------------------------
# Accessors
#--------------------------------------------------------------------------
@@ -184,17 +198,16 @@ class Attribute(abc.ABC, ObjectSpecification):
return DEFAULT.get(name, None)
return value
- # Shortcuts
-
def has_reverse_attribute(self):
return self.reverse_name and self.multiplicity
@property
def is_collection(self):
- return self.multiplicity in (Multiplicity._1_N, Multiplicity._N_N)
+ return self.multiplicity in (Multiplicity.OneToMany,
+ Multiplicity.ManyToMany)
def is_set(self, instance):
- return self.name in instance_dict(instance)
+ return instance.is_set(self.name)
#--------------------------------------------------------------------------
# Operations
@@ -217,46 +230,3 @@ class Attribute(abc.ABC, ObjectSpecification):
value.extend(parent_value)
else:
setattr(self, prop, parent_value)
-
- #--------------------------------------------------------------------------
- # Attribute values
- #--------------------------------------------------------------------------
-
- def _handle_getitem(self, instance, item):
- return item
-
- def _handle_add(self, instance, item):
- instance._state.dirty = True
- instance._state.attr_dirty.add(self.name)
- print('marking', self.name, 'as dirty')
- return item
-
- def _handle_remove(self, instance, item):
- instance._state.dirty = True
- instance._state.attr_dirty.add(self.name)
- print('marking', self.name, 'as dirty')
-
- def _handle_before_remove(self, instance):
- pass
-
- #--------------------------------------------------------------------------
- # Attribute values
- #--------------------------------------------------------------------------
-
-class Relation(Attribute):
- properties = Attribute.properties[:]
- properties.extend([
- 'reverse_name',
- 'reverse_description',
- 'multiplicity',
- ])
-
-class SelfRelation(Relation):
- def __init__(self, *args, **kwargs):
- if args:
- if not len(args) == 1:
- raise ValueError('Bad initialized for SelfRelation')
- name, = args
- super().__init__(name, None, *args, **kwargs)
- else:
- super().__init__(None, *args, **kwargs)