code: def _wrapped(self):
          
  
          # It is possible for a callable instance without __name__ attribute or/and
          # __module__ attribute to be wrapped here. For example, functools.partial. In this case,
          # we should avoid wrapping the attributes from the wrapped function to the wrapper
          # function. So, we take out these attribute names from the default names to set and
          # then manually assign it after being wrapped.
          assignments = tuple(
              a for a in functools.WRAPPER_ASSIGNMENTS if a != '__name__' and a != '__module__')
  
          @functools.wraps(self.func, assigned=assignments)
          def wrapper(*args):
              return self(*args)
  
          wrapper.__name__ = self._name
          wrapper.__module__ = (self.func.__module__ if hasattr(self.func, '__module__')
                                else self.func.__class__.__module__)
  
          wrapper.func = self.func
          wrapper.returnType = self.returnType
          wrapper.evalType = self.evalType
          wrapper.deterministic = self.deterministic
          wrapper.asNondeterministic = functools.wraps(
              self.asNondeterministic)(lambda: self.asNondeterministic()._wrapped())
          return wrapper
docs: Wrap this udf with a function and attach docstring from func