def visit_struct(self, typ): """ Visit StructValue :type typ: :class:`vmware.vapi.bindings.type.StructType` :param typ: Binding type of the value """ in_value = self._in_value out_value = {} typ_field_names = typ.get_field_names() value_field_names = in_value.get_field_names() for field_name in typ_field_names: if typ.binding_class: pep_name = typ.binding_class._get_pep_name(field_name) # pylint: disable=W0212 else: pep_name = Converter.canonical_to_pep(field_name) field_type = typ.get_field(field_name) # When the request is converted from DataValue to Native value # on the server side: # - if the client - server version matches: we wont hit this case # - if new client talks to old server, runtime would have # raised InvalidArgument error if there are unexpected optional # fields # - if old client talks to new server, runtime adds the missing # optional fields, so we wont hit this case # # When the response is converted from DataValue to Native value # on the client side: # - if the client - server version matches: we wont hit this case # - if new client talks to old server, client bindings should # tolerate the absence of expected optional properties. So, # we have to set it to None! # - if old client talks to new server, we will visit all the known # fields here and the unexpected fields are added to the # VapiStruct object if ((isinstance(field_type, OptionalType) or self._allow_skip_struct_fields) and not in_value.has_field(field_name)): out_value[pep_name] = None else: out_value[pep_name] = self._visit_struct_field( in_value.get_field(field_name), field_type) self._in_value = in_value struct_class = typ.binding_class if struct_class is not None: struct_class.validate_struct_value(self._in_value) self._out_value = struct_class(**out_value) # Fields present in struct value but not in struct binding type. extra_field_names = set(value_field_names) - set(typ_field_names) if extra_field_names: extra_fields = {} for field_name in extra_field_names: extra_fields[field_name] = in_value.get_field(field_name) self._out_value._set_extra_fields(extra_fields) # pylint: disable=E1103,W0212 else: self._out_value = out_value
def _get_pep_name(cls, canonical_name): """ Return the pep name for the provided canonical name :rtype: :class:`str` :return: Pep name used in the binding """ if (cls._canonical_to_pep_names and canonical_name in cls._canonical_to_pep_names): return cls._canonical_to_pep_names[canonical_name] else: return Converter.canonical_to_pep(canonical_name)
def __dir__(cls): """ Return the names of the factory methods that are synthesized for each of standard error types in addition to the name of the attributes in the base class (object). """ #pylint: disable=R0201 method_names = [ 'new_' + Converter.capwords_to_underscore(name) for name in enumerate_standard_error_names() ] return sorted(dir(object) + method_names)
def _pepify_args(meth_args): """ Pepify the names of the method arguments :type meth_args: :class:`dict` :param meth_args: Actual method arguments :rtype: :class:`dict` :return: Modified method arguments with pepified names """ new_args = {} for k, v in six.iteritems(meth_args): new_args[Converter.pepify(k)] = v return new_args
def _pepify_args(meth_args): """ Converts all the keys of given keyword arguments into PEP8 standard names :type meth_args: :class:`dict` :param meth_args: The keyword arguments to be converted :rtype: :class:`dict` :return: The converted keyword arguments """ new_args = {} for k, v in six.iteritems(meth_args): new_args[Converter.canonical_to_pep(k)] = v return new_args
def _build_py_value(data_value, data_def, impl=None): """" Converts a data value to python native value impl input is required to create Struct class instances :type data_value: :class:`vmware.vapi.data.value.DataValue` :param data_value: Input data value :type data_def: :class:`vmware.vapi.data.definition.DataDefinition` :param data_def: Data definition :type impl: :class:`vmware.vapi.bindings.stub.VapiInterface` or :class:`vmware.vapi.bindings.skeleton.VapiInterface` or ``None`` :param impl: Python generated class to resolve structure classes :rtype: :class:`object` :return: Native python value """ if data_def.type == Type.OPTIONAL: if data_value.is_set(): element_def = data_def.element_type element_value = data_value.value py_value = _build_py_value(element_value, element_def, impl) else: py_value = None elif data_def.type == Type.LIST: py_value = [] element_def = data_def.element_type for element_value in data_value: py_value.append(_build_py_value(element_value, element_def, impl)) elif data_def.type in (Type.STRUCTURE, Type.ERROR): struct_name = data_def.name class_name = Converter.underscore_to_capwords(struct_name) py_value = {} for field in data_def.get_field_names(): field_def = data_def.get_field(field) field_val = data_value.get_field(field) py_value[field] = _build_py_value(field_val, field_def, impl) if impl and hasattr(impl, class_name): kwargs = _pepify_args(py_value) py_value = getattr(impl, class_name)(**kwargs) elif data_def.type == Type.VOID: py_value = None # For opaque value, no need of any conversion elif data_def.type == Type.OPAQUE: py_value = data_value # Primitive type Integer/Double/String/Boolean/Secret else: py_type = _py_type_map.get(data_def.type) py_value = py_type(data_value.value) return py_value
def create_stub(self, service_name): """ Create a stub corresponding to the specified service name :type service_name: :class:`str` :param service_name: Name of the service :rtype: :class:`VapiInterface` :return: The stub correspoding to the specified service name """ path_split = service_name.split('.') module_name = '%s_client' % '.'.join(path_split[:-1]) class_name = Converter.underscore_to_capwords(path_split[-1]) module = __import__(module_name, globals(), locals(), class_name) cls = getattr(module, class_name) return cls(self._config)
def visit(self, value): """ Dispatch the call to the appropriate method based on the type of the input argument :type value: :class:`object` :param value: The object to be used for dispatch """ class_name = value.__class__.__name__ method = self._cache.get(class_name) if not method: type_name = class_name if self._suffix and type_name.endswith(self._suffix): type_name = type_name[:-len(self._suffix)] type_name = Converter.capwords_to_underscore(type_name) method = getattr(self, 'visit_' + type_name) self._cache[class_name] = method return method(value)
def __getattr__(cls, name): """ Return a synthesized factory method if the given name matches the name of one of the standard error types (after converting from lower-case-with-underscores to cap-words). """ if name.startswith(cls.METHOD_PREFIX) and name is not 'new_vapi_error': canonical_error_type_name = name[cls.METHOD_PREFIX_LENGTH:] capwords_error_type_name = Converter.underscore_to_capwords( canonical_error_type_name) error_type = getattr(errors_provider, capwords_error_type_name) if (isinstance(error_type, type) and issubclass(error_type, VapiError)): def factory_method(**kwargs): """ Synthesized factory function for a standard error type. """ return error_type(**kwargs) return factory_method msg = "type object '%s' has no attribute '%s'" % (cls.__name__, name) raise AttributeError(msg)
def _visit_python_dict(self, typ): """ Visit an instance of Python native dictionary :type typ: :class:`vmware.vapi.bindings.type.StructType` :param typ: Binding type of the value :rtype: :class:`vmware.vapi.data.value.DataValue` :return: vAPI Data value """ in_value = self._in_value out_value = typ.definition.new_value() field_names = typ.get_field_names() for field_name in field_names: field_type = typ.get_field(field_name) try: if typ.binding_class: # pylint: disable=W0212 pep_name = typ.binding_class._get_pep_name(field_name) else: pep_name = Converter.canonical_to_pep(field_name) self._in_value = in_value[pep_name] except KeyError: if isinstance(field_type, OptionalType): # If the field is optional, then tolerate # the absence of it in the dictionary self._in_value = None else: msg = message_factory.get_message( 'vapi.bindings.typeconverter.dict.missing.key', pep_name) logger.debug(msg) raise CoreException(msg) self.visit(field_type) out_value.set_field(field_name, self._out_value) self._in_value = in_value self._out_value = out_value
def test_capitalize(self): self.assertEqual(Converter.capitalize('abc'), 'Abc')
def invoke(self, ctx, method_id, input_value): """ Invokes the specified method using the execution context and the input provided :type ctx: :class:`vmware.vapi.core.ExecutionContext` :param ctx: Execution context for this method :type input_value: :class:`vmware.vapi.data.value.StructValue` :param input_value: Method input parameters :rtype: :class:`vmware.vapi.core.MethodResult` :return: Result of the method invocation """ op_info = self._operations.get(method_id.get_name()) # Set execution context set_context(ctx) try: # input validators validators = op_info['input_value_validator_list'] input_type = op_info['input_type'] for validator in validators: msg_list = validator.validate(input_value, input_type) if msg_list: error_value = make_error_value_from_msgs( self._invalid_argument_def, *msg_list) return MethodResult(error=error_value) error_value = ApiInterfaceSkeleton.check_for_unknown_fields( input_type, input_value) if error_value: return MethodResult(error=error_value) try: meth_args = TypeConverter.convert_to_python( input_value, binding_type=input_type, resolver=self._resolver) except CoreException as e: error_value = make_error_value_from_msgs( self._invalid_argument_def, *e.messages) return MethodResult(error=error_value) method_name = Converter.canonical_to_pep( get_non_task_operation_name(method_id.get_name())) method = getattr(self._impl, method_name) # If it's a task method then create a new thread to run provider # impl and return task id or result depending upon type of # invocation. if op_info['task_type'] != TaskType.NONE: meth_output, task_accepted = self._invoke_task_operation( ctx, method_id, method, meth_args) if isinstance(meth_output, VapiError): raise meth_output # pylint: disable=raising-bad-type # In case of provider not accepting task throw an error. if task_accepted is False: msg_list = [message_factory.get_message( 'vapi.bindings.skeleton.task.invalidstate')] error_value = make_error_value_from_msgs( self._internal_server_error_def, *msg_list) return MethodResult(error=error_value) else: meth_output = method(**meth_args) output_type = op_info['output_type'] # output validators validators = op_info['output_validator_list'] output = TypeConverter.convert_to_vapi(meth_output, output_type) for validator in validators: msg_list = validator.validate(output, output_type) if msg_list: error_value = make_error_value_from_msgs( self._internal_server_error_def, *msg_list) return MethodResult(error=error_value) result = MethodResult(output=output) except CoreException as e: logger.exception("Error in invoking %s - %s", str(method_id), e) error_value = make_error_value_from_msgs( self._internal_server_error_def, *e.messages) result = MethodResult(error=error_value) except VapiError as e: exc_info = sys.exc_info() error_type = e.__class__.get_binding_type() try: error = TypeConverter.convert_to_vapi(e, error_type) except CoreException as ce: logger.error('Failed to convert %s to error type %s because %s', e, error_type.name, ' because '.join((e.def_msg for e in ce.messages)), exc_info=exc_info) raise result = MethodResult(error=error) finally: # Reset the execution context after the operation clear_context() return result
def test_capwords_to_underscore(self): self.assertEqual(Converter.mixedcase_to_underscore('CapWords'), 'cap_words') self.assertEqual(Converter.mixedcase_to_underscore('cap_words'), 'cap_words')
def test_underscore_to_mixedcase(self): self.assertEqual(Converter.underscore_to_mixedcase('mixed_case'), 'mixedCase') self.assertEqual(Converter.underscore_to_mixedcase('mixedCase'), 'mixedCase')
def test_uncapitalize(self): self.assertEqual(Converter.uncapitalize('Abc'), 'abc')
def test_underscore_to_capwords(self): self.assertEqual(Converter.underscore_to_capwords('cap_words'), 'CapWords') self.assertEqual(Converter.underscore_to_capwords('CapWords'), 'CapWords')
def test_pepify(self): self.assertEqual(Converter.pepify('class'), 'class_')