From 52c98b2bea6728595ce7849f56f2df6dee9a62fc Mon Sep 17 00:00:00 2001 From: "Teal, D" Date: Mon, 28 Nov 2022 16:22:56 -0800 Subject: [PATCH] Adding positional-only argument test. --- porchlight/door.py | 18 +++++++++++------- porchlight/tests/test_basedoor.py | 27 ++++++++++++++++++--------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/porchlight/door.py b/porchlight/door.py index 401f806..51cef1b 100644 --- a/porchlight/door.py +++ b/porchlight/door.py @@ -31,6 +31,9 @@ class BaseDoor: Dictionary of all arguments taken as input when the `BaseDoor` object is called. + positional_only : :py:obj:`list` of :py:obj:`str` + List of positional-only arguments accepted by the function. + keyword_args : :py:obj:`dict`, :py:obj:`str`: :class:`~typing.Any` Keyword arguments accepted by the `BaseDoor` as input when called. This includes all arguments that are not positional-only. Positional @@ -146,6 +149,7 @@ def _inspect_base_callable(self): self.name = function.__name__ self.__name__ = function.__name__ self.arguments = {} + self.positional_only = [] self.keyword_args = {} self.keyword_only_args = {} @@ -164,19 +168,19 @@ def _inspect_base_callable(self): self.return_types = None + # Use function signature to introspect properties about the parameters. for name, param in inspect.signature(function).parameters.items(): self.arguments[name] = param.annotation # Check for positional-only arguments first, then proceed to other # argument types. if param.kind == inspect.Parameter.POSITIONAL_ONLY: - msg = ( - f"porchlight does not support positional-only " - f"arguments, which were found in {self.name}." - ) - - logger.error(msg) - raise NotImplementedError(msg) + # Positional-only arguments will not support default values for + # the function. That said, this is effectively overriden by + # Neighborhood objects, since they store the parameter's value + # and pass it regardless of whether the argument is + # positional-only or not. + self.positional_only.append(name) elif param.default != inspect._empty: self.keyword_args[name] = Param(name, param.default) diff --git a/porchlight/tests/test_basedoor.py b/porchlight/tests/test_basedoor.py index d5a56fc..b6d325d 100644 --- a/porchlight/tests/test_basedoor.py +++ b/porchlight/tests/test_basedoor.py @@ -298,15 +298,24 @@ def bigfxn(x, y, *, z=5): self.assertEqual(new_door.keyword_only_args, {"z": Param("z", 5)}) - # For now, there should *not* be any functionality for required - # positional arguments. That will come later, and this test will need - # to be updated. - def bad_fxn(x1, y1, /, x3, *, z7): - c = "blah" - return c - - with self.assertRaises(NotImplementedError): - BaseDoor(bad_fxn) + # Positional-only arguments. + def test1( + pos1, pos2, /, kwpos, kwposdef="default", *, kwonly="def4ult" + ): + pass + + new_door = BaseDoor(test1) + + expected_arguments = { + "pos1": Empty(), + "pos2": Empty(), + "kwpos": Empty(), + "kwposdef": Empty(), + "kwonly": Empty, + } + + self.assertEqual(new_door.arguments, expected_arguments) + self.assertEqual(new_door.positional_only, ["pos1", "pos2"]) def test__returned_def_to_door(self): def my_func_gen():