Skip to content

Commit

Permalink
Adding PEP484 Type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
Suszyński Krzysztof committed Jul 28, 2017
1 parent 82bb6d2 commit 87d96e6
Show file tree
Hide file tree
Showing 20 changed files with 150 additions and 80 deletions.
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ include LICENSE

# Include the data files
recursive-include puppeter *.py
recursive-include puppeter *.pyi
recursive-include puppeter *.sh
recursive-include puppeter *.pp

68 changes: 46 additions & 22 deletions puppeter/container.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from abc import ABCMeta, abstractmethod

from six import with_metaclass
from os.path import dirname
from typing import Type, TypeVar, Any, List, Sequence
from typing import Generic, TypeVar, cast, Any, Callable, Union, Type, \
Sequence, MutableSequence, Dict, Optional

from puppeter import __program__

Expand All @@ -10,10 +14,27 @@ def initialize():
__load_modules(__program__)


class NamedBean(with_metaclass(ABCMeta)):
@staticmethod
@abstractmethod
def bean_name():
# type: () -> str
pass

@staticmethod
@abstractmethod
def original_cls():
# type: () -> Type
pass


NamedClass = Union[Type[T], Callable[[Any, Any], T], NamedBean]


def Named(bean_name):
def named_decorator(cls):

class NamedBean(cls):
class __NamedBean(NamedBean, cls):
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)

Expand All @@ -30,7 +51,7 @@ def __repr__(self):

def __getattr__(self, name):
return getattr(self.wrapped, name)
return NamedBean
return __NamedBean
return named_decorator


Expand All @@ -47,7 +68,7 @@ def bind_to_instance(cls, impl):


def get_all(cls, *args, **kwargs):
# type: (Type[T], str, Any, Any) -> Sequence[T]
# type: (Type[T], Any, Any) -> Sequence[T]
beans = __get_all_beans(cls)
try:
return __instantinate_beans(beans, *args, **kwargs)
Expand All @@ -61,7 +82,7 @@ def get(cls, *args, **kwargs):
if len(beans) == 1:
return beans[0].impl(*args, **kwargs)
else:
impls = list(map(lambda bean: bean.impl_cls_name(), beans))
impls = list(map(lambda bean: str(bean.impl_cls()), beans))
raise ValueError('Zero or more then one implementation found for class %s. '
'Found those implementations: %s. '
'Use @Named beans and get_named() function!' % (cls, impls))
Expand All @@ -79,42 +100,44 @@ def get_all_with_name_starting_with(cls, name_prefix, *args, **kwargs):
# type: (Type[T], str, Any, Any) -> Sequence[T]
beans = []
for bean in __get_all_beans(cls):
if bean.name().startswith(name_prefix):
name = bean.name()
if name is not None and name.startswith(name_prefix):
beans.append(bean)
return __instantinate_beans(beans, *args, **kwargs)


def get_bean(cls):
# type: (Type[T]) -> __Bean
# type: (Type[T]) -> __Bean[T]
return __get_all_beans(cls)[0]


__ROOT_DIR = dirname(dirname(__file__))
__beans = {}
__beans = {} # type: Dict[Type, MutableSequence[__Bean]]


def __instantinate_beans(beans, *args, **kwargs):
# type: (Sequence[__Bean], Any, Any) -> Sequence[T]
# type: (Sequence[__Bean[T]], Any, Any) -> Sequence[T]
impls = tuple(map(lambda bean: bean.impl(*args, **kwargs), beans)) # type: Sequence[T]
return impls


def __get_all_beans(cls):
# type: (Type[T]) -> List[__Bean]
# type: (Type[T]) -> MutableSequence[__Bean[T]]
try:
return __beans[cls]
except KeyError:
lst = []
lst = [] # type: MutableSequence[__Bean[T]]
__beans[cls] = lst
return lst


class __Bean:
class __Bean(Generic[T]):
def __init__(self, cls, impl=None, impl_cls=None):
if impl is None and impl_cls is None:
raise Exception('20170707:164636')
self.__cls = cls
self.__impl = impl
self.__impl_cls = impl_cls
self.__cls = cls # type: Type[T]
self.__impl = impl # type: T
self.__impl_cls = impl_cls # type: NamedClass[T]

def __repr__(self):
name = self.name()
Expand All @@ -123,25 +146,26 @@ def __repr__(self):
else:
return 'Bean of %s' % repr(self.impl_cls())

def impl_cls_name(self):
return self.__impl_cls

def impl_cls(self):
if self.__impl is None:
# type: () -> NamedClass[T]
if self.__impl is None and self.__impl_cls is not None:
return self.__impl_cls
else:
return self.__impl.__class__

def name(self):
# type: () -> str | None
# type: () -> Optional[str]
try:
return self.impl_cls().bean_name()
impl_cls = cast(NamedBean, self.impl_cls())
return impl_cls.bean_name()
except AttributeError:
return None

def impl(self, *args, **kwargs):
if self.__impl is None:
# type: (Any, Any) -> T
if self.__impl is None and self.__impl_cls is not None:
self.__impl = self.__impl_cls(*args, **kwargs)
# noinspection PyTypeChecker
return self.__impl


Expand Down
2 changes: 1 addition & 1 deletion puppeter/domain/gateway/answers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from six import with_metaclass
from abc import ABCMeta, abstractmethod

from puppeter.domain.model.answers import Answers # NOQA
from puppeter.domain.model.answers import Answers


class AnswersGateway(with_metaclass(ABCMeta, object)):
Expand Down
2 changes: 1 addition & 1 deletion puppeter/domain/model/answers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from puppeter.domain.model.installer import Installer # NOQA
from puppeter.domain.model.installer import Installer


class Answers:
Expand Down
8 changes: 2 additions & 6 deletions puppeter/domain/model/configurer.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
from abc import ABCMeta, abstractmethod
from collections import OrderedDict
from enum import Enum
from string import Template
from typing import Sequence, Any, Dict, Type
from typing import Sequence, Any, Dict

import pkg_resources
import re
from six import with_metaclass, iteritems
from six import with_metaclass

from puppeter import container

Expand Down
20 changes: 9 additions & 11 deletions puppeter/domain/model/installer.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from abc import abstractmethod, ABCMeta

import re
from typing import Sequence, Dict, Any

from six import with_metaclass
from abc import abstractmethod, ABCMeta
from enum import Enum
from typing import Sequence, Dict, Any

from puppeter.container import Named
from enum import Enum


class Mode(Enum):
Expand Down Expand Up @@ -35,8 +33,8 @@ def raw_options(self):
# noinspection PyUnresolvedReferences
installer_type = self.bean_name()
return {
'mode': self.__mode.name,
'type': installer_type
'mode': self.__mode.name,
'type': installer_type
}

def read_raw_options(self, options):
Expand Down Expand Up @@ -65,7 +63,7 @@ def raw_options(self):
parent_options = Installer.raw_options(self)
merged = parent_options.copy()
merged.update({
'version': self.__version
'version': self.__version
})
return merged

Expand Down Expand Up @@ -139,7 +137,7 @@ def __init__(self, heap_maximum=None, heap_minimum=None, metaspace_maximum=None)
self.__heap_minimum = heap_minimum # type: JavaMemorySpec
else:
self.__heap_minimum = heap_maximum # type: JavaMemorySpec
self.__metaspace_maximum = metaspace_maximum # type: JavaMemorySpec
self.__metaspace_maximum = metaspace_maximum # type: JavaMemorySpec

def raw_options(self):
d = {
Expand Down Expand Up @@ -177,8 +175,8 @@ def metaspace_maximum(self):

def is_set(self):
return self.heap_maximum() is not None \
or self.heap_minimum() is not None \
or self.metaspace_maximum() is not None
or self.heap_minimum() is not None \
or self.metaspace_maximum() is not None


class JvmArgs(WithOptions, Sequence):
Expand Down
2 changes: 1 addition & 1 deletion puppeter/persistence/gateway/installer/debian/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from six import with_metaclass

from puppeter.domain.model import Installer # NOQA
from puppeter.domain.model import Installer
from puppeter.domain.model.configurer import Configurer
from puppeter.domain.model.installer import Mode

Expand Down
2 changes: 1 addition & 1 deletion puppeter/persistence/gateway/installer/redhat/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from six import with_metaclass

from puppeter.domain.facter import Facter
from puppeter.domain.model import Installer # NOQA
from puppeter.domain.model import Installer
from puppeter.domain.model.configurer import Configurer
from puppeter.domain.model.installer import Mode
from puppeter.domain.model.osfacts import OperatingSystem, OperatingSystemRelease
Expand Down
6 changes: 3 additions & 3 deletions puppeter/persistence/gateway/services/puppetserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ def __init__(self, installer):

def produce_commands(self):
install = self.__installer
if not (isinstance(install, After4xCollectionInstaller)
and install.mode() == Mode.Server
and install.is_after_4x()):
if not (isinstance(install, After4xCollectionInstaller) and
install.mode() == Mode.Server and
install.is_after_4x()):
# Only for Java written PuppetServer
return []
return self.__produce_commands(install)
Expand Down
1 change: 0 additions & 1 deletion puppeter/persistence/service/commandscollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,3 @@ def __get_linesof_script(self, script):
shellscript = tpl.substitute(dict(tmpfilename=tmpfilename, pp=shellscript))

return self.__strip_shebang(shellscript).split("\n")

5 changes: 2 additions & 3 deletions puppeter/presentation/answersprocessor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from argparse import Namespace
from typing import Sequence, List

import logging

import puppeter
from puppeter import container
from puppeter.domain.facter import Facter
Expand All @@ -15,7 +14,7 @@
class AnswersProcessorImpl(AnswersProcessor):

def __init__(self, options):
self.options = options # type:
self.options = options # type: Namespace
self.__log = puppeter.get_logger(AnswersProcessorImpl)

def process(self, answers):
Expand Down
9 changes: 5 additions & 4 deletions puppeter/presentation/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@
from puppeter.domain.gateway.answers import AnswersProcessor
from puppeter.domain.model.answers import Answers
from puppeter.domain.model.osfacts import OsFamily
from puppeter.presentation.cmdparser import Options


class App(with_metaclass(ABCMeta, object)):

def __init__(self, parsed):
self._parsed = parsed
def __init__(self, options):
self._options = options # type: Options

def run(self):
root = logging.getLogger()
level = self.__get_log_level(self._parsed.verbose)
level = self.__get_log_level(self._options.verbose())
root.setLevel(level)
handlers = (self.__syslog_handler(), self.__stderr_handler())
for hndl in handlers:
Expand All @@ -37,7 +38,7 @@ def _collect_answers(self):

def __process(self, answers):
# type: (Answers) -> None
processor = container.get(AnswersProcessor, options=self._parsed) # type: AnswersProcessor
processor = container.get(AnswersProcessor, options=self._options) # type: AnswersProcessor
processor.process(answers)

@staticmethod
Expand Down
12 changes: 8 additions & 4 deletions puppeter/presentation/appfactory.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
from puppeter.presentation.app import App
from puppeter.presentation.cmdparser import Options
from puppeter.presentation.interactiveapp import InteractiveApp
from puppeter.presentation.unattendedapp import UnattendedApp


class AppFactory:
def interactive(self, parsed):
return InteractiveApp(parsed)
def interactive(self, options):
# type: (Options) -> App
return InteractiveApp(options)

def unattended(self, parsed):
return UnattendedApp(parsed)
def unattended(self, options):
# type: (Options) -> App
return UnattendedApp(options)
28 changes: 26 additions & 2 deletions puppeter/presentation/cmdparser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import argparse
import sys
from typing import IO, Any

import puppeter
from puppeter.presentation.appfactory import AppFactory

Expand Down Expand Up @@ -37,6 +39,25 @@ def print_help(self, file=None):
self._print_message(self.format_help(), file)


class Options:
def __init__(self, namespace):
self.__answers = namespace.answers # type: IO[Any]
self.__verbose = namespace.verbose # type: int
self.__execute = namespace.execute # type: bool

def answers(self):
# type: () -> IO[Any]
return self.__answers

def verbose(self):
# type: () -> int
return self.__verbose

def execute(self):
# type: () -> bool
return self.__execute


class CommandLineParser(object):
"""CommandLineParser for Puppeter"""
def __init__(self, argv, appfactory=AppFactory()):
Expand All @@ -58,6 +79,9 @@ def parse(self):
help='Executes setup commands instead of printing them')

parsed = parser.parse_args(self.__argv)
factory = self.__appfactory.interactive if parsed.answers is None else self.__appfactory.unattended
app = factory(parsed)
options = Options(parsed)
if options.answers() is None:
app = self.__appfactory.interactive(options)
else:
app = self.__appfactory.unattended(options)
return app

0 comments on commit 87d96e6

Please sign in to comment.