示例#1
0
    def test_numpy(self):
        # Docstring taken from Napoleon's example (plus a keyword argument).
        doc = """
        One line summary.

        Extended description.

        Parameters
        ----------
        arg1 : int
            Description of arg1
        arg2 : str
            Description of arg2

        Keyword Arguments
        -----------------
        arg3 : float
            Description of arg3

        Returns
        -------
        str
            Description of return value.

        Examples
        --------
        >>> print("hello, world")
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        self._check_doc(doc)
示例#2
0
    def test_parse_doubles(self):
        doc = """
        Test function

        :param int param: the parameter
        :type param: int
        """
        with self.assertRaises(ValueError):
            defopt._parse_docstring(inspect.cleandoc(doc))

        doc = """Test function

        :type param: int
        :param int param: the parameter
        """
        with self.assertRaises(ValueError):
            defopt._parse_docstring(inspect.cleandoc(doc))
示例#3
0
    def test_literal_block(self):
        doc = """
        ::

            Literal block
                Multiple lines
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        self.assertEqual(doc.text, '    Literal block\n        Multiple lines')
示例#4
0
    def test_sphinx(self):
        doc = """
        One line summary.

        Extended description.

        :param int arg1: Description of arg1
        :param str arg2: Description of arg2
        :keyword float arg3: Description of arg3
        :returns: Description of return value.
        :rtype: str

        .. rubric:: examples

        >>> print("hello, world")
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        self._check_doc(doc)
示例#5
0
    def test_parse_params(self):
        doc = """
        Test function

        :param first: first param
        :parameter int second: second param
        :arg third: third param
        :argument float fourth: fourth param
        :key fifth: fifth param
        :keyword str sixth: sixth param
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        self.assertEqual(doc.params['first'].text, 'first param')
        self.assertEqual(doc.params['second'].text, 'second param')
        self.assertEqual(doc.params['third'].text, 'third param')
        self.assertEqual(doc.params['fourth'].text, 'fourth param')
        self.assertEqual(doc.params['fifth'].text, 'fifth param')
        self.assertEqual(doc.params['sixth'].text, 'sixth param')
示例#6
0
    def test_parse_docstring(self):
        doc = """
        Test function

        :param one: first param
        :type one: int
        :param float two: second param
        :returns: str
        :junk one two: nothing
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        self.assertEqual(doc.text, 'Test function')
        one = doc.params['one']
        self.assertEqual(one.text, 'first param')
        self.assertEqual(one.type, 'int')
        two = doc.params['two']
        self.assertEqual(two.text, 'second param')
        self.assertEqual(two.type, 'float')
示例#7
0
    def test_newlines(self):
        doc = """
        Bar
        Baz

        .. a comment

        - bar
        - baz

        quux::

            hello


        1. bar
        #. baz

        ii. bar
        #.  baz
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        # Use inspect.cleandoc and not textwrap.dedent, as we want to keep
        # whitespace in lines that contain more than the common leading
        # whitespace.
        self.assertEqual(doc.text, inspect.cleandoc("""\
            Bar
            Baz 
             
            - bar 
            - baz 
             
            quux: 
             
                hello 
             
             
            1. bar 
            2. baz 
             
            ii.  bar 
            iii. baz"""))
示例#8
0
    def test_google(self):
        # Docstring taken from Napoleon's example (plus a keyword argument).
        doc = """
        One line summary.

        Extended description.

        Args:
          arg1(int): Description of arg1
          arg2(str): Description of arg2

        Keyword Arguments:
          arg3(float): Description of arg3

        Returns:
          str: Description of return value.

        Examples:
          >>> print("hello, world")
        """
        doc = defopt._parse_docstring(inspect.cleandoc(doc))
        self._check_doc(doc)
示例#9
0
 def test_explicit_role(self):
     doc = defopt._parse_docstring("""start :py:class:`int` end""")
     self.assertEqual(doc.text, 'start int end')
示例#10
0
 def test_implicit_role(self):
     doc = defopt._parse_docstring("""start `int` end""")
     self.assertEqual(doc.text, 'start \033[4mint\033[0m end')
示例#11
0
 def test_param_only(self):
     doc = defopt._parse_docstring(""":param int param: test""")
     self.assertEqual(doc.text, '')
     param = doc.params['param']
     self.assertEqual(param.text, 'test')
     self.assertEqual(param.type, 'int')
示例#12
0
 def test_no_doc(self):
     doc = defopt._parse_docstring(None)
     self.assertEqual(doc.text, '')
     self.assertEqual(doc.params, {})
def function_to_form(func,
                     *,
                     config: dict = None,
                     name: str = None) -> Type[forms.Form]:
    """Convert a function to a Django Form.

    Args:
        func: the function to be changed
        config: A dictionary with keys ``widgets`` and ``fields`` each mapping types/specific
        arguments to custom fields
    """
    name = name or func.__qualname__
    sig = signature(func)
    # i.e., class body for form
    fields = {}
    defaults = {}
    for parameter in sig.parameters.values():
        field = param_to_field(parameter, config)
        fields[parameter.name] = field
        if parameter.default is not Parameter.empty:
            defaults[parameter.name] = parameter.default
        if isinstance(field, forms.TypedChoiceField):
            field._parameter_name = parameter.name
            field._func_name = name
            if parameter.default and parameter.default is not Parameter.empty:
                for potential_default in [
                        parameter.default.name, parameter.default.value
                ]:
                    if any(potential_default == x[0] for x in field.choices):
                        defaults[parameter.name] = potential_default
                        break
                else:
                    raise ValueError(
                        f"Cannot figure out how to assign default for {parameter.name}: {parameter.default}"
                    )
    fields["__doc__"] = re.sub("\n+", "\n",
                               _parse_docstring(inspect.getdoc(func)).text)
    form_name = "".join(part.capitalize() for part in func.__name__.split("_"))

    class BaseForm(forms.Form):
        _func = func
        _input_defaults = defaults

        # use this for ignoring extra args from createview and such
        def __init__(self, *a, instance=None, user=None, **k):
            from crispy_forms.helper import FormHelper
            from crispy_forms.layout import Submit

            super().__init__(*a, **k)
            self.user = user
            self.helper = FormHelper(self)
            self.helper.add_input(Submit("submit", "Execute!"))

        def execute_function(self):
            # TODO: reconvert back to enum type! :(
            return func(**self.cleaned_data)

        def save(self):
            from .models import ExecutionResult

            obj = ExecutionResult(func_name=name,
                                  input_json=self.cleaned_data,
                                  user=self.user)
            obj.save()
            return obj

    return type(form_name, (BaseForm, ), fields)