@@ -1160,7 +1160,6 @@ def wrapper(self, *args, **kwargs):
11601160 # Avoid circular import in Python 2.7
11611161 from google .cloud .ndb import context as context_module
11621162 from google .cloud .ndb import _datastore_api
1163- from google .cloud .ndb import model
11641163
11651164 # Maybe we already did this (in the case of X calling X_async)
11661165 if "_options" in kwargs :
@@ -1184,6 +1183,12 @@ def wrapper(self, *args, **kwargs):
11841183 "deprecated. Please pass arguments directly."
11851184 )
11861185
1186+ projection = kwargs .get ("projection" )
1187+ if projection :
1188+ projection = _to_property_names (projection )
1189+ _check_properties (self .kind , projection )
1190+ kwargs ["projection" ] = projection
1191+
11871192 if kwargs .get ("keys_only" ):
11881193 if kwargs .get ("projection" ):
11891194 raise TypeError (
@@ -1192,22 +1197,6 @@ def wrapper(self, *args, **kwargs):
11921197 kwargs ["projection" ] = ["__key__" ]
11931198 del kwargs ["keys_only" ]
11941199
1195- # When projection fields are passed as property objects, we need to
1196- # convert them into property names. Fixes #295.
1197- if kwargs .get ("projection" ):
1198- property_names = []
1199- for prop in kwargs ["projection" ]:
1200- if isinstance (prop , six .string_types ):
1201- property_names .append (prop )
1202- elif isinstance (prop , model .Property ):
1203- property_names .append (prop ._name )
1204- else :
1205- raise TypeError (
1206- "Unexpected projection value {}; "
1207- "should be string or Property" .format (prop )
1208- )
1209- kwargs ["projection" ] = property_names
1210-
12111200 if kwargs .get ("transaction" ):
12121201 read_consistency = kwargs .pop (
12131202 "read_consistency" , kwargs .pop ("read_policy" , None )
@@ -1451,8 +1440,8 @@ def __init__(
14511440 "projection must be a tuple, list or None; "
14521441 "received {}" .format (projection )
14531442 )
1454- projection = self . _to_property_names (projection )
1455- self . _check_properties (projection )
1443+ projection = _to_property_names (projection )
1444+ _check_properties (self . kind , projection )
14561445 self .projection = tuple (projection )
14571446
14581447 if distinct_on is not None and group_by is not None :
@@ -1472,8 +1461,8 @@ def __init__(
14721461 "distinct_on must be a tuple, list or None; "
14731462 "received {}" .format (distinct_on )
14741463 )
1475- distinct_on = self . _to_property_names (distinct_on )
1476- self . _check_properties (distinct_on )
1464+ distinct_on = _to_property_names (distinct_on )
1465+ _check_properties (self . kind , distinct_on )
14771466 self .distinct_on = tuple (distinct_on )
14781467
14791468 def __repr__ (self ):
@@ -1492,11 +1481,11 @@ def __repr__(self):
14921481 args .append ("order_by=%r" % self .order_by )
14931482 if self .projection :
14941483 args .append (
1495- "projection=%r" % (self . _to_property_names (self .projection ))
1484+ "projection=%r" % (_to_property_names (self .projection ))
14961485 )
14971486 if self .distinct_on :
14981487 args .append (
1499- "distinct_on=%r" % (self . _to_property_names (self .distinct_on ))
1488+ "distinct_on=%r" % (_to_property_names (self .distinct_on ))
15001489 )
15011490 if self .default_options is not None :
15021491 args .append ("default_options=%r" % self .default_options )
@@ -1511,8 +1500,8 @@ def is_distinct(self):
15111500 """
15121501 return bool (
15131502 self .distinct_on
1514- and set (self . _to_property_names (self .distinct_on ))
1515- <= set (self . _to_property_names (self .projection ))
1503+ and set (_to_property_names (self .distinct_on ))
1504+ <= set (_to_property_names (self .projection ))
15161505 )
15171506
15181507 def filter (self , * filters ):
@@ -1662,23 +1651,6 @@ def bind(self, *positional, **keyword):
16621651 distinct_on = self .distinct_on ,
16631652 )
16641653
1665- def _to_property_names (self , properties ):
1666- # Avoid circular import in Python 2.7
1667- from google .cloud .ndb import model
1668-
1669- fixed = []
1670- for prop in properties :
1671- if isinstance (prop , six .string_types ):
1672- fixed .append (prop )
1673- elif isinstance (prop , model .Property ):
1674- fixed .append (prop ._name )
1675- else :
1676- raise TypeError (
1677- "Unexpected property {}; "
1678- "should be string or Property" .format (prop )
1679- )
1680- return fixed
1681-
16821654 def _to_property_orders (self , order_by ):
16831655 # Avoid circular import in Python 2.7
16841656 from google .cloud .ndb import model
@@ -1703,14 +1675,6 @@ def _to_property_orders(self, order_by):
17031675 raise TypeError ("Order values must be properties or strings" )
17041676 return orders
17051677
1706- def _check_properties (self , fixed , ** kwargs ):
1707- # Avoid circular import in Python 2.7
1708- from google .cloud .ndb import model
1709-
1710- modelclass = model .Model ._kind_map .get (self .kind )
1711- if modelclass is not None :
1712- modelclass ._check_properties (fixed , ** kwargs )
1713-
17141678 @_query_options
17151679 @utils .keyword_only (
17161680 keys_only = None ,
@@ -2400,3 +2364,30 @@ def gql(query_string, *args, **kwds):
24002364 if args or kwds :
24012365 query = query .bind (* args , ** kwds )
24022366 return query
2367+
2368+
2369+ def _to_property_names (properties ):
2370+ # Avoid circular import in Python 2.7
2371+ from google .cloud .ndb import model
2372+
2373+ fixed = []
2374+ for prop in properties :
2375+ if isinstance (prop , six .string_types ):
2376+ fixed .append (prop )
2377+ elif isinstance (prop , model .Property ):
2378+ fixed .append (prop ._name )
2379+ else :
2380+ raise TypeError (
2381+ "Unexpected property {}; "
2382+ "should be string or Property" .format (prop )
2383+ )
2384+ return fixed
2385+
2386+
2387+ def _check_properties (kind , fixed , ** kwargs ):
2388+ # Avoid circular import in Python 2.7
2389+ from google .cloud .ndb import model
2390+
2391+ modelclass = model .Model ._kind_map .get (kind )
2392+ if modelclass is not None :
2393+ modelclass ._check_properties (fixed , ** kwargs )
0 commit comments