makeapi: optimize API.txt

Change Param formatting to:
* always use quantified names rather than the `required` and `multivalue`
  kwargs,
* ignore kwargs with default value,
* ignore kwargs related to validation, as validation is now strictly
  server-side,
* ignore the `attribute` and `primary_key` kwargs, as they are relevant
  only on object params,
* ignore the `include` and `exclude` kwargs, as makeapi takes into account
  only params available in the 'cli' context,
* ignore the unused `csv` kwarg.

Format optional Output arguments as kwargs.

https://fedorahosted.org/freeipa/ticket/4739

Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
Jan Cholasta 2015-07-15 19:10:14 +00:00
parent ac2e9e84cf
commit 77e27de147
4 changed files with 4744 additions and 4683 deletions

9268
API.txt

File diff suppressed because it is too large Load Diff

View File

@ -77,6 +77,8 @@ class Output(ReadOnly):
def __init__(self, name, type=None, doc=None, flags=[]): def __init__(self, name, type=None, doc=None, flags=[]):
self.name = name self.name = name
if type is not None: if type is not None:
if not isinstance(type, tuple):
type = (type,)
self.type = type self.type = type
if doc is not None: if doc is not None:
self.doc = doc self.doc = doc
@ -84,10 +86,23 @@ class Output(ReadOnly):
lock(self) lock(self)
def __repr__(self): def __repr__(self):
return '%s(%r, %r, %r)' % ( return '%s(%s)' % (
self.__class__.__name__, self.name, self.type, self.doc, self.__class__.__name__,
', '.join(self.__repr_iter())
) )
def __repr_iter(self):
yield repr(self.name)
for key in ('type', 'doc', 'flags'):
value = self.__dict__.get(key)
if not value:
continue
if isinstance(value, tuple):
value = repr(list(value))
else:
value = repr(value)
yield '%s=%s' % (key, value)
class Entry(Output): class Entry(Output):
type = dict type = dict

View File

@ -221,7 +221,7 @@ class DefaultFrom(ReadOnly):
lock(self) lock(self)
def __repr__(self): def __repr__(self):
args = (self.callback.__name__,) + tuple(repr(k) for k in self.keys) args = tuple(repr(k) for k in self.keys)
return '%s(%s)' % ( return '%s(%s)' % (
self.__class__.__name__, self.__class__.__name__,
', '.join(args) ', '.join(args)
@ -426,61 +426,34 @@ class Param(ReadOnly):
return (self.type,) return (self.type,)
def __init__(self, name, *rules, **kw): def __init__(self, name, *rules, **kw):
# We keep these values to use in __repr__():
self.param_spec = name
self.__kw = dict(kw)
# Merge in kw from parse_param_spec(): # Merge in kw from parse_param_spec():
(name, kw_from_spec) = parse_param_spec(name) (name, kw_from_spec) = parse_param_spec(name)
check_name(name)
if not 'required' in kw: if not 'required' in kw:
kw['required'] = kw_from_spec['required'] kw['required'] = kw_from_spec['required']
if not 'multivalue' in kw: if not 'multivalue' in kw:
kw['multivalue'] = kw_from_spec['multivalue'] kw['multivalue'] = kw_from_spec['multivalue']
self.name = check_name(name)
self.nice = '%s(%r)' % (self.__class__.__name__, self.param_spec)
# Add 'default' to self.kwargs and makes sure no unknown kw were given: # Add 'default' to self.kwargs
assert all(type(t) is type for t in self.allowed_types)
if kw.get('multivalue', True): if kw.get('multivalue', True):
self.kwargs += (('default', tuple, None),) self.kwargs += (('default', tuple, None),)
else: else:
self.kwargs += (('default', self.type, None),) self.kwargs += (('default', self.type, None),)
if not set(t[0] for t in self.kwargs).issuperset(self.__kw):
extra = set(kw) - set(t[0] for t in self.kwargs)
raise TypeError(
'%s: takes no such kwargs: %s' % (self.nice,
', '.join(repr(k) for k in sorted(extra))
)
)
# Merge in default for 'cli_name', label, doc if not given:
if kw.get('cli_name') is None:
kw['cli_name'] = self.name
if kw.get('label') is None:
kw['label'] = FixMe(self.name)
if kw.get('doc') is None:
kw['doc'] = kw['label']
# Wrap 'default_from' in a DefaultFrom if not already: # Wrap 'default_from' in a DefaultFrom if not already:
df = kw.get('default_from', None) df = kw.get('default_from')
if callable(df) and not isinstance(df, DefaultFrom): if callable(df) and not isinstance(df, DefaultFrom):
kw['default_from'] = DefaultFrom(df) kw['default_from'] = DefaultFrom(df)
# We keep this copy with merged values also to use when cloning: # Perform type validation on kw:
self.__clonekw = kw
# Perform type validation on kw, add in class rules:
class_rules = []
for (key, kind, default) in self.kwargs: for (key, kind, default) in self.kwargs:
value = kw.get(key, default) value = kw.get(key)
if value is not None: if value is not None:
if kind is frozenset: if kind in (tuple, frozenset):
if type(value) in (list, tuple, set): if type(value) in (list, tuple, set, frozenset):
value = frozenset(value) value = kind(value)
elif type(value) is str: elif type(value) is str:
value = frozenset([value]) value = kind([value])
if ( if (
type(kind) is type and not isinstance(value, kind) type(kind) is type and not isinstance(value, kind)
or or
@ -493,6 +466,55 @@ class Param(ReadOnly):
raise TypeError( raise TypeError(
CALLABLE_ERROR % (key, value, type(value)) CALLABLE_ERROR % (key, value, type(value))
) )
kw[key] = value
else:
kw.pop(key, None)
# We keep these values to use in __repr__():
if kw['required']:
if kw['multivalue']:
self.param_spec = name + '+'
else:
self.param_spec = name
else:
if kw['multivalue']:
self.param_spec = name + '*'
else:
self.param_spec = name + '?'
self.__kw = dict(kw)
del self.__kw['required']
del self.__kw['multivalue']
self.name = name
self.nice = '%s(%r)' % (self.__class__.__name__, self.param_spec)
# Make sure no unknown kw were given:
assert all(type(t) is type for t in self.allowed_types)
if not set(t[0] for t in self.kwargs).issuperset(self.__kw):
extra = set(kw) - set(t[0] for t in self.kwargs)
raise TypeError(
'%s: takes no such kwargs: %s' % (self.nice,
', '.join(repr(k) for k in sorted(extra))
)
)
# We keep this copy with merged values also to use when cloning:
self.__clonekw = dict(kw)
# Merge in default for 'cli_name', label, doc if not given:
if kw.get('cli_name') is None:
kw['cli_name'] = self.name
if kw.get('label') is None:
kw['label'] = FixMe(self.name)
if kw.get('doc') is None:
kw['doc'] = kw['label']
# Add in class rules:
class_rules = []
for (key, kind, default) in self.kwargs:
value = kw.get(key, default)
if hasattr(self, key): if hasattr(self, key):
raise ValueError('kwarg %r conflicts with attribute on %s' % ( raise ValueError('kwarg %r conflicts with attribute on %s' % (
key, self.__class__.__name__) key, self.__class__.__name__)
@ -560,6 +582,8 @@ class Param(ReadOnly):
value = value.__name__ value = value.__name__
elif isinstance(value, six.integer_types): elif isinstance(value, six.integer_types):
value = str(value) value = str(value)
elif isinstance(value, (tuple, set, frozenset)):
value = repr(list(value))
else: else:
value = repr(value) value = repr(value)
yield '%s=%s' % (key, value) yield '%s=%s' % (key, value)

42
makeapi
View File

@ -44,18 +44,40 @@ API_NO_FILE = 4
API_DOC_ERROR = 8 API_DOC_ERROR = 8
# attributes removed from Param.__kw dictionary # attributes removed from Param.__kw dictionary
PARAM_IGNORED_KW_ATTRIBUTES = ('label', PARAM_IGNORED_KW_ATTRIBUTES = (
'doc', 'attribute',
'normalizer', 'csv',
'default_from', 'default_from',
'hint', 'doc',
'flags', 'exclude',
'sortorder', 'exponential',
'pattern_errmsg',) 'flags',
'hint',
'include',
'label',
'length',
'maxlength',
'maxvalue',
'minlength',
'minvalue',
'noextrawhitespace',
'normalizer',
'numberclass',
'only_absolute',
'only_relative',
'pattern',
'pattern_errmsg',
'precision',
'primary_key',
'query',
'sortorder',
)
# attributes removed from Output object # attributes removed from Output object
OUTPUT_IGNORED_ATTRIBUTES = ('doc', OUTPUT_IGNORED_ATTRIBUTES = (
'flags',) 'doc',
'flags',
)
def parse_options(): def parse_options():
from optparse import OptionParser from optparse import OptionParser