Skip to content

Commit f8f094e

Browse files
committed
skeleton of django installable app
1 parent 4bcd9bf commit f8f094e

File tree

22 files changed

+177
-41
lines changed

22 files changed

+177
-41
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Django IDOM Build Artifacts
2+
src/django_idom/static/js
3+
14
# Django #
25
logs
36
*.log

MANIFEST.in

Whitespace-only changes.

setup.py

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1-
import os
1+
from __future__ import print_function
2+
3+
import pipes
4+
import shutil
5+
import subprocess
26
import sys
7+
import traceback
8+
from distutils import log
9+
from distutils.command.build import build # type: ignore
10+
from distutils.command.sdist import sdist # type: ignore
311
from pathlib import Path
412

513
from setuptools import find_packages, setup
14+
from setuptools.command.develop import develop
15+
16+
17+
if sys.platform == "win32":
18+
from subprocess import list2cmdline
19+
else:
20+
21+
def list2cmdline(cmd_list):
22+
return " ".join(map(pipes.quote, cmd_list))
623

724

825
# the name of the project
@@ -31,6 +48,7 @@
3148
"license": "MIT",
3249
"platforms": "Linux, Mac OS X, Windows",
3350
"keywords": ["interactive", "widgets", "DOM", "React"],
51+
"include_package_data": True,
3452
"zip_safe": False,
3553
"classifiers": [
3654
"Framework :: Django",
@@ -52,14 +70,14 @@
5270
# Library Version
5371
# -----------------------------------------------------------------------------
5472

55-
with open(os.path.join(package_dir, "__init__.py")) as f:
56-
for line in f.read().split("\n"):
57-
if line.startswith("__version__ = "):
58-
package["version"] = eval(line.split("=", 1)[1])
59-
break
60-
else:
61-
print("No version found in %s/__init__.py" % package_dir)
62-
sys.exit(1)
73+
74+
for line in (package_dir / "__init__.py").read_text().split("\n"):
75+
if line.startswith("__version__ = "):
76+
package["version"] = eval(line.split("=", 1)[1])
77+
break
78+
else:
79+
print("No version found in %s/__init__.py" % package_dir)
80+
sys.exit(1)
6381

6482

6583
# -----------------------------------------------------------------------------
@@ -87,6 +105,42 @@
87105
package["long_description_content_type"] = "text/markdown"
88106

89107

108+
# ----------------------------------------------------------------------------
109+
# Build Javascript
110+
# ----------------------------------------------------------------------------
111+
112+
113+
def build_javascript_first(cls):
114+
class Command(cls):
115+
def run(self):
116+
log.info("Installing Javascript...")
117+
try:
118+
js_dir = str(src_dir / "js")
119+
npm = shutil.which("npm") # this is required on windows
120+
if npm is None:
121+
raise RuntimeError("NPM is not installed.")
122+
for args in (f"{npm} install", f"{npm} run build"):
123+
args_list = args.split()
124+
log.info(f"> {list2cmdline(args_list)}")
125+
subprocess.run(args_list, cwd=js_dir, check=True)
126+
except Exception:
127+
log.error("Failed to install Javascript")
128+
log.error(traceback.format_exc())
129+
raise
130+
else:
131+
log.info("Successfully installed Javascript")
132+
super().run()
133+
134+
return Command
135+
136+
137+
package["cmdclass"] = {
138+
"sdist": build_javascript_first(sdist),
139+
"build": build_javascript_first(build),
140+
"develop": build_javascript_first(develop),
141+
}
142+
143+
90144
# -----------------------------------------------------------------------------
91145
# Install It
92146
# -----------------------------------------------------------------------------

src/django_idom/app_settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.conf import settings
2+
3+
IDOM_WEBSOCKET_URL = getattr(settings, "IDOM_WEBSOCKET_URL", "_idom/")

src/django_idom/static/js/idom.js

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
<!-- The importable IDOM JS -->
2-
<script src="{% static 'js/idom.js' %}" crossorigin="anonymous"></script>
2+
<script src="{% static 'js/idom.js' %}" crossorigin="anonymous"></script>
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
<!-- Allows for making the IDOM root object the Django way
22
Developers will often opt not to use this,
33
but having this makes getting started a little bit easier to explain -->
4-
<div id="{{ html_id }}"></div>
4+
<div id="{{ idom_view_id }}"></div>
5+
<script type="module" crossorigin="anonymous">
6+
import { mountToElement } from "{% static 'js/idom.js' %}";
7+
mountViewToElement("{{ idom_websocket_url }}", "{{ idom_view_id }}");
8+
</script>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div id="{{ idom_view_id }}"></div>
2+
<script type="module" crossorigin="anonymous">
3+
import { mountToElement } from "{% static 'js/idom.js' %}";
4+
mountViewToElement("{{ idom_websocket_url }}", "{{ idom_view_id }}");
5+
</script>

src/django_idom/templatetags/idom.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from django import template
22

3+
from django_idom.app_settings import IDOM_WEBSOCKET_URL
4+
35

46
register = template.Library()
57

@@ -10,7 +12,6 @@ def idom_scripts():
1012
pass
1113

1214

13-
# Template tag that renders an empty idom root object
14-
@register.inclusion_tag("idom/root.html")
15-
def idom_view(html_id):
16-
return {"html_id": html_id}
15+
@register.inclusion_tag("idom/view.html")
16+
def idom_view(view_id):
17+
return {"idom_websocket_url": IDOM_WEBSOCKET_URL, "view_id": view_id}

src/django_idom/view_loader.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import logging
2+
from importlib import import_module
3+
from pathlib import Path
4+
from typing import Dict
5+
6+
from django.conf import settings
7+
from idom.core.proto import ComponentConstructor
8+
9+
10+
ALL_VIEWS: Dict[str, ComponentConstructor] = {}
11+
logger = logging.getLogger(__name__)
12+
13+
for app_name in settings.INSTALLED_APPS:
14+
app_mod = import_module(app_name)
15+
if not hasattr(app_mod, "idom"):
16+
continue
17+
18+
for idom_view_path in Path(app_mod.__file__).iterdir():
19+
if idom_view_path.suffix == ".py" and idom_view_path.is_file():
20+
idom_view_mod_name = ".".join([app_name, "idom", idom_view_path.stem])
21+
idom_view_mod = import_module(idom_view_mod_name)
22+
23+
if hasattr(idom_view_mod, "Root") and callable(idom_view_mod.Root):
24+
ALL_VIEWS[idom_view_mod_name] = idom_view_mod.Root
25+
else:
26+
logger.warning(
27+
f"Expected module {idom_view_mod_name} to expose a 'Root' "
28+
" attribute that is an IDOM component."
29+
)

0 commit comments

Comments
 (0)