Skip to content

Adding prop reorder exceptions #1866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
2 changes: 1 addition & 1 deletion components/dash-core-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"test:pyimport": "python -m unittest tests/test_dash_import.py",
"prebuild:js": "cp node_modules/plotly.js/dist/plotly.min.js dash_core_components_base/plotly.min.js",
"build:js": "webpack --mode production",
"build:backends": "dash-generate-components ./src/components dash_core_components -p package-info.json && cp dash_core_components_base/** dash_core_components/ && dash-generate-components ./src/components dash_core_components -p package-info.json --r-prefix 'dcc' --r-suggests 'dash,dashHtmlComponents,jsonlite,plotly' --jl-prefix 'dcc' && black dash_core_components",
"build:backends": "dash-generate-components ./src/components dash_core_components -p package-info.json && cp dash_core_components_base/** dash_core_components/ && dash-generate-components ./src/components dash_core_components -p package-info.json -k RangeSlider,Slider,DataTable,Dropdown,RadioItems,Checklist --r-prefix 'dcc' --r-suggests 'dash,dashHtmlComponents,jsonlite,plotly' --jl-prefix 'dcc' && black dash_core_components",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Likewise here, there are some funny orders that I think we should be more careful about. In Checklist and RadioItems, what's inline doing way at the end, past the dash standards and far from any of the other style props? Some of these are alphabetized, other than the ones we explicitly want upfront, but some aren't - can we be consistent about this?

(BTW DataTable isn't needed in this list 😁)

"build": "run-s prepublishOnly build:js build:backends",
"postbuild": "es-check es5 dash_core_components/*.js",
"build:watch": "watch 'npm run build' src",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,6 @@ RadioItems.propTypes = {
),
]),

/**
* The ID of this component, used to identify dash components
* in callbacks. The ID needs to be unique across all of the
* components in an app.
*/
id: PropTypes.string,

/**
* The currently selected value
*/
Expand All @@ -147,6 +140,13 @@ RadioItems.propTypes = {
PropTypes.bool,
]),

/**
* The ID of this component, used to identify dash components
* in callbacks. The ID needs to be unique across all of the
* components in an app.
*/
id: PropTypes.string,

/**
* The style of the container (div)
*/
Expand Down
2 changes: 1 addition & 1 deletion components/dash-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"private::build:js": "run-s \"private::build -- --mode production\"",
"private::build:js-test": "run-s \"private::build -- --mode development --config webpack.test.config.js\"",
"private::build:js-test-watch": "run-s \"private::build -- --mode development --config webpack.test.config.js --watch\"",
"private::build:backends": "dash-generate-components src/dash-table/dash/DataTable.js dash_table -p package-info.json && cp dash_table_base/** dash_table/ && dash-generate-components src/dash-table/dash/DataTable.js dash_table -p package-info.json --r-prefix 'dash' --r-suggests 'dash' --jl-prefix 'dash' && black dash_table",
"private::build:backends": "dash-generate-components src/dash-table/dash/DataTable.js dash_table -p package-info.json && cp dash_table_base/** dash_table/ && dash-generate-components src/dash-table/dash/DataTable.js dash_table -p package-info.json -k DataTable --r-prefix 'dash' --r-suggests 'dash' --jl-prefix 'dash' && black dash_table",
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we make prop order explicit for table, I think we should be a little more careful about what order we end up with, especially since this will be reflected in the docs. The first two are right: data and columns. And it makes sense to keep derived_* and the dash standards (loading_state, persistence) at the end. Other than that it's currently a bit random, will be a bit hard for users to find what they want. @chriddyp do you want to give this a shot?

"private::format.ts": "npm run private::lint.ts -- --fix",
"private::format.prettier": "prettier --config .prettierrc --write \"{src,tests,demo}/**/*.{js,ts,tsx}\"",
"private::format.black": "black dash_table_base tests",
Expand Down
47 changes: 38 additions & 9 deletions dash/development/_py_components_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@


# pylint: disable=unused-argument
def generate_class_string(typename, props, description, namespace):
def generate_class_string(
typename, props, description, namespace, prop_reorder_exceptions=None
):
"""Dynamically generate class strings to have nicely formatted docstrings,
keyword arguments, and repr.
Inspired by http://jameso.be/2013/08/06/namedtuple.html
Expand All @@ -20,6 +22,7 @@ def generate_class_string(typename, props, description, namespace):
props
description
namespace
prop_reorder_exceptions
Returns
-------
string
Expand Down Expand Up @@ -62,11 +65,19 @@ def __init__(self, {default_argtext}):
super({typename}, self).__init__({argtext})
'''

filtered_props = reorder_props(filter_props(props))
filtered_props = (
filter_props(props)
if (prop_reorder_exceptions is not None and typename in prop_reorder_exceptions)
or (prop_reorder_exceptions is not None and "ALL" in prop_reorder_exceptions)
else reorder_props(filter_props(props))
)
wildcard_prefixes = repr(parse_wildcards(props))
list_of_valid_keys = repr(list(map(str, filtered_props.keys())))
docstring = create_docstring(
component_name=typename, props=filtered_props, description=description
component_name=typename,
props=filtered_props,
description=description,
prop_reorder_exceptions=prop_reorder_exceptions,
).replace("\r\n", "\n")

prohibit_events(props)
Expand Down Expand Up @@ -106,14 +117,17 @@ def __init__(self, {default_argtext}):
)


def generate_class_file(typename, props, description, namespace):
def generate_class_file(
typename, props, description, namespace, prop_reorder_exceptions=None
):
"""Generate a Python class file (.py) given a class string.
Parameters
----------
typename
props
description
namespace
prop_reorder_exceptions
Returns
-------
"""
Expand All @@ -122,7 +136,10 @@ def generate_class_file(typename, props, description, namespace):
+ "from dash.development.base_component import "
+ "Component, _explicitize_args\n\n\n"
)
class_string = generate_class_string(typename, props, description, namespace)

class_string = generate_class_string(
typename, props, description, namespace, prop_reorder_exceptions
)
file_name = "{:s}.py".format(typename)

file_path = os.path.join(namespace, file_name)
Expand Down Expand Up @@ -162,7 +179,9 @@ def generate_classes_files(project_shortname, metadata, *component_generators):
return components


def generate_class(typename, props, description, namespace):
def generate_class(
typename, props, description, namespace, prop_reorder_exceptions=None
):
"""Generate a Python class object given a class string.
Parameters
----------
Expand All @@ -173,7 +192,9 @@ def generate_class(typename, props, description, namespace):
Returns
-------
"""
string = generate_class_string(typename, props, description, namespace)
string = generate_class_string(
typename, props, description, namespace, prop_reorder_exceptions
)
scope = {"Component": Component, "_explicitize_args": _explicitize_args}
# pylint: disable=exec-used
exec(string, scope)
Expand All @@ -194,7 +215,7 @@ def required_props(props):
return [prop_name for prop_name, prop in list(props.items()) if prop["required"]]


def create_docstring(component_name, props, description):
def create_docstring(component_name, props, description, prop_reorder_exceptions=None):
"""Create the Dash component docstring.
Parameters
----------
Expand All @@ -210,7 +231,15 @@ def create_docstring(component_name, props, description):
Dash component docstring
"""
# Ensure props are ordered with children first
props = reorder_props(props=props)
props = (
props
if (
prop_reorder_exceptions is not None
and component_name in prop_reorder_exceptions
)
or (prop_reorder_exceptions is not None and "ALL" in prop_reorder_exceptions)
else reorder_props(props)
)

return (
"A{n} {name} component.\n{description}\n\nKeyword arguments:\n{args}"
Expand Down
7 changes: 6 additions & 1 deletion dash/development/_r_components_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,12 @@ def write_help_file(name, props, description, prefix, rpkg_data):

# pylint: disable=too-many-arguments
def write_class_file(
name, props, description, project_shortname, prefix=None, rpkg_data=None
name,
props,
description,
project_shortname,
prefix=None,
rpkg_data=None,
):
props = reorder_props(props=props)

Expand Down
23 changes: 20 additions & 3 deletions dash/development/component_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import argparse
import shutil
import functools

import pkg_resources
import yaml

Expand All @@ -20,7 +19,6 @@
from ._jl_components_generation import generate_struct_file
from ._jl_components_generation import generate_module


reserved_words = [
"UNDEFINED",
"REQUIRED",
Expand All @@ -38,7 +36,7 @@ class _CombinedFormatter(
pass


# pylint: disable=too-many-locals, too-many-arguments
# pylint: disable=too-many-locals, too-many-arguments, too-many-branches
def generate_components(
components_source,
project_shortname,
Expand All @@ -50,6 +48,7 @@ def generate_components(
rsuggests="",
jlprefix=None,
metadata=None,
keep_prop_order=None,
):

project_shortname = project_shortname.replace("-", "_").rstrip("/\\")
Expand Down Expand Up @@ -119,6 +118,14 @@ def generate_components(
functools.partial(generate_struct_file, prefix=jlprefix)
)

if keep_prop_order is not None:
keep_prop_order = [
component.strip(" ") for component in keep_prop_order.split(",")
]
generator_methods[0] = functools.partial(
generate_class_file, prop_reorder_exceptions=keep_prop_order
)

components = generate_classes_files(project_shortname, metadata, *generator_methods)

with open(os.path.join(project_shortname, "metadata.json"), "w") as f:
Expand Down Expand Up @@ -201,6 +208,15 @@ def component_build_arg_parser():
help="Specify a prefix for Dash for R component names, write "
"components to R dir, create R package.",
)
parser.add_argument(
"-k",
"--keep-prop-order",
default=None,
help="Specify a comma-separated list of components which will use the prop "
"order described in the component proptypes instead of alphabetically reordered "
"props. Pass the 'ALL' keyword to have every component retain "
"its original prop order.",
)
return parser


Expand All @@ -216,6 +232,7 @@ def cli():
rimports=args.r_imports,
rsuggests=args.r_suggests,
jlprefix=args.jl_prefix,
keep_prop_order=args.keep_prop_order,
)


Expand Down
2 changes: 1 addition & 1 deletion dash/development/component_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def load_components(metadata_path, namespace="default_namespace"):
# the name of the component atm.
name = componentPath.split("/").pop().split(".")[0]
component = generate_class(
name, componentData["props"], componentData["description"], namespace
name, componentData["props"], componentData["description"], namespace, None
)

components.append(component)
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.