Merge branch 'master' into namespaced-items

This commit is contained in:
Sebastian Thiel
2021-01-06 21:54:15 +08:00
14 changed files with 52 additions and 43 deletions

2
.gitignore vendored
View File

@@ -12,7 +12,7 @@ gen/doc
# Python: Makefile lead dirs # Python: Makefile lead dirs
.pyenv-* .pyenv-*
.virtualenv .virtualenv.marker
# Sublime # Sublime
*.sublime-workspace *.sublime-workspace

View File

@@ -2,13 +2,13 @@
.SUFFIXES: .SUFFIXES:
VIRTUALENV_VERSION = 16.0.0 VIRTUALENV_VERSION = 16.0.0
VENV_BIN = .virtualenv/virtualenv.py VENV_BIN = .virtualenv.marker
VENV_VERSION = 20.2.2
VENV_DIR := .pyenv-$(shell uname) VENV_DIR := .pyenv-$(shell uname)
PYTHON_BIN := $(VENV_DIR)/bin/python PYTHON_BIN := $(VENV_DIR)/bin/python
PYTHON := . $(VENV_DIR)/bin/activate; python PYTHON := . $(VENV_DIR)/bin/activate; python
PIP := $(PYTHON) -m pip
PYTEST := $(PYTHON) -m pytest PYTEST := $(PYTHON) -m pytest
MAKO_RENDER := etc/bin/mako-render MAKO_RENDER := etc/bin/mako-render
@@ -63,13 +63,12 @@ $(PREPROC): $(PREPROC_DIR)/src/main.rs
cd "$(PREPROC_DIR)" && cargo build --release cd "$(PREPROC_DIR)" && cargo build --release
$(VENV_BIN): $(VENV_BIN):
wget -nv https://pypi.python.org/packages/source/v/virtualenv/virtualenv-$(VIRTUALENV_VERSION).tar.gz -O virtualenv-$(VIRTUALENV_VERSION).tar.gz python3 -m pip install --user virtualenv==$(VENV_VERSION)
tar -xzf virtualenv-$(VIRTUALENV_VERSION).tar.gz && mv virtualenv-$(VIRTUALENV_VERSION) ./.virtualenv && rm -f virtualenv-$(VIRTUALENV_VERSION).tar.gz touch $@
chmod +x $@
$(PYTHON_BIN): $(VENV_BIN) requirements.txt $(PYTHON_BIN): $(VENV_BIN) requirements.txt
$(VENV_BIN) -p python2.7 $(VENV_DIR) python3 -m virtualenv -p python3 $(VENV_DIR)
$(PIP) install -r requirements.txt $@ -m pip install -r requirements.txt
$(MAKO_RENDER): $(PYTHON_BIN) $(wildcard $(MAKO_LIB_DIR)/*) $(MAKO_RENDER): $(PYTHON_BIN) $(wildcard $(MAKO_LIB_DIR)/*)

View File

@@ -70,9 +70,6 @@ class DictObject(object):
def __repr__(self): def __repr__(self):
return repr(self.__dict__) return repr(self.__dict__)
def __getattr__(self, name):
return object.__getattribute__(self, name)
def __getitem__(self, name): def __getitem__(self, name):
try: try:
return getattr(self, name) return getattr(self, name)
@@ -191,9 +188,9 @@ class DictObject(object):
"""as dict.items""" """as dict.items"""
return list(self.__dict__.items()) return list(self.__dict__.items())
def iteritems(self): def _items(self):
"""as dict.iteritems""" """as dict.items, avoiding name clashes"""
return iter(self.__dict__.items()) return list(self.__dict__.items())
def pop(self, key, default=sys): def pop(self, key, default=sys):
"""as dict.pop""" """as dict.pop"""

View File

@@ -1,4 +1,4 @@
mako mako==1.1.3
pyyaml pyyaml
mkdocs==0.16.3 mkdocs==0.16.3
pytest pytest

View File

@@ -155,7 +155,7 @@ let r = hub.resource().activity(...).${api.terms.action}()
Or specifically ... Or specifically ...
```ignore ```ignore
% for an, a in c.sta_map[fr.id].iteritems(): % for an, a in c.sta_map[fr.id].items():
<% category, resource, activity = activity_split(an) %>\ <% category, resource, activity = activity_split(an) %>\
let r = hub.${mangle_ident(resource)}().${mangle_ident(activity)}(...).${api.terms.action}() let r = hub.${mangle_ident(resource)}().${mangle_ident(activity)}(...).${api.terms.action}()
% endfor % endfor

View File

@@ -11,7 +11,7 @@
DELEGATE_PROPERTY_NAME, struct_type_bounds_s, scope_url_to_variant, DELEGATE_PROPERTY_NAME, struct_type_bounds_s, scope_url_to_variant,
re_find_replacements, ADD_PARAM_FN, ADD_PARAM_MEDIA_EXAMPLE, upload_action_fn, METHODS_RESOURCE, re_find_replacements, ADD_PARAM_FN, ADD_PARAM_MEDIA_EXAMPLE, upload_action_fn, METHODS_RESOURCE,
method_name_to_variant, size_to_bytes, method_default_scope, method_name_to_variant, size_to_bytes, method_default_scope,
is_repeated_property, setter_fn_name, ADD_SCOPE_FN, rust_doc_sanitize) is_repeated_property, setter_fn_name, ADD_SCOPE_FN, rust_doc_sanitize, items)
def get_parts(part_prop): def get_parts(part_prop):
if not part_prop: if not part_prop:
@@ -154,7 +154,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
/// ///
/// # Additional Parameters /// # Additional Parameters
/// ///
% for opn, op in list((opn, op) for (opn, op) in parameters.iteritems() if opn not in [p.name for p in params]): % for opn, op in list((opn, op) for (opn, op) in parameters.items() if opn not in [p.name for p in params]):
/// * *${opn}* (${op.location}-${op.type}) - ${op.description} /// * *${opn}* (${op.location}-${op.type}) - ${op.description}
% endfor % endfor
% endif % endif
@@ -336,7 +336,7 @@ ${capture(lib.test_hub, hub_type_name, comments=show_all) | hide_filter}
// into the respective structure. Some of the parts shown here might not be applicable ! // into the respective structure. Some of the parts shown here might not be applicable !
// ${random_value_warning} // ${random_value_warning}
let mut ${rb_name} = ${request_value_type}::default(); let mut ${rb_name} = ${request_value_type}::default();
% for spn, sp in request_value.get('properties', dict()).iteritems(): % for spn, sp in items(request_value.get('properties', dict())):
% if parts is not None and spn not in parts: % if parts is not None and spn not in parts:
<% continue %> <% continue %>
% endif % endif
@@ -903,7 +903,7 @@ if enable_resource_parsing \
% for p in media_params: % for p in media_params:
${p.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} ${p.description | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
/// ///
% for item_name, item in p.info.iteritems(): % for item_name, item in p.info.items():
/// * *${split_camelcase_s(item_name)}*: ${isinstance(item, (list, tuple)) and put_and(enclose_in("'", item)) or str(item)} /// * *${split_camelcase_s(item_name)}*: ${isinstance(item, (list, tuple)) and put_and(enclose_in("'", item)) or str(item)}
% endfor % endfor
pub fn ${upload_action_fn(api.terms.upload_action, p.type.suffix)}<${mtype_param}>(self, ${p.type.arg_name}: ${mtype_param}, mime_type: mime::Mime) -> ${rtype} pub fn ${upload_action_fn(api.terms.upload_action, p.type.suffix)}<${mtype_param}>(self, ${p.type.arg_name}: ${mtype_param}, mime_type: mime::Mime) -> ${rtype}

View File

@@ -119,7 +119,7 @@ impl${rb_params} ${ThisType} {
% for p in optional_props: % for p in optional_props:
${property(p.name)}: Default::default(), ${property(p.name)}: Default::default(),
% endfor % endfor
% for prop_key, custom_name in api.properties.iteritems(): % for prop_key, custom_name in api.properties.items():
% if prop_key == 'scopes' and not method_default_scope(m): % if prop_key == 'scopes' and not method_default_scope(m):
<% continue %>\ <% continue %>\
% endif % endif

View File

@@ -3,7 +3,7 @@
IO_TYPES, activity_split, enclose_in, REQUEST_MARKER_TRAIT, mb_type, indent_all_but_first_by, IO_TYPES, activity_split, enclose_in, REQUEST_MARKER_TRAIT, mb_type, indent_all_but_first_by,
NESTED_TYPE_SUFFIX, RESPONSE_MARKER_TRAIT, split_camelcase_s, METHODS_RESOURCE, NESTED_TYPE_SUFFIX, RESPONSE_MARKER_TRAIT, split_camelcase_s, METHODS_RESOURCE,
PART_MARKER_TRAIT, canonical_type_name, TO_PARTS_MARKER, UNUSED_TYPE_MARKER, is_schema_with_optionals, PART_MARKER_TRAIT, canonical_type_name, TO_PARTS_MARKER, UNUSED_TYPE_MARKER, is_schema_with_optionals,
rust_doc_sanitize) rust_doc_sanitize, items)
%>\ %>\
## Build a schema which must be an object ## Build a schema which must be an object
################################################################################################################### ###################################################################################################################
@@ -12,7 +12,7 @@
<% struct = 'pub struct ' + s.id %>\ <% struct = 'pub struct ' + s.id %>\
% if properties: % if properties:
${struct} { ${struct} {
% for pn, p in properties.iteritems(): % for pn, p in items(properties):
${p.get('description', 'no description provided') | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)} ${p.get('description', 'no description provided') | rust_doc_sanitize, rust_doc_comment, indent_all_but_first_by(1)}
% if pn != mangle_ident(pn): % if pn != mangle_ident(pn):
#[serde(rename="${pn}")] #[serde(rename="${pn}")]
@@ -111,7 +111,7 @@ impl ${TO_PARTS_MARKER} for ${s_type} {
/// the parts you want to see in the server response. /// the parts you want to see in the server response.
fn to_parts(&self) -> String { fn to_parts(&self) -> String {
let mut r = String::new(); let mut r = String::new();
% for pn, p in s.properties.iteritems(): % for pn, p in items(s.properties):
<% <%
mn = 'self.' + mangle_ident(pn) mn = 'self.' + mangle_ident(pn)
rt = to_rust_type(schemas, s.id, pn, p, allow_optionals=allow_optionals) rt = to_rust_type(schemas, s.id, pn, p, allow_optionals=allow_optionals)
@@ -140,7 +140,7 @@ ${s.get('description', 'There is no detailed description.')}
This type is used in activities, which are methods you may call on this type or where this type is involved in. This type is used in activities, which are methods you may call on this type or where this type is involved in.
The list links the activity name, along with information about where it is used (one of ${put_and(enclose_in('*', IO_TYPES))}). The list links the activity name, along with information about where it is used (one of ${put_and(enclose_in('*', IO_TYPES))}).
% for a, iot in c.sta_map[s.id].iteritems(): % for a, iot in c.sta_map[s.id].items():
<% <%
category, name, method = activity_split(a) category, name, method = activity_split(a)
name_suffix = ' ' + split_camelcase_s(name) name_suffix = ' ' + split_camelcase_s(name)

View File

@@ -1,7 +1,7 @@
<%namespace name="util" file="../../lib/util.mako"/>\ <%namespace name="util" file="../../lib/util.mako"/>\
<%! <%!
from mako.filters import xml_escape from mako.filters import xml_escape
from util import (hash_comment, new_context, method_default_scope, indent_all_but_first_by, is_repeated_property) from util import (hash_comment, new_context, method_default_scope, indent_all_but_first_by, is_repeated_property, custom_sorted)
from cli import (subcommand_md_filename, new_method_context, SPLIT_START, SPLIT_END, pretty, SCOPE_FLAG, from cli import (subcommand_md_filename, new_method_context, SPLIT_START, SPLIT_END, pretty, SCOPE_FLAG,
mangle_subcommand, is_request_value_property, FIELD_SEP, PARAM_FLAG, UPLOAD_FLAG, docopt_mode, mangle_subcommand, is_request_value_property, FIELD_SEP, PARAM_FLAG, UPLOAD_FLAG, docopt_mode,
FILE_ARG, MIME_ARG, OUT_ARG, OUTPUT_FLAG, to_cli_schema, cli_schema_to_yaml, SchemaEntry, FILE_ARG, MIME_ARG, OUT_ARG, OUTPUT_FLAG, to_cli_schema, cli_schema_to_yaml, SchemaEntry,
@@ -143,7 +143,7 @@ You may set the following properties to further configure the call. Please note
or more key-value-pairs, and is called like this `-${PARAM_FLAG} k1=v1 k2=v2` even though the listing below repeats the or more key-value-pairs, and is called like this `-${PARAM_FLAG} k1=v1 k2=v2` even though the listing below repeats the
`-${PARAM_FLAG}` for completeness. `-${PARAM_FLAG}` for completeness.
% for p in sorted(oprops): % for p in custom_sorted(oprops):
${self._md_property(p)} ${self._md_property(p)}
% endfor % endfor
% endif # optional method properties % endif # optional method properties

View File

@@ -16,7 +16,7 @@
return 'None' return 'None'
if isinstance(v, bool): if isinstance(v, bool):
v = v and 'true' or 'false' v = v and 'true' or 'false'
elif isinstance(v, basestring): elif isinstance(v, str):
v = 'r##"%s"##' % v v = 'r##"%s"##' % v
elif isinstance(v, list): elif isinstance(v, list):
v = 'vec![%s]' % ','.join('UploadProtocol::%s' % p.capitalize() for p in v) v = 'vec![%s]' % ','.join('UploadProtocol::%s' % p.capitalize() for p in v)

View File

@@ -357,7 +357,7 @@ if dry_run {
allow_optionals = allow_optionals_fn(schema) allow_optionals = allow_optionals_fn(schema)
if not allow_optionals: if not allow_optionals:
opt_access = '' opt_access = ''
for fn, f in schema.fields.iteritems(): for fn, f in schema.fields.items():
cur.append(['%s%s' % (mangle_ident(fn), opt_access), fn]) cur.append(['%s%s' % (mangle_ident(fn), opt_access), fn])
fields.add(fn) fields.add(fn)
if isinstance(f, SchemaEntry): if isinstance(f, SchemaEntry):

View File

@@ -4,7 +4,7 @@
<% <%
import os import os
import urllib2 import urllib
import json import json
apis = {} apis = {}
@@ -23,7 +23,7 @@
if os.environ.get('FETCH_APIS') is not None: if os.environ.get('FETCH_APIS') is not None:
discovery_url = 'https://www.googleapis.com/discovery/v1/' discovery_url = 'https://www.googleapis.com/discovery/v1/'
apis = json.loads(urllib2.urlopen(discovery_url + "apis").read()) apis = json.loads(urllib.request.urlopen(discovery_url + "apis").read())
print('Loaded {} apis from Google'.format(len(apis['items']))) print('Loaded {} apis from Google'.format(len(apis['items'])))
@@ -46,7 +46,7 @@
if mako is not UNDEFINED: if mako is not UNDEFINED:
post_processor_arg = '--post-process-python-module=%s' % mako.post_processor_module post_processor_arg = '--post-process-python-module=%s' % mako.post_processor_module
%>\ %>\
% for an, versions in api.list.iteritems(): % for an, versions in api.list.items():
% if an in api.get('blacklist', list()): % if an in api.get('blacklist', list()):
<% continue %>\ <% continue %>\
% endif % endif
@@ -98,8 +98,9 @@
api_info.append((api_target, api_clean, api_cargo, api_doc, api_crate_publish_file, gen_root)) api_info.append((api_target, api_clean, api_cargo, api_doc, api_crate_publish_file, gen_root))
space_join = lambda i: ' '.join(a[i] for a in api_info) space_join = lambda i: ' '.join(a[i] for a in api_info)
except: except Exception as e:
print('Could not open JSON file at {}'.format(api_json)) print('Could not open JSON file at {}'.format(api_json))
print(e)
%>\ %>\
${api_common}: $(RUST_SRC)/${make.id}/client.rs $(lastword $(MAKEFILE_LIST)) ${gen_root_stamp} ${api_common}: $(RUST_SRC)/${make.id}/client.rs $(lastword $(MAKEFILE_LIST)) ${gen_root_stamp}
@ echo "// COPY OF '$<'" > $@ @ echo "// COPY OF '$<'" > $@

View File

@@ -172,7 +172,7 @@ def to_cli_schema(c, schema):
properties[e.type_value] = e properties[e.type_value] = e
# end handle enumerations # end handle enumerations
for pn, p in properties.iteritems(): for pn, p in util.items(properties):
def set_nested_schema(ns): def set_nested_schema(ns):
if ns.fields: if ns.fields:
fd[pn] = ns fd[pn] = ns

View File

@@ -112,6 +112,17 @@ data_unit_multipliers = {
HUB_TYPE_PARAMETERS = ('C', 'A') HUB_TYPE_PARAMETERS = ('C', 'A')
def items(p):
if isinstance(p, dict):
return p.items()
else:
return p._items()
def custom_sorted(p):
if not isinstance(p, list):
assert(false, p, "unexpected type")
return sorted(p, key = lambda p: p['name'])
# ============================================================================== # ==============================================================================
## @name Filters ## @name Filters
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -438,7 +449,7 @@ def schema_markers(s, c, transitive=True):
continue continue
has_activity = True has_activity = True
# it should have at least one activity that matches it's type to qualify for the Resource trait # it should have at least one activity that matches it's type to qualify for the Resource trait
for fqan, iot in activities.iteritems(): for fqan, iot in activities.items():
_, resource, _ = activity_split(fqan) _, resource, _ = activity_split(fqan)
if resource and activity_name_to_type_name(resource).lower() == sid.lower(): if resource and activity_name_to_type_name(resource).lower() == sid.lower():
res.add(RESOURCE_MARKER_TRAIT) res.add(RESOURCE_MARKER_TRAIT)
@@ -502,7 +513,7 @@ def activity_name_to_type_name(an):
# yields (category, resource, activity, activity_data) # yields (category, resource, activity, activity_data)
def iter_acitivities(c): def iter_acitivities(c):
return ((activity_split(an) + [a]) for an, a in c.fqan_map.iteritems()) return ((activity_split(an) + [a]) for an, a in c.fqan_map.items())
# return a list of parameter structures of all params of the given method dict # return a list of parameter structures of all params of the given method dict
# apply a prune filter to restrict the set of returned parameters. # apply a prune filter to restrict the set of returned parameters.
@@ -510,7 +521,7 @@ def iter_acitivities(c):
def _method_params(m, required=None, location=None): def _method_params(m, required=None, location=None):
res = list() res = list()
po = m.get('parameterOrder', []) po = m.get('parameterOrder', [])
for pn, p in m.get('parameters', dict()).iteritems(): for pn, p in m.get('parameters', dict()).items():
if required is not None and p.get('required', False) != required: if required is not None and p.get('required', False) != required:
continue continue
if location is not None and p.get('location', '') != location: if location is not None and p.get('location', '') != location:
@@ -604,7 +615,7 @@ def method_media_params(m):
# actually, one of them is required, but we can't encode that ... # actually, one of them is required, but we can't encode that ...
# runtime will have to check # runtime will have to check
res = list() res = list()
for pn, proto in mu.protocols.iteritems(): for pn, proto in mu.protocols.items():
# the pi (proto-info) dict can be shown to the user # the pi (proto-info) dict can be shown to the user
pi = {'multipart': proto.multipart and 'yes' or 'no', 'maxSize': mu.get('maxSize', '0kb'), 'validMimeTypes': mu.accept} pi = {'multipart': proto.multipart and 'yes' or 'no', 'maxSize': mu.get('maxSize', '0kb'), 'validMimeTypes': mu.accept}
try: try:
@@ -663,12 +674,12 @@ def new_context(schemas, resources, methods):
res = dict() res = dict()
if fqan is None: if fqan is None:
fqan = dict() fqan = dict()
for k,a in activities.iteritems(): for k,a in activities.items():
if 'resources' in a: if 'resources' in a:
build_activity_mappings(a.resources, res, fqan) build_activity_mappings(a.resources, res, fqan)
if 'methods' not in a: if 'methods' not in a:
continue continue
for mn, m in a.methods.iteritems(): for mn, m in a.methods.items():
assert m.id not in fqan assert m.id not in fqan
category, resource, method = activity_split(m.id) category, resource, method = activity_split(m.id)
# This may be another name by which people try to find the method. # This may be another name by which people try to find the method.
@@ -737,7 +748,8 @@ def new_context(schemas, resources, methods):
# end this is already a perfectly valid type # end this is already a perfectly valid type
properties = s.get('properties', {'': s}) properties = s.get('properties', {'': s})
for pn, p in properties.iteritems():
for pn, p in items(properties):
link_used(p, rs) link_used(p, rs)
if is_nested_type_property(p): if is_nested_type_property(p):
ns = deepcopy(p) ns = deepcopy(p)
@@ -746,7 +758,7 @@ def new_context(schemas, resources, methods):
# To allow us recursing arrays, we simply put items one level up # To allow us recursing arrays, we simply put items one level up
if 'items' in p: if 'items' in p:
ns.update((k, deepcopy(v)) for k, v in p.items.iteritems()) ns.update((k, deepcopy(v)) for k, v in p.items.items())
recurse_properties(ns.id, ns, ns, append_unique(parent_ids, rs.id)) recurse_properties(ns.id, ns, ns, append_unique(parent_ids, rs.id))
elif is_map_prop(p): elif is_map_prop(p):
@@ -838,7 +850,7 @@ def library_to_crate_name(name, suffix=''):
# return version like 0.1.0+2014031421 # return version like 0.1.0+2014031421
def crate_version(build_version, revision): def crate_version(build_version, revision):
return '%s+%s' % (build_version, isinstance(revision, basestring) and revision or '00000000') return '%s+%s' % (build_version, isinstance(revision, str) and revision or '00000000')
# return a crate name for us in extern crate statements # return a crate name for us in extern crate statements
def to_extern_crate_name(crate_name): def to_extern_crate_name(crate_name):