Skip to content

Commit

Permalink
Implements Tethys Reactpy App Scaffold (#1081)
Browse files Browse the repository at this point in the history
* Reactpy configured at the baseline-level

* Added RESelectInput react component to create a reach dropdown just like original tethys gizmo
added on_click, on_change, and on_mouse_over kwargs

* Integrates reactpy and implements app scaffold

* Handle reactpy-django at app install level

* Bugfixes from fresh test
There were a few bugs found when installing from a fresh test, namely:
* The version of daphne installed by default didn't meet requirements
* There was some experimental reactpy core development that I never
  backed out

* Initial wave of tests and resulting refactors/fixes

* Adds tests and test-based fixes

* Fix broken tests on Windows, flake8 cleanup

* Applies black formatting

* Try fixing async test

* Fix flake8 warning

* Tweak test for macos

* Another tweak for tests on macos

* Fix broken test from last commit

* black reformatting

* Unpin daphne version

* Bugfix: Default arg must be passed to scaffold_command

* applies suggested changes
* Replaces all usage of os.path with pathlib.Path
* reactpy_django detected and added to INSTALLED_APPS in settings.py
* ReactPy App scaffold now has pyproject.toml instead of setup.py

* Revert spot where os.path had been converted to pathlib.Path
In this one instance, Path.exists throws a "File too long" error on Unix
machines, while os.path.exists dose not. I couldn't think of a good
way around that for now.

* Remove erroneous argument

* Fix bug with pathlib update to static_finders

* Update tests/unit_tests/test_tethys_apps/test_template_loaders.py

Co-authored-by: sdc50 <[email protected]>

* Update tethys_cli/cli_helpers.py

Co-authored-by: sdc50 <[email protected]>

* Additional tweaks per feedback
Adds tests for remaining tethys_component reactpy files
Adds reactpy-django to standard install
Fixes broken support for variable in url for pages
Adds react-loading-overlay and react-map-gl to built-in ComponentLibrary support
Fixes buggy use_workspace

* black and flake8

* remove file that was unintentionally committed

* Fixes pyproject.toml_tmpl for reacpty scaffold
The authors field cannot be present if name and email
are blank, so they are now conditional upon those
values being filled

* Update tethys_apps/base/url_map.py

Co-authored-by: Nathan Swain <[email protected]>

* Implements latest feedback from @swainn
- pyproject.toml added to all scaffolds
- reactpy_base.html refactored to extend app_base.html
- minor cleanups and refactors

* Additional tweaks per feedback/tests
- Reverted last commit's swap of argparse.Namespace for mock.MagicMock since mock requires the "name" argument, which isn't allowed by MagicMock on initialization
- Added reactpy to dependencies in environment.yml

* Fix broken test

* Removes reactpy[-django] from dependencies

Since reactpy and reactpy-django are not yet available on conda-forge, they were added as pip dependencies. However, that was preventing the tethys coda package from building successfully. Thus, we're backing that out for now until they can be added to conda-forge

* Replace Path.walk with os.walk

Path.walk didn't exist until Python 3.12, so to support those versions of Python, I had to downgrade back to os.walk.

* Replaces odd Namespace usage with UrlMap

* Applies black formatting

* Separates channels and daphne

---------

Co-authored-by: Corey Krewson <[email protected]>
Co-authored-by: sdc50 <[email protected]>
Co-authored-by: Nathan Swain <[email protected]>
  • Loading branch information
4 people authored Nov 25, 2024
1 parent 4d7ca52 commit 6d524e5
Show file tree
Hide file tree
Showing 105 changed files with 3,397 additions and 1,278 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/tethys.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ jobs:
run: |
cd ..
. ~/miniconda/etc/profile.d/conda.sh;
conda create -y -c conda-forge -n conda-build conda-build anaconda-client
conda create -y -c conda-forge -n conda-build conda-build anaconda-client
conda activate conda-build
conda config --set anaconda_upload no
mkdir -p ~/conda-bld
Expand Down Expand Up @@ -259,7 +259,7 @@ jobs:
run: |
cd ..
. ~/miniconda/etc/profile.d/conda.sh;
conda create -y -c conda-forge -n conda-build conda-build anaconda-client
conda create -y -c conda-forge -n conda-build conda-build anaconda-client
conda activate conda-build
conda config --set anaconda_upload no
mkdir -p ~/conda-bld
Expand Down
12 changes: 6 additions & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import os
import sys
import subprocess
from dataclasses import asdict
from os import environ
from pathlib import Path
from unittest import mock

Expand Down Expand Up @@ -106,7 +106,7 @@ def __getattr__(cls, name):
# patcher.start()

# Fixes django settings module problem
sys.path.insert(0, os.path.abspath(".."))
sys.path.insert(0, Path("..").absolute().resolve())

installed_apps = [
"django.contrib.admin",
Expand Down Expand Up @@ -165,7 +165,7 @@ def __getattr__(cls, name):
copyright = "2023, Tethys Platform"

# on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org
on_rtd = os.environ.get("READTHEDOCS") == "True"
on_rtd = environ.get("READTHEDOCS") == "True"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand All @@ -178,7 +178,7 @@ def __getattr__(cls, name):
print(f'Using simplified version "{version}"')

# Determine branch
git_directory = Path(__file__).parent.parent
git_directory = Path(__file__).parents[1]
ret = subprocess.run(
["git", "-C", git_directory, "rev-parse", "--abbrev-ref", "HEAD"],
capture_output=True,
Expand Down Expand Up @@ -256,10 +256,10 @@ def __getattr__(cls, name):
todo_emit_warnings = True

# Define the canonical URL if you are using a custom domain on Read the Docs
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
html_baseurl = environ.get("READTHEDOCS_CANONICAL_URL", "")

# Tell Jinja2 templates the build is running on Read the Docs
if os.environ.get("READTHEDOCS", "") == "True":
if environ.get("READTHEDOCS", "") == "True":
if "html_context" not in globals():
html_context = {}
html_context["READTHEDOCS"] = True
Expand Down
2 changes: 1 addition & 1 deletion tests/apps/tethysapp-test_app/install-with-post.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ requirements:
- geojson
- shapely
post:
- ./test.sh
- ./test.py
1 change: 1 addition & 0 deletions tests/apps/tethysapp-test_app/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("test")
1 change: 0 additions & 1 deletion tests/apps/tethysapp-test_app/test.sh

This file was deleted.

2 changes: 2 additions & 0 deletions tests/coverage.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
[run]
source = $TETHYS_TEST_DIR/../tethys_apps
$TETHYS_TEST_DIR/../tethys_cli
$TETHYS_TEST_DIR/../tethys_components/library.py
$TETHYS_TEST_DIR/../tethys_components/utils.py
$TETHYS_TEST_DIR/../tethys_compute
$TETHYS_TEST_DIR/../tethys_config
$TETHYS_TEST_DIR/../tethys_gizmos
Expand Down
6 changes: 3 additions & 3 deletions tests/unit_tests/test_tethys_apps/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os
from pathlib import Path
import unittest
from unittest import mock
from django.db.utils import ProgrammingError
Expand Down Expand Up @@ -47,8 +47,8 @@ class TestTethysAppAdmin(unittest.TestCase):
def setUp(self):
from tethys_apps.models import TethysApp

self.src_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
self.root_app_path = os.path.join(self.src_dir, "apps", "tethysapp-test_app")
self.src_dir = Path(__file__).parents[1]
self.root_app_path = self.src_dir / "apps" / "tethysapp-test_app"
self.app_model = TethysApp(name="admin_test_app", package="admin_test_app")
self.app_model.save()
self.proxy_app_model = ProxyApp(
Expand Down
50 changes: 50 additions & 0 deletions tests/unit_tests/test_tethys_apps/test_base/test_app_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
TethysAppSettingNotAssigned,
)
import tethys_apps.base.app_base as tethys_app_base
from tethys_apps.base.url_map import UrlMapBase
from tethys_apps.base.paths import TethysPath
from tethys_apps.base.permissions import Permission, PermissionGroup
from ... import UserFactory
Expand Down Expand Up @@ -1543,3 +1544,52 @@ def test_remove_from_db_2(self, mock_ta, mock_log):

# Check tethys log error
mock_log.error.assert_called()

def test_navigation_links_not_auto(self):
app = tethys_app_base.TethysAppBase()
app.nav_links = ["test", "1", "2", "3"]
links = app.navigation_links
self.assertListEqual(links, app.nav_links)

def test_navigation_links_auto_excluded_page(self):
app = tethys_app_base.TethysAppBase()
app.nav_links = "auto"
app.index = "home"
app.root_url = "test-app"

app._registered_url_maps = [
UrlMapBase(
name="exclude_page",
url="",
controller=None,
title="Exclude Page",
index=-1,
),
UrlMapBase(
name="last_page", url="", controller=None, title="Last Page", index=3
),
UrlMapBase(
name="third_page", url="", controller=None, title="Third Page", index=2
),
UrlMapBase(
name="second_page",
url="",
controller=None,
title="Second Page",
index=1,
),
UrlMapBase(name="home", url="", controller=None, title="Home", index=0),
]

links = app.navigation_links

self.assertListEqual(
links,
[
{"title": "Home", "href": "/apps/test-app/"},
{"title": "Second Page", "href": "/apps/test-app/second-page/"},
{"title": "Third Page", "href": "/apps/test-app/third-page/"},
{"title": "Last Page", "href": "/apps/test-app/last-page/"},
],
)
self.assertEqual(links, app.nav_links)
4 changes: 2 additions & 2 deletions tests/unit_tests/test_tethys_apps/test_base/test_consumer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import json
import asyncio
from os import environ

from tethys_sdk.testing import TethysTestCase
from channels.testing import WebsocketCommunicator
Expand All @@ -15,7 +15,7 @@ def test_consumer(self):
asyncio.set_event_loop(event_loop)

async def run_test():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tethys_portal.settings")
environ.setdefault("DJANGO_SETTINGS_MODULE", "tethys_portal.settings")
settings.CHANNEL_LAYERS = {}

communicator = WebsocketCommunicator(
Expand Down
Loading

0 comments on commit 6d524e5

Please sign in to comment.