Esempio n. 1
0
 def _register(self, mfr, override=False):
     validate.is_type(mfr, Manufacturer, "mfr")
     cls = mfr.cls
     with self._lock:
         if cls in self._mfrs:
             if not override:
                 raise errors.KeyConflictError(
                     "Manufacturer with target class `{}` exists.".format(
                         misc.qualname(cls)))
             self._mfrs.pop(cls)._bind = None
         mfr._bind(self)  # pylint: disable=protected-access
         self._mfrs[cls] = mfr
Esempio n. 2
0
    def _register(self,
                  key,
                  factory,
                  signature,
                  defaults=None,
                  descriptions=None,
                  override=False,
                  _builtins=False):
        key_is_reserved = misc.is_reserved(key)
        if _builtins and not key_is_reserved:
            key = misc.join_reserved(key)
        elif not _builtins and key_is_reserved:
            pass

        # Retrieve registry
        registry = self._builtin_fcts if _builtins else self._user_fcts
        # Key conflict short-circuiting
        if not override and key in registry:
            raise errors.KeyConflictError(key)

        if signature is None:
            # This block is for Manufacturer merges
            if not isinstance(factory, fct_lib.Factory):
                raise errors.InputError()
        else:
            # Validate arguments
            # 1. Validate `key`
            validate.is_type(key, str, "key")

            # 2. Validate `factory` and `signature`
            with self._exc_proxy(prefix="[key: {}] ".format(key)):
                validate.is_callable(factory, "factory")
                validate.is_type(signature, dict, "signature")
                defaults = defaults or {}
                validate.is_kwargs(defaults, "defaults")

            # 3. Create `Factory`
            factory = fct_lib.Factory(self._cls,
                                      factory,
                                      signature,
                                      descriptions=descriptions,
                                      defaults=defaults)

        # Register factory.
        with self._lock:
            if not override and key in registry:
                raise errors.KeyConflictError(key)
            registry[key] = factory
Esempio n. 3
0
    def _validate_merge(self,
                        mfr,
                        key,
                        override=None,
                        ignore_collision=None,
                        sep="/"):
        validate.is_type(key, str, "key")

        if not issubclass(mfr.cls, self.cls):
            raise TypeError(
                "The target of `mfr` must be a subclass of {}. Given: {}".
                format(misc.qualname(self.cls), misc.qualname(mfr.cls)))

        if override or ignore_collision:
            return

        merged_names = set(_merged_name(key, n, sep=sep) for n in mfr.keys())
        collisions = merged_names.intersection(self._user_fcts)
        if collisions:
            raise errors.KeyConflictError(
                "Factory key conflicts detected, "
                "please use another key for merge instead: {}".format(
                    sorted(collisions)))
Esempio n. 4
0
def _validate_param_spec(spec):
    assert isinstance(spec, dict)

    if "description" in spec:
        validate.is_type(spec["description"], str, "description")
    if "required" in spec:
        validate.is_type(spec["required"], bool, "required")
    if "forced" in spec:
        validate.is_type(spec["forced"], bool, "forced")
Esempio n. 5
0
    def register_dict(self, registrants, keyword_mode=None):
        """Registers factories from dictionary.

    This method allows a dictionary of factories to be registered at once.
    The argument is expected to be a dictionary that maps factory keys to
    arguments for the `Manufacturer.register` call, either in tuple or
    dictionary, or a zero-argument function that returns either of them.
    For instance, the value can be a tuple:

        (factory, signature,
         defaults (optional), descriptions (optional), override (optional))

    Or a dictionary:

        {"factory": factory,            # required
         "signature": signature,        # required
         "defaults": defaults,          # optional
         "descriptions": descriptions,  # optional
         "override": override}          # optional

    Or a zero-argument function that returns either of the above.

    A typical pattern one would encounter is to have a dictionary as a registry
    to manage a group of factories as "plugin"s, so that whenever a new
    factory is implemented it can be made available for the manufacturer to
    call by adding it in the dictionary. For example:

    `registry.py`
    ```python
    from . import factories as fct

    REGISTRY = {
      "create": fct.create.get_create,
      "load": fct.load.get_load,
    }
    ```

    `factories/create.py`:
    ```python
    def create(arg_1, arg_2, arg_3=True):
      ...
      return obj

    def get_create():
      sig = {
          "arg_1": {
              "type": str,
              "description": "Some string",
              "required": True,
          },
          "arg_2": {
              "type": [int],
              "description": "List of ints",
              "required": True,
          },
          "arg_3": {
              "type": bool,
              "description": "Some boolean",
              "required": False,
          },
      }
      return create, sig, {"arg_1": "Hello World!", "arg_2": [1, -1, 0]}
    ```

    `factories/load.py`:
    ```python
    def load(filename, mode):
      ...
      return obj

    def get_load():
      sig = {
        "filename": str,
        "mode": bool
      }
      return load, sig  # The default parameter is optional.
    ```

    The `REGISTRY` can then be passed to its manufacturer for registration.

    Args:
      registrants: A dictionary that maps each factory key to its
        `Manufacturer.register` call arguments (or zero-argument function that
        returns it).
      keyword_mode: Deprecated. Has no effect at all.
    Raises:
      ArgumentError:
        - Invalid inputs for `Manufacturer.register` call.
      TypeError:
        - `registrants` is not a `dict`
    """
        if keyword_mode is not None:
            deprecation.warn("Parameter `keyword_mode` is not used anymore.")

        validate.is_type(registrants, dict, "registrants")
        reg_dicts = [_prep_reg_args(k, r) for k, r in registrants.items()]

        [self.register(**kwargs) for kwargs in reg_dicts]
Esempio n. 6
0
 def default(self, key):
     validate.is_type(key, str, "key")
     if key is not None and key not in self:
         raise KeyError("Factory not found: {}".format(key))
     self._default = key