Skip to content

v2.1.0 #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,28 @@ Using the following categories, list your changes in this order:

- Nothing (yet)

## [2.0.1]- 2022-10-18
## [2.1.0] - 2022-11-01

## Changed

- Minimum `channels` version is now `4.0.0`.

### Fixed

- Change type hint on `view_to_component` callable to have `request` argument be optional.
- Change type hint on `view_to_component` to represent it as a decorator with paranthesis (ex `@view_to_component(compatibility=True)`)

## Security

- Add note to docs about potential information exposure via `view_to_component` when using `compatibility=True`.

## [2.0.1] - 2022-10-18

### Fixed

- Ability to use `key=...` parameter on all prefabricated components
- Ability to use `key=...` parameter on all prefabricated components.

## [2.0.0]- 2022-10-17
## [2.0.0] - 2022-10-17

### Added

Expand Down Expand Up @@ -155,7 +170,8 @@ Using the following categories, list your changes in this order:

- Support for IDOM within the Django

[unreleased]: https://github.com/idom-team/django-idom/compare/2.0.1...HEAD
[unreleased]: https://github.com/idom-team/django-idom/compare/2.1.0...HEAD
[2.1.0]: https://github.com/idom-team/django-idom/compare/2.0.1...2.1.0
[2.0.1]: https://github.com/idom-team/django-idom/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/idom-team/django-idom/compare/1.2.0...2.0.0
[1.2.0]: https://github.com/idom-team/django-idom/compare/1.1.0...1.2.0
Expand Down
23 changes: 17 additions & 6 deletions docs/src/contribute/running-tests.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
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:
This repo uses [Nox](https://nox.thea.codes/en/stable/) to run tests. For a full test of available scripts run `nox -l`.

If you plan to run tests, you'll need to install the following dependencies first:

- [Python 3.8+](https://www.python.org/downloads/)
- [Git](https://git-scm.com/downloads)

Once done, you should clone this repository:

```bash
git clone https://github.com/idom-team/django-idom.git
cd django-idom
pip install -r ./requirements/test-run.txt --upgrade
```

Then, by running the command below you can run the full test suite:

```
nox -s test
```

If you do not want to run the tests in the background:
Or, if you want to run the tests in the foreground:

```
nox -s test -- --headed
```

!!! warning "Most tests will not run on Windows"

Due to [bugs within Django Channels](https://github.com/django/channels/issues/1207), functional tests are not run on Windows. In order for Windows users to test Django-IDOM functionality, you will need to run tests via [Windows Subsystem for Linux](https://code.visualstudio.com/docs/remote/wsl).
121 changes: 82 additions & 39 deletions docs/src/features/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## View To Component

Convert any Django view into a IDOM component by usng this decorator. Compatible with sync/async [Function Based Views](https://docs.djangoproject.com/en/dev/topics/http/views/) and [Class Based Views](https://docs.djangoproject.com/en/dev/topics/class-based-views/).
Convert any Django view into a IDOM component by usng this decorator. Compatible with [Function Based Views](https://docs.djangoproject.com/en/dev/topics/http/views/) and [Class Based Views](https://docs.djangoproject.com/en/dev/topics/class-based-views/). Views can be sync or async.

=== "components.py"

Expand Down Expand Up @@ -41,11 +41,42 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible
| --- | --- |
| `_ViewComponentConstructor` | A function that takes `request: HttpRequest | None, *args: Any, key: Key | None, **kwargs: Any` and returns an IDOM component. |

??? warning "Existing limitations"
??? Warning "Potential information exposure when using `compatibility = True`"

When using `compatibility` mode, IDOM automatically exposes a URL to your view.

It is your responsibility to ensure priveledged information is not leaked via this method.

This can be done via directly writing conditionals into your view, or by adding decorators such as [user_passes_test](https://docs.djangoproject.com/en/dev/topics/auth/default/#django.contrib.auth.decorators.user_passes_test) to your views prior to using `view_to_component`.

=== "Function Based View"

```python
...

@view_to_component(compatibility=True)
@user_passes_test(lambda u: u.is_superuser)
def example_view(request):
...
```

=== "Class Based View"

```python
...

@view_to_component(compatibility=True)
@method_decorator(user_passes_test(lambda u: u.is_superuser), name="dispatch")
class ExampleView(TemplateView):
...
```

??? info "Existing limitations"

There are currently several limitations of using `view_to_component` that may be resolved in a future version of `django_idom`.

- Requires manual intervention to change request methods beyond `GET`.
- IDOM events cannot conveniently be attached to converted view HTML.
- Does not currently load any HTML contained with a `<head>` tag
- Has no option to automatically intercept local anchor link (ex. `#!html <a href='example/'></a>`) click events

Expand Down Expand Up @@ -77,87 +108,95 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible

??? question "How do I transform views from external libraries?"

=== "components.py"
In order to convert external views, you can utilize `view_to_component` as a function, rather than a decorator.

In order to convert external views, you can utilize `view_to_component` as a function, rather than a decorator.
=== "components.py"

```python linenums="1"
from idom import component, html
from django.http import HttpResponse
from django_idom.components import view_to_component
from some_library.views import example_view

converted_view = view_to_component(example_view)
example_vtc = view_to_component(example_view)

@component
def my_component():
return html.div(
converted_view(),
example_vtc(),
)
```

??? question "How do I provide `args` and `kwargs` to a view?"
??? question "How do I provide `request`, `args`, and `kwargs` to a view?"

You can use the `args` and `kwargs` parameters to provide positional and keyworded arguments to a view.
<font size="4">**`Request`**</font>

You can use the `request` parameter to provide the view a custom request object.

=== "components.py"

```python linenums="1"
from idom import component, html
from django.http import HttpResponse
from django.http import HttpResponse, HttpRequest
from django_idom.components import view_to_component

example_request = HttpRequest()
example_request.method = "PUT"

@view_to_component
def hello_world_view(request, arg1, arg2, key1=None, key2=None):
return HttpResponse(f"Hello World! {arg1} {arg2} {key1} {key2}")
def hello_world_view(request):
return HttpResponse(f"Hello World! {request.method}")

@component
def my_component():
return html.div(
hello_world_view(
None, # Your request object (optional)
"value_1",
"value_2",
key1="abc",
key2="123",
example_request,
),
)
```

??? question "How do I provide a custom `request` object to a view?"
---

You can use the `request` parameter to provide the view a custom request object.
<font size="4">**`args` and `kwargs`**</font>

You can use the `args` and `kwargs` parameters to provide positional and keyworded arguments to a view.

=== "components.py"

```python linenums="1"
from idom import component, html
from django.http import HttpResponse, HttpRequest
from django.http import HttpResponse
from django_idom.components import view_to_component

example_request = HttpRequest()
example_request.method = "PUT"

@view_to_component
def hello_world_view(request):
return HttpResponse(f"Hello World! {request.method}")
def hello_world_view(request, arg1, arg2, key1=None, key2=None):
return HttpResponse(f"Hello World! {arg1} {arg2} {key1} {key2}")

@component
def my_component():
return html.div(
hello_world_view(
example_request,
None, # Your request object (optional)
"value_1",
"value_2",
key1="abc",
key2="123",
),
)
```

??? question "What is `compatibility` mode?"
??? question "How do I use `strict_parseing`, `compatibility`, and `transforms`?"

For views that rely on HTTP responses other than `GET` (such as `PUT`, `POST`, `PATCH`, etc), you should consider using compatibility mode to render your view within an iframe.
<font size="4">**`strict_parsing`**</font>

Any view can be rendered within compatibility mode. However, the `transforms`, `strict_parsing`, `request`, `args`, and `kwargs` arguments do not apply to compatibility mode.
By default, an exception will be generated if your view's HTML does not perfectly adhere to HTML5.

Please note that by default the iframe is unstyled, and thus won't look pretty until you add some CSS.
However, there are some circumstances where you may not have control over the original HTML, so you may be unable to fix it. Or you may be relying on non-standard HTML tags such as `#!html <my-tag> Hello World </my-tag>`.

In these scenarios, you may want to rely on best-fit parsing by setting the `strict_parsing` parameter to `False`.

Note that best-fit parsing is designed to be similar to how web browsers would handle non-standard or broken HTML.

=== "components.py"

Expand All @@ -166,9 +205,9 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible
from django.http import HttpResponse
from django_idom.components import view_to_component

@view_to_component(compatibility=True)
@view_to_component(strict_parsing=False)
def hello_world_view(request):
return HttpResponse("Hello World!")
return HttpResponse("<my-tag> Hello World </my-tag>")

@component
def my_component():
Expand All @@ -177,13 +216,17 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible
)
```

??? question "What is `strict_parsing`?"

By default, an exception will be generated if your view's HTML does not perfectly adhere to HTML5.

However, there are some circumstances where you may not have control over the original HTML, so you may be unable to fix it. Or you may be relying on non-standard HTML tags such as `#!html <my-tag> Hello World </my-tag>`.
---

In these scenarios, you may want to rely on best-fit parsing by setting the `strict_parsing` parameter to `False`.
<font size="4">**`compatibility`**</font>

For views that rely on HTTP responses other than `GET` (such as `PUT`, `POST`, `PATCH`, etc), you should consider using compatibility mode to render your view within an iframe.

Any view can be rendered within compatibility mode. However, the `transforms`, `strict_parsing`, `request`, `args`, and `kwargs` arguments do not apply to compatibility mode.

Please note that by default the iframe is unstyled, and thus won't look pretty until you add some CSS.

=== "components.py"

Expand All @@ -192,9 +235,9 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible
from django.http import HttpResponse
from django_idom.components import view_to_component

@view_to_component(strict_parsing=False)
@view_to_component(compatibility=True)
def hello_world_view(request):
return HttpResponse("<my-tag> Hello World </my-tag>")
return HttpResponse("Hello World!")

@component
def my_component():
Expand All @@ -203,9 +246,9 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible
)
```

Note that best-fit parsing is very similar to how web browsers will handle broken HTML.
---

??? question "What is `transforms`?"
<font size="4">**`transforms`**</font>

After your view has been turned into [VDOM](https://idom-docs.herokuapp.com/docs/reference/specifications.html#vdom) (python dictionaries), `view_to_component` will call your `transforms` functions on every VDOM node.

Expand Down
12 changes: 6 additions & 6 deletions docs/src/features/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,6 @@ You can expect this hook to provide strings such as `/idom/my_path`.
return html.div(my_location)
```

??? info "This hook's behavior will be changed in a future update"

This hook will be updated to return the browser's currently active path. This change will come in alongside IDOM URL routing support.

Check out [idom-team/idom-router#2](https://github.com/idom-team/idom-router/issues/2) for more information.

??? example "See Interface"

<font size="4">**Parameters**</font>
Expand All @@ -342,6 +336,12 @@ You can expect this hook to provide strings such as `/idom/my_path`.
| --- | --- |
| `Location` | A object containing the current URL's `pathname` and `search` query. |

??? info "This hook's behavior will be changed in a future update"

This hook will be updated to return the browser's currently active path. This change will come in alongside IDOM URL routing support.

Check out [idom-team/idom-router#2](https://github.com/idom-team/idom-router/issues/2) for more information.

## Use Origin

This is a shortcut that returns the Websocket's `origin`.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/getting-started/learn-more.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ Additionally, the vast majority of tutorials/guides you find for React can be ap

| Learn More |
| --- |
| [Django-IDOM Advanced Usage](../features/components.md){ .md-button } [IDOM Hooks, Events, and More](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button } [Ask Questions on GitHub Discussions](https://github.com/idom-team/idom/discussions){ .md-button .md-button--primary } |
| [Django-IDOM Advanced Usage](../features/components.md){ .md-button } [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button } [Ask Questions on GitHub Discussions](https://github.com/idom-team/idom/discussions){ .md-button .md-button--primary } |
4 changes: 2 additions & 2 deletions docs/src/installation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ In your settings you'll need to add `django_idom` to [`INSTALLED_APPS`](https://

Django-IDOM requires ASGI in order to use Websockets.

If you haven't enabled ASGI on your **Django project** yet, you'll need to add `channels` to `INSTALLED_APPS` and set your `ASGI_APPLICATION` variable.
If you haven't enabled ASGI on your **Django project** yet, you'll need to install `channels[daphne]`, add `daphne` to `INSTALLED_APPS`, then set your `ASGI_APPLICATION` variable.

Read the [Django Channels Docs](https://channels.readthedocs.io/en/stable/installation.html) for more info.

=== "settings.py"

```python linenums="1"
INSTALLED_APPS = [
"channels",
"daphne",
...
]
ASGI_APPLICATION = "example_project.asgi.application"
Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_suite(session: Session) -> None:
def test_types(session: Session) -> None:
install_requirements_file(session, "check-types")
install_requirements_file(session, "pkg-deps")
session.run("mypy", "--show-error-codes", "src/django_idom")
session.run("mypy", "--show-error-codes", "src/django_idom", "tests/test_app")


@nox.session
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ ignore_missing_imports = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
check_untyped_defs = true
2 changes: 1 addition & 1 deletion requirements/pkg-deps.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
channels >=3.0.0
channels >=4.0.0
idom >=0.40.2, <0.41.0
aiofile >=3.0
typing_extensions
2 changes: 1 addition & 1 deletion src/django_idom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django_idom.websocket.paths import IDOM_WEBSOCKET_PATH


__version__ = "2.0.1"
__version__ = "2.1.0"
__all__ = [
"IDOM_WEBSOCKET_PATH",
"IdomWebsocket",
Expand Down
Loading