<commit_before>import os
import copy

from napalm_yang import helpers

import logging
logger = logging.getLogger("napalm-yang")

class Parser(object):

    def __init__(self, model, device=None, profile=None, is_config=None,
                 native=None, keys=None, bookmarks=None, extra_vars=None):
        self.model = model
        self.device = device
        self.profile = profile or device.profile
        self.is_config = is_config
        self._defining_module = model._defining_module
        self._yang_name = model._yang_name

        parser_path = os.path.join("parsers", "config" if is_config else "state")
        self.mapping = helpers.read_yang_map(model._defining_module, model._yang_name,
                                             self.profile, parser_path)

        self.keys = keys or {"parent_key": None}
        self.extra_vars = extra_vars or {}

        if self.mapping and device:
            device_config = self._execute_methods(device,
                                                  self.mapping["metadata"].get("execute", []))

        else:
            device_config = []

        native = native or []

        self.native = []

        for n in native + device_config:
            self.native.append(n.replace("\r", ""))  # Parsing will be easier

        if not self.native:
            raise Exception("I don't have any data to operate with")

        self.bookmarks = {self._yang_name: self.native, "parent": self.native}
        self.bookmarks = bookmarks or self.bookmarks

        if self.mapping:
            self.parser = helpers.get_parser(self.mapping["metadata"]["parser"])

    def _execute_methods(self, device, methods):
        result = []
        for m in methods:
            attr = device
            for p in m["method"].split("."):
                attr = getattr(attr, p)
            r = attr(**m["args"])

            if isinstance(r, dict) and all([isinstance(x, (str, unicode)) for x in r.values()]):
                # Some vendors like junos return commands enclosed by a key
                r = "\n".join(r.values())

            result.append(r)

        return result

    def parse(self):
        if not self.mapping:
            return
        self._parse(self._yang_name, self.model, self.mapping[self._yang_name])

    def _parse(self, attribute, model, mapping):
        logger.debug("Parsing attribute: {}".format(model._yang_path()))

        if model._is_container in ("container", ):
            self._parse_container(attribute, model, mapping)
        elif model._yang_type in ("list", ):
            self._parse_list(attribute, model, mapping)
        else:
            self._parse_leaf(attribute, model, mapping)

    def _parse_container(self, attribute, model, mapping):
        mapping["_parse"] = helpers.resolve_rule(mapping["_parse"], attribute, self.keys,
                                                 self.extra_vars, None, self.bookmarks)
        for k, v in model:
            logger.debug("Parsing attribute: {}".format(v._yang_path()))
            if self.is_config and (not v._is_config or k == "state"):
                continue
            elif not self.is_config and (v._is_config or k == "config") \
                    and v._yang_type not in ("container", "list"):
                continue

            if v._defining_module != self._defining_module and v._defining_module is not None:
                logger.debug("Skipping attribute: {}:{}".format(v._defining_module, attribute))
                parser = Parser(v, self.device, self.profile, self.is_config, self.native,
                                self.keys, self.bookmarks, self.extra_vars)
                parser.parse()
            else:
                self._parse(k, v, mapping[k])

    def _parse_list(self, attribute, model, mapping):
        mapping_copy = copy.deepcopy(mapping)
        mapping_copy["_parse"] = helpers.resolve_rule(mapping_copy["_parse"], attribute, self.keys,
                                                      self.extra_vars, None, self.bookmarks)
        # Saving state to restore them later
        old_parent_key = self.keys["parent_key"]
        old_parent_bookmark = self.bookmarks["parent"]
        old_parent_extra_vars = self.extra_vars

        # We will use this to store blocks of configuration
        # for each individual element of the list
        self.bookmarks[attribute] = {}

        for key, block, extra_vars in self.parser.parse_list(mapping_copy["_parse"]):
            logger.debug("Parsing element {}[{}]".format(attribute, key))
            obj = model.add(key)

            key_name = "{}_key".format(attribute)
            self.keys[key_name] = key
            self.bookmarks[attribute][key] = block
            self.extra_vars[attribute] = extra_vars

            # These two are necessary in cases where an element may be present in subtrees. For
            # example, ipv4.config.enabled is present in both interfaces and subinterfaces
            self.keys["parent_key"] = key
            self.bookmarks["parent"] = block
            self.extra_vars = extra_vars

            element_mapping = copy.deepcopy(mapping)
            self._parse(key, obj, element_mapping)

        # Restore state
        self.keys["parent_key"] = old_parent_key
        self.bookmarks["parent"] = old_parent_bookmark
        self.extra_vars = old_parent_extra_vars

    def _parse_leaf(self, attribute, model, mapping):
        mapping["_parse"] = helpers.resolve_rule(mapping["_parse"], attribute, self.keys,
                                                 self.extra_vars, None, self.bookmarks)

        # We can't set attributes that are keys
        if model._is_keyval:
            return

        value = self.parser.parse_leaf(mapping["_parse"])

        if value is not None and (value != model.default() or isinstance(value, bool)):
            setter = getattr(model._parent, "_set_{}".format(attribute))
            setter(value)

            # parent.model is now a new class
            model = getattr(model._parent, attribute)
            model._mchanged = True
<commit_msg>Don't assume device_config is a list of strings.<commit_after>import os
import copy

from napalm_yang import helpers

import logging
logger = logging.getLogger("napalm-yang")

class Parser(object):

    def __init__(self, model, device=None, profile=None, is_config=None,
                 native=None, keys=None, bookmarks=None, extra_vars=None):
        self.model = model
        self.device = device
        self.profile = profile or device.profile
        self.is_config = is_config
        self._defining_module = model._defining_module
        self._yang_name = model._yang_name

        parser_path = os.path.join("parsers", "config" if is_config else "state")
        self.mapping = helpers.read_yang_map(model._defining_module, model._yang_name,
                                             self.profile, parser_path)

        self.keys = keys or {"parent_key": None}
        self.extra_vars = extra_vars or {}

        if self.mapping and device:
            device_config = self._execute_methods(device,
                                                  self.mapping["metadata"].get("execute", []))

        else:
            device_config = []

        native = native or []

        self.native = []

        for n in native + device_config:
            if isinstance(n, basestring):
                self.native.append(n.replace("\r", ""))  # Parsing will be easier
            else:
                self.native.append(n)

        if not self.native:
            raise Exception("I don't have any data to operate with")

        self.bookmarks = {self._yang_name: self.native, "parent": self.native}
        self.bookmarks = bookmarks or self.bookmarks

        if self.mapping:
            self.parser = helpers.get_parser(self.mapping["metadata"]["parser"])

    def _execute_methods(self, device, methods):
        result = []
        for m in methods:
            attr = device
            for p in m["method"].split("."):
                attr = getattr(attr, p)
            r = attr(**m["args"])

            if isinstance(r, dict) and all([isinstance(x, (str, unicode)) for x in r.values()]):
                # Some vendors like junos return commands enclosed by a key
                r = "\n".join(r.values())

            result.append(r)

        return result

    def parse(self):
        if not self.mapping:
            return
        self._parse(self._yang_name, self.model, self.mapping[self._yang_name])

    def _parse(self, attribute, model, mapping):
        logger.debug("Parsing attribute: {}".format(model._yang_path()))

        if model._is_container in ("container", ):
            self._parse_container(attribute, model, mapping)
        elif model._yang_type in ("list", ):
            self._parse_list(attribute, model, mapping)
        else:
            self._parse_leaf(attribute, model, mapping)

    def _parse_container(self, attribute, model, mapping):
        mapping["_parse"] = helpers.resolve_rule(mapping["_parse"], attribute, self.keys,
                                                 self.extra_vars, None, self.bookmarks)
        for k, v in model:
            logger.debug("Parsing attribute: {}".format(v._yang_path()))
            if self.is_config and (not v._is_config or k == "state"):
                continue
            elif not self.is_config and (v._is_config or k == "config") \
                    and v._yang_type not in ("container", "list"):
                continue

            if v._defining_module != self._defining_module and v._defining_module is not None:
                logger.debug("Skipping attribute: {}:{}".format(v._defining_module, attribute))
                parser = Parser(v, self.device, self.profile, self.is_config, self.native,
                                self.keys, self.bookmarks, self.extra_vars)
                parser.parse()
            else:
                self._parse(k, v, mapping[k])

    def _parse_list(self, attribute, model, mapping):
        mapping_copy = copy.deepcopy(mapping)
        mapping_copy["_parse"] = helpers.resolve_rule(mapping_copy["_parse"], attribute, self.keys,
                                                      self.extra_vars, None, self.bookmarks)
        # Saving state to restore them later
        old_parent_key = self.keys["parent_key"]
        old_parent_bookmark = self.bookmarks["parent"]
        old_parent_extra_vars = self.extra_vars

        # We will use this to store blocks of configuration
        # for each individual element of the list
        self.bookmarks[attribute] = {}

        for key, block, extra_vars in self.parser.parse_list(mapping_copy["_parse"]):
            logger.debug("Parsing element {}[{}]".format(attribute, key))
            obj = model.add(key)

            key_name = "{}_key".format(attribute)
            self.keys[key_name] = key
            self.bookmarks[attribute][key] = block
            self.extra_vars[attribute] = extra_vars

            # These two are necessary in cases where an element may be present in subtrees. For
            # example, ipv4.config.enabled is present in both interfaces and subinterfaces
            self.keys["parent_key"] = key
            self.bookmarks["parent"] = block
            self.extra_vars = extra_vars

            element_mapping = copy.deepcopy(mapping)
            self._parse(key, obj, element_mapping)

        # Restore state
        self.keys["parent_key"] = old_parent_key
        self.bookmarks["parent"] = old_parent_bookmark
        self.extra_vars = old_parent_extra_vars

    def _parse_leaf(self, attribute, model, mapping):
        mapping["_parse"] = helpers.resolve_rule(mapping["_parse"], attribute, self.keys,
                                                 self.extra_vars, None, self.bookmarks)

        # We can't set attributes that are keys
        if model._is_keyval:
            return

        value = self.parser.parse_leaf(mapping["_parse"])

        if value is not None and (value != model.default() or isinstance(value, bool)):
            setter = getattr(model._parent, "_set_{}".format(attribute))
            setter(value)

            # parent.model is now a new class
            model = getattr(model._parent, attribute)
            model._mchanged = True
<|endoftext|>


<commit_before>import logging
import os
import os.path

from typing import *
import rstcloth.rstcloth

import mut

__all__ = ['PREFIXES', 'run']

LEVEL_CHARACTERS = {
    '=': 1,
    '-': 2,
    '~': 3,
    '`': 4,
    '^': 5,
    '\'': 6
}

CHARACTER_LEVELS = dict(zip(LEVEL_CHARACTERS.values(),
                            LEVEL_CHARACTERS.keys()))

PREFIXES = ['steps']

logger = logging.getLogger(__name__)

def str_or_str_dict(value: Union[str, Dict[str, str]]) -> Union[str, Dict[str, str]]:
    if isinstance(value, str):
        return value

    return mut.str_dict(value)

def str_or_unmangled_list(items: Union[str, List[Any]]) -> Union[str, List[Any]]:
    if isinstance(items, str):
        return items

    return list(items)

class StepsConfig:
    def __init__(self, root_config: mut.RootConfig) -> None:
        self.root_config = root_config
        self.steps = {}  # type: Dict[str, Step]
        self.final_steps = []  # type: List[StepsList]

    def register_step_list(self, steps: 'StepsList') -> None:
        self.final_steps.append(steps)

        for step in steps.steps:
            self._register_step(step)

    def get_step(self, path: str, ref: str) -> 'Step':
        return self.steps[self.step_global_id(path, ref)]

    def output(self) -> None:
        try:
            os.makedirs(self.output_path)
        except FileExistsError:
            pass

        for step_list in self.final_steps:
            step_list.output()

    @property
    def output_path(self) -> str:
        return os.path.join(self.root_config.output_path, 'source', 'includes', 'steps')

    @staticmethod
    def step_global_id(path: str, ref: str) -> str:
        return '{}#{}'.format(path, ref)

    def _register_step(self, step: 'Step') -> None:
        step_id = self.step_global_id(step.path, step.ref)
        if step_id in self.steps:
            raise ValueError('Already registered')

        self.steps[step_id] = step

class StepsInputError(mut.MutInputError):
    @property
    def plugin_name(self) -> str:
        return 'steps'

class Action:
    def __init__(self) -> None:
        self.heading = ''
        self.heading_char = None  # type: str

        self.pre = ''
        self.language = None  # type: str
        self.code = ''
        self.content = ''
        self.post = ''

    def render(self, indent: int, level: int, cloth: rstcloth.rstcloth.RstCloth) -> None:
        if self.heading:
            heading_char = self.heading_char if self.heading_char is not None \
                                             else CHARACTER_LEVELS[level]

            if level in (0, 1):
                cloth.title(text=self.heading,
                            char=heading_char,
                            indent=indent)
            else:
                cloth.heading(text=self.heading,
                              char=heading_char,
                              indent=indent)
            cloth.newline()

        if self.pre:
            cloth.content(content=self.pre,
                          indent=indent,
                          wrap=False)
            cloth.newline()

        if self.code:
            cloth.directive(name='code-block',
                            arg=self.language,
                            indent=indent,
                            wrap=False)
            cloth.newline()
            cloth.content(self.code, wrap=False, indent=indent + 3)

        if self.content:
            cloth.content(content=self.content,
                          indent=indent,
                          wrap=False)
            cloth.newline()

        if self.post:
            cloth.content(content=self.post,
                          indent=indent,
                          wrap=False)
            cloth.newline()

    @classmethod
    def load(cls, value: Any) -> 'Action':
        action = cls()  # type: Action

        if isinstance(value, str):
            action.content = value
            return action

        raw_heading = value.get('heading', '')
        if isinstance(raw_heading, str):
            action.heading = raw_heading
        else:
            action.heading = raw_heading['text']
            action.heading_char = raw_heading.get('character', None)

        action.pre = value.get('pre', '')
        action.language = value.get('language', '')
        action.code = value.get('code', '')
        action.content = value.get('content', '')
        action.post = value.get('post', '')
        return action

class Step:
    def __init__(self, ref: str, path: str, config: StepsConfig) -> None:
        self.ref = ref
        self.path = path
        self.config = config

        self.pre = ''
        self.orig_content = ''
        self.actions = []  # type: List[Action]
        self.post = ''

        self.inherit = None  # type: Tuple[str, str]
        self.title = ''
        self.level = 2

    def render(self, indent: int, cloth: rstcloth.rstcloth.RstCloth) -> None:
        """Render this step's contents into the given RstCloth instance."""
        # Apply pre
        if self.pre:
            cloth.content(self.pre, indent=indent, wrap=False)
            cloth.newline()

        if self.inherit is not None:
            source_path, source_id = self.inherit
            source = self.config.get_step(source_path, source_id)
            source.render(indent, cloth)

        for action in self.actions:
            action.render(indent, self.level + 1, cloth)
            cloth.newline()

        if self.orig_content:
            cloth.content(self.orig_content, indent=indent, wrap=False)
            cloth.newline()

        # Apply post
        if self.post:
            cloth.content(self.post, indent=indent, wrap=False)
            cloth.newline()

    @classmethod
    def load(cls, value: Any, path: str, config: StepsConfig) -> 'Step':
        inherit = mut.withdraw(value, 'inherit', mut.str_dict) or \
                  mut.withdraw(value, 'source', mut.str_dict)

        ref = mut.withdraw(value, 'ref', str)
        if ref is None:
            ref = inherit.get('ref') if inherit else None
        if ref is None:
            raise KeyError('ref: {}'.format(path))

        step = cls(ref, path, config)  # type: Step
        step.pre = mut.withdraw(value, 'pre', str)
        step.post = mut.withdraw(value, 'post', str)

        title = mut.withdraw(value, 'title', str_or_str_dict)
        if isinstance(title, str):
            step.title = title
        elif title:
            step.title = title['text']
            if 'character' in title:
                step.level = LEVEL_CHARACTERS[title['character']]

        step.level = mut.withdraw(value, 'level', int, default=step.level)
        step.orig_content = mut.withdraw(value, 'content', str)
        raw_actions = mut.withdraw(value, 'action', str_or_unmangled_list)
        if isinstance(raw_actions, str) or isinstance(raw_actions, dict):
            step.actions = [Action.load(raw_actions)]
        elif raw_actions:
            step.actions = [Action.load(raw_action) for raw_action in raw_actions]

        if raw_actions and step.orig_content:
            msg = '"action" will replace "content"'
            config.root_config.warn(StepsInputError(path, ref, msg))

        if inherit:
            step.inherit = (inherit['file'], inherit['ref'])

        if mut.withdraw(value, 'stepnum', int):
            msg = 'Deprecated field: "stepnum"'
            config.root_config.warn(StepsInputError(path, ref, msg))

        if value:
            msg = 'Unknown fields "{}"'.format(', '.join(value.keys()))
            config.root_config.warn(StepsInputError(path, ref, msg))

        return step

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, repr(self.ref))

class StepsList:
    def __init__(self, steps: List[Step], path: str, config: StepsConfig) -> None:
        self.ref = os.path.splitext(os.path.basename(path))[0]
        self.path = path
        self.config = config

        self.steps = steps
        config.register_step_list(self)

    def output(self) -> None:
        cloth = rstcloth.rstcloth.RstCloth()
        header_html = ('
'
                       '
'
                       '
'
                       '{0}'
                       '
'
                       '
')

        for step_number, step in enumerate(self.steps):
            step_number += 1

            cloth.directive('only', 'html or dirhtml or singlehtml')
            cloth.newline()

            cloth.directive(name='raw',
                            arg='html',
                            content=header_html.format(step_number),
                            indent=3)
            cloth.newline()

            if step.title:
                cloth.heading(text=step.title,
                              char=CHARACTER_LEVELS[step.level],
                              indent=3)
                cloth.newline()

            step.render(3, cloth)

            cloth.directive(name='raw',
                            arg='html',
                            content='
',
                            indent=3)
            cloth.newline()

            cloth.directive('only', 'latex or epub')
            cloth.newline()

            if step.title:
                cloth.heading(text='Step {0}: {1}'.format(step_number, step.title),
                              char=CHARACTER_LEVELS[step.level],
                              indent=3)
                cloth.newline()
            else:
                cloth.heading(text='Step {0}'.format(step_number),
                              char=CHARACTER_LEVELS[step.level],
                              indent=3)
                cloth.newline()

            step.render(3, cloth)

        cloth.write(self.output_path)

    @property
    def output_path(self) -> str:
        bare_ref = self.ref.replace('steps-', '', 1)
        return os.path.join(self.config.output_path, bare_ref) + '.rst'

    @classmethod
    def load(cls, values: List[Any], path: str, config: StepsConfig) -> 'StepsList':
        filename = os.path.basename(path)
        steps = [Step.load(v, filename, config) for v in values]
        return cls(steps, filename, config)

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, repr(self.ref))

def run(root_config: mut.RootConfig, paths: List[str]) -> List[StepsInputError]:
    logger.info('Steps')
    config = StepsConfig(root_config)
    for path in paths:
        raw_steps = mut.load_yaml(path)
        StepsList.load(raw_steps, path, config)

    config.output()

    return config.root_config.warnings
<commit_msg>steps: Fix incorrect type annotation<commit_after>import logging
import os
import os.path

from typing import *
import rstcloth.rstcloth

import mut

__all__ = ['PREFIXES', 'run']

LEVEL_CHARACTERS = {
    '=': 1,
    '-': 2,
    '~': 3,
    '`': 4,
    '^': 5,
    '\'': 6
}

CHARACTER_LEVELS = dict(zip(LEVEL_CHARACTERS.values(),
                            LEVEL_CHARACTERS.keys()))

PREFIXES = ['steps']

logger = logging.getLogger(__name__)

def str_or_str_dict(value: Union[str, Dict[str, str]]) -> Union[str, Dict[str, str]]:
    if isinstance(value, str):
        return value

    return mut.str_dict(value)

def str_or_unmangled_list(items: Union[str, List[Any]]) -> Union[str, List[Any]]:
    if isinstance(items, str):
        return items

    return list(items)

class StepsConfig:
    def __init__(self, root_config: mut.RootConfig) -> None:
        self.root_config = root_config
        self.steps = {}  # type: Dict[str, Step]
        self.final_steps = []  # type: List[StepsList]

    def register_step_list(self, steps: 'StepsList') -> None:
        self.final_steps.append(steps)

        for step in steps.steps:
            self._register_step(step)

    def get_step(self, path: str, ref: str) -> 'Step':
        return self.steps[self.step_global_id(path, ref)]

    def output(self) -> None:
        try:
            os.makedirs(self.output_path)
        except FileExistsError:
            pass

        for step_list in self.final_steps:
            step_list.output()

    @property
    def output_path(self) -> str:
        return os.path.join(self.root_config.output_path, 'source', 'includes', 'steps')

    @staticmethod
    def step_global_id(path: str, ref: str) -> str:
        return '{}#{}'.format(path, ref)

    def _register_step(self, step: 'Step') -> None:
        step_id = self.step_global_id(step.path, step.ref)
        if step_id in self.steps:
            raise ValueError('Already registered')

        self.steps[step_id] = step

class StepsInputError(mut.MutInputError):
    @property
    def plugin_name(self) -> str:
        return 'steps'

class Action:
    def __init__(self) -> None:
        self.heading = ''
        self.heading_char = None  # type: str

        self.pre = ''
        self.language = None  # type: str
        self.code = ''
        self.content = ''
        self.post = ''

    def render(self, indent: int, level: int, cloth: rstcloth.rstcloth.RstCloth) -> None:
        if self.heading:
            heading_char = self.heading_char if self.heading_char is not None \
                                             else CHARACTER_LEVELS[level]

            if level in (0, 1):
                cloth.title(text=self.heading,
                            char=heading_char,
                            indent=indent)
            else:
                cloth.heading(text=self.heading,
                              char=heading_char,
                              indent=indent)
            cloth.newline()

        if self.pre:
            cloth.content(content=self.pre,
                          indent=indent,
                          wrap=False)
            cloth.newline()

        if self.code:
            cloth.directive(name='code-block',
                            arg=self.language,
                            indent=indent,
                            wrap=False)
            cloth.newline()
            cloth.content(self.code, wrap=False, indent=indent + 3)

        if self.content:
            cloth.content(content=self.content,
                          indent=indent,
                          wrap=False)
            cloth.newline()

        if self.post:
            cloth.content(content=self.post,
                          indent=indent,
                          wrap=False)
            cloth.newline()

    @classmethod
    def load(cls, value: Any) -> 'Action':
        action = cls()  # type: Action

        if isinstance(value, str):
            action.content = value
            return action

        raw_heading = value.get('heading', '')
        if isinstance(raw_heading, str):
            action.heading = raw_heading
        else:
            action.heading = raw_heading['text']
            action.heading_char = raw_heading.get('character', None)

        action.pre = value.get('pre', '')
        action.language = value.get('language', '')
        action.code = value.get('code', '')
        action.content = value.get('content', '')
        action.post = value.get('post', '')
        return action

class Step:
    def __init__(self, ref: str, path: str, config: StepsConfig) -> None:
        self.ref = ref
        self.path = path
        self.config = config

        self.pre = ''
        self.orig_content = ''
        self.actions = []  # type: List[Action]
        self.post = ''

        self.inherit = None  # type: Tuple[str, str]
        self.title = ''
        self.level = 2

    def render(self, indent: int, cloth: rstcloth.rstcloth.RstCloth) -> None:
        """Render this step's contents into the given RstCloth instance."""
        # Apply pre
        if self.pre:
            cloth.content(self.pre, indent=indent, wrap=False)
            cloth.newline()

        if self.inherit is not None:
            source_path, source_id = self.inherit
            source = self.config.get_step(source_path, source_id)
            source.render(indent, cloth)

        for action in self.actions:
            action.render(indent, self.level + 1, cloth)
            cloth.newline()

        if self.orig_content:
            cloth.content(self.orig_content, indent=indent, wrap=False)
            cloth.newline()

        # Apply post
        if self.post:
            cloth.content(self.post, indent=indent, wrap=False)
            cloth.newline()

    @classmethod
    def load(cls, value: Any, path: str, config: StepsConfig) -> 'Step':
        inherit = mut.withdraw(value, 'inherit', mut.str_dict) or \
                  mut.withdraw(value, 'source', mut.str_dict)

        ref = mut.withdraw(value, 'ref', str)
        if ref is None:
            ref = inherit.get('ref') if inherit else None
        if ref is None:
            raise KeyError('ref: {}'.format(path))

        step = cls(ref, path, config)  # type: Step
        step.pre = mut.withdraw(value, 'pre', str)
        step.post = mut.withdraw(value, 'post', str)

        title = mut.withdraw(value, 'title', str_or_str_dict)
        if isinstance(title, str):
            step.title = title
        elif title:
            step.title = title['text']
            if 'character' in title:
                step.level = LEVEL_CHARACTERS[title['character']]

        step.level = mut.withdraw(value, 'level', int, default=step.level)
        step.orig_content = mut.withdraw(value, 'content', str)
        raw_actions = mut.withdraw(value, 'action', str_or_unmangled_list)
        if isinstance(raw_actions, str) or isinstance(raw_actions, dict):
            step.actions = [Action.load(raw_actions)]
        elif raw_actions:
            step.actions = [Action.load(raw_action) for raw_action in raw_actions]

        if raw_actions and step.orig_content:
            msg = '"action" will replace "content"'
            config.root_config.warn(StepsInputError(path, ref, msg))

        if inherit:
            step.inherit = (inherit['file'], inherit['ref'])

        if mut.withdraw(value, 'stepnum', int):
            msg = 'Deprecated field: "stepnum"'
            config.root_config.warn(StepsInputError(path, ref, msg))

        if value:
            msg = 'Unknown fields "{}"'.format(', '.join(value.keys()))
            config.root_config.warn(StepsInputError(path, ref, msg))

        return step

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, repr(self.ref))

class StepsList:
    def __init__(self, steps: List[Step], path: str, config: StepsConfig) -> None:
        self.ref = os.path.splitext(os.path.basename(path))[0]
        self.path = path
        self.config = config

        self.steps = steps
        config.register_step_list(self)

    def output(self) -> None:
        cloth = rstcloth.rstcloth.RstCloth()
        header_html = ('
'
                       '
'
                       '
'
                       '{0}'
                       '
'
                       '
')

        for step_number, step in enumerate(self.steps):
            step_number += 1

            cloth.directive('only', 'html or dirhtml or singlehtml')
            cloth.newline()

            cloth.directive(name='raw',
                            arg='html',
                            content=header_html.format(step_number),
                            indent=3)
            cloth.newline()

            if step.title:
                cloth.heading(text=step.title,
                              char=CHARACTER_LEVELS[step.level],
                              indent=3)
                cloth.newline()

            step.render(3, cloth)

            cloth.directive(name='raw',
                            arg='html',
                            content='
',
                            indent=3)
            cloth.newline()

            cloth.directive('only', 'latex or epub')
            cloth.newline()

            if step.title:
                cloth.heading(text='Step {0}: {1}'.format(step_number, step.title),
                              char=CHARACTER_LEVELS[step.level],
                              indent=3)
                cloth.newline()
            else:
                cloth.heading(text='Step {0}'.format(step_number),
                              char=CHARACTER_LEVELS[step.level],
                              indent=3)
                cloth.newline()

            step.render(3, cloth)

        cloth.write(self.output_path)

    @property
    def output_path(self) -> str:
        bare_ref = self.ref.replace('steps-', '', 1)
        return os.path.join(self.config.output_path, bare_ref) + '.rst'

    @classmethod
    def load(cls, values: List[Any], path: str, config: StepsConfig) -> 'StepsList':
        filename = os.path.basename(path)
        steps = [Step.load(v, filename, config) for v in values]
        return cls(steps, filename, config)

    def __repr__(self):
        return '{}({})'.format(self.__class__.__name__, repr(self.ref))

def run(root_config: mut.RootConfig, paths: List[str]) -> List[mut.MutInputError]:
    logger.info('Steps')
    config = StepsConfig(root_config)
    for path in paths:
        raw_steps = mut.load_yaml(path)
        StepsList.load(raw_steps, path, config)

    config.output()

    return config.root_config.warnings
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import os
import sys

import alagitpull

import libtmux  # NOQA
from libtmux import test  # NOQA

# Get the project root dir, which is the parent dir of this
cwd = os.getcwd()
project_root = os.path.dirname(cwd)

sys.path.insert(0, project_root)

# package data
about = {}
with open("../libtmux/__about__.py") as fp:
    exec(fp.read(), about)

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinxcontrib.napoleon',
    'releases',
    'alagitpull',
]

releases_unstable_prehistory = True
releases_document_name = "history"
releases_issue_uri = "https://github.com/tmux-python/libtmux/issues/%s"
releases_release_uri = "https://github.com/tmux-python/libtmux/tree/v%s"
releases_future_release_uri = "https://github.com/tmux-python/libtmux/tree/%s"

templates_path = ['_templates']

source_suffix = '.rst'

master_doc = 'index'

project = about['__title__']
copyright = about['__copyright__']

version = '%s' % ('.'.join(about['__version__'].split('.'))[:2])
release = '%s' % (about['__version__'])

exclude_patterns = ['_build']

pygments_style = 'sphinx'

html_theme_path = [alagitpull.get_path()]
html_favicon = 'favicon.ico'
html_theme = 'alagitpull'
html_theme_options = {
    'logo': 'img/libtmux.svg',
    'github_user': 'tmux-python',
    'github_repo': 'libtmux',
    'github_type': 'star',
    'github_banner': True,
    'projects': alagitpull.projects,
    'project_name': about['__title__'],
}
alagitpull_internal_hosts = ['libtmux.git-pull.com', '0.0.0.0']
alagitpull_external_hosts_new_window = True

html_sidebars = {
    '**': [
        'about.html',
        'navigation.html',
        'relations.html',
        'more.html',
        'book.html',
        'searchbox.html',
    ]
}

html_theme_path = ['_themes']
html_static_path = ['_static']

htmlhelp_basename = '%sdoc' % about['__title__']

latex_documents = [
    (
        'index',
        '{0}.tex'.format(about['__package_name__']),
        '{0} Documentation'.format(about['__title__']),
        about['__author__'],
        'manual',
    )
]

man_pages = [
    (
        'index',
        about['__package_name__'],
        '{0} Documentation'.format(about['__title__']),
        about['__author__'],
        1,
    )
]

texinfo_documents = [
    (
        'index',
        '{0}'.format(about['__package_name__']),
        '{0} Documentation'.format(about['__title__']),
        about['__author__'],
        about['__package_name__'],
        about['__description__'],
        'Miscellaneous',
    )
]

intersphinx_mapping = {'http://docs.python.org/': None}
<commit_msg>Add code linking in API docs<commit_after># -*- coding: utf-8 -*-
import inspect
import os
import sys
from os.path import dirname, relpath

import alagitpull

import libtmux  # NOQA
from libtmux import test  # NOQA

# Get the project root dir, which is the parent dir of this
cwd = os.getcwd()
project_root = os.path.dirname(cwd)

sys.path.insert(0, project_root)

# package data
about = {}
with open("../libtmux/__about__.py") as fp:
    exec(fp.read(), about)

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinx.ext.linkcode',
    'sphinxcontrib.napoleon',
    'releases',
    'alagitpull',
]

releases_unstable_prehistory = True
releases_document_name = "history"
releases_issue_uri = "https://github.com/tmux-python/libtmux/issues/%s"
releases_release_uri = "https://github.com/tmux-python/libtmux/tree/v%s"
releases_future_release_uri = "https://github.com/tmux-python/libtmux/tree/%s"

templates_path = ['_templates']

source_suffix = '.rst'

master_doc = 'index'

project = about['__title__']
copyright = about['__copyright__']

version = '%s' % ('.'.join(about['__version__'].split('.'))[:2])
release = '%s' % (about['__version__'])

exclude_patterns = ['_build']

pygments_style = 'sphinx'

html_theme_path = [alagitpull.get_path()]
html_favicon = 'favicon.ico'
html_theme = 'alagitpull'
html_theme_options = {
    'logo': 'img/libtmux.svg',
    'github_user': 'tmux-python',
    'github_repo': 'libtmux',
    'github_type': 'star',
    'github_banner': True,
    'projects': alagitpull.projects,
    'project_name': about['__title__'],
}
alagitpull_internal_hosts = ['libtmux.git-pull.com', '0.0.0.0']
alagitpull_external_hosts_new_window = True

html_sidebars = {
    '**': [
        'about.html',
        'navigation.html',
        'relations.html',
        'more.html',
        'book.html',
        'searchbox.html',
    ]
}

html_theme_path = ['_themes']
html_static_path = ['_static']

htmlhelp_basename = '%sdoc' % about['__title__']

latex_documents = [
    (
        'index',
        '{0}.tex'.format(about['__package_name__']),
        '{0} Documentation'.format(about['__title__']),
        about['__author__'],
        'manual',
    )
]

man_pages = [
    (
        'index',
        about['__package_name__'],
        '{0} Documentation'.format(about['__title__']),
        about['__author__'],
        1,
    )
]

texinfo_documents = [
    (
        'index',
        '{0}'.format(about['__package_name__']),
        '{0} Documentation'.format(about['__title__']),
        about['__author__'],
        about['__package_name__'],
        about['__description__'],
        'Miscellaneous',
    )
]

intersphinx_mapping = {'http://docs.python.org/': None}

def linkcode_resolve(domain, info):  # NOQA: C901
    """
    Determine the URL corresponding to Python object

    Notes
    -----
    From https://github.com/numpy/numpy/blob/v1.15.1/doc/source/conf.py, 7c49cfa
    on Jul 31. License BSD-3. https://github.com/numpy/numpy/blob/v1.15.1/LICENSE.txt
    """
    if domain != 'py':
        return None

    modname = info['module']
    fullname = info['fullname']

    submod = sys.modules.get(modname)
    if submod is None:
        return None

    obj = submod
    for part in fullname.split('.'):
        try:
            obj = getattr(obj, part)
        except Exception:
            return None

    # strip decorators, which would resolve to the source of the decorator
    # possibly an upstream bug in getsourcefile, bpo-1764286
    try:
        unwrap = inspect.unwrap
    except AttributeError:
        pass
    else:
        obj = unwrap(obj)

    try:
        fn = inspect.getsourcefile(obj)
    except Exception:
        fn = None
    if not fn:
        return None

    try:
        source, lineno = inspect.getsourcelines(obj)
    except Exception:
        lineno = None

    if lineno:
        linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1)
    else:
        linespec = ""

    fn = relpath(fn, start=dirname(libtmux.__file__))

    if 'dev' in about['__version__']:
        return "%s/blob/master/%s/%s%s" % (
            about['__github__'],
            about['__package_name__'],
            fn,
            linespec,
        )
    else:
        return "%s/blob/v%s/%s/%s%s" % (
            about['__github__'],
            about['__version__'],
            about['__package_name__'],
            fn,
            linespec,
        )
<|endoftext|>


<commit_before>
import uuid

RESET_OPTION = """
                require({requires},function(echarts){{
                    var myChart = echarts.init(document.getElementById("{chartId}"),"{theme}");
                    myChart.setOption({option});
                    myChart.on('mouseover',function(params){{
                        console.log(params)

                    }});
                }});
                """
APPEND_ELEMENT = """
$('#{id}').attr('id','{id}'+'_old');
element.append('

');"""

OPTION_TEMPLATE = {
        'title': {
            'text': ''
        },
        'tooltip': {'axisPointer':{'type':''}},
        'legend': {
            'data':[]
        },
        'xAxis': {
            'data': []
        },
        'yAxis': {},
        'series': []
    }

class Chart():
    def __init__(self,**kwargs):
        self._chartId = str(uuid.uuid4())
        self._option = deepcopy(OPTION_TEMPLATE)
        self._kwargs_chart_ = kwargs
        self._theme = ''

    def set_legend(self,):
        pass

    def set_theme(self,theme):
        """Set the theme of the chart.
        theme: {'dark','vintage','rima','shine','infographic','dark'}, default None
        """
        self._theme = theme
        return self

    def resync_data(self,data):
        """Update data but still using the same chart option.
        Currently just update the current cell it exist, but not the chart option
        itself.

        Parameters
        ----------
        data: pd.DataFrame

        """
        option = make_chart(data,**self._kwargs_chart_)._option
        return Javascript(self._get_resync_option_strings(option))

    def replot(self,chart):
        """Replot entire chart to its current cell"""
        return Javascript(self._get_resync_option_strings(chart._option))

    def _get_resync_option_strings(self,option):
        """Resync Chart option"""

        return RESET_OPTION.format(requires=list(d_paths.keys()).__repr__(),
                                   chartId=self._chartId,
                                   theme=self._theme,
                                   option=json.dumps(option))

    def set_tooltip(self,trigger='axis',axis_pointer='shadow'):
        """Set Tooltip options.

        Parameters
        ----------
        trigger: {'axis',None}, default 'axis'
            When tooltip should be triggered. Default to axis
        axis_pointer: {'shadow',None}, default 'shadow'
            Effect of pointing the axis.

        Returns
        -------

        """

        self._option['tooltip']['trigger'] = trigger
        self._option['tooltip']['axisPointer']['type'] = axis_pointer
        return self

    def get_option(self):

        return self._option

    def set_title(self,title):
        """Set title for the plot"""
        self._option['title']['text'] = title
        return self

    def flip_axes(self):
        """Flip the axes to make it horizontal"""
        self._axes_swapped = not self._axes_swapped
        self._option['xAxis'],self._option['yAxis'] = self._option['yAxis'],self._option['xAxis']
        return self

    def _repr_javascript_(self):
        """Embedding the result of the plot to Jupyter"""
        return (APPEND_ELEMENT.format(id=self._chartId))+\
                (self._get_resync_option_strings(self._option))

    _axes_swapped = True
    _kwargs_chart_ = {}

    <commit_msg>Add events template and api<commit_after>
import uuid

RESET_OPTION = """
require({requires},function(echarts){{
    var myChart = echarts.init(document.getElementById("{chartId}"),"{theme}");
    myChart.setOption({option});
    {events}
}});
"""
APPEND_ELEMENT = """
$('#{id}').attr('id','{id}'+'_old');
element.append('

');"""

OPTION_TEMPLATE = {
        'title': {
            'text': ''
        },
        'tooltip': {'axisPointer':{'type':''}},
        'legend': {
            'data':[]
        },
        'xAxis': {
            'data': []
        },
        'yAxis': {},
        'series': []
    }

EVENTS_TEMPLATE = """
myChart.on('{event}',function(params){{
    console.log(params);
    IPython.notebook.kernel.execute("params = params");
    IPython.notebook.kernel.execute("{function}(params['componentType'])");
}});
"""

class Chart():
    def __init__(self,**kwargs):
        self._chartId = str(uuid.uuid4())
        self._option = deepcopy(OPTION_TEMPLATE)
        self._kwargs_chart_ = kwargs
        self._theme = ''

    # Color and Themes

    def set_theme(self,theme):
        """
        Set the theme of the chart.
        theme: string
            {'dark','vintage','rima','shine','infographic','dark'}, default None
        """

        if theme not in ['dark','vintage','rima','shine','infographic','dark']:
            raise AssertionError("Invalid theme name: {theme}".format(theme=theme))

        self._theme = theme
        return self

    def set_color(background=None,palletes=None):
        """
        Return
        """
        pass

    # ---------------------------------------------------------------------------

    def set_tooltip(self,trigger='axis',axis_pointer='shadow'):
        """Set Tooltip options.

        Parameters
        ----------
        trigger: {'axis',None}, default 'axis'
            When tooltip should be triggered. Default to axis
        axis_pointer: {'shadow',None}, default 'shadow'
            Effect of pointing the axis.

        Returns
        -------

        """

        self._option['tooltip']['trigger'] = trigger
        self._option['tooltip']['axisPointer']['type'] = axis_pointer
        return self

    def get_option(self):

        return self._option

    def set_title(self,title):
        """Set title for the plot"""
        self._option['title']['text'] = title
        return self

    def set_legend(self,):
        pass

    def flip_axes(self):
        """Flip the axes to make it horizontal"""
        self._axes_swapped = not self._axes_swapped
        self._option['xAxis'],self._option['yAxis'] = self._option['yAxis'],self._option['xAxis']
        return self

    # Events
    def on_event(self,event,handler):

        events = ['click','dblclick','mousedown','mouseup','mouseover','mouseout','globalout']
        if event not in events:
            raise AssertionError('Invalid event name: %s'% event)

        self._events[event] = handler.__name__
        return self

    # --------------------------------------------------------------------------

    # Replot Functions
    def resync_data(self,data):
        """Update data but still using the same chart option.
        Currently just update the current cell it exist, but not the chart option
        itself.

        Parameters
        ----------
        data: pd.DataFrame

        """
        option = make_chart(data,**self._kwargs_chart_)._option
        return Javascript(self._get_resync_option_strings(option))

    def replot(self,chart):
        """Replot entire chart to its current cell"""
        return Javascript(self._get_resync_option_strings(chart._option))

    def _get_resync_option_strings(self,option):
        """Resync Chart option"""

        events = [EVENTS_TEMPLATE.format(event=e,function=self._events[e]) for e in self._events]
        OPTION_KWS = dict(
            requires=list(d_paths.keys()).__repr__(),
            chartId=self._chartId,
            theme=self._theme,
            option=json.dumps(option),
            events='\n'.join(events)
        )
        return RESET_OPTION.format(**OPTION_KWS)

    def _repr_javascript_(self):
        """Embedding the result of the plot to Jupyter"""
        return (APPEND_ELEMENT.format(id=self._chartId))+\
                (self._get_resync_option_strings(self._option))
    "# ----------------------------------------------------------------------"

    # Saving chart option
    def to_json(self,path):
        "Save Chart option"
        pass

    def to_html(self,path):
        "Save full html file"
        pass

    _axes_swapped = True
    _kwargs_chart_ = {}
    _events = {}

    <|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2013, bleader
# Written by bleader <bleader@ratonland.org>
# Based on pkgin module written by Shaun Zinck <shaun.zinck at gmail.com>
# that was based on pacman module written by Afterburn <http://github.com/afterburn>
#  that was based on apt module written by Matthew Williams <matthew@flowroute.com>
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software.  If not, see <http://www.gnu.org/licenses/>.

DOCUMENTATION = '''
---
module: pkgng
short_description: Package manager for FreeBSD >= 9.0
description:
    - Manage binary packages for FreeBSD using 'pkgng' which
      is available in versions after 9.0.
version_added: "1.2"
options:
    name:
        description:
            - name of package to install/remove
        required: true
    state:
        description:
            - state of the package
        choices: [ 'present', 'absent' ]
        required: false
        default: present
    cached:
        description:
            - use local package base or try to fetch an updated one
        choices: [ 'yes', 'no' ]
        required: false
        default: no
    annotation:
        description:
            - a comma-separated list of keyvalue-pairs of the form
              <+/-/:><key>[=<value>]. A '+' denotes adding an annotation, a
              '-' denotes removing an annotation, and ':' denotes modifying an
              annotation.
              If setting or modifying annotations, a value must be provided.
        required: false
        version_added: "1.6"
    pkgsite:
        description:
            - for pkgng versions before 1.1.4, specify packagesite to use
              for downloading packages, if not specified, use settings from
              /usr/local/etc/pkg.conf
              for newer pkgng versions, specify a the name of a repository
              configured in /usr/local/etc/pkg/repos
        required: false
author: bleader
notes:
    - When using pkgsite, be careful that already in cache packages won't be downloaded again.
'''

EXAMPLES = '''
# Install package foo
- pkgng: name=foo state=present

# Annotate package foo and bar
- pkgng: name=foo,bar annotation=+test1=baz,-test2,:test3=foobar

# Remove packages foo and bar
- pkgng: name=foo,bar state=absent
'''

import json
import shlex
import os
import re
import sys

def query_package(module, pkgng_path, name):

    rc, out, err = module.run_command("%s info -g -e %s" % (pkgng_path, name))

    if rc == 0:
        return True

    return False

def pkgng_older_than(module, pkgng_path, compare_version):

    rc, out, err = module.run_command("%s -v" % pkgng_path)
    version = map(lambda x: int(x), re.split(r'[\._]', out))

    i = 0
    new_pkgng = True
    while compare_version[i] == version[i]:
        i += 1
        if i == min(len(compare_version), len(version)):
            break
    else:
        if compare_version[i] > version[i]:
            new_pkgng = False
    return not new_pkgng

def remove_packages(module, pkgng_path, packages):

    remove_c = 0
    # Using a for loop incase of error, we can report the package that failed
    for package in packages:
        # Query the package first, to see if we even need to remove
        if not query_package(module, pkgng_path, package):
            continue

        if not module.check_mode:
            rc, out, err = module.run_command("%s delete -y %s" % (pkgng_path, package))

        if not module.check_mode and query_package(module, pkgng_path, package):
            module.fail_json(msg="failed to remove %s: %s" % (package, out))

        remove_c += 1

    if remove_c > 0:

        return (True, "removed %s package(s)" % remove_c)

    return (False, "package(s) already absent")

def install_packages(module, pkgng_path, packages, cached, pkgsite):

    install_c = 0

    # as of pkg-1.1.4, PACKAGESITE is deprecated in favor of repository definitions
    # in /usr/local/etc/pkg/repos
    old_pkgng = pkgng_older_than(module, pkgng_path, [1, 1, 4])
    if pkgsite != "":
        if old_pkgng:
            pkgsite = "PACKAGESITE=%s" % (pkgsite)
        else:
            pkgsite = "-r %s" % (pkgsite)

    if not module.check_mode and not cached:
        if old_pkgng:
            rc, out, err = module.run_command("%s %s update" % (pkgsite, pkgng_path))
        else:
            rc, out, err = module.run_command("%s update" % (pkgng_path))
        if rc != 0:
            module.fail_json(msg="Could not update catalogue")

    for package in packages:
        if query_package(module, pkgng_path, package):
            continue

        if not module.check_mode:
            if old_pkgng:
                rc, out, err = module.run_command("%s %s install -g -U -y %s" % (pkgsite, pkgng_path, package))
            else:
                rc, out, err = module.run_command("%s install %s -g -U -y %s" % (pkgng_path, pkgsite, package))

        if not module.check_mode and not query_package(module, pkgng_path, package):
            module.fail_json(msg="failed to install %s: %s" % (package, out), stderr=err)

        install_c += 1

    if install_c > 0:
        return (True, "added %s package(s)" % (install_c))

    return (False, "package(s) already present")

def annotation_query(module, pkgng_path, package, tag):
    rc, out, err = module.run_command("%s info -g -A %s" % (pkgng_path, package))
    match = re.search(r'^\s*(?P<tag>%s)\s*:\s*(?P<value>\w+)' % tag, out, flags=re.MULTILINE)
    if match:
        return match.group('value')
    return False

def annotation_add(module, pkgng_path, package, tag, value):
    _value = annotation_query(module, pkgng_path, package, tag)
    if not _value:
        # Annotation does not exist, add it.
        rc, out, err = module.run_command('%s annotate -y -A %s %s "%s"'
            % (pkgng_path, package, tag, value))
        if rc != 0:
            module.fail_json("could not annotate %s: %s"
                % (package, out), stderr=err)
        return True
    elif _value != value:
        # Annotation exists, but value differs
        module.fail_json(
            mgs="failed to annotate %s, because %s is already set to %s, but should be set to %s"
            % (package, tag, _value, value))
        return False
    else:
        # Annotation exists, nothing to do
        return False

def annotation_delete(module, pkgng_path, package, tag, value):
    _value = annotation_query(module, pkgng_path, package, tag)
    if _value:
        rc, out, err = module.run_command('%s annotate -y -D %s %s'
            % (pkgng_path, package, tag))
        if rc != 0:
            module.fail_json("could not delete annotation to %s: %s"
                % (package, out), stderr=err)
        return True
    return False

def annotation_modify(module, pkgng_path, package, tag, value):
    _value = annotation_query(module, pkgng_path, package, tag)
    if not value:
        # No such tag
        module.fail_json("could not change annotation to %s: tag %s does not exist"
            % (package, tag))
    elif _value == value:
        # No change in value
        return False
    else:
        rc,out,err = module.run_command('%s annotate -y -M %s %s "%s"'
            % (pkgng_path, package, tag, value))
        if rc != 0:
            module.fail_json("could not change annotation annotation to %s: %s"
                % (package, out), stderr=err)
        return True

def annotate_packages(module, pkgng_path, packages, annotation):
    annotate_c = 0
    annotations = map(lambda _annotation:
        re.match(r'(?P<operation>[\+-:])(?P<tag>\w+)(=(?P<value>\w+))?',
            _annotation).groupdict(),
        re.split(r',', annotation))

    operation = {
        '+': annotation_add,
        '-': annotation_delete,
        ':': annotation_modify
    }

    for package in packages:
        for _annotation in annotations:
            annotate_c += ( 1 if operation[_annotation['operation']](
                module, pkgng_path, package,
                _annotation['tag'], _annotation['value']) else 0 )

    if annotate_c > 0:
        return (True, "added %s annotations." % annotate_c)
    return (False, "changed no annotations")

def main():
    module = AnsibleModule(
            argument_spec       = dict(
                state           = dict(default="present", choices=["present","absent"], required=False),
                name            = dict(aliases=["pkg"], required=True),
                cached          = dict(default=False, type='bool'),
                annotation      = dict(default="", required=False),
                pkgsite         = dict(default="", required=False)),
            supports_check_mode = True)

    pkgng_path = module.get_bin_path('pkg', True)

    p = module.params

    pkgs = p["name"].split(",")

    changed = False
    msgs = []

    if p["state"] == "present":
        _changed, _msg = install_packages(module, pkgng_path, pkgs, p["cached"], p["pkgsite"])
        changed = changed or _changed
        msgs.append(_msg)

    elif p["state"] == "absent":
        _changed, _msg = remove_packages(module, pkgng_path, pkgs)
        changed = changed or _changed
        msgs.append(_msg)

    if p["annotation"]:
        _changed, _msg = annotate_packages(module, pkgng_path, pkgs, p["annotation"])
        changed = changed or _changed
        msgs.append(_msg)

    module.exit_json(changed=changed, msg=", ".join(msgs))

# import module snippets
from ansible.module_utils.basic import *

main()
<commit_msg>pkgng: add 'batch' parameter<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2013, bleader
# Written by bleader <bleader@ratonland.org>
# Based on pkgin module written by Shaun Zinck <shaun.zinck at gmail.com>
# that was based on pacman module written by Afterburn <http://github.com/afterburn>
#  that was based on apt module written by Matthew Williams <matthew@flowroute.com>
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software.  If not, see <http://www.gnu.org/licenses/>.

DOCUMENTATION = '''
---
module: pkgng
short_description: Package manager for FreeBSD >= 9.0
description:
    - Manage binary packages for FreeBSD using 'pkgng' which
      is available in versions after 9.0.
version_added: "1.2"
options:
    name:
        description:
            - name of package to install/remove
        required: true
    state:
        description:
            - state of the package
        choices: [ 'present', 'absent' ]
        required: false
        default: present
    cached:
        description:
            - use local package base or try to fetch an updated one
        choices: [ 'yes', 'no' ]
        required: false
        default: no
    annotation:
        description:
            - a comma-separated list of keyvalue-pairs of the form
              <+/-/:><key>[=<value>]. A '+' denotes adding an annotation, a
              '-' denotes removing an annotation, and ':' denotes modifying an
              annotation.
              If setting or modifying annotations, a value must be provided.
        required: false
        version_added: "1.6"
    pkgsite:
        description:
            - for pkgng versions before 1.1.4, specify packagesite to use
              for downloading packages, if not specified, use settings from
              /usr/local/etc/pkg.conf
              for newer pkgng versions, specify a the name of a repository
              configured in /usr/local/etc/pkg/repos
        required: false
    batch:
        description:
            - for packages with interactive prompts during installation,
              this makes pkgng automatically accept all default options for
              the installation of the package.
        default: yes
        required: false
author: bleader
notes:
    - When using pkgsite, be careful that already in cache packages won't be downloaded again.
'''

EXAMPLES = '''
# Install package foo
- pkgng: name=foo state=present

# Annotate package foo and bar
- pkgng: name=foo,bar annotation=+test1=baz,-test2,:test3=foobar

# Remove packages foo and bar
- pkgng: name=foo,bar state=absent
'''

import json
import shlex
import os
import re
import sys

def query_package(module, pkgng_path, name):

    rc, out, err = module.run_command("%s info -g -e %s" % (pkgng_path, name))

    if rc == 0:
        return True

    return False

def pkgng_older_than(module, pkgng_path, compare_version):

    rc, out, err = module.run_command("%s -v" % pkgng_path)
    version = map(lambda x: int(x), re.split(r'[\._]', out))

    i = 0
    new_pkgng = True
    while compare_version[i] == version[i]:
        i += 1
        if i == min(len(compare_version), len(version)):
            break
    else:
        if compare_version[i] > version[i]:
            new_pkgng = False
    return not new_pkgng

def remove_packages(module, pkgng_path, packages):

    remove_c = 0
    # Using a for loop incase of error, we can report the package that failed
    for package in packages:
        # Query the package first, to see if we even need to remove
        if not query_package(module, pkgng_path, package):
            continue

        if not module.check_mode:
            rc, out, err = module.run_command("%s delete -y %s" % (pkgng_path, package))

        if not module.check_mode and query_package(module, pkgng_path, package):
            module.fail_json(msg="failed to remove %s: %s" % (package, out))

        remove_c += 1

    if remove_c > 0:

        return (True, "removed %s package(s)" % remove_c)

    return (False, "package(s) already absent")

def install_packages(module, pkgng_path, packages, cached, pkgsite, batch):

    install_c = 0

    # as of pkg-1.1.4, PACKAGESITE is deprecated in favor of repository definitions
    # in /usr/local/etc/pkg/repos
    old_pkgng = pkgng_older_than(module, pkgng_path, [1, 1, 4])
    if pkgsite != "":
        if old_pkgng:
            pkgsite = "PACKAGESITE=%s" % (pkgsite)
        else:
            pkgsite = "-r %s" % (pkgsite)

    if batch == True:
      batch_var = 'env BATCH=yes'
    else:
      batch_var = ''

    if not module.check_mode and not cached:
        if old_pkgng:
            rc, out, err = module.run_command("%s %s update" % (pkgsite, pkgng_path))
        else:
            rc, out, err = module.run_command("%s update" % (pkgng_path))
        if rc != 0:
            module.fail_json(msg="Could not update catalogue")

    for package in packages:
        if query_package(module, pkgng_path, package):
            continue

        if not module.check_mode:
            if old_pkgng:
                rc, out, err = module.run_command("%s %s %s install -g -U -y %s" % (batch_var, pkgsite, pkgng_path, package))
            else:
                rc, out, err = module.run_command("%s %s install %s -g -U -y %s" % (batch_var, pkgng_path, pkgsite, package))

        if not module.check_mode and not query_package(module, pkgng_path, package):
            module.fail_json(msg="failed to install %s: %s" % (package, out), stderr=err)

        install_c += 1

    if install_c > 0:
        return (True, "added %s package(s)" % (install_c))

    return (False, "package(s) already present")

def annotation_query(module, pkgng_path, package, tag):
    rc, out, err = module.run_command("%s info -g -A %s" % (pkgng_path, package))
    match = re.search(r'^\s*(?P<tag>%s)\s*:\s*(?P<value>\w+)' % tag, out, flags=re.MULTILINE)
    if match:
        return match.group('value')
    return False

def annotation_add(module, pkgng_path, package, tag, value):
    _value = annotation_query(module, pkgng_path, package, tag)
    if not _value:
        # Annotation does not exist, add it.
        rc, out, err = module.run_command('%s annotate -y -A %s %s "%s"'
            % (pkgng_path, package, tag, value))
        if rc != 0:
            module.fail_json("could not annotate %s: %s"
                % (package, out), stderr=err)
        return True
    elif _value != value:
        # Annotation exists, but value differs
        module.fail_json(
            mgs="failed to annotate %s, because %s is already set to %s, but should be set to %s"
            % (package, tag, _value, value))
        return False
    else:
        # Annotation exists, nothing to do
        return False

def annotation_delete(module, pkgng_path, package, tag, value):
    _value = annotation_query(module, pkgng_path, package, tag)
    if _value:
        rc, out, err = module.run_command('%s annotate -y -D %s %s'
            % (pkgng_path, package, tag))
        if rc != 0:
            module.fail_json("could not delete annotation to %s: %s"
                % (package, out), stderr=err)
        return True
    return False

def annotation_modify(module, pkgng_path, package, tag, value):
    _value = annotation_query(module, pkgng_path, package, tag)
    if not value:
        # No such tag
        module.fail_json("could not change annotation to %s: tag %s does not exist"
            % (package, tag))
    elif _value == value:
        # No change in value
        return False
    else:
        rc,out,err = module.run_command('%s annotate -y -M %s %s "%s"'
            % (pkgng_path, package, tag, value))
        if rc != 0:
            module.fail_json("could not change annotation annotation to %s: %s"
                % (package, out), stderr=err)
        return True

def annotate_packages(module, pkgng_path, packages, annotation):
    annotate_c = 0
    annotations = map(lambda _annotation:
        re.match(r'(?P<operation>[\+-:])(?P<tag>\w+)(=(?P<value>\w+))?',
            _annotation).groupdict(),
        re.split(r',', annotation))

    operation = {
        '+': annotation_add,
        '-': annotation_delete,
        ':': annotation_modify
    }

    for package in packages:
        for _annotation in annotations:
            annotate_c += ( 1 if operation[_annotation['operation']](
                module, pkgng_path, package,
                _annotation['tag'], _annotation['value']) else 0 )

    if annotate_c > 0:
        return (True, "added %s annotations." % annotate_c)
    return (False, "changed no annotations")

def main():
    module = AnsibleModule(
            argument_spec       = dict(
                state           = dict(default="present", choices=["present","absent"], required=False),
                name            = dict(aliases=["pkg"], required=True),
                cached          = dict(default=False, type='bool'),
                annotation      = dict(default="", required=False),
                pkgsite         = dict(default="", required=False),
                batch           = dict(default=False, required=False, type='bool')),
            supports_check_mode = True)

    pkgng_path = module.get_bin_path('pkg', True)

    p = module.params

    pkgs = p["name"].split(",")

    changed = False
    msgs = []

    if p["state"] == "present":
        _changed, _msg = install_packages(module, pkgng_path, pkgs, p["cached"], p["pkgsite"], p["batch"])
        changed = changed or _changed
        msgs.append(_msg)

    elif p["state"] == "absent":
        _changed, _msg = remove_packages(module, pkgng_path, pkgs)
        changed = changed or _changed
        msgs.append(_msg)

    if p["annotation"]:
        _changed, _msg = annotate_packages(module, pkgng_path, pkgs, p["annotation"])
        changed = changed or _changed
        msgs.append(_msg)

    module.exit_json(changed=changed, msg=", ".join(msgs))

# import module snippets
from ansible.module_utils.basic import *

main()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "mib"
__date__ = "$2011-01-22 12:02:41$"

from abstract import Abstract
from local import Local

__all__ = ['Abstract', 'Local']
<commit_msg>Load conditionally all available adapters in order to make them available right inside pygrapes.adapter module<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "mib"
__date__ = "$2011-01-22 12:02:41$"

from pygrapes.util import not_implemented
from pygrapes.adapter.abstract import Abstract
from pygrapes.adapter.local import Local

try:
    from pygrapes.adapter.zeromq import Zmq
except ImportError:
    Zmq = not_implemented('A working pyzmq lib is required!')

try:
    from pygrapes.adapter.amqp import Amqp
except ImportError:
    Amqp = not_implemented('A working amqplib lib is required!')

__all__ = ['Abstract', 'Amqp', 'Local', 'Zmq']
<|endoftext|>


<commit_before>#!/usr/bin/env python

'''Test that close event works correctly.

Expected behaviour:
    One window will be opened.  Click the close button and ensure the
    event is printed to the terminal.  The window should not close
    when you do this.

    Click Left mouse button to end the test.
'''

__docformat__ = 'restructuredtext'
__version__ = '$Id: $'

import unittest

from pyglet import window
from pyglet import event

class EVENT_CLOSE(unittest.TestCase):
    def on_close(self):
        print 'Window close event.'
        return event.EVENT_HANDLED

    def on_mouse_press(self, x, y, button, modifiers):
        super(window.Window, self.w).on_close()

    def test_close(self):
        self.w = window.Window(200, 200)
        self.w.push_handlers(self)
        while not self.w.has_exit:
            self.w.dispatch_events()
        self.w.close()

if __name__ == '__main__':
    unittest.main()
<commit_msg>updated from maintenance<commit_after>#!/usr/bin/env python

'''Test that close event works correctly.

Expected behaviour:
    One window will be opened.  Click the close button and ensure the
    event is printed to the terminal.  The window should not close
    when you do this.

    Click Left mouse button to end the test.
'''

__docformat__ = 'restructuredtext'
__version__ = '$Id: $'

import unittest

from pyglet import window
from pyglet import event
w = None

class EVENT_CLOSE(unittest.TestCase):
    def on_close(self):
        print 'Window close event.'
        return event.EVENT_HANDLED

    def on_key_press(self, symbol, mods):
        if symbol == window.key.ESCAPE:
            global w
            super(window.Window, w).on_close()

    def test_close(self):
        global w
        w = window.Window(200, 200)
        w.push_handlers(self)
        while not w.has_exit:
            w.dispatch_events()
        w.close()

if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# PySimSearch documentation build configuration file, created by
# sphinx-quickstart on Mon Jul 25 22:06:33 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinxtogithub']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'pysimsearch'
copyright = u'2011, Taher Haveliwala'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.30'
# The full version, including alpha/beta/rc tags.
release = '0.30'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['build']

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

html_style = 'custom.css'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'pysimsearchdoc'

# -- Options for LaTeX output --------------------------------------------------

# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'

# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'pysimsearch.tex', u'pysimsearch Documentation',
   u'Taher Haveliwala', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Additional stuff for the LaTeX preamble.
#latex_preamble = ''

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'pysimsearch', u'pysimsearch Documentation',
     [u'Taher Haveliwala'], 1)
]
<commit_msg>o updated ver. #<commit_after># -*- coding: utf-8 -*-
#
# PySimSearch documentation build configuration file, created by
# sphinx-quickstart on Mon Jul 25 22:06:33 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinxtogithub']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'pysimsearch'
copyright = u'2011, Taher Haveliwala'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.31'
# The full version, including alpha/beta/rc tags.
release = '0.31'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['build']

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []

# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'default'

html_style = 'custom.css'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'pysimsearchdoc'

# -- Options for LaTeX output --------------------------------------------------

# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'

# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'pysimsearch.tex', u'pysimsearch Documentation',
   u'Taher Haveliwala', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Additional stuff for the LaTeX preamble.
#latex_preamble = ''

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True

# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'pysimsearch', u'pysimsearch Documentation',
     [u'Taher Haveliwala'], 1)
]
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2013, John Dewey <john@dewey.ws>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''
---
module: rabbitmq_policy
short_description: Manage the state of policies in RabbitMQ.
description:
  - Manage the state of a virtual host in RabbitMQ.
version_added: "1.5"
author: "John Dewey (@retr0h)"
options:
  name:
    description:
      - The name of the policy to manage.
    required: true
    default: null
  vhost:
    description:
      - The name of the vhost to apply to.
    required: false
    default: /
  apply_to:
    description:
      - What the policy applies to. Requires RabbitMQ 3.2.0 or later.
    required: false
    default: all
    choices: [all, exchanges, queues]
    version_added: "2.1"
  pattern:
    description:
      - A regex of queues to apply the policy to.
    required: true
    default: null
  tags:
    description:
      - A dict or string describing the policy.
    required: true
    default: null
  priority:
    description:
      - The priority of the policy.
    required: false
    default: 0
  node:
    description:
      - Erlang node name of the rabbit we wish to configure.
    required: false
    default: rabbit
  state:
    description:
      - The state of the policy.
    default: present
    choices: [present, absent]
'''

EXAMPLES = '''
- name: ensure the default vhost contains the HA policy via a dict
  rabbitmq_policy:
    name: HA
    pattern: .*
  args:
    tags:
      ha-mode: all

- name: ensure the default vhost contains the HA policy
  rabbitmq_policy:
    name: HA
    pattern: .*
    tags:
      ha-mode: all
'''

import json
from ansible.module_utils.basic import AnsibleModule

class RabbitMqPolicy(object):

    def __init__(self, module, name):
        self._module = module
        self._name = name
        self._vhost = module.params['vhost']
        self._pattern = module.params['pattern']
        self._apply_to = module.params['apply_to']
        self._tags = module.params['tags']
        self._priority = module.params['priority']
        self._node = module.params['node']
        self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)

    def _exec(self, args, run_in_check_mode=False):
        if not self._module.check_mode or (self._module.check_mode and run_in_check_mode):
            cmd = [self._rabbitmqctl, '-q', '-n', self._node]
            args.insert(1, '-p')
            args.insert(2, self._vhost)
            rc, out, err = self._module.run_command(cmd + args, check_rc=True)
            return out.splitlines()
        return list()

    def list(self):
        policies = self._exec(['list_policies'], True)

        for policy in policies:
            if not policy:
                continue
            policy_name = policy.split('\t')[1]
            if policy_name == self._name:
                return True
        return False

    def set(self):
        args = ['set_policy']
        args.append(self._name)
        args.append(self._pattern)
        args.append(json.dumps(self._tags))
        args.append('--priority')
        args.append(self._priority)
        if self._apply_to != 'all':
            args.append('--apply-to')
            args.append(self._apply_to)
        return self._exec(args)

    def clear(self):
        return self._exec(['clear_policy', self._name])

def main():
    arg_spec = dict(
        name=dict(required=True),
        vhost=dict(default='/'),
        pattern=dict(required=True),
        apply_to=dict(default='all', choices=['all', 'exchanges', 'queues']),
        tags=dict(type='dict', required=True),
        priority=dict(default='0'),
        node=dict(default='rabbit'),
        state=dict(default='present', choices=['present', 'absent']),
    )

    module = AnsibleModule(
        argument_spec=arg_spec,
        supports_check_mode=True
    )

    name = module.params['name']
    state = module.params['state']
    rabbitmq_policy = RabbitMqPolicy(module, name)

    result = dict(changed=False, name=name, state=state)
    if rabbitmq_policy.list():
        if state == 'absent':
            rabbitmq_policy.clear()
            result['changed'] = True
        else:
            result['changed'] = False
    elif state == 'present':
        rabbitmq_policy.set()
        result['changed'] = True

    module.exit_json(**result)

if __name__ == '__main__':
    main()
<commit_msg>Fix description for rabbitmq_policy (#36149)<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2013, John Dewey <john@dewey.ws>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''
---
module: rabbitmq_policy
short_description: Manage the state of policies in RabbitMQ.
description:
  - Manage the state of a policy in RabbitMQ.
version_added: "1.5"
author: "John Dewey (@retr0h)"
options:
  name:
    description:
      - The name of the policy to manage.
    required: true
    default: null
  vhost:
    description:
      - The name of the vhost to apply to.
    required: false
    default: /
  apply_to:
    description:
      - What the policy applies to. Requires RabbitMQ 3.2.0 or later.
    required: false
    default: all
    choices: [all, exchanges, queues]
    version_added: "2.1"
  pattern:
    description:
      - A regex of queues to apply the policy to.
    required: true
    default: null
  tags:
    description:
      - A dict or string describing the policy.
    required: true
    default: null
  priority:
    description:
      - The priority of the policy.
    required: false
    default: 0
  node:
    description:
      - Erlang node name of the rabbit we wish to configure.
    required: false
    default: rabbit
  state:
    description:
      - The state of the policy.
    default: present
    choices: [present, absent]
'''

EXAMPLES = '''
- name: ensure the default vhost contains the HA policy via a dict
  rabbitmq_policy:
    name: HA
    pattern: .*
  args:
    tags:
      ha-mode: all

- name: ensure the default vhost contains the HA policy
  rabbitmq_policy:
    name: HA
    pattern: .*
    tags:
      ha-mode: all
'''

import json
from ansible.module_utils.basic import AnsibleModule

class RabbitMqPolicy(object):

    def __init__(self, module, name):
        self._module = module
        self._name = name
        self._vhost = module.params['vhost']
        self._pattern = module.params['pattern']
        self._apply_to = module.params['apply_to']
        self._tags = module.params['tags']
        self._priority = module.params['priority']
        self._node = module.params['node']
        self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)

    def _exec(self, args, run_in_check_mode=False):
        if not self._module.check_mode or (self._module.check_mode and run_in_check_mode):
            cmd = [self._rabbitmqctl, '-q', '-n', self._node]
            args.insert(1, '-p')
            args.insert(2, self._vhost)
            rc, out, err = self._module.run_command(cmd + args, check_rc=True)
            return out.splitlines()
        return list()

    def list(self):
        policies = self._exec(['list_policies'], True)

        for policy in policies:
            if not policy:
                continue
            policy_name = policy.split('\t')[1]
            if policy_name == self._name:
                return True
        return False

    def set(self):
        args = ['set_policy']
        args.append(self._name)
        args.append(self._pattern)
        args.append(json.dumps(self._tags))
        args.append('--priority')
        args.append(self._priority)
        if self._apply_to != 'all':
            args.append('--apply-to')
            args.append(self._apply_to)
        return self._exec(args)

    def clear(self):
        return self._exec(['clear_policy', self._name])

def main():
    arg_spec = dict(
        name=dict(required=True),
        vhost=dict(default='/'),
        pattern=dict(required=True),
        apply_to=dict(default='all', choices=['all', 'exchanges', 'queues']),
        tags=dict(type='dict', required=True),
        priority=dict(default='0'),
        node=dict(default='rabbit'),
        state=dict(default='present', choices=['present', 'absent']),
    )

    module = AnsibleModule(
        argument_spec=arg_spec,
        supports_check_mode=True
    )

    name = module.params['name']
    state = module.params['state']
    rabbitmq_policy = RabbitMqPolicy(module, name)

    result = dict(changed=False, name=name, state=state)
    if rabbitmq_policy.list():
        if state == 'absent':
            rabbitmq_policy.clear()
            result['changed'] = True
        else:
            result['changed'] = False
    elif state == 'present':
        rabbitmq_policy.set()
        result['changed'] = True

    module.exit_json(**result)

if __name__ == '__main__':
    main()
<|endoftext|>