def test_route_with_auth_mode1(self): # type: () -> None route1 = ApiRoute('get_metadata', 1, None) route1.set_attributes(None, ':route:`get_metadata:2`', Void(), Void(), Void(), {'auth': 'app'}) route2 = ApiRoute('get_metadata', 2, None) route2.set_attributes(None, None, Void(), Int32(), Void(), {'auth': 'user, app'}) ns = ApiNamespace('files') ns.add_route(route1) ns.add_route(route2) result = self._evaluate_namespace_with_auth_mode(ns, 'user') expected = textwrap.dedent('''\ # ------------------------------------------ # Routes in files namespace def files_get_metadata_v2(self): arg = None r = self.request( files.get_metadata_v2, 'files', arg, None, ) return r ''') self.assertEqual(result, expected)
def _make_namespace_with_nested_types(): # type: (...) -> ApiNamespace ns = ApiNamespace('ns_w_nested_types') struct = Struct(name='NestedTypes', namespace=ns, ast_node=None) struct.set_attributes( doc=None, fields=[ StructField( name='NullableList', data_type=Nullable( List(UInt64()) ), doc=None, ast_node=None, ), StructField( name='ListOfNullables', data_type=List( Nullable(UInt64()) ), doc=None, ast_node=None, ) ] ) ns.add_data_type(struct) return ns
def test__generate_types_empty_ns(self): # type: () -> None backend = _make_backend(target_folder_path="output", template_path="") empty_ns = ApiNamespace("empty_namespace") result = _evaluate_namespace(backend, [empty_ns]) expected = textwrap.dedent("") self.assertEqual(result, expected)
def test_namespace_comments(self): # type: () -> None ns = ApiNamespace('files') ns.add_doc("Test Doc testing a :type:`Type`.") route_schema = self._mk_route_schema() api = Api('0.0') api.add_route_schema(route_schema) result = self._evaluate_namespace_definition(api, ns) expected = textwrap.dedent("""\ # -*- coding: utf-8 -*- # Auto-generated by Stone, do not modify. # @generated # flake8: noqa # pylint: skip-file \"\"\" Test Doc testing a :class:`Type`. \"\"\" from __future__ import unicode_literals from stone.backends.python_rsrc import stone_base as bb from stone.backends.python_rsrc import stone_validators as bv ROUTES = { } """) self.assertEqual(result, expected)
def test_annotation_type_class(self): # type: () -> None ns = ApiNamespace('files') annotation_type = AnnotationType('MyAnnotationType', ns, "documented", [ AnnotationTypeParam( 'test_param', Int32(), "test parameter", False, None, None, ), AnnotationTypeParam( 'test_default_param', Int32(), None, True, 5, None, ), ]) result = self._evaluate_annotation_type(ns, annotation_type) expected = textwrap.dedent('''\ class MyAnnotationType(bb.AnnotationType): """ documented :ivar test_param: test parameter """ __slots__ = [ '_test_param', '_test_default_param', ] def __init__(self, test_param=None, test_default_param=5): self._test_param = test_param self._test_default_param = test_default_param @property def test_param(self): """ test parameter :rtype: int """ return self._test_param @property def test_default_param(self): """ :rtype: int """ return self._test_default_param ''') self.assertEqual(result, expected)
def _make_namespace_with_nullable_and_dafault_fields(): # type: (...) -> ApiNamespace ns = ApiNamespace('ns_w_nullable__fields') struct = Struct(name='Struct1', namespace=ns, ast_node=None) default_field = StructField( name='DefaultField', data_type=UInt64(), doc=None, ast_node=None, ) default_field.set_default(1) struct.set_attributes(doc=None, fields=[ StructField( name='NullableField', data_type=Nullable(UInt64()), doc=None, ast_node=None, ), default_field, StructField( name='RequiredField', data_type=UInt64(), doc=None, ast_node=None, ) ]) ns.add_data_type(struct) return ns
def _make_namespace_with_a_union(): # type: (...) -> ApiNamespace ns = ApiNamespace('ns_with_a_union') u1 = Union(name='Union', namespace=ns, ast_node=None, closed=True) u1.set_attributes( doc=None, fields=[ UnionField(name="first", doc=None, data_type=Void(), ast_node=None), UnionField(name="last", doc=None, data_type=Void(), ast_node=None), ], ) ns.add_data_type(u1) # A more interesting case with non-void variants. shape_union = Union(name='Shape', namespace=ns, ast_node=None, closed=True) shape_union.set_attributes( doc=None, fields=[ UnionField(name="point", doc=None, data_type=Void(), ast_node=None), UnionField(name="circle", doc=None, data_type=Float64(), ast_node=None), ], ) ns.add_data_type(shape_union) return ns
def test_struct_with_custom_annotations(self): # type: () -> None ns = ApiNamespace('files') annotation_type = AnnotationType('MyAnnotationType', ns, None, [ AnnotationTypeParam('test_param', Int32(), None, False, None, None) ]) ns.add_annotation_type(annotation_type) annotation = CustomAnnotation('MyAnnotation', ns, None, 'MyAnnotationType', None, [], {'test_param': 42}) annotation.set_attributes(annotation_type) ns.add_annotation(annotation) struct = Struct('MyStruct', ns, None) struct.set_attributes(None, [ StructField('annotated_field', Int32(), None, None), StructField('unannotated_field', Int32(), None, None), ]) struct.fields[0].set_annotations([annotation]) struct.recursive_custom_annotations = set([annotation]) result = self._evaluate_struct(ns, struct) expected = textwrap.dedent('''\ class MyStruct(bb.Struct): __slots__ = [ '_annotated_field_value', '_unannotated_field_value', ] _has_required_fields = True def __init__(self, annotated_field=None, unannotated_field=None): self._annotated_field_value = bb.NOT_SET self._unannotated_field_value = bb.NOT_SET if annotated_field is not None: self.annotated_field = annotated_field if unannotated_field is not None: self.unannotated_field = unannotated_field # Instance attribute type: int (validator is set below) annotated_field = bb.Attribute("annotated_field") # Instance attribute type: int (validator is set below) unannotated_field = bb.Attribute("unannotated_field") def _process_custom_annotations(self, annotation_type, field_path, processor): super(MyStruct, self)._process_custom_annotations(annotation_type, field_path, processor) if annotation_type is MyAnnotationType: self.annotated_field = bb.partially_apply(processor, MyAnnotationType(test_param=42))('{}.annotated_field'.format(field_path), self.annotated_field) MyStruct_validator = bv.Struct(MyStruct) ''') # noqa self.maxDiff = None self.assertEqual(result, expected)
def _make_namespace_with_empty_union(): # type: (...) -> ApiNamespace ns = ApiNamespace('ns_with_empty_union') union = Union(name='EmptyUnion', namespace=ns, ast_node=None, closed=True) union.set_attributes( doc=None, fields=[], ) ns.add_data_type(union) return ns
def _make_namespace_with_alias(): # type: (...) -> ApiNamespace ns = ApiNamespace('ns_with_alias') struct1 = Struct(name='Struct1', namespace=ns, ast_node=None) struct1.set_attributes(None, [StructField('f1', Boolean(), None, None)]) ns.add_data_type(struct1) alias = Alias(name='AliasToStruct1', namespace=ns, ast_node=None) alias.set_attributes(doc=None, data_type=struct1) ns.add_alias(alias) return ns
def _get_api(self): # type () -> Api api = Api(version='0.1b1') api.route_schema = Struct(u'Route', 'stone_cfg', None) route1 = ApiRoute('get_metadata', 1, None) route1.set_attributes(None, ':route:`get_metadata`', Void(), Void(), Void(), {}) route2 = ApiRoute('get_metadata', 2, None) route2.set_attributes(None, ':route:`get_metadata:2`', Void(), Int32(), Void(), {}) ns = ApiNamespace('files') ns.add_route(route1) ns.add_route(route2) api.namespaces[ns.name] = ns return api, ns
def test_route_argument_doc_string(self): backend = PythonClientBackend( target_folder_path='output', args=['-m', 'files', '-c', 'DropboxBase', '-t', 'dropbox']) ns = ApiNamespace('files') self.assertEqual(backend._format_type_in_doc(ns, Int32()), 'int') self.assertEqual(backend._format_type_in_doc(ns, Void()), 'None') self.assertEqual(backend._format_type_in_doc(ns, List(String())), 'List[str]') self.assertEqual(backend._format_type_in_doc(ns, Nullable(String())), 'Nullable[str]') self.assertEqual( backend._format_type_in_doc(ns, Map(String(), Int32())), 'Map[str, int]')
def _make_namespace_with_route(): # type: (...) -> ApiNamespace ns = ApiNamespace("_make_namespace_with_route()") mock_ast_node = Mock() route_one = ApiRoute( name="route_one", ast_node=mock_ast_node, ) route_two = ApiRoute( name="route_two", ast_node=mock_ast_node, ) ns.add_route(route_one) ns.add_route(route_two) return ns
def test_route_with_version_number_name_conflict(self): # type: () -> None route1 = ApiRoute('get_metadata', 2, None) route1.set_attributes(None, None, Void(), Int32(), Void(), {}) route2 = ApiRoute('get_metadata_v2', 1, None) route2.set_attributes(None, None, Void(), Void(), Void(), {}) ns = ApiNamespace('files') ns.add_route(route1) ns.add_route(route2) with self.assertRaises(RuntimeError) as cm: self._evaluate_namespace(ns) self.assertEqual( 'There is a name conflict between {!r} and {!r}'.format( route1, route2), str(cm.exception))
def _make_namespace_with_route_name_conflict(): # type: (...) -> ApiNamespace ns = ApiNamespace("_make_namespace_with_route()") mock_ast_node = Mock() route_one = ApiRoute( name="route_one_v2", version=1, ast_node=mock_ast_node, ) route_two = ApiRoute( name="route_one", version=2, ast_node=mock_ast_node, ) ns.add_route(route_one) ns.add_route(route_two) return ns
def test_api_namespace(self): ns = ApiNamespace('files') a1 = Struct('A1', None, ns) a1.set_attributes(None, [StructField('f1', Boolean(), None, None)]) a2 = Struct('A2', None, ns) a2.set_attributes(None, [StructField('f2', Boolean(), None, None)]) l1 = List(a1) s = String() route = ApiRoute('test/route', 1, None) route.set_attributes(None, None, l1, a2, s, None) ns.add_route(route) # Test that only user-defined types are returned. route_io = ns.get_route_io_data_types() self.assertIn(a1, route_io) self.assertIn(a2, route_io) self.assertNotIn(l1, route_io) self.assertNotIn(s, route_io)
def test__generate_types_with_empty_ns(self): # type: () -> None backend = _make_backend(target_folder_path="output", template_path="") ns = _make_namespace() empty_ns = ApiNamespace("empty_namespace") result = _evaluate_namespace(backend, [ns, empty_ns]) expected = textwrap.dedent(""" type Timestamp = string; namespace accounts { export interface User { exists: boolean; } } """) self.assertEqual(result, expected)
def test_route_with_version_number(self): # type: () -> None route1 = ApiRoute('get_metadata', 1, None) route1.set_attributes(None, ':route:`get_metadata:2`', Void(), Void(), Void(), {}) route2 = ApiRoute('get_metadata', 2, None) route2.set_attributes(None, None, Void(), Int32(), Void(), {}) ns = ApiNamespace('files') ns.add_route(route1) ns.add_route(route2) result = self._evaluate_namespace(ns) expected = textwrap.dedent('''\ def files_get_metadata(self): """ :meth:`files_get_metadata_v2` :rtype: None """ arg = None r = self.request( files.get_metadata, 'files', arg, None, ) return None def files_get_metadata_v2(self): arg = None r = self.request( files.get_metadata_v2, 'files', arg, None, ) return r ''') self.assertEqual(result, expected)
def _make_namespace_with_many_structs(): # type: (...) -> ApiNamespace ns = ApiNamespace('ns_with_many_structs') struct1 = Struct(name='Struct1', namespace=ns, ast_node=None) struct1.set_attributes(None, [StructField('f1', Boolean(), None, None)]) ns.add_data_type(struct1) struct2 = Struct(name='Struct2', namespace=ns, ast_node=None) struct2.set_attributes( doc=None, fields=[ StructField('f2', List(UInt64()), None, None), StructField('f3', Timestamp(ISO_8601_FORMAT), None, None), StructField('f4', Map(String(), UInt64()), None, None) ] ) ns.add_data_type(struct2) return ns
def test_route_with_version_number(self): # type: () -> None route1 = ApiRoute('alpha/get_metadata', 1, None) route1.set_attributes(None, None, Void(), Void(), Void(), {}) route2 = ApiRoute('alpha/get_metadata', 2, None) route2.set_attributes(None, None, Void(), Int32(), Void(), {}) ns = ApiNamespace('files') ns.add_route(route1) ns.add_route(route2) result = self._evaluate_namespace(ns) expected = textwrap.dedent("""\ alpha_get_metadata = bb.Route( 'alpha/get_metadata', 1, False, bv.Void(), bv.Void(), bv.Void(), {}, ) alpha_get_metadata_v2 = bb.Route( 'alpha/get_metadata', 2, False, bv.Void(), bv.Int32(), bv.Void(), {}, ) ROUTES = { 'alpha/get_metadata': alpha_get_metadata, 'alpha/get_metadata:2': alpha_get_metadata_v2, } """) self.assertEqual(result, expected)
def test_union(self): ns = ApiNamespace('files') update_parent_rev = Struct( 'UpdateParentRev', None, ns, ) update_parent_rev.set_attributes( "Overwrite existing file if the parent rev matches.", [ StructField('parent_rev', String(), 'The revision to be updated.', None) ], ) update_parent_rev._add_example( AstExample(path=None, lineno=None, lexpos=None, label='default', text=None, fields={ 'parent_rev': AstExampleField(None, None, None, 'parent_rev', 'xyz123') })) # test variants with only tags, as well as those with structs. conflict = Union( 'WriteConflictPolicy', None, ns, True, ) conflict.set_attributes( 'Policy for managing write conflicts.', [ UnionField('reject', Void(), 'On a write conflict, reject the new file.', None), UnionField( 'overwrite', Void(), 'On a write conflict, overwrite the existing file.', None), UnionField( 'update_if_matching_parent_rev', update_parent_rev, 'On a write conflict, overwrite the existing file.', None), ], ) conflict._add_example( AstExample(path=None, lineno=None, lexpos=None, label='default', text=None, fields={ 'update_if_matching_parent_rev': AstExampleField( None, None, None, 'update_if_matching_parent_rev', AstExampleRef(None, None, None, 'default')) })) conflict._compute_examples() # test that only null value is returned for an example of a Void type self.assertEqual(conflict.get_examples()['reject'].value, {'.tag': 'reject'}) # test that dict is returned for a tagged struct variant self.assertEqual(conflict.get_examples()['default'].value, { '.tag': 'update_if_matching_parent_rev', 'parent_rev': 'xyz123' })
def test_struct(self): ns = ApiNamespace('test') quota_info = Struct( 'QuotaInfo', None, ns, ) quota_info.set_attributes( "Information about a user's space quota.", [ StructField('quota', UInt64(), 'Total amount of space.', None), ], ) # add an example that doesn't fit the definition of a struct with self.assertRaises(InvalidSpec) as cm: quota_info._add_example( AstExample(path=None, lineno=None, lexpos=None, label='default', text=None, fields={ 'bad_field': AstExampleField(None, None, None, 'bad_field', 'xyz123') })) self.assertIn('has unknown field', cm.exception.msg) quota_info._add_example( AstExample(path=None, lineno=None, lexpos=None, label='default', text=None, fields={ 'quota': AstExampleField(None, None, None, 'quota', 64000) })) # set null for a required field with self.assertRaises(InvalidSpec) as cm: quota_info._add_example( AstExample(path=None, lineno=None, lexpos=None, label='null', text=None, fields={ 'quota': AstExampleField(None, None, None, 'quota', None) })) self.assertEqual( "Bad example for field 'quota': null is not a valid integer", cm.exception.msg) self.assertTrue(quota_info._has_example('default')) quota_info.nullable = True # test for structs within structs account_info = Struct( 'AccountInfo', None, ns, ) account_info.set_attributes( "Information about an account.", [ StructField('account_id', String(), 'Unique identifier for account.', None), StructField('quota_info', quota_info, 'Quota', None) ], ) account_info._add_example( AstExample(path=None, lineno=None, lexpos=None, label='default', text=None, fields={ 'account_id': AstExampleField(None, None, None, 'account_id', 'xyz123'), 'quota_info': AstExampleField( None, None, None, 'quota_info', AstExampleRef(None, None, None, 'default')) })) account_info._compute_examples() # ensure that an example for quota_info is propagated up self.assertIn('quota_info', account_info.get_examples()['default'].value)
def _make_namespace(ns_name="accounts"): # type: (typing.Text) -> ApiNamespace ns = ApiNamespace(ns_name) struct = _make_struct('User', 'exists', ns) ns.add_data_type(struct) return ns
def test_struct_with_custom_annotations(self): # type: () -> None ns = ApiNamespace('files') annotation_type = AnnotationType('MyAnnotationType', ns, None, [ AnnotationTypeParam('test_param', Int32(), None, False, None, None) ]) ns.add_annotation_type(annotation_type) annotation = CustomAnnotation('MyAnnotation', ns, None, 'MyAnnotationType', None, [], {'test_param': 42}) annotation.set_attributes(annotation_type) ns.add_annotation(annotation) struct = Struct('MyStruct', ns, None) struct.set_attributes(None, [ StructField('annotated_field', Int32(), None, None), StructField('unannotated_field', Int32(), None, None), ]) struct.fields[0].set_annotations([annotation]) result = self._evaluate_struct(ns, struct) expected = textwrap.dedent('''\ class MyStruct(bb.Struct): __slots__ = [ '_annotated_field_value', '_annotated_field_present', '_unannotated_field_value', '_unannotated_field_present', ] _has_required_fields = True def __init__(self, annotated_field=None, unannotated_field=None): self._annotated_field_value = None self._annotated_field_present = False self._unannotated_field_value = None self._unannotated_field_present = False if annotated_field is not None: self.annotated_field = annotated_field if unannotated_field is not None: self.unannotated_field = unannotated_field @property def annotated_field(self): """ :rtype: long """ if self._annotated_field_present: return self._annotated_field_value else: raise AttributeError("missing required field 'annotated_field'") @annotated_field.setter def annotated_field(self, val): val = self._annotated_field_validator.validate(val) self._annotated_field_value = val self._annotated_field_present = True @annotated_field.deleter def annotated_field(self): self._annotated_field_value = None self._annotated_field_present = False @property def unannotated_field(self): """ :rtype: long """ if self._unannotated_field_present: return self._unannotated_field_value else: raise AttributeError("missing required field 'unannotated_field'") @unannotated_field.setter def unannotated_field(self, val): val = self._unannotated_field_validator.validate(val) self._unannotated_field_value = val self._unannotated_field_present = True @unannotated_field.deleter def unannotated_field(self): self._unannotated_field_value = None self._unannotated_field_present = False def _process_custom_annotations(self, annotation_type, processor): super(MyStruct, self)._process_custom_annotations(annotation_type, processor) if annotation_type is MyAnnotationType: self.annotated_field = bb.partially_apply(processor, MyAnnotationType(test_param=42))(self.annotated_field) def __repr__(self): return 'MyStruct(annotated_field={!r}, unannotated_field={!r})'.format( self._annotated_field_value, self._unannotated_field_value, ) MyStruct_validator = bv.Struct(MyStruct) ''') # noqa self.assertEqual(result, expected)
def _mk_route_schema(self): s = Struct('Route', ApiNamespace('stone_cfg'), None) s.set_attributes(None, [], None) return s