@@ -72,7 +72,9 @@ class PackageBaseResourceWrapper(PackageRepositoryResourceWrapper):
7272 def __init__ (self , resource , context = None ):
7373 super (PackageBaseResourceWrapper , self ).__init__ (resource )
7474 self .context = context
75- self ._late_bindings = {}
75+
76+ # cached results of late-bound funcs
77+ self ._late_binding_returnvalues = {}
7678
7779 def set_context (self , context ):
7880 self .context = context
@@ -134,16 +136,19 @@ def print_info(self, buf=None, format_=FileFormat.yaml,
134136
135137 def _wrap_forwarded (self , key , value ):
136138 if isinstance (value , SourceCode ) and value .late_binding :
137- value_ = self ._late_bindings .get (key , KeyError )
139+ # get cached return value if present
140+ value_ = self ._late_binding_returnvalues .get (key , KeyError )
138141
139142 if value_ is KeyError :
143+ # evaluate the late-bound function
140144 value_ = self ._eval_late_binding (value )
141145
142146 schema = self .late_bind_schemas .get (key )
143147 if schema is not None :
144148 value_ = schema .validate (value_ )
145149
146- self ._late_bindings [key ] = value_
150+ # cache result of late bound func
151+ self ._late_binding_returnvalues [key ] = value_
147152
148153 return value_
149154 else :
@@ -162,14 +167,12 @@ def _eval_late_binding(self, sourcecode):
162167 bindings = self .context ._get_pre_resolve_bindings ()
163168 g .update (bindings )
164169
165- # note that what 'this' actually points to depends on whether the context
166- # is available or not. If not, then 'this' is a Package instance; if the
167- # context is available, it is a Variant instance. So for example, if
168- # in_context() is True, 'this' will have a 'root' attribute, but will
169- # not if in_context() is False.
170+ # Note that 'this' could be a `Package` or `Variant` instance. This is
171+ # intentional; it just depends on how the package is accessed.
170172 #
171173 g ["this" ] = self
172174
175+ # evaluate the late-bound function
173176 sourcecode .set_package (self )
174177 return sourcecode .exec_ (globals_ = g )
175178
@@ -183,6 +186,12 @@ class Package(PackageBaseResourceWrapper):
183186 """
184187 keys = schema_keys (package_schema )
185188
189+ # This is to allow for a simple check like 'this.is_package' in late-bound
190+ # funcs, where 'this' may be a package or variant.
191+ #
192+ is_package = True
193+ is_variant = False
194+
186195 def __init__ (self , resource , context = None ):
187196 _check_class (resource , PackageResource )
188197 super (Package , self ).__init__ (resource , context )
@@ -268,6 +277,10 @@ class Variant(PackageBaseResourceWrapper):
268277 keys = schema_keys (variant_schema )
269278 keys .update (["index" , "root" , "subpath" ])
270279
280+ # See comment in `Package`
281+ is_package = False
282+ is_variant = True
283+
271284 def __init__ (self , resource , context = None , parent = None ):
272285 _check_class (resource , VariantResource )
273286 super (Variant , self ).__init__ (resource , context )
@@ -316,23 +329,31 @@ def parent(self):
316329
317330 return self ._parent
318331
332+ @property
333+ def variant_requires (self ):
334+ """Get the subset of requirements specific to this variant.
335+
336+ Returns:
337+ List of `Requirement` objects.
338+ """
339+ if self .index is None :
340+ return []
341+ else :
342+ return self .parent .variants [self .index ] or []
343+
319344 @property
320345 def requires (self ):
321346 """Get variant requirements.
322347
323348 This is a concatenation of the package requirements and those of this
324349 specific variant.
325- """
326- try :
327- package_requires = self .parent .requires or []
328350
329- if self .index is None :
330- return package_requires
331- else :
332- variant_requires = self .parent .variants [self .index ] or []
333- return package_requires + variant_requires
334- except AttributeError as e :
335- reraise (e , ValueError )
351+ Returns:
352+ List of `Requirement` objects.
353+ """
354+ return (
355+ (self .parent .requires or []) + self .variant_requires
356+ )
336357
337358 def get_requires (self , build_requires = False , private_build_requires = False ):
338359 """Get the requirements of the variant.
@@ -433,9 +454,9 @@ def _repository_uids(self):
433454 return uids
434455
435456
436- #------------------------------------------------------------------------------
457+ # ------------------------------------------------------------------------------
437458# resource acquisition functions
438- #------------------------------------------------------------------------------
459+ # ------------------------------------------------------------------------------
439460
440461def iter_package_families (paths = None ):
441462 """Iterate over package families, in no particular order.
@@ -551,6 +572,15 @@ def get_package_from_string(txt, paths=None):
551572
552573
553574def get_developer_package (path , format = None ):
575+ """Create a developer package.
576+
577+ Args:
578+ path (str): Path to dir containing package definition file.
579+ format (str): Package definition file format, detected if None.
580+
581+ Returns:
582+ `DeveloperPackage`.
583+ """
554584 from rez .developer_package import DeveloperPackage
555585 return DeveloperPackage .from_path (path , format = format )
556586
0 commit comments