Skip to content
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

update to dash 1.0, plus R build #75

Merged
merged 8 commits into from
Aug 6, 2019
Merged
Show file tree
Hide file tree
Changes from 6 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
8 changes: 4 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,16 @@ jobs:
name: Generate Project & test
command: |
. venv/bin/activate
mkdir test_component
cd test_component
mkdir test_install
cd test_install
cookiecutter .. --config-file ../tests/test_config.yaml --no-input
cd test_component
python -m venv venv
. venv/bin/activate
pip install -r tests/requirements.txt --quiet
npm install --ignore-scripts
npm run build:all
pytest tests/test_usage.py
npm run build
pytest


workflows:
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,22 @@ To use this boilerplate:
$ cookiecutter https://github.com/plotly/dash-component-boilerplate.git
```
3. Answer the questions about the project.
- `project_name`: This is the "human-readable" name of your project. For example, "Dash Core Components".
- `project_name`: This is the "human-readable" name of your project. For example, "Dash Core Components".
- `project_shortname`: is derived from the project name, it is the name of the "python library" for your project. By default, this is generated from your `project_name` by lowercasing the name and replacing spaces & `-` with underscores. For example, for "Dash Core Components" this would be "dash_core_components".
- `component_name`: This is the name of the initial component that is generated. The default takes the `project_name` and remove the whitespace and `-`. As a javascript class name it should be in PascalCase.
- `author info`: author_name and author_email for package.json metadata.
- `component_name`: This is the name of the initial component that is generated. As a javascript class name it should be in PascalCase. defaults to the PascalCase version of `project_shortname`.
- `r_prefix`: Optional prefix for R components. For example, `dash_core_components` uses "dcc" so the Python `dcc.Input` becomes `dccInput` in R, and `dash_table` uses "dash" to make `dashDataTable`.
- `author_name` and `author_email`: for package.json and DESCRIPTION (for R) metadata.
- `github_org`: If you plan to push this to github, enter the organization or username that will own it (for URLs to the project homepage and bug report page)
- `description`: the project description, included in package.json.
- `license`: License type for the component library.
- `license`: License type for the component library. Plotly recommends the MIT license, but you should read the generated LICENSE file carefully to make sure this is right for you.
- `publish_on_npm`: Set to false to only serve locally from the package data.
- `install_dependencies`: Set to false to only generate the project structure.
4. The project will be generated in the folder of `project_shortname`.
4. The project will be generated in a folder named with your `project_shortname`.
5. Follow the directions in the generated README to start developing your new Dash component.

Installing the dependencies can take a long time. They will be installed in a
folder named `venv`, created by virtualenv. This ensures that dash is installed
to generate the components in the `build:py` script of the generated
to generate the components in the `build:py_and_r` script of the generated
`package.json`.


Expand Down
10 changes: 6 additions & 4 deletions cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"project_name": "my dash component",
"project_shortname": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}",
"component_name": "{{ cookiecutter.project_name.replace(' ', '').replace('-', '') }}",
"author_name": "Enter your name (For package.json)",
"project_shortname": "{{ cookiecutter.project_name.lower()|replace(' ', '_')|replace('-', '_') }}",
"component_name": "{{ cookiecutter.project_shortname.split('_')|map('capitalize')|join('') }}",
"r_prefix": "",
"author_name": "Enter your first and last name (For package.json)",
"author_email": "Enter your email (For package.json)",
"github_org": "",
"description": "Project Description",
"license": [
"MIT License",
Expand All @@ -15,4 +17,4 @@
],
"publish_on_npm": true,
"install_dependencies": true
}
}
16 changes: 9 additions & 7 deletions hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,30 @@ def _execute_command(cmd):

# Install python requirements.
_execute_command(
r'{} -m pip install -r requirements.txt'.format(python_executable))
r'{} -m pip install -r requirements.txt'.format(python_executable)
)

# Install node_modules
_execute_command('npm install --ignore-scripts')

# Run the first build
print('Building initial bundles...')

_execute_command('npm run build:js')

# Activating the venv and running the command
# doesn't work on linux with subprocess.
# The command need to run in the venv we just created to use the dash cmd.
# But it also needs shell to be true for the command to work.
# And shell doesn't work with `npm run` nor `. venv/bin/activate`
# The command works in a terminal.
_execute_command('{} -m dash.development.component_generator'
' ./src/lib/components'
' {{cookiecutter.project_shortname}}'
_execute_command("{} -m dash.development.component_generator"
" ./src/lib/components"
" {{cookiecutter.project_shortname}}"
" -p package-info.json"
" --r-prefix '{{ cookiecutter.r_prefix }}'"
.format(python_executable))

_execute_command('npm run build:js')
_execute_command('npm run build:js-dev')

print('\n{} ready!\n'.format(project_shortname))

sys.exit(0)
3 changes: 1 addition & 2 deletions tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
dash==0.38.0
dash[testing]>=1.0.2
pytest
Copy link

Choose a reason for hiding this comment

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

no need to have pytest relevant dependencies here as dash[testing] will control that

pytest-cookies
pytest-dash==2.1.1
2 changes: 2 additions & 0 deletions tests/test_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ default_context:
project_name: Test Component
project_shortname: test_component
component_name: TestComponent
r_prefix: dash
author_name: Test
author_email: Test
github_org: test-org
license: MIT License
publish_on_npm: false
install_dependencies: false
5 changes: 2 additions & 3 deletions tests/test_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@ def test_package_json(cookies):

assert package_json['name'] == 'test_component'
assert package_json['license'] == 'MIT'
assert package_json['author'] == \
'{} {}'.format(default_context['author_name'],
default_context['author_email'])
author = '{author_name} <{author_email}>'.format(**default_context)
assert package_json['author'] == author
68 changes: 45 additions & 23 deletions tests/test_install.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,64 @@
import os
import shutil
import sys

from dash.testing.application_runners import import_app

from pytest_dash.wait_for import (
wait_for_text_to_equal,
wait_for_element_by_css_selector
)

from pytest_dash.application_runners import import_app


def test_install(cookies, dash_threaded):
def test_install(cookies, dash_duo):
results = cookies.bake(extra_context={
'project_name': 'Test Component',
'author_name': 'test',
'author_email': 'test',
'r_prefix': 'dash',
})

# Add the generated project to the path so it can be loaded from usage.py
# It lies somewhere in a temp directory created by pytest-cookies
sys.path.insert(0, str(results.project))

selenium = dash_threaded.driver
# Test that `usage.py` works after building the default component.
dash_threaded(import_app('usage'))

input_component = wait_for_element_by_css_selector(
selenium,
'#input > input'
)
input_component.clear()
input_component.send_keys('Hello dash component')

wait_for_text_to_equal(
selenium,
'#output',
'You have entered Hello dash component'
)
app = import_app('usage')
dash_duo.start_server(app)

my_component = dash_duo.find_element('#input > input')
assert 'my-value' == my_component.get_attribute('value')

dash_duo.clear_input(my_component)
my_component.send_keys('Hello dash')
dash_duo.wait_for_text_to_equal('#output', 'You have entered Hello dash')

# Check for the existence of the right autogenerated files (R etc)
# We'll leave their contents to other tests at least for now,
# but existence tests verify that we can make the right directories
# on a clean installation.

expected_files = [
# base cookiecutter
['README.md'],
['package.json'],
['LICENSE'],
# Py
['test_component', '__init__.py'],
['test_component', '_imports_.py'],
['test_component', 'TestComponent.py'],
['test_component', 'test_component.min.js'],
['test_component', 'test_component.min.js.map'],
['test_component', 'package-info.json'],
['test_component', 'metadata.json'],
# R
['DESCRIPTION'],
['NAMESPACE'],
['R', 'dashTestComponent.R'],
['R', 'internal.R'],
['man', 'dashTestComponent.Rd'],
['inst', 'deps', 'test_component.min.js'],
['inst', 'deps', 'test_component.min.js.map'],
]

for path in expected_files:
path_str = str(results.project.join(*path))
assert os.path.exists(path_str), path_str

node_modules = str(results.project.join('node_modules'))

Expand Down
13 changes: 12 additions & 1 deletion {{cookiecutter.project_shortname}}/.babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
{
"presets": ["env", "react"]
"presets": ["@babel/preset-env", "@babel/preset-react"],
"env": {
"production": {
"plugins": ["@babel/plugin-proposal-object-rest-spread", "styled-jsx/babel"]
},
"development": {
"plugins": ["@babel/plugin-proposal-object-rest-spread", "styled-jsx/babel"]
},
"test": {
"plugins": ["@babel/plugin-proposal-object-rest-spread", "styled-jsx/babel-test"]
}
}
}
6 changes: 4 additions & 2 deletions {{cookiecutter.project_shortname}}/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
include {{cookiecutter.project_shortname}}/{{cookiecutter.project_shortname}}.min.js
include {{cookiecutter.project_shortname}}/{{cookiecutter.project_shortname}}.dev.js
include {{cookiecutter.project_shortname}}/{{cookiecutter.project_shortname}}.min.js.map
include {{cookiecutter.project_shortname}}/metadata.json
include {{cookiecutter.project_shortname}}/package.json
include {{cookiecutter.project_shortname}}/package-info.json
include README.md
include LICENSE
include package.json
18 changes: 9 additions & 9 deletions {{cookiecutter.project_shortname}}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ If you have selected install_dependencies during the prompt, you can skip this p
$ pip install -r tests/requirements.txt
```

### Write your component code in `src/lib/components/{{cookiecutter.component_name}}.react.js`.
### Write your component code in `src/lib/components/{{cookiecutter.component_name}}.react.js`.

- The demo app is in `src/demo` and you will import your example component code into your demo app.
- Test your code in a Python environment:
1. Build your code
```
$ npm run build:all
$ npm run build
```
2. Run and modify the `usage.py` sample dash app:
```
Expand All @@ -60,7 +60,7 @@ If you have selected install_dependencies during the prompt, you can skip this p

1. Build your code:
```
$ npm run build:all
$ npm run build
```
2. Create a Python tarball
```
Expand All @@ -74,21 +74,21 @@ If you have selected install_dependencies during the prompt, you can skip this p
```

4. If it works, then you can publish the component to NPM and PyPI:
1. Cleanup the dist folder (optional)
1. Publish on PyPI
```
$ rm -rf dist
$ twine upload dist/*
```
2. Publish on PyPI
2. Cleanup the dist folder (optional)
```
$ twine upload dist/*
$ rm -rf dist
```
3. Publish on NPM (Optional if chosen False in `publish_on_npm`)
```
$ npm publish
```
_Publishing your component to NPM will make the JavaScript bundles available on the unpkg CDN. By default, Dash servers the component library's CSS and JS from the remote unpkg CDN, so if you haven't published the component package to NPM you'll need to set the `serve_locally` flags to `True` (unless you choose `False` on `publish_on_npm`). We will eventually make `serve_locally=True` the default, [follow our progress in this issue](https://github.com/plotly/dash/issues/284)._
_Publishing your component to NPM will make the JavaScript bundles available on the unpkg CDN. By default, Dash serves the component library's CSS and JS locally, but if you choose to publish the package to NPM you can set `serve_locally` to `False` and you may see faster load times._

5. Share your component with the community! https://community.plot.ly/c/dash
1. Publish this repository to GitHub
2. Tag your GitHub repository with the plotly-dash tag so that it appears here: https://github.com/topics/plotly-dash
3. Create a post in the Dash community forum: https://community.plot.ly/c/dash

62 changes: 37 additions & 25 deletions {{cookiecutter.project_shortname}}/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,55 @@
"name": "{{ cookiecutter.project_shortname }}",
"version": "0.0.1",
"description": "{{ cookiecutter.description }}",
{% if cookiecutter.github_org -%}
"repository": {
"type": "git",
"url": "git://github.com/{{ cookiecutter.github_org }}/{{ cookiecutter.project_shortname.replace('_', '-') }}.git"
},
"bugs": {
"url": "https://github.com/{{ cookiecutter.github_org }}/{{ cookiecutter.project_shortname.replace('_', '-') }}/issues"
},
"homepage": "https://github.com/{{ cookiecutter.github_org }}/{{ cookiecutter.project_shortname.replace('_', '-') }}",
{%- endif %}
"main": "build/index.js",
"scripts": {
"start": "webpack-serve ./webpack.serve.config.js --open",
"validate-init": "python _validate_init.py",
"prepublish": "npm run validate-init",
"build:js-dev": "webpack --mode development",
"build:js": "webpack --mode production",
"build:py": "dash-generate-components ./src/lib/components {{ cookiecutter.project_shortname }}",
"build:py-activated": "(. venv/bin/activate || venv\\scripts\\activate && npm run build:py)",
"build:all": "npm run build:js && npm run build:js-dev && npm run build:py",
"build:all-activated": "(. venv/bin/activate || venv\\scripts\\activate && npm run build:all)"
"build:py_and_r": "dash-generate-components ./src/lib/components {{ cookiecutter.project_shortname }} -p package-info.json --r-prefix '{{ cookiecutter.r_prefix }}'",
"build:py_and_r-activated": "(. venv/bin/activate || venv\\scripts\\activate && npm run build:py_and_r)",
"build": "npm run build:js && npm run build:py_and_r",
"build:activated": "npm run build:js && npm run build:py_and_r-activated"
},
"author": "{{ cookiecutter.author_name }} {{ cookiecutter.author_email }}",
"author": "{{ cookiecutter.author_name }} <{{ cookiecutter.author_email }}>",
"license": "{% set _license_identifiers = {'MIT License': 'MIT','BSD License': 'BSD','ISC License': 'ISC','Apache Software License 2.0': 'Apache-2.0','GNU General Public License v3': 'GPL-3.0','Not open source': ''} %}{{ _license_identifiers[cookiecutter.license] }}",
"dependencies": {
"ramda": "^0.25.0"
"ramda": "^0.26.1"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4",
"copyfiles": "^2.0.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"css-loader": "^0.28.11",
"eslint": "^4.19.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-react": "^7.9.1",
"@babel/core": "^7.5.4",
"@babel/plugin-proposal-object-rest-spread": "^7.5.4",
"@babel/preset-env": "^7.5.4",
"@babel/preset-react": "^7.0.0",
"babel-eslint": "^10.0.2",
"babel-loader": "^8.0.6",
"copyfiles": "^2.1.1",
"css-loader": "^3.0.0",
"eslint": "^6.0.1",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-import": "^2.18.0",
"eslint-plugin-react": "^7.14.2",
"npm": "^6.1.0",
"react-docgen": "^2.20.1",
"style-loader": "^0.21.0",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.1",
"webpack-serve": "^1.0.2",
"react": ">=0.14",
"react-dom": ">=0.14"
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-docgen": "^4.1.1",
"react-dom": "^16.8.6",
"styled-jsx": "^3.2.1",
"style-loader": "^0.23.1",
"webpack": "4.36.1",
"webpack-cli": "3.3.6",
"webpack-serve": "3.1.0"
},
"engines": {
"node": ">=8.11.0",
Expand Down
4 changes: 3 additions & 1 deletion {{cookiecutter.project_shortname}}/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[pytest]
testpaths = tests/
webdriver = Chrome
addopts = -rsxX -vv
log_format = %(asctime)s | %(levelname)s | %(name)s:%(lineno)d | %(message)s
log_cli_level = ERROR
2 changes: 1 addition & 1 deletion {{cookiecutter.project_shortname}}/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# dash is required to call `build:py`
dash>=0.38.0
dash>=1.0.2
Loading