Skip to content

Commit

Permalink
v1.0.0 (#73)
Browse files Browse the repository at this point in the history
- Change Django IDOM version to 1.0.0
- Unpins top boundary on `channels` and `aiofile`
- Bumps IDOM's minimum version
- Use f-strings when possible
- Use `contexlib.suppress` when possible
- Implement `use_websocket`, `use_scope`, and `use_location`
- Remove `websocket` parameter from components (replaced by `use_websocket` hook)
- Create formal docs
- Rename `idom_component` template tag to `component` in preparation for repo rename
- Logging for when a component fails to import, or if no components were found within Django.
  • Loading branch information
Archmonger authored May 31, 2022
1 parent 83fcb8d commit a0a6555
Show file tree
Hide file tree
Showing 30 changed files with 803 additions and 232 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/publish-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Publish Docs
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.x
- run: pip install requirements/build-docs.txt
- run: mkdocs gh-deploy --force
73 changes: 48 additions & 25 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
<!--attr-start-->

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

<!--attr-end-->

<!--
Types of changes are to be listed in this order
Expand All @@ -15,72 +18,92 @@ Types of changes are to be listed in this order
- "Security" in case of vulnerabilities.
-->

<!--changelog-start-->

## [Unreleased]

- Nothing (yet)
- Nothing (yet)

## [1.0.0] - 2022-05-22

### Added

- Django-specific hooks! `use_websocket`, `use_scope`, and `use_location` are now available within the `django_idom.hooks` module.
- Documentation has been placed into a formal docs webpage.
- Logging for when a component fails to import, or if no components were found within Django.

### Changed

- `idom_component` template tag has been renamed to `component`
- Bumped the minimum IDOM version to 0.38.0

### Removed

- `websocket` parameter for components has been removed. Functionally, it is replaced with `django_idom.hooks.use_websocket`.

## [0.0.5] - 2022-04-04

### Changed

- Bumped the minimum IDOM version to 0.37.2
- Bumped the minimum IDOM version to 0.37.2

### Fixed

- ModuleNotFoundError: No module named `idom.core.proto` caused by IDOM 0.37.2
- ModuleNotFoundError: No module named `idom.core.proto` caused by IDOM 0.37.2

## [0.0.4] - 2022-03-05

### Changed

- Bumped the minimum IDOM version to 0.37.1
- Bumped the minimum IDOM version to 0.37.1

## [0.0.3] - 2022-02-19

### Changed

- Bumped the minimum IDOM version to 0.36.3
- Bumped the minimum IDOM version to 0.36.3

## [0.0.2] - 2022-01-30

### Added

- Ability to declare the HTML class of the top-level component `div`
- `name = ...` parameter to IDOM HTTP paths for use with `django.urls.reverse()`
- Cache versioning to automatically invalidate old web module files from the cache backend
- Automatic pre-population of the IDOM component registry
- Type hinting for `IdomWebsocket`
- Ability to declare the HTML class of the top-level component `div`
- `name = ...` parameter to IDOM HTTP paths for use with `django.urls.reverse()`
- Cache versioning to automatically invalidate old web module files from the cache backend
- Automatic pre-population of the IDOM component registry
- Type hinting for `IdomWebsocket`

### Changed

- Fetching web modules from disk and/or cache is now fully async
- Static files are now contained within a `django_idom/` parent folder
- Upgraded IDOM to version `0.36.0`
- Minimum Django version required is now `4.0`
- Minimum Python version required is now `3.8`
- Fetching web modules from disk and/or cache is now fully async
- Static files are now contained within a `django_idom/` parent folder
- Upgraded IDOM to version `0.36.0`
- Minimum Django version required is now `4.0`
- Minimum Python version required is now `3.8`

### Removed

- `IDOM_WEB_MODULES_PATH` has been replaced with Django `include(...)`
- `IDOM_WS_MAX_RECONNECT_DELAY` has been renamed to `IDOM_WS_MAX_RECONNECT_TIMEOUT`
- `idom_web_modules` cache backend has been renamed to `idom`
- `IDOM_WEB_MODULES_PATH` has been replaced with Django `include(...)`
- `IDOM_WS_MAX_RECONNECT_DELAY` has been renamed to `IDOM_WS_MAX_RECONNECT_TIMEOUT`
- `idom_web_modules` cache backend has been renamed to `idom`

### Fixed

- Increase test timeout values to prevent false positives
- Windows compatibility for building Django-IDOM
- Increase test timeout values to prevent false positives
- Windows compatibility for building Django-IDOM

### Security

- Fixed potential directory travesal attack on the IDOM web modules URL
- Fixed potential directory travesal attack on the IDOM web modules URL

## [0.0.1] - 2021-08-18

### Added

- Support for IDOM within the Django
- Support for IDOM within the Django

[unreleased]: https://github.com/idom-team/django-idom/compare/0.0.2...HEAD
[unreleased]: https://github.com/idom-team/django-idom/compare/1.0.0...HEAD
[1.0.0]: https://github.com/idom-team/django-idom/compare/0.0.5...1.0.0
[0.0.5]: https://github.com/idom-team/django-idom/compare/0.0.4...0.0.5
[0.0.4]: https://github.com/idom-team/django-idom/compare/0.0.3...0.0.4
[0.0.3]: https://github.com/idom-team/django-idom/compare/0.0.2...0.0.3
Expand Down
201 changes: 48 additions & 153 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,184 +1,79 @@
# Django IDOM &middot; [![Tests](https://github.com/idom-team/django-idom/workflows/Test/badge.svg?event=push)](https://github.com/idom-team/django-idom/actions?query=workflow%3ATest) [![PyPI Version](https://img.shields.io/pypi/v/django-idom.svg)](https://pypi.python.org/pypi/django-idom) [![License](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/idom-team/django-idom/blob/main/LICENSE)

`django-idom` allows Django to integrate with [IDOM](https://github.com/idom-team/idom), a reactive Python web framework for building **interactive websites without needing a single line of Javascript**.

**You can try IDOM now in a Jupyter Notebook:**
<a
target="_blank"
href="https://mybinder.org/v2/gh/idom-team/idom-jupyter/main?filepath=notebooks%2Fintroduction.ipynb">
<img
alt="Binder"
valign="bottom"
height="21px"
src="https://mybinder.org/badge_logo.svg"/>
</a>

# Quick Example

## `example_app/components.py`

This is where you'll define your [IDOM](https://github.com/idom-team/idom) components. Ultimately though, you should
feel free to organize your component modules as you wish. Any components created will ultimately be referenced
by Python dotted path in `your-template.html`.

```python
from idom import component, html
from django_idom import IdomWebsocket

# Components are CamelCase by ReactJS convention
@component
def Hello(websocket: IdomWebsocket, greeting_recipient: str):
return html.h1(f"Hello {greeting_recipient}!")
```

## [`example_app/templates/your-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/)

In your templates, you may add IDOM components into your HTML by using the `idom_component`
template tag. This tag requires the dotted path to the component function.

Additonally, you can pass in keyworded arguments into your component function.

In context this will look a bit like the following...

```jinja
{% load idom %}
<!DOCTYPE html>
<html>
<head>
<title>Example Project</title>
</head>
<body>
{% idom_component "my_django_project.example_app.components.Hello" greeting_recipient="World" %}
</body>
</html>
```

# Installation

Install `django-idom` via pip.
<!--header-start-->

```bash
pip install django-idom
```

You'll also need to modify a few files in your Django project.

## [`settings.py`](https://docs.djangoproject.com/en/dev/topics/settings/)

In your settings you'll need to add `channels` and `django_idom` to [`INSTALLED_APPS`](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-INSTALLED_APPS).

```python
INSTALLED_APPS = [
...,
"channels",
"django_idom",
]

# Ensure ASGI_APPLICATION is set properly based on your project name!
ASGI_APPLICATION = "my_django_project.asgi.application"
```

**Optional:** You can also configure IDOM settings.
# Django IDOM &middot; [![Tests](https://github.com/idom-team/django-idom/workflows/Test/badge.svg?event=push)](https://github.com/idom-team/django-idom/actions?query=workflow%3ATest) [![PyPI Version](https://img.shields.io/pypi/v/django-idom.svg)](https://pypi.python.org/pypi/django-idom) [![License](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/idom-team/django-idom/blob/main/LICENSE)

```python
# If "idom" cache is not configured, then we'll use "default" instead
CACHES = {
"idom": {"BACKEND": ...},
}
<!--header-end-->
<!--intro-start-->

# Maximum seconds between two reconnection attempts that would cause the client give up.
# 0 will disable reconnection.
IDOM_WS_MAX_RECONNECT_TIMEOUT: int = 604800
Django-IDOM connects your project to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!**

# The URL for IDOM to serve websockets
IDOM_WEBSOCKET_URL: str = "idom/"
```
Following ReactJS styling, web elements are combined into [reusable "components"](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/your-first-components/index.html#parametrizing-components). These components can utilize [hooks](https://idom-docs.herokuapp.com/docs/reference/hooks-api.html) and [events](https://idom-docs.herokuapp.com/docs/guides/adding-interactivity/responding-to-events/index.html#async-event-handlers) to create infinitely complex web pages.

## [`urls.py`](https://docs.djangoproject.com/en/dev/topics/http/urls/)
When needed, IDOM can [use components directly from NPM](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#dynamically-loaded-components). For additional flexibility, components can also be [fully developed in JavaScript](https://idom-docs.herokuapp.com/docs/guides/escape-hatches/javascript-components.html#custom-javascript-components).

Add IDOM HTTP paths to your `urlpatterns`.
Any Python web framework with Websockets can support IDOM. See below for what frameworks are supported out of the box.

```python
from django.urls import include, path
| Supported Frameworks | Supported Frameworks (External) |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`Flask`, `FastAPI`, `Sanic`, `Tornado`](https://idom-docs.herokuapp.com/docs/guides/getting-started/installing-idom.html#officially-supported-servers) | [`Django`](https://github.com/idom-team/django-idom), [`Plotly-Dash`](https://github.com/idom-team/idom-dash), [`Jupyter`](https://github.com/idom-team/idom-jupyter) |

urlpatterns = [
path("idom/", include("django_idom.http.urls")),
...
]
```
<!--intro-end-->

## [`asgi.py`](https://docs.djangoproject.com/en/dev/howto/deployment/asgi/)
---

Register IDOM's websocket using `IDOM_WEBSOCKET_PATH`.
# At a Glance

_Note: If you do not have an `asgi.py`, follow the [`channels` installation guide](https://channels.readthedocs.io/en/stable/installation.html)._
## `my_app/components.py`

```python
<!--py-header-start-->

import os
from django.core.asgi import get_asgi_application
You'll need a file to define your [IDOM](https://github.com/idom-team/idom) components. We recommend creating a `components.py` file within your chosen **Django app** to start out.

# Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name!
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_project.settings")
django_asgi_app = get_asgi_application()
<!--py-header-end-->
<!--py-code-start-->

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.sessions import SessionMiddlewareStack
from django_idom import IDOM_WEBSOCKET_PATH
```python title="components.py"
from idom import component, html

application = ProtocolTypeRouter(
{
"http": django_asgi_app,
"websocket": SessionMiddlewareStack(
AuthMiddlewareStack(URLRouter([IDOM_WEBSOCKET_PATH]))
),
}
)
@component
def HelloWorld(recipient: str):
return html.h1(f"Hello {recipient}!")
```

# Developer Guide
<!--py-code-end-->

If you plan to make code changes to this repository, you'll need to install the
following dependencies first:
## [`my_app/templates/my-template.html`](https://docs.djangoproject.com/en/dev/topics/templates/)

- [NPM](https://docs.npmjs.com/try-the-latest-stable-version-of-npm) for
installing and managing Javascript
- [ChromeDriver](https://chromedriver.chromium.org/downloads) for testing with
[Selenium](https://www.seleniumhq.org/)
<!--html-header-start-->

Once done, you should clone this repository:
In your **Django app**'s HTML located within your `templates` folder, you can now embed your IDOM component using the `component` template tag. Within this tag, you will need to type in your dotted path to the component function as the first argument.

```bash
git clone https://github.com/idom-team/django-idom.git
cd django-idom
```

Then, by running the command below you can:
Additonally, you can pass in keyword arguments into your component function. For example, after reading the code below, pay attention to how the function definition for `HelloWorld` (_in the previous example_) accepts a `recipient` argument.

- Install an editable version of the Python code
<!--html-header-end-->
<!--html-code-start-->

- Download, build, and install Javascript dependencies

```bash
pip install -e . -r requirements.txt
```jinja title="my-template.html"
{% load idom %}
<!DOCTYPE html>
<html>
<body>
{% component "example_project.my_app.components.HelloWorld" recipient="World" %}
</body>
</html>
```

Finally, to verify that everything is working properly, you'll want to run the test suite.
<!--html-code-end-->

## Running The Tests
---

This repo uses [Nox](https://nox.thea.codes/en/stable/) to run scripts which can
be found in `noxfile.py`. For a full test of available scripts run `nox -l`. To run the full test suite simple execute:
# Resources

```
nox -s test
```
<!--resources-start-->

To run the tests using a headless browser:
Follow the links below to find out more about this project.

```
nox -s test -- --headless
```
- [Try it Now](https://mybinder.org/v2/gh/idom-team/idom-jupyter/main?urlpath=lab/tree/notebooks/introduction.ipynb) - Check out IDOM in a Jupyter Notebook.
- [Documentation](https://idom-team.github.io/django-idom) - Learn how to install, run, and use IDOM.
- [Community Forum](https://github.com/idom-team/idom/discussions) - Ask questions, share ideas, and show off projects.
<!--resources-end-->
11 changes: 11 additions & 0 deletions docs/changelog/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
hide:
- navigation
- toc
---

!!! note "Attribution"

{% include-markdown "../../CHANGELOG.md" start="<!--attr-start-->" end="<!--attr-end-->" %}

{% include-markdown "../../CHANGELOG.md" start="<!--changelog-start-->" %}
Loading

0 comments on commit a0a6555

Please sign in to comment.