@@ -334,16 +334,6 @@ class partial:
334334 def __new__ (cls , func , / , * args , ** keywords ):
335335 if not callable (func ):
336336 raise TypeError ("the first argument must be callable" )
337- if args and args [- 1 ] is Placeholder :
338- # Trim trailing placeholders
339- j = len (args ) - 1
340- if not j :
341- args = ()
342- else :
343- while (j := j - 1 ) >= 0 :
344- if args [j ] is not Placeholder :
345- break
346- args = args [:j + 1 ]
347337 if isinstance (func , partial ):
348338 pto_phcount = func ._phcount
349339 tot_args = func .args
@@ -411,8 +401,8 @@ def __setstate__(self, state):
411401 (namespace is not None and not isinstance (namespace , dict ))):
412402 raise TypeError ("invalid partial state" )
413403
414- if args and args [- 1 ] is Placeholder :
415- raise TypeError ("unexpected trailing Placeholders" )
404+ # if args and args[-1] is Placeholder:
405+ # raise TypeError("unexpected trailing Placeholders")
416406 phcount , merger = _partial_prepare_merger (args )
417407
418408 args = tuple (args ) # just in case it's a subclass
@@ -435,6 +425,7 @@ def __setstate__(self, state):
435425except ImportError :
436426 pass
437427
428+
438429# Descriptor version
439430class partialmethod :
440431 """Method descriptor with partial application of the given arguments
@@ -446,50 +437,49 @@ class partialmethod:
446437
447438 __slots__ = ("func" , "args" , "keywords" , "wrapper" ,
448439 "__isabstractmethod__" , "__dict__" , "__weakref__" )
440+
449441 __repr__ = _partial_repr
442+ __class_getitem__ = classmethod (GenericAlias )
450443
451444 def __init__ (self , func , / , * args , ** keywords ):
452445 if isinstance (func , partialmethod ):
453446 # Subclass optimization
454447 temp = partial (lambda : None , * func .args , ** func .keywords )
455448 temp = partial (temp , * args , ** keywords )
449+ isabstract = func .__isabstractmethod__
456450 func = func .func
457451 args = temp .args
458452 keywords = temp .keywords
453+ else :
454+ isabstract = getattr (func , '__isabstractmethod__' , False )
459455 self .func = func
460456 self .args = args
461457 self .keywords = keywords
462- self .__isabstractmethod__ = getattr ( func , "__isabstractmethod__" , False )
458+ self .__isabstractmethod__ = isabstract
463459
464460 # 5 cases
465- rewrap = None
466461 if isinstance (func , staticmethod ):
467- self . wrapper = partial (func .__wrapped__ , * args , ** keywords )
468- rewrap = staticmethod
462+ wrapper = partial (func .__wrapped__ , * args , ** keywords )
463+ self . wrapper = _rewrap_func ( wrapper , isabstract , staticmethod )
469464 elif isinstance (func , classmethod ):
470- self . wrapper = partial (func .__wrapped__ , Placeholder , * args , ** keywords )
471- rewrap = classmethod
465+ wrapper = _partial_unbound (func .__wrapped__ , args , keywords )
466+ self . wrapper = _rewrap_func ( wrapper , isabstract , classmethod )
472467 elif isinstance (func , (FunctionType , partial )):
473468 # instance method
474- self .wrapper = partial (func , Placeholder , * args , ** keywords )
469+ wrapper = _partial_unbound (func , args , keywords )
470+ self .wrapper = _rewrap_func (wrapper , isabstract )
475471 elif getattr (func , '__get__' , None ) is None :
476- if not callable (func ):
477- raise TypeError (f"the first argument { func !r} must be a callable "
478- "or a descriptor" )
479472 # callable object without __get__
480473 # treat this like an instance method
481- self .wrapper = partial (func , Placeholder , * args , ** keywords )
474+ if not callable (func ):
475+ raise TypeError (f'the first argument { func !r} must be a callable '
476+ 'or a descriptor' )
477+ wrapper = _partial_unbound (func , args , keywords )
478+ self .wrapper = _rewrap_func (wrapper , isabstract )
482479 else :
483480 # Unknown descriptor
484481 self .wrapper = None
485482
486- # Adjust for abstract and rewrap if needed
487- if self .wrapper is not None :
488- if self .__isabstractmethod__ :
489- self .wrapper = abstractmethod (self .wrapper )
490- if rewrap is not None :
491- self .wrapper = rewrap (self .wrapper )
492-
493483 def __get__ (self , obj , cls = None ):
494484 if self .wrapper is not None :
495485 return self .wrapper .__get__ (obj , cls )
@@ -503,25 +493,32 @@ def __get__(self, obj, cls=None):
503493 pass
504494 return result
505495
506- __class_getitem__ = classmethod (GenericAlias )
507-
508496
509497# Helper functions
510498
499+ def _partial_unbound (func , args , keywords ):
500+ if not args :
501+ return partial (func , ** keywords )
502+ return partial (func , Placeholder , * args , ** keywords )
503+
504+ def _rewrap_func (func , isabstract , decorator = None ):
505+ if isabstract :
506+ func = abstractmethod (func )
507+ if decorator is not None :
508+ func = decorator (func )
509+ return func
510+
511511def _unwrap_partial (func ):
512512 while isinstance (func , partial ):
513513 func = func .func
514514 return func
515515
516516def _unwrap_partialmethod (func ):
517- prev = None
518- while func is not prev :
519- prev = func
520- while isinstance (func , partialmethod ):
521- func = getattr (func , 'func' )
522- func = _unwrap_partial (func )
517+ while isinstance (func , (partial , partialmethod )):
518+ func = func .func
523519 return func
524520
521+
525522################################################################################
526523### LRU Cache function decorator
527524################################################################################
0 commit comments