77class ContextViewMetaClass (type ):
88 """Context view meta class."""
99
10- attributes = dict ()
11-
1210 def __new__ (mcs , class_name , bases , attributes ):
1311 """Context view class factory."""
14- mcs .attributes = attributes
15- mcs .validate (bases )
12+ mcs .validate (bases , attributes )
1613 cls = type .__new__ (mcs , class_name , bases , attributes )
17- cls .__fields__ = mcs .get_properties ()
14+ cls .__fields__ = mcs .get_properties (attributes )
1815 return cls
1916
2017 @classmethod
21- def validate (mcs , bases ):
18+ def validate (mcs , bases , attributes ):
2219 """Check attributes."""
2320 if bases [0 ] is object :
2421 return None
25- mcs .check_model_cls ()
26- mcs .check_include_exclude ()
2722
28- @classmethod
29- def check_model_cls (mcs ):
30- """Check __model_cls__ attribute."""
31- model_cls = mcs .attributes .get ('__model_cls__' )
23+ mcs .check_model_cls (attributes )
24+ mcs .check_include_exclude (attributes )
25+ mcs .check_properties (attributes )
26+ mcs .match_unknown_attrs (attributes )
27+
28+ @staticmethod
29+ def check_model_cls (attributes ):
30+ """Check __model_cls__ attribute.
31+
32+ :type attributes: dict
33+ """
34+ model_cls = attributes .get ('__model_cls__' )
3235 if model_cls is None :
3336 raise AttributeError ("Attribute __model_cls__ is required." )
3437
3538 if not issubclass (model_cls , models .DomainModel ):
3639 raise TypeError ("Attribute __model_cls__ must be subclass of "
3740 "DomainModel." )
3841
39- @classmethod
40- def check_include_exclude (mcs ):
41- """Check __include__ and __exclude__ attributes."""
42- include = mcs .attributes .get ('__include__' , tuple ())
43- exclude = mcs .attributes .get ('__exclude__' , tuple ())
42+ @staticmethod
43+ def get_prepared_include_exclude (attributes ):
44+ """Return tuple with prepared __include__ and __exclude__ attributes.
45+
46+ :type attributes: dict
47+ :rtype: tuple
48+ """
49+ attrs = dict ()
50+ for attr in ('__include__' , '__exclude__' ):
51+ attrs [attr ] = tuple ([item .name for item in
52+ attributes .get (attr , tuple ())])
53+ return attrs ['__include__' ], attrs ['__exclude__' ]
54+
55+ @staticmethod
56+ def check_include_exclude (attributes ):
57+ """Check __include__ and __exclude__ attributes.
58+
59+ :type attributes: dict
60+ """
61+ include = attributes .get ('__include__' , tuple ())
62+ exclude = attributes .get ('__exclude__' , tuple ())
4463
4564 if not isinstance (include , tuple ):
4665 raise TypeError ("Attribute __include__ must be a tuple." )
@@ -55,71 +74,80 @@ def check_include_exclude(mcs):
5574 raise AttributeError ("Usage of __include__ and __exclude__ "
5675 "at the same time is prohibited." )
5776
58- include_names = [item .name for item in include ]
59- exclude_names = [item .name for item in exclude ]
77+ @staticmethod
78+ def get_properties (attributes ):
79+ """Return tuple of names of defined properties.
6080
61- mcs .chk_intersections (include_names , exclude_names )
62- mcs .match_unknown_attrs (include_names , exclude_names )
81+ :type attributes: dict
82+ :rtype: list
83+ """
84+ return [key for key , value in six .iteritems (attributes )
85+ if isinstance (value , property )]
6386
6487 @classmethod
65- def chk_intersections (mcs , include , exclude ):
66- """Check whether intersections exist."""
67- intersections = mcs .get_intersections (include )
68- attr , intersections = ('__include__' , intersections ) \
69- if intersections \
70- else ('__exclude__' , mcs .get_intersections (exclude ))
71-
72- if intersections :
73- raise AttributeError (
74- "It is not allowed to mention already defined properties: "
75- "{0} in {1} attributes." .format (", " .join (intersections ),
76- attr ))
88+ def check_properties (mcs , attributes ):
89+ """Check whether intersections exist.
90+
91+ :type attributes: dict
92+ """
93+ include , exclude = mcs .get_prepared_include_exclude (attributes )
94+
95+ if include :
96+ intersections = mcs .get_intersections (attributes , include )
97+ attr = '__include__'
98+ elif exclude :
99+ intersections = mcs .get_intersections (attributes , exclude )
100+ attr = '__exclude__'
101+ else :
102+ return None
103+
104+ if not intersections :
105+ return None
106+
107+ raise AttributeError (
108+ "It is not allowed to mention already defined properties: "
109+ "{0} in {1} attributes." .format (", " .join (intersections ), attr ))
77110
78111 @classmethod
79- def get_intersections (mcs , attr ):
112+ def get_intersections (mcs , attributes , attr ):
80113 """Return intersection with defined properties if exists.
81114
115+ :type attributes: dict
82116 :type attr: list
83117 :rtype: list
84118 """
85119 if not attr :
86120 return []
87- return list (set (mcs .get_properties ()).intersection (attr ))
88-
89- @classmethod
90- def match_unknown_attrs (mcs , include , exclude ):
91- """Check about using nonexistent attributes."""
92- model_cls = mcs .attributes .get ('__model_cls__' )
93- unknown_attr = []
94- for item in include :
95- if not hasattr (model_cls , item ):
96- unknown_attr .append (item )
97-
98- for item in exclude :
99- if not hasattr (model_cls , item ):
100- unknown_attr .append (item )
101-
102- if unknown_attr :
103- raise AttributeError (
104- "Nonexistent attributes: {0}." .format (
105- ", " .join (unknown_attr )))
121+ properties = mcs .get_properties (attributes )
122+ return list (set (properties ).intersection (attr ))
106123
107124 @classmethod
108- def get_properties (mcs ):
109- """Return list of names of defined properties .
125+ def match_unknown_attrs (mcs , attributes ):
126+ """Check about using nonexistent attributes .
110127
111- :rtype: list
128+ :type attributes: dict
112129 """
113- return [key for key , value in six .iteritems (mcs .attributes )
114- if isinstance (value , property )]
130+ model_cls = attributes .get ('__model_cls__' )
131+ include , exclude = mcs .get_prepared_include_exclude (attributes )
132+ attrs = include if include else exclude
133+ unknown_attr = list ()
134+
135+ for attr in attrs :
136+ if not hasattr (model_cls , attr ):
137+ unknown_attr .append (attr )
138+
139+ if not unknown_attr :
140+ return None
141+
142+ raise AttributeError (
143+ "Nonexistent attributes: {0}." .format (", " .join (unknown_attr )))
115144
116145
117146@six .add_metaclass (ContextViewMetaClass )
118147class ContextView (object ):
119148 """Contextual view class."""
120149
121150 __model_cls__ = None
122- __model__ = None
123151 __include__ = tuple ()
124152 __exclude__ = tuple ()
125153 __fields__ = list ()
@@ -133,7 +161,7 @@ def __init__(self, model):
133161 raise TypeError ("\" {0}\" is not an instance of {1}" .format (
134162 model , self .__model_cls__ ))
135163
136- self .__model__ = model
164+ self ._model = model
137165
138166 if self .__include__ :
139167 self ._include ()
@@ -143,21 +171,24 @@ def __init__(self, model):
143171 self ._fields ()
144172
145173 def _include (self ):
174+ """Fill __fields__ out based on __include__."""
146175 for field in self .__include__ :
147- value = getattr (self .__model__ , field .name )
176+ value = getattr (self ._model , field .name )
148177 setattr (self , field .name , value )
149178 self .__fields__ .append (field .name )
150179
151180 def _exclude (self ):
181+ """Fill __fields__ out based on __exclude__."""
152182 exclude = [field .name for field in self .__exclude__ ]
153- for (field , value ) in six .iteritems (self .__model__ .get_data ()):
183+ for (field , value ) in six .iteritems (self ._model .get_data ()):
154184 if field in exclude :
155185 continue
156186 setattr (self , field , value )
157187 self .__fields__ .append (field )
158188
159189 def _fields (self ):
160- for (field , value ) in six .iteritems (self .__model__ .get_data ()):
190+ """Fill __fields__ out based on full model data."""
191+ for (field , value ) in six .iteritems (self ._model .get_data ()):
161192 if field in self .__fields__ :
162193 continue
163194 setattr (self , field , value )
0 commit comments