diff --git a/.circleci/config.yml b/.circleci/config.yml index 8cc681c73e..7769e703c1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -49,13 +49,13 @@ jobs: name: 🏁 Build Component Packages & Update Dependencies/Artifacts command: | python -m venv venv && . venv/bin/activate - pip install --upgrade pip wheel setuptools + pip install --upgrade pip set -eo pipefail pip install -e .[ci,dev,testing,celery,diskcache] --progress-bar off pip list | grep dash npm ci npm run build.sequential - python setup.py sdist + python -m build mkdir dash-package && cp dist/*.tar.gz dash-package/dash-package.tar.gz ls -la dash-package no_output_timeout: 30m diff --git a/.gitignore b/.gitignore index bcfe7ce877..bfff5a38d0 100644 --- a/.gitignore +++ b/.gitignore @@ -42,13 +42,13 @@ coverage.xml # Distribution / packaging .Python build/ -dash/deps/ -dash/html/* -!dash/html/.gitkeep -dash/dcc/* -!dash/dcc/.gitkeep -dash/dash_table/* -!dash/dash_table/.gitkeep +src/dash/deps/ +src/dash/html/* +!src/dash/html/.gitkeep +src/dash/dcc/* +!src/dash/dcc/.gitkeep +src/dash/dash_table/* +!src/dash/dash_table/.gitkeep develop-eggs/ dist/ downloads/ diff --git a/.pylintrc b/.pylintrc index c2330d844b..b626177156 100644 --- a/.pylintrc +++ b/.pylintrc @@ -15,9 +15,9 @@ ignore-patterns= # Add files or directories matching the regex patterns to the ignore-list. # The regex matches against paths. -ignore-paths=^dash/dcc/.*$, - ^dash/html/.*$, - ^dash/dash_table/.*$ +ignore-paths=^src/dash/dcc/.*$, + ^src/dash/html/.*$, + ^src/dash/dash_table/.*$ # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). diff --git a/.pylintrc312 b/.pylintrc312 index eb25586d08..9493e42dd6 100644 --- a/.pylintrc312 +++ b/.pylintrc312 @@ -15,9 +15,9 @@ ignore-patterns= # Add files or directories matching the regex patterns to the ignore-list. # The regex matches against paths. -ignore-paths=^dash/dcc/.*$, - ^dash/html/.*$, - ^dash/dash_table/.*$ +ignore-paths=^src/dash/dcc/.*$, + ^src/dash/html/.*$, + ^src/dash/dash_table/.*$ # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). diff --git a/@plotly/dash-jupyterlab/package.json b/@plotly/dash-jupyterlab/package.json index d81245ad2a..f4cd307dd0 100644 --- a/@plotly/dash-jupyterlab/package.json +++ b/@plotly/dash-jupyterlab/package.json @@ -25,10 +25,10 @@ }, "scripts": { "build": "tsc", - "build:pack": "jlpm run prepare && jlpm pack --filename ../../dash/labextension/dist/dash-jupyterlab.tgz && jlpm run build:copy", - "build:copy": "cp package.json ../../dash/labextension/dist/package.json", + "build:pack": "jlpm run prepare && jlpm pack --filename ../../src/dash/labextension/dist/dash-jupyterlab.tgz && jlpm run build:copy", + "build:copy": "cp package.json ../../src/dash/labextension/dist/package.json", "clean": "rimraf lib", - "prepare": "mkdir -p ../../dash/labextension/dist && jlpm run clean && jlpm run build", + "prepare": "mkdir -p ../../src/dash/labextension/dist && jlpm run clean && jlpm run build", "prettier": "prettier --write '{!(package),src/**,!(lib)/**}{.js,.jsx,.ts,.tsx,.css,.json,.md}'", "watch": "tsc -w" }, diff --git a/MAKE_A_NEW_BACK_END.md b/MAKE_A_NEW_BACK_END.md index c6f17ae47d..a6f3137a60 100644 --- a/MAKE_A_NEW_BACK_END.md +++ b/MAKE_A_NEW_BACK_END.md @@ -17,7 +17,7 @@ We also include a couple of files that are only used to generate the components: Then we also have Python files. Most of these are generated directly from `metadata.json` - for example `Checklist.py` is a class definition corresponding to the Checklist React component, and if you look inside it you’ll see it inherits from the `dash.development.base_component.Component` class, it has a docstring listing all props and their types in Python notation (instead of “array of objects”, it says “list of dicts”), and it has a constructor that ensures you can only create it with appropriate props. Then there are some Python files that are NOT generated, but copied from https://github.com/plotly/dash-core-components/tree/master/dash_core_components_base - `__init__.py` collects all the component classes and explicitly lists all the browser assets in `_js_dist` and possibly `_css_dist`. -Each back end must have a way to generate its own wrappers for these React components. The Python wrappers are generated source code files as described above, created by [`_py_components_generation.py`](https://github.com/plotly/dash/blob/dev/dash/development/_py_components_generation.py) - other languages may choose to either generate files, or create precompiled objects of some sort, but the key requirements are: +Each back end must have a way to generate its own wrappers for these React components. The Python wrappers are generated source code files as described above, created by [`_py_components_generation.py`](https://github.com/plotly/dash/blob/dev/src/dash/development/_py_components_generation.py) - other languages may choose to either generate files, or create precompiled objects of some sort, but the key requirements are: - Provide a natural way for users of this language to create components as data structures, keeping in mind that components may be nested inside the children prop of some other components, and most props are optional. - To the extent that we can help users with built-in documentation and IDE auto-completion, we should try to do that. - When requested by the framework, the component must serialize to JSON. This looks like: diff --git a/MANIFEST.in b/MANIFEST.in index 960033c813..6945f54f54 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,14 +1,14 @@ include README.md include LICENSE include requires-*.txt -include dash/favicon.ico -include dash/extract-meta.js -include dash/deps/*.js -include dash/deps/*.map -include dash/dcc/* -include dash/html/* -include dash/dash_table/* -include dash/dash-renderer/build/*.js -include dash/dash-renderer/build/*.map -include dash/labextension/dist/dash-jupyterlab.tgz -include dash/labextension/package.json +include src/dash/favicon.ico +include src/dash/extract-meta.js +include src/dash/deps/*.js +include src/dash/deps/*.map +include src/dash/dcc/* +include src/dash/html/* +include src/dash/dash_table/* +include src/dash/dash-renderer/build/*.js +include src/dash/dash-renderer/build/*.map +include src/dash/labextension/dist/dash-jupyterlab.tgz +include src/dash/labextension/package.json diff --git a/package.json b/package.json index d868cd52fa..fea14c1ce5 100644 --- a/package.json +++ b/package.json @@ -3,19 +3,19 @@ "license": "UNLICENSED", "scripts": { "private::format.black": "black dash tests --exclude metadata_test.py", - "private::format.renderer": "cd dash/dash-renderer && npm run format", + "private::format.renderer": "cd src/dash/dash-renderer && npm run format", "private::format.dcc": "cd components/dash-core-components && npm run format", - "private::initialize.renderer": "cd dash/dash-renderer && npm ci", - "private::cibuild.components": "python dash/development/update_components.py 'all' --ci True", - "private::build.components": "python dash/development/update_components.py 'all'", - "private::cibuild.renderer": "cd dash/dash-renderer && renderer build", - "private::build.renderer": "cd dash/dash-renderer && renderer build", + "private::initialize.renderer": "cd src/dash/dash-renderer && npm ci", + "private::cibuild.components": "python src/dash/development/update_components.py 'all' --ci True", + "private::build.components": "python src/dash/development/update_components.py 'all'", + "private::cibuild.renderer": "cd src/dash/dash-renderer && renderer build", + "private::build.renderer": "cd src/dash/dash-renderer && renderer build", "private::build.jupyterlab": "cd \\@plotly/dash-jupyterlab && jlpm install && jlpm build:pack", - "private::lint.black": "node -e \"if ((process.env.PYVERSION || 'python312') !== 'python38'){process.exit(1)} \" || black dash tests --exclude metadata_test.py --check", - "private::lint.flake8": "flake8 --exclude=metadata_test.py dash tests", - "private::lint.pylint-dash": "PYLINTRC=${PYLINTRC:=.pylintrc312} && pylint dash setup.py --rcfile=$PYLINTRC", + "private::lint.black": "node -e \"if ((process.env.PYVERSION || 'python312') !== 'python38'){process.exit(1)} \" || black src tests --exclude metadata_test.py --check", + "private::lint.flake8": "flake8 --exclude=metadata_test.py src tests", + "private::lint.pylint-dash": "PYLINTRC=${PYLINTRC:=.pylintrc312} && pylint src setup.py --rcfile=$PYLINTRC", "private::lint.pylint-tests": "PYLINTRC=${PYLINTRC:=.pylintrc312} && pylint tests/unit tests/integration -d all -e C0410,C0413,W0109 --rcfile=$PYLINTRC", - "private::lint.renderer": "cd dash/dash-renderer && npm run lint", + "private::lint.renderer": "cd src/dash/dash-renderer && npm run lint", "private::test.setup-components": "cd \\@plotly/dash-test-components && npm ci && npm run build", "private::test.setup-nested": "cd \\@plotly/dash-generator-test-component-nested && npm ci && npm run build", "private::test.setup-standard": "cd \\@plotly/dash-generator-test-component-standard && npm ci && npm run build", @@ -28,7 +28,7 @@ "private::test.R.deploy-nested": "npm run private::test.setup-nested && cd \\@plotly/dash-generator-test-component-nested && sudo R CMD INSTALL .", "private::test.R.deploy-standard": "npm run private::test.setup-standard && cd \\@plotly/dash-generator-test-component-standard && sudo R CMD INSTALL .", "private::test.unit-dash": "pytest tests/unit", - "private::test.unit-renderer": "cd dash/dash-renderer && npm run test", + "private::test.unit-renderer": "cd src/dash/dash-renderer && npm run test", "private::test.unit-generation": "cd \\@plotly/dash-generator-test-component-typescript && npm ci && npm test", "private::test.integration-dash": "TESTFILES=$(circleci tests glob \"tests/integration/**/test_*.py\" | circleci tests split --split-by=timings) && pytest --headless --nopercyfinalize --junitxml=test-reports/junit_intg.xml ${TESTFILES}", "private::test.integration-dash-import": "cd tests/integration/dash && python dash_import_test.py", @@ -43,7 +43,7 @@ "setup-tests.R": "run-s private::test.R.deploy-*", "citest.integration": "run-s setup-tests.py private::test.integration-*", "citest.unit": "run-s private::test.unit-**", - "test": "pytest && cd dash/dash-renderer && npm run test" + "test": "pytest && cd src/dash/dash-renderer && npm run test" }, "devDependencies": { "husky": "8.0.3", diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..3508c0f9a1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,73 @@ +[build-system] +requires = ["setuptools>=61.2"] +build-backend = "setuptools.build_meta" + +[project] +name = "dash" +authors = [{name = "Chris Parmer", email = "chris@plotly.com"}] +license = {text = "MIT"} +description = "A Python framework for building reactive web-apps. Developed by Plotly." +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Framework :: Dash", + "Framework :: Flask", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: Financial and Insurance Industry", + "Intended Audience :: Healthcare Industry", + "Intended Audience :: Manufacturing", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Database :: Front-Ends", + "Topic :: Office/Business :: Financial :: Spreadsheet", + "Topic :: Scientific/Engineering :: Visualization", + "Topic :: Software Development :: Libraries :: Application Frameworks", + "Topic :: Software Development :: Widget Sets", +] +requires-python = ">=3.8" +dynamic = ["version", "dependencies", "optional-dependencies"] + +[project.readme] +file = "README.md" +content-type = "text/markdown" + +[project.urls] +Homepage = "https://plotly.com/dash" +Documentation = "https://dash.plotly.com" +Source = "https://github.com/plotly/dash" +"Issue Tracker" = "https://github.com/plotly/dash/issues" + +[project.entry-points] +pytest11 = {dash = "dash.testing.plugin"} + +[project.scripts] +dash-generate-components = "dash.development.component_generator:cli" +renderer = "dash.development.build_process:renderer" +dash-update-components = "dash.development.update_components:cli" + +[tool.setuptools] +include-package-data = true + +[tool.setuptools.dynamic] +version = {attr = "dash.version.__version__"} +dependencies = { file = "requires-install.txt"} + +[tool.setuptools.dynamic.optional-dependencies] +ci = { file = "requires-ci.txt" } +dev = { file = "requires-dev.txt" } +testing = { file = "requires-testing.txt" } +celery = { file = "requires-celery.txt" } +diskcache = { file = "requires-diskcache.txt" } +compress = { file = "requires-compress.txt" } + +[tool.setuptools.packages.find] +namespaces = false +where = ["src"] diff --git a/requires-ci.txt b/requires-ci.txt index bd16dc51bb..a8060aead0 100644 --- a/requires-ci.txt +++ b/requires-ci.txt @@ -25,3 +25,4 @@ xlrd>=2.0.1;python_version>="3.8" xlrd<2;python_version<"3.8" pytest-rerunfailures jupyterlab<4.0.0 +build==1.0.3 diff --git a/setup.py b/setup.py index 940d128e59..9ec06c801d 100644 --- a/setup.py +++ b/setup.py @@ -1,92 +1,19 @@ -import io -from setuptools import setup, find_packages - -main_ns = {} -exec(open("dash/version.py", encoding="utf-8").read(), main_ns) # pylint: disable=exec-used, consider-using-with - - -def read_req_file(req_type): - with open(f"requires-{req_type}.txt", encoding="utf-8") as fp: - requires = (line.strip() for line in fp) - return [req for req in requires if req and not req.startswith("#")] +from setuptools import setup setup( - name="dash", - version=main_ns["__version__"], - author="Chris Parmer", - author_email="chris@plotly.com", - packages=find_packages(exclude=["tests*"]), - include_package_data=True, - license="MIT", - description=( - "A Python framework for building reactive web-apps. " - "Developed by Plotly." - ), - long_description=io.open("README.md", encoding="utf-8").read(), # pylint: disable=consider-using-with - long_description_content_type="text/markdown", - install_requires=read_req_file("install"), - python_requires=">=3.8", - extras_require={ - "ci": read_req_file("ci"), - "dev": read_req_file("dev"), - "testing": read_req_file("testing"), - "celery": read_req_file("celery"), - "diskcache": read_req_file("diskcache"), - "compress": read_req_file("compress") - }, - entry_points={ - "console_scripts": [ - "dash-generate-components = " - "dash.development.component_generator:cli", - "renderer = dash.development.build_process:renderer", - "dash-update-components = dash.development.update_components:cli" - ], - "pytest11": ["dash = dash.testing.plugin"], - }, - url="https://plotly.com/dash", - project_urls={ - "Documentation": "https://dash.plotly.com", - "Source": "https://github.com/plotly/dash", - "Issue Tracker": "https://github.com/plotly/dash/issues", - }, - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Web Environment", - "Framework :: Dash", - "Framework :: Flask", - "Intended Audience :: Developers", - "Intended Audience :: Education", - "Intended Audience :: Financial and Insurance Industry", - "Intended Audience :: Healthcare Industry", - "Intended Audience :: Manufacturing", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Topic :: Database :: Front-Ends", - "Topic :: Office/Business :: Financial :: Spreadsheet", - "Topic :: Scientific/Engineering :: Visualization", - "Topic :: Software Development :: Libraries :: Application Frameworks", - "Topic :: Software Development :: Widget Sets", - ], data_files=[ # like `jupyter nbextension install --sys-prefix` ("share/jupyter/nbextensions/dash", [ - "dash/nbextension/main.js", + "src/dash/nbextension/main.js", ]), # like `jupyter nbextension enable --sys-prefix` ("etc/jupyter/nbconfig/notebook.d", [ - "dash/nbextension/dash.json" + "src/dash/nbextension/dash.json" ]), # Place jupyterlab extension in extension directory ("share/jupyter/lab/extensions", [ - "dash/labextension/dist/dash-jupyterlab.tgz" + "src/dash/labextension/dist/dash-jupyterlab.tgz" ]), ], ) diff --git a/src/dash/development/update_components.py b/src/dash/development/update_components.py index fa6dee2c77..7f95d8a64f 100644 --- a/src/dash/development/update_components.py +++ b/src/dash/development/update_components.py @@ -99,7 +99,7 @@ def build_components(components_source, concurrency): else "dash_table" ) - dest_path = os.path.join("dash", dest_dir) + dest_path = os.path.join("src", "dash", dest_dir) if not os.path.exists(dest_path): try: diff --git a/tests/integration/dash/dash_import_test.py b/tests/integration/dash/dash_import_test.py index f9b1ddf89e..c2f2534efa 100644 --- a/tests/integration/dash/dash_import_test.py +++ b/tests/integration/dash/dash_import_test.py @@ -9,7 +9,7 @@ assert isinstance(dash, types.ModuleType), "dash can be imported" this_dir = os.path.dirname(__file__) -with open(os.path.join(this_dir, "../../../dash/version.py")) as fp: +with open(os.path.join(this_dir, "../../../src/dash/version.py")) as fp: assert dash.__version__ in fp.read(), "version is consistent" assert getattr(dash, "Dash").__name__ == "Dash", "access to main Dash class is valid"