def travel_distance(self, value): if not Number.is_real_number(value): raise ValidationError("Travel distance must be a number (value is %s)" % value) elif not Number.is_finite(value): raise ValidationError("Travel distance must be a finite number (value is %s)" % value) else: self.set_input("travel_distance", value)
def duration(self, value): """Sets the duration that the robot should wait for (in seconds) :param value: (float) Duration robot should wait :raises ValidationError if d is not a number :raises ValidationError if d is not a positive number """ if isinstance(value, timedelta): self.set_input("duration", value) elif isinstance(value, basestring): match = TIMEDELTA_REGEX.match(value) if match: groups = match.groupdict() self.set_input( "duration", timedelta(hours=int(groups['hours']), minutes=int(groups['minutes']), seconds=int(groups['seconds']))) else: raise ValidationError( "Duration string %s could not be parsed into a timedelta." % value) else: raise ValidationError( "Duration must be a timedelta or string, not a %s." % type(value).__name__)
def required_config(self, configs): """Sets the required hardware configurations necessary for this action. :param ~__builtin__.list configs: The list of required configuration names comprised of only capital letters and underscores. :raise fetchcore.exceptions.ValidationError: Thrown if configs is not a list or if any item in configs is not a string in the correct format. """ if configs is None: self._set("required_config", configs) else: if not isinstance(configs, list): raise ValidationError("Required configurations must be a list") for config in configs: try: if not re.match(re.compile(REGEX_CAPITAL_UNDERSCORE), config): raise ValidationError( 'Required configuration "%s" is in the wrong format (should be comprised of only capital ' 'letters and underscore)' % config) except TypeError: raise ValidationError( "All items in required configurations must be string (%s is a %s)." % (config, type(config).__name__)) self._set("required_config", configs)
def modifiers(self, modifier_ids): """Set the the users who modified this annotation. :param modifier_ids: A list of user IDs. :type modifier_ids: list of int :raise: ValidationError: Thrown if modifier_ids is not a list, if each item's ID is not an integer, or if each item's ID in the list is not a finite positive integer. """ if modifier_ids is None: self._set('modifiers', []) elif not isinstance(modifier_ids, list): raise ValidationError("Modifier ids must be a list, not a %s." % type(modifier_ids).__name__) else: modifier_ids = list(set(modifier_ids)) for modifier_id in modifier_ids: if not Number.is_integer(modifier_id): raise ValidationError( "Each item in modifier IDs must be an int (%s is %s)." % (modifier_id, type(modifier_id).__name__)) elif not Number.is_finite_positive(modifier_id): raise ValidationError( "Each item in modifier IDs must be finite positive (item is %s)." % modifier_id) self._set('modifiers', modifier_ids)
def _get(self, field): """Get the given field. :param field: The field name to get. :return: The value of the field. :raise ValidationError: Thrown if field is not a string or an iterable. """ # TODO: reconsider how the iterable field is dealt with if isinstance(field, basestring): try: # If field is a string, try getting the value by the field return self.__json[field] except KeyError: raise UndefinedFieldError("%s is not set." % field) elif isinstance(field, Iterable): if not field: raise ValidationError( "Input attribute 'field' cannot be a empty list") # Get the value from the nested dictionary value = self.__json for i, f in enumerate(field): try: value = value[f] except KeyError: raise UndefinedFieldError("%s is not set" % ".".join(field[:i + 1])) return value else: raise ValidationError("Field must be a string or an iterable")
def planning_robot_radius(self, planning_robot_radius): """Set the robot's estimated radius for planning. :param float planning_robot_radius: The robot radius for planning. :raise: fetchcore.exceptions.ValidationError: Thrown if planning_robot_radius is: - not a finite non-negative number. - None while the planning footprint type is 'radius'. """ if planning_robot_radius is None: if self.planning_footprint_type == FootprintTypes.RADIUS: raise ValidationError( "Planning robot radius cannot be set to None if planning footprint type is %s." % FootprintTypes.RADIUS) self._set('planning_robot_radius', planning_robot_radius) elif Number.is_real_number(planning_robot_radius): if not Number.is_finite_non_negative(planning_robot_radius): raise ValidationError( "Planning robot radius must be a finite non-negative number (was given as %s)." % planning_robot_radius) self._set('planning_robot_radius', planning_robot_radius) else: raise ValidationError( "Planning Robot radius must be a real number (was given as %s)." % planning_robot_radius)
def __set_footprint_blacklist(self, new_blacklist, blacklist_type, footprint_class): """Set the value of robot/cart footprint blacklist. :param new_blacklist: (iterable) New value to set to the blacklist. :param blacklist_type: (string) Type of the blacklist as a string. Should be either robot_footprint or cart_footprint. :param footprint_class: Resource class of this blacklist type. """ if blacklist_type not in ('robot_footprint', 'cart_footprint'): raise ValidationError( 'EdgeDraft.__set_footprint_blacklist received an unrecognized blacklist type.' ) json_field = blacklist_type + '_blacklist' readable_blacklist_type = ' '.join(blacklist_type.split('_')).title() if new_blacklist is None: self._set(json_field, []) elif isinstance(new_blacklist, collections.Iterable) and not isinstance( new_blacklist, basestring): old_blacklist = deepcopy( self._get(json_field)) if self.is_set(json_field) else [] self._set(json_field, []) for footprint in new_blacklist: try: self.__add_footprint_to_blacklist(footprint, blacklist_type, footprint_class) except ValidationError as e: self._set(json_field, old_blacklist) raise e else: raise ValidationError( '%s blacklist must be an iterable or None, not a %s.' % (readable_blacklist_type, type(new_blacklist).__name__))
def task_templates(self, task_templates): """Set the associated task templates for this schedule. :param task_templates: (list of integers|list of TaskTemplates) A list of task templates or task template IDs. :raise: fetchcore.exceptions.ValidationError Thrown if task_templates is not a list, if each item in values is not an integer, or if each item in the list is not a finite positive integer. """ from .task_template import TaskTemplate if task_templates is None: self.task_template_ids = task_templates elif not isinstance(task_templates, (list, tuple)): raise ValidationError( 'Task templates must be either None, a list or a tuple.') elif not all( isinstance(task_template, (int, TaskTemplate)) for task_template in task_templates): raise ValidationError( 'Task templates must be a list of TaskTemplate objects or integers.' ) else: for task_template in task_templates: if isinstance(task_template, TaskTemplate) and not hasattr( task_template, 'id'): task_template.save() self.task_template_ids = [ task_template.id if isinstance(task_template, TaskTemplate) else task_template for task_template in task_templates ]
def __init__( self, id=None, action=None, survey_pose_states=None, survey_node_states=None, created=None, modified=None, **kwargs): """ :param id: The ID of the survey state. :param action: The action that this state belongs to. :param survey_pose_states: The survey poses associated with this survey state. :param survey_node_states: The survey nodes associated with this survey state. :param created: The date and time of this survey state's creation. :param modified: The date and time this survey state was last modified. :type created: str, ~datetime.datetime :type modified: str, ~datetime.datetime """ super(SurveyState, self).__init__(id=id, created=created, modified=modified, **kwargs) self.action = action if survey_pose_states is None: self._set('survey_pose_states', []) elif not isinstance(survey_pose_states, list): raise ValidationError("Survey poses must be a list, not a %s." % type(survey_pose_states).__name__) else: self._set('survey_pose_states', survey_pose_states) if survey_node_states is None: self._set('survey_node_states', []) elif not isinstance(survey_node_states, list): raise ValidationError("Survey nodes must be a list, not a %s." % type(survey_node_states).__name__) else: self._set('survey_node_states', survey_node_states)
def __remove_footprint_from_blacklist(self, footprint, blacklist_type, footprint_class): """Remove a footprint from a blacklist. :param footprint: Footprint to remove from a blacklist. :param blacklist_type: (string) Type of the blacklist as a string. Should be either robot_footprint or cart_footprint. :param footprint_class: Resource class of this blacklist type. """ if blacklist_type not in ('robot_footprint', 'cart_footprint'): raise ValidationError( 'EdgeDraft.__remove_footprint_from_blacklist received an unrecognized blacklist type.' ) if type(footprint) != footprint_class and not isinstance( footprint, basestring): readable_blacklist_type = ' '.join( blacklist_type.split('_')).title() raise ValidationError( '%s must be a string or a %s object (%s is a %s).' % (readable_blacklist_type, footprint_class.__name__, str(footprint), type(footprint).__name__)) json_field = blacklist_type + '_blacklist' if self.is_set(json_field): try: self._get(json_field).remove(footprint if isinstance( footprint, basestring) else footprint.name) except ValueError: # Footprint is not in list pass
def task_template_ids(self, task_template_ids): """Set the associated task templates IDs for this schedule. :param task_template_ids: A list of task template IDs. :type task_template_ids: list of int :raise: ValidationError: Thrown if task_template_ids is not a list, if each item's ID is not an integer, or if each item's ID in the list is not a finite positive integer. """ if task_template_ids is None: self._set('task_templates', []) elif not isinstance(task_template_ids, list): raise ValidationError( "Task template ids must be a list, not a %s." % type(task_template_ids).__name__) else: task_template_ids = list(set(task_template_ids)) for task_template_id in task_template_ids: if not Number.is_integer(task_template_id): raise ValidationError( "Each item in task template IDs must be an int (%s is %s)." % (task_template_id, type(task_template_id).__name__)) elif not Number.is_finite_positive(task_template_id): raise ValidationError( "Each item in task template IDs must be finite positive (item is %s)." % task_template_id) self._set('task_templates', task_template_ids)
def __init__(self, id=None, version=None, parent=None, map=None, areas=None, name=None, created=None, modified=None, **kwargs): """ :param integer id: The ID of the revision (assigned automatically upon creation). :param integer version: The version of this revision. If NULL, it is considered to be a draft, unpublished version. :param parent: The parent revision that this revision was based off of. :param integer map: The map this revision is associated with. :param string name: The display name for this revision. :param created: The date and time of this revision's creation (assigned automatically). :param modified: The date and time this revision was last modified (updated automatically). :type parent: int, Revision :type created: str, ~datetime.datetime :type modified: str, ~datetime.datetime """ super(Revision, self).__init__(id=id, created=created, modified=modified, **kwargs) self.version = version self.parent = parent self.map = map self.name = name if Number.is_integer(map): if not Number.is_finite_positive(map): raise ValidationError("Map ID must be finite positive (item is %s)." % map) self.endpoint = 'maps/%(map_id)s/revisions' % {'map_id': str(map)} else: raise ValidationError("Map ID must be an integer (%s is %s)." % (map, type(map).__name__)) if areas: self.__areas = areas
def available_action_names(self, available_actions): """Sets the available action names for this configuration. :param available_actions: (list) The list of available action names comprised of only capital letters and underscores. :raise fetchcore.exceptions.ValidationError: Thrown if available_actions is not a list or if any item in available_actions is not a string in the correct format """ if available_actions is None: self._set("available_actions", []) elif not isinstance(available_actions, list): raise ValidationError("Available actions must be a list") else: for available_action in available_actions: try: if not re.match(CAPITAL_UNDERSCORE_PATTERN, available_action): raise ValidationError( "Available action %s does not match the pattern %s" % (available_action, REGEX_CAPITAL_UNDERSCORE)) except TypeError: raise ValidationError( "All items in available actions must be string (%s is a %s)." % (available_action, type(available_action).__name__)) self._set("available_actions", available_actions)
def clearing_footprint_type(self, clearing_footprint_type): """Set the type of clearing footprint described for this configuration. :param str clearing_footprint_type: The footprint type for clearing. :raise fetchcore.exceptions.ValidationError: Thrown if value is: - not a string """ if isinstance(clearing_footprint_type, basestring): if not clearing_footprint_type: raise ValidationError("Footprint type cannot be empty.") if clearing_footprint_type == FootprintTypes.RADIUS: try: if self.clearing_robot_radius is None or self.clearing_inflation_factor is None: raise ValidationError( "Cannot set clearing footprint type to %s when either clearing robot " "radius or clearing inflation factor is None." % FootprintTypes.RADIUS) except UndefinedFieldError: raise ValidationError( "Cannot set clearing footprint type to %s when either clearing robot radius " "or clearing inflation factor is not set." % FootprintTypes.RADIUS) self._set('clearing_footprint_type', clearing_footprint_type) else: raise ValidationError( "Clearing footprint type must be a string, not a %s." % type(clearing_footprint_type).__name__)
def clearing_polygon(self, clearing_polygon): """Set the clearing polygon for this configuration. :param clearing_polygon: The polygon for clearing. :type: A list of three or more dicts, each containing number values for keys 'x' and 'y' """ if clearing_polygon is None: self._set('clearing_polygon', clearing_polygon) elif isinstance(clearing_polygon, (list, tuple)): if len(clearing_polygon) < 3: raise ValidationError( "Length of clearing polygon entry must be greater than or equal to 3 (given " "length was %s)." % len(clearing_polygon)) for item in clearing_polygon: if not isinstance(item, dict): raise ValidationError( "Provided point '%s' for clearing polygon entry is a %s instead of a dict." % (item, type(item).__name__)) if len(item) == 2 and all(key in item for key in ('x', 'y')) and \ all(Number.is_finite(num) and Number.is_real_number(num) for num in item.values()): continue else: raise ValidationError( "Provided point %s for clearing polygon is not a length 2 dictionary " "containing real, finite numbers for 'x' and 'y'." % item) self._set('clearing_polygon', clearing_polygon) else: raise ValidationError( "Clearing polygon must be a list, tuple, or None, not a %s." % type(clearing_polygon).__name__)
def planning_inflation_factor(self, planning_inflation_factor): """Set the factor by which to inflate the robot's radius for planning. :param float planning_inflation_factor: The inflation factor for planning. :raise: fetchcore.exceptions.ValidationError: Thrown if planning_inflation_factor is: - not a finite non-negative number. - None while the planning footprint type is 'radius'. """ if planning_inflation_factor is None: if self.planning_footprint_type == FootprintTypes.RADIUS: raise ValidationError( "Planning robot radius cannot be set to None if planning footprint type is %s." % FootprintTypes.RADIUS) self._set('planning_inflation_factor', planning_inflation_factor) elif Number.is_real_number(planning_inflation_factor): if not Number.is_finite_non_negative(planning_inflation_factor): raise ValidationError( "Planning inflation factor must be a finite positive number (was given as %s)." % planning_inflation_factor) self._set('planning_inflation_factor', planning_inflation_factor) else: raise ValidationError( "Planning inflation factor must be a real number (was given as %s)." % planning_inflation_factor)
def __add_footprint_to_blacklist(self, footprint, blacklist_type, footprint_class): """Add a footprint to a blacklist. :param footprint: New footprint to add to a blacklist. :param blacklist_type: (string) Type of the blacklist as a string. Should be either robot_footprint or cart_footprint. :param footprint_class: Resource class of this blacklist type. """ if blacklist_type not in ('robot_footprint', 'cart_footprint'): raise ValidationError( 'EdgeDraft.__add_footprint_to_blacklist received an unrecognized blacklist type.' ) if type(footprint) != footprint_class and not isinstance( footprint, basestring): readable_blacklist_type = ' '.join( blacklist_type.split('_')).title() raise ValidationError( '%s must be a string or a %s object (%s is a %s).' % (readable_blacklist_type, footprint_class.__name__, str(footprint), type(footprint).__name__)) json_field = blacklist_type + '_blacklist' if not self.is_set(json_field): self._set(json_field, []) blacklist = self._get(json_field) new_footprint = footprint if isinstance(footprint, basestring) else footprint.name if new_footprint not in blacklist: blacklist.append(new_footprint) self._set(json_field, blacklist)
def assignable_robot_names(self, assignable_robot_names): """Set the list of robot names assigned to this task template. :param assignable_robot_names: A list of assignable robot names. :type assignable_robot_names: list of int :raise: fetchcore.exceptions.ValidationError Thrown if assignable_robot_names is not a list or if each item's name is not None or not a Freight's name. """ if assignable_robot_names is None: self._set('assignable_robots', []) elif not isinstance(assignable_robot_names, list): raise ValidationError( "Assignable robot names must be a list, not a %s." % type(assignable_robot_names).__name__) else: for assignable_robot_name in assignable_robot_names: try: if not re.compile(ROBOT_NAME_PATTERN).match( assignable_robot_name): raise ValidationError( 'Only Freights can be assigned to tasks. %s does not seem to be a Freight.' % assignable_robot_name) except TypeError: raise ValidationError( 'Robot name can only be the name of a Freight or None.' ) self._set("assignable_robots", assignable_robot_names)
def assignable_robots(self, assignable_robots): """Set the list of robots assigned to this task template. :param assignable_robots: A list of assignable robots or assignable robot names. :type assignable_robots: list of integers, list of Robots :raise: fetchcore.exceptions.ValidationError Thrown if assignable_robots is not a list, if each item in values is not a AssignableRobot object, or if each item in the list is not a finite positive integer. """ if assignable_robots is None: self.assignable_robot_names = assignable_robots elif not isinstance(assignable_robots, (list, tuple)): raise ValidationError( 'Assignable robots must be either None, a list or a tuple.') elif not all( isinstance(assignable_robot, (basestring, Robot)) for assignable_robot in assignable_robots): raise ValidationError( 'Assignable robots must be a list of Robot objects or strings.' ) else: self.assignable_robot_names = [ assignable_robot.name if isinstance(assignable_robot, Robot) else assignable_robot for assignable_robot in assignable_robots ]
def cart_footprint_name(self, value): try: if re.match(REGEX_CAPITAL_UNDERSCORE, value): self.set_input("cart_footprint_name", value) else: raise ValidationError("%s does not match the pattern %s" % (value, REGEX_CAPITAL_UNDERSCORE)) except TypeError: raise ValidationError("Cart footprint name must be a string, not a %s" % type(value).__name__)
def shape_name(self, value): if not isinstance(value, basestring): raise ValidationError("Shape name must be a string, not a %s" % type(value).__name__) elif value not in ComponentShapes: raise ValidationError( "Shape name '%s' is not a valid component shape." % value) else: self._set('shape_name', value)
def goal_yaw_tolerance(self, value): if not Number.is_real_number(value): raise ValidationError( "Goal yaw tolerance must be a number (value is %s)" % value) elif not Number.is_finite(value): raise ValidationError( "Goal yaw tolerance must be a finite number (value is %s)" % value) else: self.set_input("goal_yaw_tolerance", value)
def sound_id(self, sound_id): """Sets the ID of the sound file to be played :param sound_id: (string) The sound_id :raises ValidationError if sound_id is not an integer or if sound_id is None """ if sound_id is None: raise ValidationError("Sound ID must not be none") elif not isinstance(sound_id, int): raise ValidationError("Sound ID must be an integer.") self.set_input("sound_id", sound_id)
def dict_to_float_list(value): if isinstance(value, dict): try: return [value[key] for key in ['x', 'y', 'theta']] except ValueError: raise ValidationError( "%s is not a pose dict (a dict containing 3 finite numbers assigned to x, y," " and theta)" % value) else: raise ValidationError("Value must be a dict, not %s" % type(value).__name__)
def hint_position_tolerance(self, value): if not Number.is_real_number(value): raise ValidationError( "Hint position tolerance must be a number (value is %s)" % value) elif not Number.is_finite(value): raise ValidationError( "Hint position tolerance must be a finite number (value is %s)" % value) else: self.set_input("hint_position_tolerance", value)
def survey_path_id(self, value): """Sets the ID of survey path for this action to follow. :param value: (integer) Survey path ID :raises ValidationError if value is not a positive finite integer """ if Number.is_integer(value): if not Number.is_finite_positive(value): raise ValidationError("Survey path ID must be a finite positive number (value is %s)" % value) self.set_input("survey_path_id", value) else: raise ValidationError("Survey path ID must be a number (value is %s)" % value)
def password(self, value): """Set the robot's password. :param password: (string) The robot's password. :raise fetchcore.exceptions.ValidationError: Thrown if password is not a string or if password is empty. """ if isinstance(value, basestring): if not value: raise ValidationError("Password cannot be empty.") self._set('password', value) else: raise ValidationError("Password must be a string, not a %s." % type(value).__name__)
def ip(self, ip): """Set the IP address of the reporter of this log. :param str ip: The IP address of the reporter of this log. :raise: fetchcore.exceptions.ValidationError Thrown if the ip is not a valid IP address string. """ if not IP.valid_type(ip): raise ValidationError("IP must be a string.") elif not IP.valid_address(ip): raise ValidationError("%s is not a legal IP address." % ip) else: self._set('ip', ip)
def map(self, map): """Set the map that this revision belongs to. :param integer map: The map. :raise fetchcore.exceptions.ValidationError:: Thrown if map not a finite positive integer. """ if Number.is_integer(map): if not Number.is_finite_positive(map): raise ValidationError("Map ID must be finite positive (item is %s)." % map) self._set('map', map) else: raise ValidationError("Map ID must be an integer (%s is %s)." % (map, type(map).__name__))
def distance_ratio(self, distance_ratio): """Sets the distance along the edge where this pose sits (bound between 0 and 1). :param float distance_ratio: The distance ratio. :raise fetchcore.exceptions.ValidationError: Thrown if distance_ratio is not a finite number in between 0 and 1. """ if not Number.is_real_number(distance_ratio): raise ValidationError("Distance ratio must be a number (distance_ratio is %s)" % distance_ratio) elif distance_ratio < 0 or distance_ratio > 1: raise ValidationError("Distance ratio must be between 0 and 1 (distance_ratio is %s)" % distance_ratio) else: self._set("distance_ratio", distance_ratio)