mirror of
https://github.com/wassname/ray.git
synced 2026-06-28 21:12:15 +08:00
e0867c8845
* 4 space indentation for actor.py. * 4 space indentation for worker.py. * 4 space indentation for more files. * 4 space indentation for some test files. * Check indentation in Travis. * 4 space indentation for some rl files. * Fix failure test. * Fix multi_node_test. * 4 space indentation for more files. * 4 space indentation for remaining files. * Fixes.
178 lines
7.0 KiB
Python
178 lines
7.0 KiB
Python
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
from collections import namedtuple
|
|
import funcsigs
|
|
|
|
FunctionSignature = namedtuple("FunctionSignature", ["arg_names",
|
|
"arg_defaults",
|
|
"arg_is_positionals",
|
|
"keyword_names",
|
|
"function_name"])
|
|
"""This class is used to represent a function signature.
|
|
|
|
Attributes:
|
|
keyword_names: The names of the functions keyword arguments. This is used
|
|
to test if an incorrect keyword argument has been passed to the
|
|
function.
|
|
arg_defaults: A dictionary mapping from argument name to argument default
|
|
value. If the argument is not a keyword argument, the default value
|
|
will be funcsigs._empty.
|
|
arg_is_positionals: A dictionary mapping from argument name to a bool. The
|
|
bool will be true if the argument is a *args argument. Otherwise it
|
|
will be false.
|
|
function_name: The name of the function whose signature is being
|
|
inspected. This is used for printing better error messages.
|
|
"""
|
|
|
|
|
|
def check_signature_supported(func, warn=False):
|
|
"""Check if we support the signature of this function.
|
|
|
|
We currently do not allow remote functions to have **kwargs. We also do not
|
|
support keyword arguments in conjunction with a *args argument.
|
|
|
|
Args:
|
|
func: The function whose signature should be checked.
|
|
warn: If this is true, a warning will be printed if the signature is
|
|
not supported. If it is false, an exception will be raised if the
|
|
signature is not supported.
|
|
|
|
Raises:
|
|
Exception: An exception is raised if the signature is not supported.
|
|
"""
|
|
function_name = func.__name__
|
|
sig_params = [(k, v) for k, v
|
|
in funcsigs.signature(func).parameters.items()]
|
|
|
|
has_vararg_param = False
|
|
has_kwargs_param = False
|
|
has_keyword_arg = False
|
|
for keyword_name, parameter in sig_params:
|
|
if parameter.kind == parameter.VAR_KEYWORD:
|
|
has_kwargs_param = True
|
|
if parameter.kind == parameter.VAR_POSITIONAL:
|
|
has_vararg_param = True
|
|
if parameter.default != funcsigs._empty:
|
|
has_keyword_arg = True
|
|
|
|
if has_kwargs_param:
|
|
message = ("The function {} has a **kwargs argument, which is "
|
|
"currently not supported.".format(function_name))
|
|
if warn:
|
|
print(message)
|
|
else:
|
|
raise Exception(message)
|
|
# Check if the user specified a variable number of arguments and any
|
|
# keyword arguments.
|
|
if has_vararg_param and has_keyword_arg:
|
|
message = ("Function {} has a *args argument as well as a keyword "
|
|
"argument, which is currently not supported."
|
|
.format(function_name))
|
|
if warn:
|
|
print(message)
|
|
else:
|
|
raise Exception(message)
|
|
|
|
|
|
def extract_signature(func, ignore_first=False):
|
|
"""Extract the function signature from the function.
|
|
|
|
Args:
|
|
func: The function whose signature should be extracted.
|
|
ignore_first: True if the first argument should be ignored. This should
|
|
be used when func is a method of a class.
|
|
|
|
Returns:
|
|
A function signature object, which includes the names of the keyword
|
|
arguments as well as their default values.
|
|
"""
|
|
sig_params = [(k, v) for k, v
|
|
in funcsigs.signature(func).parameters.items()]
|
|
|
|
if ignore_first:
|
|
if len(sig_params) == 0:
|
|
raise Exception("Methods must take a 'self' argument, but the "
|
|
"method '{}' does not have one."
|
|
.format(func.__name__))
|
|
sig_params = sig_params[1:]
|
|
|
|
# Extract the names of the keyword arguments.
|
|
keyword_names = set()
|
|
for keyword_name, parameter in sig_params:
|
|
if parameter.default != funcsigs._empty:
|
|
keyword_names.add(keyword_name)
|
|
|
|
# Construct the argument default values and other argument information.
|
|
arg_names = []
|
|
arg_defaults = []
|
|
arg_is_positionals = []
|
|
for keyword_name, parameter in sig_params:
|
|
arg_names.append(keyword_name)
|
|
arg_defaults.append(parameter.default)
|
|
arg_is_positionals.append(parameter.kind == parameter.VAR_POSITIONAL)
|
|
|
|
return FunctionSignature(arg_names, arg_defaults, arg_is_positionals,
|
|
keyword_names, func.__name__)
|
|
|
|
|
|
def extend_args(function_signature, args, kwargs):
|
|
"""Extend the arguments that were passed into a function.
|
|
|
|
This extends the arguments that were passed into a function with the
|
|
default arguments provided in the function definition.
|
|
|
|
Args:
|
|
function_signature: The function signature of the function being
|
|
called.
|
|
args: The non-keyword arguments passed into the function.
|
|
kwargs: The keyword arguments passed into the function.
|
|
|
|
Returns:
|
|
An extended list of arguments to pass into the function.
|
|
|
|
Raises:
|
|
Exception: An exception may be raised if the function cannot be called
|
|
with these arguments.
|
|
"""
|
|
arg_names = function_signature.arg_names
|
|
arg_defaults = function_signature.arg_defaults
|
|
arg_is_positionals = function_signature.arg_is_positionals
|
|
keyword_names = function_signature.keyword_names
|
|
function_name = function_signature.function_name
|
|
|
|
args = list(args)
|
|
|
|
for keyword_name in kwargs:
|
|
if keyword_name not in keyword_names:
|
|
raise Exception("The name '{}' is not a valid keyword argument "
|
|
"for the function '{}'."
|
|
.format(keyword_name, function_name))
|
|
|
|
# Fill in the remaining arguments.
|
|
zipped_info = list(zip(arg_names, arg_defaults,
|
|
arg_is_positionals))[len(args):]
|
|
for keyword_name, default_value, is_positional in zipped_info:
|
|
if keyword_name in kwargs:
|
|
args.append(kwargs[keyword_name])
|
|
else:
|
|
if default_value != funcsigs._empty:
|
|
args.append(default_value)
|
|
else:
|
|
# This means that there is a missing argument. Unless this is
|
|
# the last argument and it is a *args argument in which case it
|
|
# can be omitted.
|
|
if not is_positional:
|
|
raise Exception("No value was provided for the argument "
|
|
"'{}' for the function '{}'."
|
|
.format(keyword_name, function_name))
|
|
|
|
too_many_arguments = (len(args) > len(arg_names) and
|
|
(len(arg_is_positionals) == 0 or
|
|
not arg_is_positionals[-1]))
|
|
if too_many_arguments:
|
|
raise Exception("Too many arguments were passed to the function '{}'"
|
|
.format(function_name))
|
|
return args
|