Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7e96e57
Change 'A' to 'An' for component names that begin with vowels.
Jun 19, 2019
cf13ccb
Add support for adding default values to the end of the docstring.
Jun 19, 2019
ec642f1
Handle periods for nested props, and clean up default value logic.
Jun 19, 2019
31fe48f
Put default values next to the type definition in docstring.
Jun 19, 2019
31210a7
Add prop type specification for nested props (PropTypes.shape).
Jun 20, 2019
dd99c0d
Merge branch 'master' into docstring-default-values
Jun 20, 2019
6ae9004
Fix pylint errors.
Jun 20, 2019
cc2253a
Add 'dict' to all props that are objects.
Jun 20, 2019
60809ab
Replace 'optional' with default values for props that have them speci…
Jun 20, 2019
77754e1
Add more logic to adding period to the end of descriptions in docstri…
Jun 20, 2019
db2230b
Remove unnecessary comma.
Jun 20, 2019
9fa5f62
Merge branch 'master' into docstring-default-values
Jun 20, 2019
9271f5b
Remove '.keys()' when searching prop dictionary.
Jun 21, 2019
f5bbab4
Remove unnecessary '.keys()'.
Jun 21, 2019
7c6d72b
Add 'default' to docstring.
Jun 21, 2019
c70659e
Check whether default values equal null/empty types instead of whethe…
Jun 21, 2019
bbccf47
Make default value logic shorter.
Jun 21, 2019
56d984d
Add more logic for 'list of' types.
Jun 21, 2019
37043d8
Simplify logic for adding periods onto ends of descriptions.
Jun 21, 2019
20cf393
Move logic for determining default value into create_prop_docstring.
Jun 21, 2019
0e090f3
Merge branch 'master' into docstring-default-values
Jun 21, 2019
bf78b45
Remove periods from empty descriptions.
Jun 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 52 additions & 23 deletions dash/development/_py_components_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,12 @@ def create_docstring(component_name, props, description):
props = reorder_props(props=props)

return (
"""A {name} component.\n{description}
"""A{n} {name} component.\n{description}

Keyword arguments:\n{args}"""
).format(
n='n' if component_name[0].lower() in ['a', 'e', 'i', 'o', 'u']
else '',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Classy touch 🥂

name=component_name,
description=description,
args='\n'.join(
Expand All @@ -249,6 +251,7 @@ def create_docstring(component_name, props, description):
else prop['flowType'],
required=prop['required'],
description=prop['description'],
default=prop.get('defaultValue'),
indent_num=0,
is_flow_type='flowType' in prop and 'type' not in prop)
for p, prop in list(filter_props(props).items())))
Expand Down Expand Up @@ -289,7 +292,7 @@ def parse_wildcards(props):
"""
list_of_valid_wildcard_attr_prefixes = []
for wildcard_attr in ["data-*", "aria-*"]:
if wildcard_attr in props.keys():
if wildcard_attr in props:
list_of_valid_wildcard_attr_prefixes.append(wildcard_attr[:-1])
return list_of_valid_wildcard_attr_prefixes

Expand Down Expand Up @@ -393,7 +396,7 @@ def filter_props(props):

# pylint: disable=too-many-arguments
def create_prop_docstring(prop_name, type_object, required, description,
indent_num, is_flow_type=False):
default, indent_num, is_flow_type=False):
"""
Create the Dash component prop docstring

Expand All @@ -407,6 +410,10 @@ def create_prop_docstring(prop_name, type_object, required, description,
Component is required?
description: str
Dash component description
default: dict
Either None if a default value is not defined, or
dict containing the key 'value' that defines a
default value for the prop
indent_num: int
Number of indents to use for the context block
(creates 2 spaces for every indent)
Expand All @@ -422,25 +429,40 @@ def create_prop_docstring(prop_name, type_object, required, description,
type_object=type_object,
is_flow_type=is_flow_type,
indent_num=indent_num + 1)

indent_spacing = ' ' * indent_num

if default is None:
default = ''
else:
default = default['value']

is_required = 'optional'
if required:
is_required = 'required'
elif default and default not in ['null', '{}', '[]']:
is_required = 'default {}'.format(
default.replace('\n', '\n' + indent_spacing)
)

if '\n' in py_type_name:
return '{indent_spacing}- {name} ({is_required}): {description}. ' \
'{name} has the following type: {type}'.format(
indent_spacing=indent_spacing,
name=prop_name,
type=py_type_name,
description=description,
is_required='required' if required else 'optional')
return '{indent_spacing}- {name} (dict; {is_required}): ' \
'{description}{period}' \
'{name} has the following type: {type}'.format(
indent_spacing=indent_spacing,
name=prop_name,
type=py_type_name,
description=description.strip().strip('.'),
period='. ' if description else '',
is_required=is_required)
return '{indent_spacing}- {name} ({type}' \
'{is_required}){description}'.format(
indent_spacing=indent_spacing,
name=prop_name,
type='{}; '.format(py_type_name) if py_type_name else '',
description=(
': {}'.format(description) if description != '' else ''
),
is_required='required' if required else 'optional')
'{is_required}){description}'.format(
indent_spacing=indent_spacing,
name=prop_name,
type='{}; '.format(py_type_name) if py_type_name else '',
description=(
': {}'.format(description) if description != '' else ''
),
is_required=is_required)


def map_js_to_py_types_prop_types(type_object):
Expand All @@ -458,6 +480,7 @@ def shape_or_exact():
type_object=prop,
required=prop['required'],
description=prop.get('description', ''),
default=prop.get('defaultValue'),
indent_num=1
) for prop_name, prop in
list(type_object['value'].items())))
Expand Down Expand Up @@ -489,8 +512,13 @@ def shape_or_exact():

# React's PropTypes.arrayOf
arrayOf=lambda: (
"list" + ((" of {}s").format(
js_to_py_type(type_object["value"]))
"list" + ((" of {}").format(
js_to_py_type(type_object["value"]) + 's'
if js_to_py_type(type_object["value"]).split(' ')[0] != 'dict'
else js_to_py_type(type_object["value"]).replace(
'dict', 'dicts', 1
)
)
if js_to_py_type(type_object["value"]) != ""
else "")
),
Expand All @@ -504,7 +532,7 @@ def shape_or_exact():
# React's PropTypes.shape
shape=shape_or_exact,
# React's PropTypes.exact
exact=shape_or_exact,
exact=shape_or_exact
)


Expand Down Expand Up @@ -548,6 +576,7 @@ def map_js_to_py_types_flow_types(type_object):
type_object=prop['value'],
required=prop['value']['required'],
description=prop['value'].get('description', ''),
default=prop.get('defaultValue'),
indent_num=indent_num,
is_flow_type=True)
for prop in type_object['signature']['properties']))),
Expand Down Expand Up @@ -580,7 +609,7 @@ def js_to_py_type(type_object, is_flow_type=False, indent_num=0):
if 'computed' in type_object and type_object['computed'] \
or type_object.get('type', '') == 'function':
return ''
elif js_type_name in js_to_py_types:
if js_type_name in js_to_py_types:
if js_type_name == 'signature': # This is a Flow object w/ signature
return js_to_py_types[js_type_name](indent_num)
# All other types
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/development/metadata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@ class Table(Component):
- children (a list of or a singular dash component, string or number; optional)
- optionalArray (list; optional): Description of optionalArray
- optionalBool (boolean; optional)
- optionalNumber (number; optional)
- optionalNumber (number; default 42)
- optionalObject (dict; optional)
- optionalString (string; optional)
- optionalString (string; default 'hello world')
- optionalNode (a list of or a singular dash component, string or number; optional)
- optionalElement (dash component; optional)
- optionalEnum (a value equal to: 'News', 'Photos'; optional)
- optionalUnion (string | number; optional)
- optionalArrayOf (list of numbers; optional)
- optionalObjectOf (dict with strings as keys and values of type number; optional)
- optionalObjectWithExactAndNestedDescription (optional): . optionalObjectWithExactAndNestedDescription has the following type: dict containing keys 'color', 'fontSize', 'figure'.
- optionalObjectWithExactAndNestedDescription (dict; optional): optionalObjectWithExactAndNestedDescription has the following type: dict containing keys 'color', 'fontSize', 'figure'.
Those keys have the following types:
- color (string; optional)
- fontSize (number; optional)
- figure (optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.
- figure (dict; optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.
Those keys have the following types:
- data (list of dicts; optional): data is a collection of traces
- layout (dict; optional): layout describes the rest of the figure
- optionalObjectWithShapeAndNestedDescription (optional): . optionalObjectWithShapeAndNestedDescription has the following type: dict containing keys 'color', 'fontSize', 'figure'.
- optionalObjectWithShapeAndNestedDescription (dict; optional): optionalObjectWithShapeAndNestedDescription has the following type: dict containing keys 'color', 'fontSize', 'figure'.
Those keys have the following types:
- color (string; optional)
- fontSize (number; optional)
- figure (optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.
- figure (dict; optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.
Those keys have the following types:
- data (list of dicts; optional): data is a collection of traces
- layout (dict; optional): layout describes the rest of the figure
Expand Down
28 changes: 14 additions & 14 deletions tests/unit/development/test_base_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ def setUp(self):
"Those keys have the following types:",
" - color (string; optional)",
" - fontSize (number; optional)",
" - figure (optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.", # noqa: E501
" - figure (dict; optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.", # noqa: E501
"Those keys have the following types:",
" - data (list of dicts; optional): data is a collection of traces",
" - layout (dict; optional): layout describes the rest of the figure" # noqa: E501
Expand All @@ -828,7 +828,7 @@ def setUp(self):
"Those keys have the following types:",
" - color (string; optional)",
" - fontSize (number; optional)",
" - figure (optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.", # noqa: E501
" - figure (dict; optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.", # noqa: E501
"Those keys have the following types:",
" - data (list of dicts; optional): data is a collection of traces",
" - layout (dict; optional): layout describes the rest of the figure" # noqa: E501
Expand Down Expand Up @@ -881,9 +881,9 @@ def assert_docstring(assertEqual, docstring):
"- children (a list of or a singular dash component, string or number; optional)", # noqa: E501
"- optionalArray (list; optional): Description of optionalArray",
"- optionalBool (boolean; optional)",
"- optionalNumber (number; optional)",
"- optionalNumber (number; default 42)",
"- optionalObject (dict; optional)",
"- optionalString (string; optional)",
"- optionalString (string; default 'hello world')",

"- optionalNode (a list of or a singular dash component, "
"string or number; optional)",
Expand All @@ -896,7 +896,7 @@ def assert_docstring(assertEqual, docstring):
"- optionalObjectOf (dict with strings as keys and values "
"of type number; optional)",

"- optionalObjectWithExactAndNestedDescription (optional): . "
"- optionalObjectWithExactAndNestedDescription (dict; optional): "
"optionalObjectWithExactAndNestedDescription has the "
"following type: dict containing keys "
"'color', 'fontSize', 'figure'.",
Expand All @@ -905,7 +905,7 @@ def assert_docstring(assertEqual, docstring):
" - color (string; optional)",
" - fontSize (number; optional)",

" - figure (optional): Figure is a plotly graph object. "
" - figure (dict; optional): Figure is a plotly graph object. "
"figure has the following type: dict containing "
"keys 'data', 'layout'.",

Expand All @@ -915,7 +915,7 @@ def assert_docstring(assertEqual, docstring):
" - layout (dict; optional): layout describes "
"the rest of the figure",

"- optionalObjectWithShapeAndNestedDescription (optional): . "
"- optionalObjectWithShapeAndNestedDescription (dict; optional): "
"optionalObjectWithShapeAndNestedDescription has the "
"following type: dict containing keys "
"'color', 'fontSize', 'figure'.",
Expand All @@ -924,7 +924,7 @@ def assert_docstring(assertEqual, docstring):
" - color (string; optional)",
" - fontSize (number; optional)",

" - figure (optional): Figure is a plotly graph object. "
" - figure (dict; optional): Figure is a plotly graph object. "
"figure has the following type: dict containing "
"keys 'data', 'layout'.",

Expand Down Expand Up @@ -995,7 +995,7 @@ def setUp(self):

"dict containing keys 'customData', 'value'.",
"Those keys have the following types:",
"- customData (required): . customData has the following type: dict containing keys 'checked', 'children', 'customData', 'disabled', 'label', 'primaryText', 'secondaryText', 'style', 'value'.",
"- customData (dict; required): customData has the following type: dict containing keys 'checked', 'children', 'customData', 'disabled', 'label', 'primaryText', 'secondaryText', 'style', 'value'.",
" Those keys have the following types:",
" - checked (boolean; optional)",
" - children (a list of or a singular dash component, string or number; optional)",
Expand Down Expand Up @@ -1040,8 +1040,8 @@ def assert_flow_docstring(assertEqual, docstring):
"",
"Keyword arguments:",
"- requiredString (string; required): A required string",
"- optionalString (string; optional): A string that isn't required.",
"- optionalBoolean (boolean; optional): A boolean test",
"- optionalString (string; default ''): A string that isn't required.",
"- optionalBoolean (boolean; default false): A boolean test",

"- optionalNode (a list of or a singular dash component, string or number; optional): "
"A node test",
Expand All @@ -1052,7 +1052,7 @@ def assert_flow_docstring(assertEqual, docstring):

"- requiredUnion (string | number; required)",

"- optionalSignature(shape) (optional): This is a test of an object's shape. "
"- optionalSignature(shape) (dict; optional): This is a test of an object's shape. "
"optionalSignature(shape) has the following type: dict containing keys 'checked', "
"'children', 'customData', 'disabled', 'label', 'primaryText', 'secondaryText', "
"'style', 'value'.",
Expand All @@ -1068,12 +1068,12 @@ def assert_flow_docstring(assertEqual, docstring):
" - style (dict; optional)",
" - value (bool | number | str | dict | list; required)",

"- requiredNested (required): . requiredNested has the following type: dict containing "
"- requiredNested (dict; required): requiredNested has the following type: dict containing "
"keys 'customData', 'value'.",

" Those keys have the following types:",

" - customData (required): . customData has the following type: dict containing "
" - customData (dict; required): customData has the following type: dict containing "
"keys 'checked', 'children', 'customData', 'disabled', 'label', 'primaryText', "
"'secondaryText', 'style', 'value'.",

Expand Down