コード例 #1
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_args_order_preserved(self):
     """
     Ensure that the var-positional arguments *aren't* re-ordered
     """
     param_a = forge.arg('a')
     param_b = forge.arg('b')
     rev = synthesize(param_b, param_a)
     assert rev.revise(FSignature()) == FSignature([param_b, param_a])
コード例 #2
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_kwargs_reordered(self):
     """
     Ensure that the var-keyword arguments *are* re-ordered
     """
     param_a = forge.arg('a')
     param_b = forge.arg('b')
     rev = synthesize(b=param_b, a=param_a)
     assert rev.revise(FSignature()) == FSignature([param_a, param_b])
コード例 #3
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_args_precede_kwargs(self):
     """
     Ensure that var-postional arguments precede var-keyword arguments
     """
     param_a = forge.arg('a')
     param_b = forge.arg('b')
     rev = synthesize(param_b, a=param_a)
     assert rev.revise(FSignature()) == FSignature([param_b, param_a])
コード例 #4
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_no_validation(self):
     """
     Ensure no validation is performed on the revision
     """
     rev = synthesize(forge.arg('b'), forge.pos('a'))
     assert rev.revise(FSignature()) == FSignature(
         [forge.arg('b'), forge.pos('a')],
         __validate_parameters__=False,
     )
コード例 #5
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_no_validation(self):
     """
     Ensure no validation is performed on the revision
     """
     rev = insert(forge.arg('b'), index=0)
     fsig = FSignature([forge.pos('a')], __validate_parameters__=False)
     assert rev.revise(fsig) == FSignature(
         [forge.arg('b'), forge.pos('a')],
         __validate_parameters__=False,
     )
コード例 #6
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_no_validation(self):
     """
     Ensure no validation is performed on the revision
     """
     rev = translocate('b', index=0)
     in_ = FSignature([forge.pos('a'), forge.arg('b')])
     out_ = FSignature(
         [forge.arg('b'), forge.pos('a')],
         __validate_parameters__=False,
     )
     assert rev.revise(in_) == out_
コード例 #7
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_no_validation(self):
     """
     Ensure no validation is performed on the revision
     """
     rev = modify('b', kind=POSITIONAL_ONLY)
     in_ = FSignature([forge.arg('a'), forge.arg('b')])
     out_ = FSignature(
         [forge.arg('a'), forge.pos('b')],
         __validate_parameters__=False,
     )
     assert rev.revise(in_) == out_
コード例 #8
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise(self, in_, sortkey, expected):
     """
     Ensure that parameter sorting:
     - doesn't validate the signature
     - by default sorts by (kind, has-default, name)
     - takes advantage of user-supplied sortkey
     """
     rev = sort(sortkey)
     in_ = FSignature(in_, __validate_parameters__=False)
     expected = FSignature(expected, __validate_parameters__=False)
     assert rev.revise(in_) == expected
コード例 #9
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_revise(self, revision):
        """
        Ensure that ``modify`` appropriately revises every attribute of a
        parameter.
        """
        in_param = forge.pos('a')
        out_param = in_param.replace(**revision)
        assert in_param != out_param  # ensure we've got a good test setup

        rev = modify('a', **revision)
        assert rev.revise(FSignature([in_param])) == FSignature([out_param])
コード例 #10
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_revise(self, selector):
        """
        Ensure that ``replace`` accepts selector values; i.e. those passed to
        ``findparam``.
        """
        new_param = forge.arg('new')
        old_param = forge.arg('old')
        in_ = FSignature([old_param])
        out_ = FSignature([new_param])

        rev = replace(selector, new_param)
        assert rev.revise(in_) == out_
コード例 #11
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_map_parameters_to_var_keyword(self, from_kind):
        """
        Ensure the mapping **strategy** produced mapping *to* ``var-keyword``
        - POSITIONAL_ONLY -> VAR_POSITIONAL (success)
        - POSTIIONAL_OR_KEYWORD -> VAR_POSITIONAL (success)
        - VAR_POSTIIONAL -> VAR_POSITIONAL (raises)
        - KEYWORD_ONLY -> VAR_POSITIONAL (success)
        - VAR_KEYWROD -> VAR_POSITIONAL (success)
        """
        from_param = self.make_param('a', from_kind)
        from_sig = inspect.Signature([from_param])
        fsig = FSignature.from_native(from_sig)
        to_param = self.make_param('kwargs', VAR_KEYWORD)
        to_sig = inspect.Signature([to_param])

        expected_exc = None
        if from_param.kind is VAR_POSITIONAL:
            expected_exc = TypeError(
                "Missing requisite mapping from variable positional "
                "parameter 'a'")

        if expected_exc:
            with pytest.raises(type(expected_exc)) as excinfo:
                Mapper.map_parameters(fsig, to_sig)
            assert excinfo.value.args[0] == expected_exc.args[0]
            return
        pmap = Mapper.map_parameters(fsig, to_sig)
        assert pmap == {from_param.name: to_param.name}
コード例 #12
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_map_parameters_to_var_positional(self, from_kind):
        """
        Ensure the mapping **strategy** produced mapping *to* ``var-positional``
        - POSITIONAL_ONLY -> VAR_POSITIONAL (raises)
        - POSTIIONAL_OR_KEYWORD -> VAR_POSITIONAL (raises)
        - VAR_POSTIIONAL -> VAR_POSITIONAL (success)
        - KEYWORD_ONLY -> VAR_POSITIONAL (raises)
        - VAR_KEYWROD -> VAR_POSITIONAL (raises)
        """
        from_param = self.make_param('from_', from_kind)
        from_sig = inspect.Signature([from_param])
        fsig = FSignature.from_native(from_sig)
        to_param = self.make_param('args', VAR_POSITIONAL)
        to_sig = inspect.Signature([to_param])

        if from_param.kind is VAR_POSITIONAL:
            pmap = Mapper.map_parameters(fsig, to_sig)
            assert pmap == {from_param.name: to_param.name}
            return

        with pytest.raises(TypeError) as excinfo:
            Mapper.map_parameters(fsig, to_sig)

        if from_param.kind is VAR_KEYWORD:
            assert excinfo.value.args[0] == (
                "Missing requisite mapping from variable keyword parameter "
                "'from_'")
        else:
            assert excinfo.value.args[0] == \
                "Missing requisite mapping from parameters (from_)"
コード例 #13
0
    def revise(self, previous: FSignature) -> FSignature:
        """
        Replaces a parameter that matches
        :paramref:`~forge.replace.selector`.

        No validation is performed on the updated :class:`~forge.FSignature`,
        allowing it to be used as an intermediate revision in the context of
        :class:`~forge.compose`.

        :param previous: the :class:`~forge.FSignature` to modify
        :returns: a modified instance of :class:`~forge.FSignature`
        """
        try:
            match = next(findparam(previous, self.selector))
        except StopIteration:
            raise ValueError("No parameter matched selector '{}'".format(
                self.selector))

        # https://github.com/python/mypy/issues/5156
        return previous.replace(  # type: ignore
            parameters=[
                self.parameter if param is match else param
                for param in previous
            ],
            __validate_parameters__=False,
        )
コード例 #14
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_none(self):
     """
     Ensure that ``compose`` without any revisions is the identity function
     """
     fsig = FSignature()
     rev = compose()
     assert rev.revise(fsig) is fsig
コード例 #15
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test__call__params_mapped(self, from_kind, to_kind, vary_name):
        """
        Ensure that call arguments are mapped from parameters of type:
        - POSITIONAL_ONLY
        - POSITIONAL_OR_KEYWORD
        - KEYWORD_ONLY

        to their interface counterparts as:
        - POSITIONAL_ONLY
        - POSITIONAL_OR_KEYWORD
        - KEYWORD_ONLY
        - VAR_KEYWORD

        with and without names being varied.
        """
        from_name, to_name = ('p1', 'p1') if not vary_name else ('p1', 'p2')
        fsig = FSignature([FParameter(from_kind, from_name, to_name)])
        func = lambda: None
        func.__signature__ = \
            inspect.Signature([inspect.Parameter(to_name, to_kind)])
        mapper = Mapper(fsig, func)

        call_args = CallArguments(**{from_name: 1}) \
            if from_kind in (KEYWORD_ONLY, VAR_KEYWORD) \
            else CallArguments(1)
        expected = CallArguments(**{to_name: 1}) \
            if to_kind in (KEYWORD_ONLY, VAR_KEYWORD) \
            else CallArguments(1)
        result = mapper(*call_args.args, **call_args.kwargs)
        assert result == expected
コード例 #16
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise(self):
     """
     Ensure that the revise function is the identity function
     """
     rev = Revision()
     in_ = FSignature()
     assert rev.revise(in_) is in_
コード例 #17
0
    def revise(self, previous: FSignature) -> FSignature:
        """
        Revises one or more parameters that matches
        :paramref:`~forge.modify.selector`.

        No validation is performed on the updated :class:`~forge.FSignature`,
        allowing it to be used as an intermediate revision in the context of
        :class:`~forge.compose`.

        :param previous: the :class:`~forge.FSignature` to modify
        :returns: a modified instance of :class:`~forge.FSignature`
        """
        matched = list(findparam(previous, self.selector))
        if not matched:
            if self.raising:
                raise ValueError("No parameter matched selector '{}'".format(
                    self.selector))
            return previous

        if not self.multiple:
            del matched[1:]

        # https://github.com/python/mypy/issues/5156
        return previous.replace(  # type: ignore
            parameters=[
                param.replace(**self.updates) if param in matched else param
                for param in previous
            ],
            __validate_parameters__=False,
        )
コード例 #18
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test__call__bound_injected(self):
     """
     Ensure ``bound`` fparams are injected into the mapping.
     """
     fsig = FSignature([forge.arg('bound', default=1, bound=True)])
     func = lambda bound: bound
     mapper = Mapper(fsig, func)
     assert mapper() == CallArguments(1)
コード例 #19
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_no_match_raises(self):
     """
     Ensure that if selector doesn't find a match, an exception is rasied.
     """
     rev = replace('i', forge.arg('a'))
     with pytest.raises(ValueError) as excinfo:
         rev.revise(FSignature())
     assert excinfo.value.args[0] == \
         "No parameter matched selector 'i'"
コード例 #20
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_map_parameters_from_hidden(self, to_kind):
        """
        Ensure mapping **strategy** success when no fparam provided.
        """
        fsig = FSignature()
        to_param = self.make_param('a', to_kind, default=1)
        to_sig = inspect.Signature([to_param])

        assert Mapper.map_parameters(fsig, to_sig) == {}
コード例 #21
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test__repr__(self):
     """
     Ensure the mapper is pretty printable with ``FSignature`` and
     ``inspect.Signature``
     """
     fsig = FSignature([forge.pos('a', 'b')])
     callable_ = lambda *, b: None
     mapper = Mapper(fsig, callable_)
     assert repr(mapper) == '<Mapper (a, /) => (*, b)>'
コード例 #22
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_no_validation(self):
     """
     Ensure no validation is performed on the revision
     """
     rev = delete('x', raising=False)
     fsig = FSignature(
         [forge.arg('b'), forge.pos('a')],
         __validate_parameters__=False,
     )
     assert rev.revise(fsig) is fsig
コード例 #23
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_void_cls(self):
     """
     Ensure that passing ``void`` as a ``default`` or ``type`` is passed
     through (distinguishing _void from void).
     """
     in_ = FSignature([forge.arg('x')])
     rev = modify('x', default=forge.void, type=forge.void)
     out_ = rev.revise(in_)
     assert out_.parameters['x'].default is forge.void
     assert out_.parameters['x'].type is forge.void
コード例 #24
0
ファイル: test_revision.py プロジェクト: dfee/forge
 def test_revise_no_validation(self):
     """
     Ensure no validation is performed on the revision
     """
     rev = returns(int)
     fsig = FSignature(
         [forge.arg('b'), forge.pos('a')],
         __validate_parameters__=False,
     )
     assert rev.revise(fsig).parameters == fsig.parameters
コード例 #25
0
    def revise(self, previous: FSignature) -> FSignature:
        """
        Translocates (moves) the :paramref:`~forge.insert.parameter` into a
        new position in the signature.

        No validation is performed on the updated :class:`~forge.FSignature`,
        allowing it to be used as an intermediate revision in the context of
        :class:`~forge.compose`.

        :param previous: the :class:`~forge.FSignature` to modify
        :returns: a modified instance of :class:`~forge.FSignature`
        """
        try:
            selected = next(findparam(previous, self.selector))
        except StopIteration:
            raise ValueError("No parameter matched selector '{}'".format(
                self.selector))

        if self.before:
            try:
                before = next(findparam(previous, self.before))
            except StopIteration:
                raise ValueError("No parameter matched selector '{}'".format(
                    self.before))

            parameters = []
            for param in previous:
                if param is before:
                    parameters.append(selected)
                elif param is selected:
                    continue
                parameters.append(param)
        elif self.after:
            try:
                after = next(findparam(previous, self.after))
            except StopIteration:
                raise ValueError("No parameter matched selector '{}'".format(
                    self.after))

            parameters = []
            for param in previous:
                if param is not selected:
                    parameters.append(param)
                if param is after:
                    parameters.append(selected)
        else:
            parameters = [param for param in previous if param is not selected]
            parameters.insert(self.index, selected)

        # https://github.com/python/mypy/issues/5156
        return previous.replace(  # type: ignore
            parameters=parameters,
            __validate_parameters__=False,
        )
コード例 #26
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_revise(self):
        """
        Ensure that manage revision passes the input signature to the user
        supplied function and returns (the user-defined function's) value.
        """
        fsig = fsignature(lambda a, b, c: None)
        reverse = Mock(
            side_effect=lambda prev: prev.replace(parameters=prev[::-1]))
        rev = manage(reverse)

        assert rev.revise(fsig) == \
            FSignature([forge.arg('c'), forge.arg('b'), forge.arg('a')])
コード例 #27
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test__call__vkw_param_mapped(self, vary_name):
        """
        Ensure ``var-keyword`` params are directly mapped
        (w/ and w/o varied name)
        """
        from_name, to_name = ('p1', 'p1') if not vary_name else ('p1', 'p2')
        fsig = FSignature([FParameter(VAR_KEYWORD, from_name, to_name)])
        func = lambda: None
        func.__signature__ = \
            inspect.Signature([inspect.Parameter(to_name, VAR_KEYWORD)])
        mapper = Mapper(fsig, func)

        call_args = CallArguments(a=1, b=2, c=3)
        assert mapper(**call_args.kwargs) == call_args
コード例 #28
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_get_context(self, has_context):
        """
        Ensure the mapper retrieves the context value from arguments
        """
        param = forge.ctx('param') \
            if has_context \
            else forge.arg('param')
        fsig = FSignature([param])
        mapper = Mapper(fsig, lambda param: None)

        assert mapper.context_param == (param if has_context else None)
        kwargs = {'param': object()}
        ctx = mapper.get_context(kwargs)
        assert ctx == (kwargs['param'] if has_context else None)
コード例 #29
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test_revise(self):
        """
        Ensure that ``compose`` applies the underlying revisions from top to
        bottom.
        """
        fsig1 = FSignature()
        mock1 = Mock(
            spec=Revision,
            revise=Mock(side_effect=lambda prev: fsig1),
        )

        fsig2 = FSignature()
        mock2 = Mock(
            spec=Revision,
            revise=Mock(side_effect=lambda prev: fsig2),
        )

        rev = compose(mock1, mock2)
        in_ = FSignature([forge.arg('a')])

        assert rev.revise(in_) is fsig2
        mock1.revise.assert_called_once_with(in_)
        mock2.revise.assert_called_once_with(fsig1)
コード例 #30
0
ファイル: test_revision.py プロジェクト: dfee/forge
    def test__call__vpo_param_mapped(self, vary_name):
        """
        Ensure ``var-positional`` params are directly mapped
        (w/ and w/o varied name)
        """
        from_name, to_name = ('p1', 'p1') if not vary_name else ('p1', 'p2')
        fsig = FSignature([FParameter(VAR_POSITIONAL, from_name, to_name)])
        func = lambda: None
        func.__signature__ = \
            inspect.Signature([inspect.Parameter(to_name, VAR_POSITIONAL)])
        mapper = Mapper(fsig, func)

        call_args = CallArguments(1, 2, 3)
        assert mapper(*call_args.args) == call_args