Skip to content

Commit a2787a0

Browse files
committed
- Move contents of commands.py to scripts in new bin directory and break
into individual scripts. - Tidy up imports etc. while doing so. - Move code generation from `./codegen` to `./bin/codegen`. - Move `plot-schema.json` to `./resources` rather than burying it under the `codegen` folder. - Add `Makefile` to run commands instead of putting everything in `commands.py`. - Run `ruff` directly for checking and formatting rather than launching a subprocess from Python as `commands.py` did. - Modify `.gitignore to ignore `docs` and `docs_tmp`. (Will eventually want to include `docs` or overwrite `doc`.) - Minor reformatting of `README.md`. - Update `CONTRIBUTING.md` to describe relocation of commands and code generation to `bin`. - `CONTRIBUTING.md` documents `--local`, `--devrepo` and `--devbranch` options for updating JavaScript bundle that `commands.py` didn't seem to provide. - Add `mkdocs.yml` configuration file for `mkdocs`. - Most of this file was vibe coded using Claude. - `mkdocs` does not support reading configuration from `pyproject.toml`, so we need the extra config file. - Use `material` theme. - Read hand-written Markdown from `pages` and write output to `docs`. - Generate module index pages on the fly using `mkdocs-gen-files` plugin. (See discussion of `bin/generate_reference_pages.py` below.) - Set docstring style to `google` (even though much of our documentation isn't formatted that way). - Add placeholder Markdown files in `pages` that include files from the root directory (README, code of conduct, contributors' guide, license). - Remove relative links between these pages because they don't work when the content is transcluded one directory lower. - Modify docstring in `plotly/_subplots.py` to escape closing `]` with backslash to avoid confusing `mkdocs` Markdown. - Here and elsewhere the escape is written `\\]` because we need `\]` in the actual string. We could convert the docstrings to literal strings prefixed with `r` to avoid the double backslash. - Have also escaped some `[` as `\\[` for the same reason. - Similar change to `plotly/basedatatypes.py`. - Reformat line breaks in docstrings in `plotly/express/_core.py`. - Modify `pyproject.toml` to install `mkdocs` and related packages for dev. - Modify `pyproject.toml` to install `pydoclint` for checking documentation. - Currently reporting a *lot* of errors. - Update `uv.lock` to match.
1 parent 6d864c4 commit a2787a0

28 files changed

+1216
-240
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ tests/test_orca/images/linux/failed/
1313

1414
doc/python/raw.githubusercontent.com/
1515

16+
docs/
17+
docs_tmp/
18+
1619
# Don't ignore dataset files
1720
!*.csv.gz
1821
!*.geojson.gz

CONTRIBUTING.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ then explains the technical aspects of preparing your contribution.
88

99
## Code of Conduct
1010

11-
Please note that all contributos are required to abide by our [Code of Conduct](CODE_OF_CONDUCT.md).
11+
Please note that all contributos are required to abide by our Code of Conduct.
1212

1313
## Different Ways to Contribute
1414

@@ -19,7 +19,7 @@ it is important to understand the structure of the code and the repository.
1919
- The [`plotly.graph_objects`](https://plotly.com/python/graph-objects/) module (usually imported as `go`)
2020
is [generated from the plotly.js schema](https://plotly.com/python/figure-structure/),
2121
so changes to be made in this package need to be contributed to [plotly.js](https://github.com/plotly/plotly.js)
22-
or to the code generation system in `./codegen/`.
22+
or to the code generation system in `./bin/codegen/`.
2323
Code generation creates traces and layout classes that have a direct correspondence to their JavaScript counterparts,
2424
while higher-level methods that work on figures regardless of the current schema (e.g., `BaseFigure.for_each_trace`)
2525
are defined in `plotly/basedatatypes.py`.
@@ -38,16 +38,17 @@ it is important to understand the structure of the code and the repository.
3838
These are organized in subdirectories according to what they test:
3939
see the "Setup" section below for more details.
4040

41-
- Documentation is found in `doc/`, and its structure is described in [its README file](doc/README.md).
41+
- Documentation is found in `doc/`, and its structure is described in its README file.
4242
The documentation is a great place to start contributing,
4343
since you can add or modify examples without setting up a full environment.
4444

45-
Code and documentation are not the only way to contribute:
46-
you can also help by:
45+
Code and documentation are not the only way to contribute.
46+
You can also help by:
4747

4848
- Reporting bugs at <https://github.com/plotly/plotly.py/issues>.
4949
Please take a moment to see if your problem has already been reported, and if so, add a comment to the existing issue;
50-
we will try to prioritize those that affect the most people.
50+
we will try to prioritize those that affect the most people
51+
and that are accompanied by small, runnable examples.
5152

5253
- Submitting feature requests (also at <https://github.com/plotly/plotly.py/issues>).
5354
Again, please add a comment to an existing issue if the feature you want has already been requested.
@@ -219,11 +220,11 @@ Once you have done that,
219220
run the `updateplotlyjs` command:
220221

221222
```bash
222-
python commands.py updateplotlyjs
223+
python bin/updatejs.py
223224
```
224225

225226
This downloads new versions of `plot-schema.json` and `plotly.min.js` from the `plotly/plotly.js` GitHub repository
226-
and places them in `plotly/package_data`.
227+
and places them in `resources` and `plotly/package_data` respectively.
227228
It then regenerates all of the `graph_objs` classes based on the new schema.
228229

229230
### Using a Development Branch of Plotly.js
@@ -232,7 +233,8 @@ If your development branch is in [the plotly.js repository](https://github.com/p
232233
you can update to development versions of `plotly.js` with this command:
233234

234235
```bash
235-
python commands.py updateplotlyjsdev --devrepo reponame --devbranch branchname
236+
# FIXME commands.py didn't provide --devrepo or --devbranch
237+
python bin/updatejs.py --dev --devrepo reponame --devbranch branchname
236238
```
237239

238240
This fetches the `plotly.js` in the CircleCI artifact of the branch `branchname` of the repo `reponame`.
@@ -255,5 +257,6 @@ You can then run the following command
255257
*in your local plotly.py repository*:
256258

257259
```bash
258-
python commands.py updateplotlyjsdev --local /path/to/your/plotly.js/
260+
# FIXME: commands.py didn't provide --local
261+
python bin/updatejs.py --dev --local /path/to/your/plotly.js/
259262
```

Makefile

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Manage plotly.py project.
2+
3+
RUN = uv run
4+
PACKAGE_DIRS = _plotly_utils plotly
5+
CODE_DIRS = ${PACKAGE_DIRS} scripts
6+
7+
## commands: show available commands
8+
commands:
9+
@grep -h -E '^##' ${MAKEFILE_LIST} | sed -e 's/## //g' | column -t -s ':'
10+
11+
## docs: rebuild documentation
12+
.PHONY: docs
13+
docs:
14+
${RUN} mkdocs build
15+
16+
## docs-lint: check documentation
17+
docs-lint:
18+
${RUN} pydoclint ${PACKAGE_DIRS}
19+
20+
## docs-tmp: rebuild documentation saving Markdown in ./tmp
21+
docs-tmp:
22+
MKDOCS_TEMP_DIR=./docs_tmp ${RUN} mkdocs build
23+
24+
## format: reformat code
25+
format:
26+
${RUN} ruff format ${CODE_DIRS}
27+
28+
## generate: generate code
29+
generate:
30+
${RUN} bin/generate_code.py --codedir plotly
31+
${RUN} ruff format plotly
32+
33+
## lint: check the code
34+
lint:
35+
${RUN} ruff check ${CODE_DIRS}
36+
37+
## test: run tests
38+
test:
39+
${RUN} pytest tests
40+
41+
## updatejs: update JavaScript bundle
42+
updatejs:
43+
${RUN} bin/updatejs.py --codedir plotly
44+
45+
## --: --
46+
47+
## clean: clean up repository
48+
clean:
49+
@find . -name '*~' -delete
50+
@find . -name '.DS_Store' -delete
51+
@rm -rf .coverage
52+
@rm -rf .pytest_cache
53+
@rm -rf .ruff_cache
54+
@rm -rf dist
55+
56+
## sync: update Python packages
57+
sync:
58+
uv sync --extra dev

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,21 @@ Built on top of [plotly.js](https://github.com/plotly/plotly.js), `plotly.py` is
7676

7777
## Installation
7878

79-
plotly.py may be installed using pip
79+
plotly.py may be installed using pip:
8080

8181
```
8282
pip install plotly
8383
```
8484

85-
or conda.
85+
or conda:
8686

8787
```
8888
conda install -c conda-forge plotly
8989
```
9090

9191
### Jupyter Widget Support
9292

93-
For use as a Jupyter widget, install `jupyter` and `anywidget`
94-
packages using `pip`:
93+
For use as a Jupyter widget, install the `jupyter` and `anywidget` packages using `pip`:
9594

9695
```
9796
pip install jupyter anywidget
@@ -112,14 +111,14 @@ command line utility (legacy as of `plotly` version 4.9).
112111

113112
#### Kaleido
114113

115-
The [`kaleido`](https://github.com/plotly/Kaleido) package has no dependencies and can be installed
116-
using pip
114+
The [`kaleido`](https://github.com/plotly/Kaleido) package has no dependencies
115+
and can be installed using pip:
117116

118117
```
119118
pip install -U kaleido
120119
```
121120

122-
or conda
121+
or conda:
123122

124123
```
125124
conda install -c conda-forge python-kaleido
@@ -129,13 +128,13 @@ conda install -c conda-forge python-kaleido
129128

130129
Some plotly.py features rely on fairly large geographic shape files. The county
131130
choropleth figure factory is one such example. These shape files are distributed as a
132-
separate `plotly-geo` package. This package can be installed using pip...
131+
separate `plotly-geo` package. This package can be installed using pip:
133132

134133
```
135134
pip install plotly-geo==1.0.0
136135
```
137136

138-
or conda
137+
or conda:
139138

140139
```
141140
conda install -c plotly plotly-geo=1.0.0
@@ -145,7 +144,7 @@ conda install -c plotly plotly-geo=1.0.0
145144

146145
## Copyright and Licenses
147146

148-
Code and documentation copyright 2019 Plotly, Inc.
147+
Code and documentation copyright Plotly, Inc.
149148

150149
Code released under the [MIT license](https://github.com/plotly/plotly.py/blob/main/LICENSE.txt).
151150

codegen/__init__.py renamed to bin/codegen/__init__.py

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import json
22
import os
3-
import os.path as opath
43
import shutil
5-
import subprocess
64
import sys
75

86
from codegen.datatypes import build_datatype_py, write_datatype_py # noqa: F401
@@ -87,45 +85,30 @@ def preprocess_schema(plotly_schema):
8785
items["colorscale"] = items.pop("concentrationscales")
8886

8987

90-
def make_paths(outdir):
91-
"""Make various paths needed for formatting and linting."""
88+
def make_paths(codedir):
89+
"""Make various paths needed for code generation."""
9290

93-
validators_dir = opath.join(outdir, "validators")
94-
graph_objs_dir = opath.join(outdir, "graph_objs")
95-
graph_objects_path = opath.join(outdir, "graph_objects", "__init__.py")
91+
validators_dir = codedir / "validators"
92+
graph_objs_dir = codedir / "graph_objs"
93+
graph_objects_path = codedir / "graph_objects" / "__init__.py"
9694
return validators_dir, graph_objs_dir, graph_objects_path
9795

9896

99-
def lint_code(outdir):
100-
"""Check Python code using settings in pyproject.toml."""
101-
102-
subprocess.call(["ruff", "check", *make_paths(outdir)])
103-
104-
105-
def reformat_code(outdir):
106-
"""Reformat Python code using settings in pyproject.toml."""
107-
108-
subprocess.call(["ruff", "format", *make_paths(outdir)])
109-
110-
111-
def perform_codegen(outdir, noformat=False):
112-
"""Generate code (and possibly reformat)."""
97+
def perform_codegen(codedir, noformat=False):
98+
"""Generate code."""
11399

114100
# Get paths
115-
validators_dir, graph_objs_dir, graph_objects_path = make_paths(outdir)
101+
validators_dir, graph_objs_dir, graph_objects_path = make_paths(codedir)
116102

117103
# Delete prior codegen output
118-
if opath.exists(validators_dir):
104+
if validators_dir.exists():
119105
shutil.rmtree(validators_dir)
120-
if opath.exists(graph_objs_dir):
106+
if graph_objs_dir.exists():
121107
shutil.rmtree(graph_objs_dir)
122108

123109
# Load plotly schema
124-
project_root = opath.dirname(outdir)
125-
plot_schema_path = opath.join(
126-
project_root, "codegen", "resources", "plot-schema.json"
127-
)
128-
110+
project_root = codedir.parent
111+
plot_schema_path = project_root / "resources" / "plot-schema.json"
129112
with open(plot_schema_path, "r") as f:
130113
plotly_schema = json.load(f)
131114

@@ -193,26 +176,26 @@ def perform_codegen(outdir, noformat=False):
193176

194177
# Write out the JSON data for the validators
195178
os.makedirs(validators_dir, exist_ok=True)
196-
write_validator_json(outdir, validator_params)
179+
write_validator_json(codedir, validator_params)
197180

198181
# Alls
199182
alls = {}
200183

201184
# Write out datatypes
202185
for node in all_compound_nodes:
203-
write_datatype_py(outdir, node)
186+
write_datatype_py(codedir, node)
204187

205188
# Deprecated
206189
# These are deprecated legacy datatypes like graph_objs.Marker
207-
write_deprecated_datatypes(outdir)
190+
write_deprecated_datatypes(codedir)
208191

209192
# Write figure class to graph_objs
210193
data_validator = get_data_validator_instance(base_traces_node)
211194
layout_validator = layout_node.get_validator_instance()
212195
frame_validator = frame_node.get_validator_instance()
213196

214197
write_figure_classes(
215-
outdir,
198+
codedir,
216199
base_traces_node,
217200
data_validator,
218201
layout_validator,
@@ -242,7 +225,7 @@ def perform_codegen(outdir, noformat=False):
242225
# Write plotly/graph_objs/graph_objs.py
243226
# This is for backward compatibility. It just imports everything from
244227
# graph_objs/__init__.py
245-
write_graph_objs_graph_objs(outdir)
228+
write_graph_objs_graph_objs(codedir)
246229

247230
# Add Figure and FigureWidget
248231
root_datatype_imports = datatype_rel_class_imports[()]
@@ -287,12 +270,13 @@ def __getattr__(import_name):
287270
# __all__
288271
for path_parts, class_names in alls.items():
289272
if path_parts and class_names:
290-
filepath = opath.join(outdir, "graph_objs", *path_parts, "__init__.py")
273+
filepath = codedir / "graph_objs"
274+
filepath = filepath.joinpath(*path_parts) / "__init__.py"
291275
with open(filepath, "at") as f:
292276
f.write(f"\n__all__ = {class_names}")
293277

294278
# Output datatype __init__.py files
295-
graph_objs_pkg = opath.join(outdir, "graph_objs")
279+
graph_objs_pkg = codedir / "graph_objs"
296280
for path_parts in datatype_rel_class_imports:
297281
rel_classes = sorted(datatype_rel_class_imports[path_parts])
298282
rel_modules = sorted(datatype_rel_module_imports.get(path_parts, []))
@@ -317,18 +301,13 @@ def __getattr__(import_name):
317301
graph_objects_rel_classes,
318302
init_extra=optional_figure_widget_import,
319303
)
320-
graph_objects_path = opath.join(outdir, "graph_objects", "__init__.py")
321-
os.makedirs(opath.join(outdir, "graph_objects"), exist_ok=True)
304+
graph_objects_path = codedir / "graph_objects"
305+
graph_objects_path.mkdir(parents=True, exist_ok=True)
306+
graph_objects_path /= "__init__.py"
322307
with open(graph_objects_path, "wt") as f:
323308
f.write("# ruff: noqa: F401\n")
324309
f.write(graph_objects_init_source)
325310

326-
# Run code formatter on output directories
327-
if noformat:
328-
print("skipping reformatting")
329-
else:
330-
reformat_code(outdir)
331-
332311

333312
if __name__ == "__main__":
334313
if len(sys.argv) != 2:

0 commit comments

Comments
 (0)