@@ -272,21 +272,6 @@ def fn(*args, **kwargs):
272272    return  fn 
273273
274274
275- class  _class_or_instancemethod (classmethod ):
276-     """Allow a method to be called both as a classmethod and an instancemethod, 
277-     giving priority to the instancemethod. 
278- 
279-     This is used to allow extracting information from the signature of a SymbolicRandomVariable 
280-     which may be provided either as a class attribute or as an instance attribute. 
281- 
282-     Adapted from https://stackoverflow.com/a/28238047 
283-     """ 
284- 
285-     def  __get__ (self , instance , type_ ):
286-         descr_get  =  super ().__get__  if  instance  is  None  else  self .__func__ .__get__ 
287-         return  descr_get (instance , type_ )
288- 
289- 
290275class  SymbolicRandomVariable (OpFromGraph ):
291276    """Symbolic Random Variable 
292277
@@ -343,37 +328,40 @@ def _parse_params_signature(signature):
343328        else :
344329            return  _parse_gufunc_signature (params_signature )
345330
346-     @_class_or_instancemethod  
347-     @property  
348-     def  ndims_params (cls_or_self ) ->  Sequence [int ] |  None :
331+     @staticmethod  
332+     def  _ndims_params_from_signature (signature : str ) ->  Sequence [int ]:
349333        """Number of core dimensions of the distribution's parameters.""" 
350-         signature  =  cls_or_self .signature 
351-         if  signature  is  None :
352-             return  None 
353-         inputs_signature , _  =  cls_or_self ._parse_params_signature (signature )
334+         inputs_signature , _  =  SymbolicRandomVariable ._parse_params_signature (signature )
354335        return  [len (sig ) for  sig  in  inputs_signature ]
355336
356-     @_class_or_instancemethod  
337+     @classmethod  
357338    @property  
358-     def  ndim_supp (cls_or_self ) ->  int  |  None :
359-         """Number of support dimensions of the RandomVariable 
360- 
361-         (0 for scalar, 1 for vector, ...) 
362-         """ 
363-         signature  =  cls_or_self .signature 
339+     def  ndims_params (cls ) ->  Sequence [int ] |  None :
340+         signature  =  cls .signature 
364341        if  signature  is  None :
365342            return  None 
366-         _ , outputs_params_signature  =  cls_or_self ._parse_params_signature (signature )
343+         return  cls ._ndims_params_from_signature (signature )
344+ 
345+     @staticmethod  
346+     def  _ndim_supp_from_signature (signature : str ) ->  int :
347+         _ , outputs_params_signature  =  SymbolicRandomVariable ._parse_params_signature (signature )
367348        return  max (len (out_sig ) for  out_sig  in  outputs_params_signature )
368349
369-     @_class_or_instancemethod  
350+     @classmethod  
370351    @property  
371-     def  default_output (cls_or_self ) ->  int  |  None :
372-         signature  =  cls_or_self .signature 
352+     def  ndim_supp (cls ) ->  int  |  None :
353+         """Number of support dimensions of the RandomVariable 
354+ 
355+         (0 for scalar, 1 for vector, ...) 
356+         """ 
357+         signature  =  cls .signature 
373358        if  signature  is  None :
374359            return  None 
360+         return  cls ._ndim_supp_from_signature (signature )
375361
376-         _ , outputs_signature  =  cls_or_self ._parse_signature (signature )
362+     @staticmethod  
363+     def  _default_output_from_signature (signature : str ) ->  int  |  None :
364+         _ , outputs_signature  =  SymbolicRandomVariable ._parse_signature (signature )
377365
378366        # If there is a single non `[rng]` outputs, that is the default one! 
379367        candidate_default_output  =  [
@@ -384,6 +372,14 @@ def default_output(cls_or_self) -> int | None:
384372        else :
385373            return  None 
386374
375+     @classmethod  
376+     @property  
377+     def  default_output (cls ) ->  int  |  None :
378+         signature  =  cls .signature 
379+         if  signature  is  None :
380+             return  None 
381+         return  cls ._default_output_from_signature (signature )
382+ 
387383    @staticmethod  
388384    def  get_idxs (signature : str ) ->  tuple [tuple [int ], int  |  None , tuple [int ]]:
389385        """Parse signature and return indexes for *[rng], [size] and parameters""" 
@@ -406,10 +402,17 @@ def __init__(
406402        ** kwargs ,
407403    ):
408404        """Initialize a SymbolicRandomVariable class.""" 
409-         if  "signature"  in  kwargs :
410-             self .signature  =  kwargs .pop ("signature" )
411- 
412-         if  "ndim_supp"  in  kwargs :
405+         signature  =  kwargs .pop ("signature" , None )
406+         if  signature  is  not None :
407+             self .signature  =  signature 
408+             # Override class properties with instance properties 
409+             self .ndims_params  =  self ._ndims_params_from_signature (signature )
410+             self .ndim_supp  =  self ._ndim_supp_from_signature (self .signature )
411+             self .default_output  =  self ._default_output_from_signature (self .signature )
412+ 
413+         elif  "ndim_supp"  in  kwargs :
414+             # For backwards compatibility we allow passing ndim_supp without signature 
415+             # This is the only variable that PyMC absolutely needs to work with SymbolicRandomVariables 
413416            self .ndim_supp  =  kwargs .pop ("ndim_supp" )
414417
415418        if  self .ndim_supp  is  None :
0 commit comments