mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
install: use standard Python classes to declare knob types
Use type(None) rather than bool to define knobs which are represented as
command line flags. This allows declaring both "--option" and
"--option={0,1}"-style command line options.
Use enum.Enum subclasses instead of set literals to declare enumerations.
Use typing.List[T] instead of (list, T) to declare lists. (Note that a
minimal reimplementation of typing.List is used instead of the Python 2
backport of the typing module due to non-technical reasons.)
Use CheckedIPAddress instead of 'ip' and 'ip-local' to declare IP
addresses.
https://fedorahosted.org/freeipa/ticket/6392
Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
@@ -7,6 +7,7 @@ Command line support.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import enum
|
||||
import functools
|
||||
import optparse
|
||||
import signal
|
||||
@@ -14,7 +15,7 @@ import signal
|
||||
import six
|
||||
|
||||
from ipapython import admintool, ipa_log_manager
|
||||
from ipapython.ipautil import private_ccache
|
||||
from ipapython.ipautil import CheckedIPAddress, private_ccache
|
||||
|
||||
from . import core, common
|
||||
|
||||
@@ -23,6 +24,8 @@ __all__ = ['install_tool', 'uninstall_tool']
|
||||
if six.PY3:
|
||||
long = int
|
||||
|
||||
NoneType = type(None)
|
||||
|
||||
|
||||
def _get_usage(configurable_class):
|
||||
usage = '%prog [options]'
|
||||
@@ -143,13 +146,17 @@ class ConfigureTool(admintool.AdminTool):
|
||||
parser, "{0} options".format(group_cls.description))
|
||||
|
||||
knob_type = knob_cls.type
|
||||
if isinstance(knob_type, tuple):
|
||||
knob_scalar_type = knob_type[1]
|
||||
if issubclass(knob_type, list):
|
||||
try:
|
||||
# typing.List[X].__parameters__ == (X,)
|
||||
knob_scalar_type = knob_type.__parameters__[0]
|
||||
except AttributeError:
|
||||
knob_scalar_type = str
|
||||
else:
|
||||
knob_scalar_type = knob_type
|
||||
|
||||
kwargs = dict()
|
||||
if knob_scalar_type is bool:
|
||||
if knob_scalar_type is NoneType:
|
||||
kwargs['type'] = None
|
||||
kwargs['const'] = True
|
||||
kwargs['default'] = False
|
||||
@@ -159,16 +166,16 @@ class ConfigureTool(admintool.AdminTool):
|
||||
kwargs['type'] = 'int'
|
||||
elif knob_scalar_type is long:
|
||||
kwargs['type'] = 'long'
|
||||
elif knob_scalar_type in ('ip', 'ip-local'):
|
||||
kwargs['type'] = knob_scalar_type
|
||||
elif isinstance(knob_scalar_type, set):
|
||||
elif knob_scalar_type is CheckedIPAddress:
|
||||
kwargs['type'] = 'ip'
|
||||
elif issubclass(knob_scalar_type, enum.Enum):
|
||||
kwargs['type'] = 'choice'
|
||||
kwargs['choices'] = list(knob_scalar_type)
|
||||
kwargs['choices'] = [i.value for i in knob_scalar_type]
|
||||
else:
|
||||
kwargs['nargs'] = 1
|
||||
kwargs['callback_args'] = (knob_scalar_type,)
|
||||
kwargs['dest'] = name
|
||||
if isinstance(knob_type, tuple):
|
||||
if issubclass(knob_type, list):
|
||||
if 'type' not in kwargs:
|
||||
kwargs['action'] = 'callback'
|
||||
kwargs['callback'] = (
|
||||
|
||||
@@ -8,20 +8,25 @@ The framework core.
|
||||
|
||||
import abc
|
||||
import collections
|
||||
import enum
|
||||
import functools
|
||||
import itertools
|
||||
import re
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
from ipapython.ipautil import CheckedIPAddress
|
||||
|
||||
from . import util
|
||||
from . import util, typing
|
||||
from .util import from_
|
||||
|
||||
__all__ = ['InvalidStateError', 'KnobValueError', 'Property', 'Knob',
|
||||
'Configurable', 'Group', 'Component', 'Composite']
|
||||
|
||||
NoneType = type(None)
|
||||
|
||||
# Configurable states
|
||||
_VALIDATE_PENDING = 'VALIDATE_PENDING'
|
||||
_VALIDATE_RUNNING = 'VALIDATE_RUNNING'
|
||||
@@ -145,11 +150,15 @@ def knob(type_or_base, default=_missing, sensitive=_missing,
|
||||
deprecated=_missing, description=_missing, cli_positional=_missing,
|
||||
cli_name=_missing, cli_short_name=_missing, cli_aliases=_missing,
|
||||
cli_metavar=_missing):
|
||||
if type_or_base is None:
|
||||
type_or_base = NoneType
|
||||
|
||||
assert isinstance(type_or_base, type)
|
||||
|
||||
class_dict = {}
|
||||
class_dict['_order'] = next(_counter)
|
||||
|
||||
if (not isinstance(type_or_base, type) or
|
||||
not issubclass(type_or_base, KnobBase)):
|
||||
if not issubclass(type_or_base, KnobBase):
|
||||
class_dict['type'] = type_or_base
|
||||
type_or_base = KnobBase
|
||||
|
||||
@@ -179,6 +188,27 @@ def Knob(type_or_base, default=_missing, sensitive=_missing,
|
||||
deprecated=_missing, description=_missing, cli_positional=_missing,
|
||||
cli_name=_missing, cli_short_name=_missing, cli_aliases=_missing,
|
||||
cli_metavar=_missing):
|
||||
if isinstance(type_or_base, tuple):
|
||||
assert type_or_base[0] is list
|
||||
scalar_type = type_or_base[1]
|
||||
else:
|
||||
scalar_type = type_or_base
|
||||
|
||||
if scalar_type is bool:
|
||||
scalar_type = NoneType
|
||||
elif scalar_type == 'ip':
|
||||
scalar_type = CheckedIPAddress
|
||||
elif isinstance(scalar_type, set):
|
||||
scalar_type = type(
|
||||
'Enum',
|
||||
(enum.Enum,),
|
||||
{re.sub(r'[^0-9A-Za-z_]', '', n): n for n in scalar_type})
|
||||
|
||||
if isinstance(type_or_base, tuple):
|
||||
type_or_base = typing.List[scalar_type]
|
||||
else:
|
||||
type_or_base = scalar_type
|
||||
|
||||
return knob(type_or_base,
|
||||
default=default,
|
||||
sensitive=sensitive,
|
||||
|
||||
34
ipapython/install/typing.py
Normal file
34
ipapython/install/typing.py
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
import weakref
|
||||
|
||||
import six
|
||||
|
||||
_cache = weakref.WeakValueDictionary()
|
||||
|
||||
|
||||
class ListMeta(type):
|
||||
def __getitem__(cls, key):
|
||||
if not isinstance(key, type):
|
||||
raise TypeError("Parameters to generic types must be types. "
|
||||
"Got {!r}.".format(key))
|
||||
|
||||
t = ListMeta(
|
||||
cls.__name__,
|
||||
cls.__bases__,
|
||||
{
|
||||
'__parameters__': (key,),
|
||||
'__init__': cls.__init__,
|
||||
}
|
||||
)
|
||||
|
||||
return _cache.get(key, t)
|
||||
|
||||
|
||||
class List(six.with_metaclass(ListMeta, list)):
|
||||
__parameters__ = ()
|
||||
|
||||
def __init__(self, *_args, **_kwargs):
|
||||
raise TypeError("Type List cannot be instantiated; use list() instead")
|
||||
Reference in New Issue
Block a user