From 101f768df4710d839c4124a5c094d30803881ee1 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 18 Sep 2023 23:04:54 -0700 Subject: [PATCH 01/13] Docs readability enhancements --- docs/includes/orm.md | 4 +- docs/python/use-mutation-thread-sensitive.py | 32 +++++++ docs/python/use-query-async.py | 22 ----- docs/src/reference/components.md | 28 +++--- docs/src/reference/decorators.md | 2 +- docs/src/reference/hooks.md | 96 +++++++++++++------- docs/src/reference/settings.md | 2 +- docs/src/reference/template-tag.md | 2 +- docs/src/reference/utils.md | 4 +- mkdocs.yml | 3 + 10 files changed, 118 insertions(+), 77 deletions(-) create mode 100644 docs/python/use-mutation-thread-sensitive.py delete mode 100644 docs/python/use-query-async.py diff --git a/docs/includes/orm.md b/docs/includes/orm.md index fafb6226..74f966c0 100644 --- a/docs/includes/orm.md +++ b/docs/includes/orm.md @@ -2,12 +2,12 @@ Due to Django's ORM design, database queries must be deferred using hooks. Otherwise, you will see a `#!python SynchronousOnlyOperation` exception. -These `#!python SynchronousOnlyOperation` exceptions may be resolved in a future version of Django containing an asynchronous ORM. However, it is best practice to always perform ORM calls in the background via hooks. +These `#!python SynchronousOnlyOperation` exceptions may be removed in a future version of Django. However, it is best practice to always perform IO operations (such as ORM queries) via hooks to prevent performance issues. -By default, automatic recursive fetching of `#!python ManyToMany` or `#!python ForeignKey` fields is enabled within the default `#!python QueryOptions.postprocessor`. This is needed to prevent `#!python SynchronousOnlyOperation` exceptions when accessing these fields within your ReactPy components. +By default, automatic recursive fetching of `#!python ManyToMany` or `#!python ForeignKey` fields is enabled within the `DjangoQueryPostprocessor`. This is needed to prevent `#!python SynchronousOnlyOperation` exceptions when accessing these fields within your ReactPy components. diff --git a/docs/python/use-mutation-thread-sensitive.py b/docs/python/use-mutation-thread-sensitive.py new file mode 100644 index 00000000..ec07377e --- /dev/null +++ b/docs/python/use-mutation-thread-sensitive.py @@ -0,0 +1,32 @@ +from reactpy import component, html +from reactpy_django.hooks import use_mutation +from reactpy_django.types import MutationOptions + + +def execute_thread_safe_mutation(): + """This is an example mutation function that does some thread-safe operation.""" + pass + + +@component +def my_component(): + item_mutation = use_mutation( + MutationOptions(thread_sensitive=False), + execute_thread_safe_mutation, + ) + + def submit_event(event): + if event["key"] == "Enter": + item_mutation.execute(text=event["target"]["value"]) + + if item_mutation.loading or item_mutation.error: + mutation_status = html.h2("Doing something...") + elif item_mutation.error: + mutation_status = html.h2("Error!") + else: + mutation_status = html.h2("Done.") + + return html.div( + html.input({"type": "text", "onKeyDown": submit_event}), + mutation_status, + ) diff --git a/docs/python/use-query-async.py b/docs/python/use-query-async.py deleted file mode 100644 index e546ed59..00000000 --- a/docs/python/use-query-async.py +++ /dev/null @@ -1,22 +0,0 @@ -from channels.db import database_sync_to_async -from example.models import TodoItem -from reactpy import component, html -from reactpy_django.hooks import use_query - - -async def get_items(): - return await database_sync_to_async(TodoItem.objects.all)() - - -@component -def todo_list(): - item_query = use_query(get_items) - - if item_query.loading: - rendered_items = html.h2("Loading...") - elif item_query.error or not item_query.data: - rendered_items = html.h2("Error when loading!") - else: - rendered_items = html.ul([html.li(item, key=item) for item in item_query.data]) - - return html.div("Rendered items: ", rendered_items) diff --git a/docs/src/reference/components.md b/docs/src/reference/components.md index d3f235da..85199f27 100644 --- a/docs/src/reference/components.md +++ b/docs/src/reference/components.md @@ -177,7 +177,7 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering. | Name | Type | Description | Default | | --- | --- | --- | --- | - | `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on a `static` template tag. | N/A | + | `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on Django's `#!jinja {% static %}` template tag. | N/A | | `#!python key` | `#!python Key | None` | A key to uniquely identify this component which is unique amongst a component's immediate siblings | `#!python None` | **Returns** @@ -186,10 +186,6 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering. | --- | --- | | `#!python Component` | A ReactPy component. | -??? question "Should I put `#!python django_css` at the top of my HTML?" - - Yes, if the stylesheet contains styling for your component. - ??? question "Can I load static CSS using `#!python html.link` instead?" While you can load stylesheets with `#!python html.link`, keep in mind that loading this way **does not** ensure load order. Thus, your stylesheet will be loaded after your component is displayed. This would likely cause unintended visual behavior, so use this at your own discretion. @@ -204,7 +200,7 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering. `#!python django_css` can only be used with local static files. - For external CSS, substitute `#!python django_css` with `#!python html.link`. + For external CSS, you should use `#!python html.link`. ```python {% include "../../python/django-css-external-link.py" %} @@ -212,14 +208,18 @@ Allows you to defer loading a CSS stylesheet until a component begins rendering. ??? question "Why not load my CSS in `#!html
`?" - Traditionally, stylesheets are loaded in your `#!html ` using the `#!jinja {% load static %}` template tag. + Traditionally, stylesheets are loaded in your `#!html ` using Django's `#!jinja {% static %}` template tag. - To help improve webpage load times, you can use the `#!python django_css` component to defer loading your stylesheet until it is needed. + However, to help improve webpage load times you can use this `#!python django_css` component to defer loading your stylesheet until it is needed. ## Django JS Allows you to defer loading JavaScript until a component begins rendering. This JavaScript must be stored within [Django's static files](https://docs.djangoproject.com/en/dev/howto/static-files/). +!!! warning "Pitfall" + + Be mindful of load order! If your JavaScript relies on the component existing on the page, you must place `django_js` at the **bottom** of your component. + === "components.py" ```python @@ -232,7 +232,7 @@ Allows you to defer loading JavaScript until a component begins rendering. This | Name | Type | Description | Default | | --- | --- | --- | --- | - | `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on a `static` template tag. | N/A | + | `#!python static_path` | `#!python str` | The path to the static file. This path is identical to what you would use on Django's `#!jinja {% static %}` template tag. | N/A | | `#!python key` | `#!python Key | None` | A key to uniquely identify this component which is unique amongst a component's immediate siblings | `#!python None` | **Returns** @@ -241,10 +241,6 @@ Allows you to defer loading JavaScript until a component begins rendering. This | --- | --- | | `#!python Component` | A ReactPy component. | -??? question "Should I put `#!python django_js` at the bottom of my HTML?" - - Yes, if your scripts are reliant on the contents of the component. - ??? question "Can I load static JavaScript using `#!python html.script` instead?" While you can load JavaScript with `#!python html.script`, keep in mind that loading this way **does not** ensure load order. Thus, your JavaScript will likely be loaded at an arbitrary time after your component is displayed. @@ -259,7 +255,7 @@ Allows you to defer loading JavaScript until a component begins rendering. This `#!python django_js` can only be used with local static files. - For external JavaScript, substitute `#!python django_js` with `#!python html.script`. + For external JavaScript, you should use `#!python html.script`. ```python {% include "../../python/django-js-remote-script.py" %} @@ -267,6 +263,6 @@ Allows you to defer loading JavaScript until a component begins rendering. This ??? question "Why not load my JS in `#!html `?" - Traditionally, JavaScript is loaded in your `#!html ` using the `#!jinja {% load static %}` template tag. + Traditionally, JavaScript is loaded in your `#!html ` using Django's `#!jinja {% static %}` template tag. - To help improve webpage load times, you can use the `#!python django_js` component to defer loading your JavaScript until it is needed. + However, to help improve webpage load times you can use this `#!python django_js` component to defer loading your JavaScript until it is needed. diff --git a/docs/src/reference/decorators.md b/docs/src/reference/decorators.md index 59440366..e5650648 100644 --- a/docs/src/reference/decorators.md +++ b/docs/src/reference/decorators.md @@ -10,7 +10,7 @@ Decorator functions can be used within your `components.py` to help simplify dev ## Auth Required -You can limit access to a component to users with a specific `#!python auth_attribute` by using this decorator (with or without parentheses). +You can limit component access to users with a specific `#!python auth_attribute` by using this decorator (with or without parentheses). By default, this decorator checks if the user is logged in and not deactivated (`#!python is_active`). diff --git a/docs/src/reference/hooks.md b/docs/src/reference/hooks.md index 3233a5bb..bdf36cee 100644 --- a/docs/src/reference/hooks.md +++ b/docs/src/reference/hooks.md @@ -16,9 +16,9 @@ Prefabricated hooks can be used within your `components.py` to help simplify dev ## Use Query -This hook is used [read](https://www.sumologic.com/glossary/crud/) data from the Django ORM. +This hook is used [read](https://www.sumologic.com/glossary/crud/) data, typically from the Django ORM. -The query function you provide must return either a `#!python Model` or `#!python QuerySet`. +The [default postprocessor](../reference/utils.md#django-query-postprocessor) expects your query function to return either a Django `#!python Model` or `#!python QuerySet`. The postprocessor needs to be changed to perform other types of queries. Query functions can be sync or async. === "components.py" @@ -59,13 +59,13 @@ The query function you provide must return either a `#!python Model` or `#!pytho {% include "../../python/use-query-args.py" %} ``` -??? question "Why does `#!python get_items` in the example return `#!python TodoItem.objects.all()`?" +??? question "How can I customize this hook's behavior?" - This was a technical design decision to based on [Apollo's `#!javascript useQuery` hook](https://www.apollographql.com/docs/react/data/queries/), but ultimately helps avoid Django's `#!python SynchronousOnlyOperation` exceptions. + This hook accepts a `#!python options = ...` parameter that can be used to customize its behavior. You can provide a `#!python reactpy_django.types.QueryOptions` object to this parameter to customize the hook's behavior. - The `#!python use_query` hook ensures the provided `#!python Model` or `#!python QuerySet` executes all [deferred](https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_deferred_fields)/[lazy queries](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy) safely prior to reaching your components. + Below are the settings that can be modified via `#!python QueryOptions`. -??? question "How can I use `#!python QueryOptions` to customize fetching behavior?" + --- **`#!python thread_sensitive`** @@ -128,27 +128,39 @@ The query function you provide must return either a `#!python Model` or `#!pytho _Note: In Django's ORM design, the field name to access foreign keys is [postfixed with `_set`](https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_one/) by default._ -??? question "Can I define async query functions?" +??? question "Can I make ORM calls without hooks?" + + {% include-markdown "../../includes/orm.md" start="" end="" %} - Async functions are supported by `#!python use_query`. You can use them in the same way as a sync query function. +??? question "Can I make a failed query try again?" - However, be mindful of Django async ORM restrictions. + Yes, a `#!python use_mutation` can be re-performed by calling `#!python reset()` on your `#!python use_mutation` instance. + + For example, take a look at `#!python reset_event` below. === "components.py" ```python - {% include "../../python/use-query-async.py" %} + {% include "../../python/use-mutation-reset.py" %} ``` -??? question "Can I make ORM calls without hooks?" + === "models.py" - {% include-markdown "../../includes/orm.md" start="" end="" %} + ```python + {% include "../../python/example/models.py" %} + ``` + +??? question "Why does the example query function return `#!python TodoItem.objects.all()`?" + + This design decision was based on [Apollo's `#!javascript useQuery` hook](https://www.apollographql.com/docs/react/data/queries/), but ultimately helps avoid Django's `#!python SynchronousOnlyOperation` exceptions. + + With the `#!python Model` or `#!python QuerySet` your function returns, this hook uses the [default postprocessor](../reference/utils.md#django-query-postprocessor) to ensure that all [deferred](https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_deferred_fields) or [lazy](https://docs.djangoproject.com/en/dev/topics/db/queries/#querysets-are-lazy) fields are executed. ## Use Mutation -This hook is used to [create, update, or delete](https://www.sumologic.com/glossary/crud/) Django ORM objects. +This hook is used to [create, update, or delete](https://www.sumologic.com/glossary/crud/) data, typically from the Django ORM. -The mutation function you provide should have no return value. +The mutation function you provide should have no return value. Mutation functions can be sync or async. === "components.py" @@ -187,27 +199,31 @@ The mutation function you provide should have no return value. {% include "../../python/use-mutation-args-kwargs.py" %} ``` -??? question "Can `#!python use_mutation` trigger a refetch of `#!python use_query`?" +??? question "How can I customize this hook's behavior?" - Yes, `#!python use_mutation` can queue a refetch of a `#!python use_query` via the `#!python refetch=...` argument. + This hook accepts a `#!python options = ...` parameter that can be used to customize its behavior. You can provide a `#!python reactpy_django.types.MutationOptions` object to this parameter to customize the hook's behavior. - The example below is a merge of the `#!python use_query` and `#!python use_mutation` examples above with the addition of a `#!python use_mutation(refetch=...)` argument. + Below are the settings that can be modified via `#!python MutationOptions`. - Please note that any `#!python use_query` hooks that use `#!python get_items` will be refetched upon a successful mutation. + --- + + **`#!python thread_sensitive`** + + Whether to run your synchronous mutation function in thread-sensitive mode. Thread-sensitive mode is turned on by default due to Django ORM limitations. See Django's [`#!python sync_to_async` docs](https://docs.djangoproject.com/en/dev/topics/async/#sync-to-async) docs for more information. + + This setting only applies to sync query functions, and will be ignored for async functions. === "components.py" ```python - {% include "../../python/use-mutation-query-refetch.py" %} + {% include "../../python/use-mutation-thread-sensitive.py" %} ``` - === "models.py" +??? question "Can I make ORM calls without hooks?" - ```python - {% include "../../python/example/models.py" %} - ``` + {% include-markdown "../../includes/orm.md" start="" end="" %} -??? question "Can I make a failed `#!python use_mutation` try again?" +??? question "Can I make a failed mutation try again?" Yes, a `#!python use_mutation` can be re-performed by calling `#!python reset()` on your `#!python use_mutation` instance. @@ -225,13 +241,29 @@ The mutation function you provide should have no return value. {% include "../../python/example/models.py" %} ``` -??? question "Can I make ORM calls without hooks?" +??? question "Can `#!python use_mutation` trigger a refetch of `#!python use_query`?" - {% include-markdown "../../includes/orm.md" start="" end="" %} + Yes, `#!python use_mutation` can queue a refetch of a `#!python use_query` via the `#!python refetch=...` argument. + + The example below is a merge of the `#!python use_query` and `#!python use_mutation` examples above with the addition of a `#!python use_mutation(refetch=...)` argument. + + Please note that `refetch` will cause all `#!python use_query` hooks that use `#!python get_items` in the current component tree will be refetched. + + === "components.py" + + ```python + {% include "../../python/use-mutation-query-refetch.py" %} + ``` + + === "models.py" + + ```python + {% include "../../python/example/models.py" %} + ``` ## Use Connection -This hook is used to fetch the Django Channels [WebSocket](https://channels.readthedocs.io/en/stable/topics/consumers.html#asyncjsonwebsocketconsumer). +This hook is used to fetch the active connection, which is either a Django [WebSocket](https://channels.readthedocs.io/en/stable/topics/consumers.html#asyncjsonwebsocketconsumer) or a [HTTP Request](https://docs.djangoproject.com/en/4.2/ref/request-response/#django.http.HttpRequest). === "components.py" @@ -249,11 +281,11 @@ This hook is used to fetch the Django Channels [WebSocket](https://channels.read | Type | Description | | --- | --- | - | `#!python Connection` | The component's WebSocket. | + | `#!python Connection` | The component's `WebSocket` or `HttpRequest`. | ## Use Scope -This is a shortcut that returns the WebSocket's [`#!python scope`](https://channels.readthedocs.io/en/stable/topics/consumers.html#scope). +This is a shortcut that returns the HTTP or WebSocket [`#!python scope`](https://channels.readthedocs.io/en/stable/topics/consumers.html#scope). === "components.py" @@ -275,7 +307,7 @@ This is a shortcut that returns the WebSocket's [`#!python scope`](https://chann ## Use Location -This is a shortcut that returns the WebSocket's `#!python path`. +This is a shortcut that returns the client's `#!python path`. You can expect this hook to provide strings such as `/reactpy/my_path`. @@ -299,7 +331,7 @@ You can expect this hook to provide strings such as `/reactpy/my_path`. ??? info "This hook's behavior will be changed in a future update" - This hook will be updated to return the browser's currently active HTTP path. This change will come in alongside ReactPy URL routing support. + This hook will be updated to always return the browser's currently active HTTP path. This change will come in alongside ReactPy URL routing support. Check out [reactive-python/reactpy-django#147](https://github.com/reactive-python/reactpy-django/issues/147) for more information. @@ -325,4 +357,4 @@ You can expect this hook to provide strings such as `http://example.com`. | Type | Description | | --- | --- | - | `#!python str | None` | A string containing the browser's current origin, obtained from WebSocket headers (if available). | + | `#!python str | None` | A string containing the browser's current origin, obtained from WebSocket or HTTP headers (if available). | diff --git a/docs/src/reference/settings.md b/docs/src/reference/settings.md index 35f65b6e..46ed7070 100644 --- a/docs/src/reference/settings.md +++ b/docs/src/reference/settings.md @@ -34,7 +34,7 @@ The prefix used for all ReactPy WebSocket and HTTP URLs. **Example Value(s):** `#!python "example_project.postprocessor"`, `#!python None` -Dotted path to the default `#!python reactpy_django.hooks.use_query` postprocessor function. +Dotted path to the global default `#!python reactpy_django.hooks.use_query` postprocessor function. Postprocessor functions can be async or sync. Here is an example of a sync postprocessor function: diff --git a/docs/src/reference/template-tag.md b/docs/src/reference/template-tag.md index 39974eb7..8fdb5695 100644 --- a/docs/src/reference/template-tag.md +++ b/docs/src/reference/template-tag.md @@ -81,7 +81,7 @@ This template tag can be used to insert any number of ReactPy components onto yo Here's a couple of things to keep in mind: 1. If your host address are completely separate ( `origin1.com != origin2.com` ) you will need to [configure CORS headers](https://pypi.org/project/django-cors-headers/) on your main application during deployment. - 2. You will not need to register ReactPy HTTP or WebSocket paths on any applications that do not perform any component rendering. + 2. You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering. 3. Your component will only be able to access your template tag's `#!python *args`/`#!python **kwargs` if your applications share a common database. diff --git a/docs/src/reference/utils.md b/docs/src/reference/utils.md index e5c10057..85633bdb 100644 --- a/docs/src/reference/utils.md +++ b/docs/src/reference/utils.md @@ -60,6 +60,6 @@ This function is used manually register a root component with ReactPy. You typically will not need to use this function. - For security reasons, ReactPy does not allow non-registered components to be root components. However, all components contained within Django templates are automatically considered root components. + For security reasons, ReactPy requires all root components to be registered. However, all components contained within Django templates are automatically registered. - This is typically only needed when you have a dedicated Django application as a rendering server that doesn't have templates, such as when modifying the [template tag `#!python host` argument](../reference/template-tag.md#component). On this dedicated rendering server, you would need to manually register your components. + This function is needed when you have configured your [`host`](../reference/template-tag.md#component) to a dedicated Django rendering application that doesn't have templates. On this dedicated rendering server, you would need to manually register your components. diff --git a/mkdocs.yml b/mkdocs.yml index af88f66b..587cf87d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -90,6 +90,9 @@ extra: generator: false version: provider: mike + analytics: + provider: google + property: G-4KFQN2LWBG extra_javascript: - assets/js/main.js From 1785ad1f61d2efc9d5dff6744455d17420f3ceac Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Mon, 18 Sep 2023 23:25:44 -0700 Subject: [PATCH 02/13] hooks rewording --- docs/src/reference/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/reference/hooks.md b/docs/src/reference/hooks.md index bdf36cee..1aad9bab 100644 --- a/docs/src/reference/hooks.md +++ b/docs/src/reference/hooks.md @@ -181,7 +181,7 @@ The mutation function you provide should have no return value. Mutation function | Name | Type | Description | Default | | --- | --- | --- | --- | | `#!python mutate` | `#!python Callable[_Params, bool | None]` | A callable that performs Django ORM create, update, or delete functionality. If this function returns `#!python False`, then your `#!python refetch` function will not be used. | N/A | - | `#!python refetch` | `#!python Callable[..., Any] | Sequence[Callable[..., Any]] | None` | A `#!python query` function (used by the `#!python use_query` hook) or a sequence of `#!python query` functions that will be called if the mutation succeeds. This is useful for refetching data after a mutation has been performed. | `#!python None` | + | `#!python refetch` | `#!python Callable[..., Any] | Sequence[Callable[..., Any]] | None` | A query function (the function typically provided to your `#!python use_query` hook) or a sequence of query functions that need a `refetch` if the mutation succeeds. This is useful for refetching data after a mutation has been performed. | `#!python None` | **Returns** From 190689dc48892489f91da421dd6f1c80ef39da9a Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 20 Sep 2023 01:43:04 -0700 Subject: [PATCH 03/13] Use async mutation/queries in main examples --- docs/python/use-mutation.py | 4 ++-- docs/python/use-query.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/python/use-mutation.py b/docs/python/use-mutation.py index 7c5c94fd..5b6f0e55 100644 --- a/docs/python/use-mutation.py +++ b/docs/python/use-mutation.py @@ -3,8 +3,8 @@ from reactpy_django.hooks import use_mutation -def add_item(text: str): - TodoItem(text=text).save() +async def add_item(text: str): + await TodoItem(text=text).asave() @component diff --git a/docs/python/use-query.py b/docs/python/use-query.py index a8ed8b46..e546ed59 100644 --- a/docs/python/use-query.py +++ b/docs/python/use-query.py @@ -1,10 +1,11 @@ +from channels.db import database_sync_to_async from example.models import TodoItem from reactpy import component, html from reactpy_django.hooks import use_query -def get_items(): - return TodoItem.objects.all() +async def get_items(): + return await database_sync_to_async(TodoItem.objects.all)() @component From 86d90ac333fc93fff15fc240203411235966896b Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 20 Sep 2023 01:43:18 -0700 Subject: [PATCH 04/13] fix postprocessor name --- docs/includes/orm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/includes/orm.md b/docs/includes/orm.md index 74f966c0..58f45477 100644 --- a/docs/includes/orm.md +++ b/docs/includes/orm.md @@ -8,6 +8,6 @@ These `#!python SynchronousOnlyOperation` exceptions may be removed in a future -By default, automatic recursive fetching of `#!python ManyToMany` or `#!python ForeignKey` fields is enabled within the `DjangoQueryPostprocessor`. This is needed to prevent `#!python SynchronousOnlyOperation` exceptions when accessing these fields within your ReactPy components. +By default, automatic recursive fetching of `#!python ManyToMany` or `#!python ForeignKey` fields is enabled within the `django_query_postprocessor`. This is needed to prevent `#!python SynchronousOnlyOperation` exceptions when accessing these fields within your ReactPy components. From 3890298d3b6ac3e6b17b47e45b29f6c0119fb10a Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 20 Sep 2023 01:47:46 -0700 Subject: [PATCH 05/13] fix docstring function descriptions --- src/reactpy_django/components.py | 20 ++++++++++---------- src/reactpy_django/decorators.py | 4 ++-- src/reactpy_django/hooks.py | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/reactpy_django/components.py b/src/reactpy_django/components.py index 31df3e2e..ceab23d4 100644 --- a/src/reactpy_django/components.py +++ b/src/reactpy_django/components.py @@ -124,16 +124,16 @@ def view_to_component( Keyword Args: view: The view function or class to convert. - compatibility: If True, the component will be rendered in an iframe. - When using compatibility mode `tranforms`, `strict_parsing`, `request`, + compatibility: If True, the component will be rendered in an iframe. \ + When using compatibility mode `tranforms`, `strict_parsing`, `request`, \ `args, and `kwargs` arguments will be ignored. - transforms: A list of functions that transforms the newly generated VDOM. + transforms: A list of functions that transforms the newly generated VDOM. \ The functions will be called on each VDOM node. - strict_parsing: If True, an exception will be generated if the HTML does not + strict_parsing: If True, an exception will be generated if the HTML does not \ perfectly adhere to HTML5. Returns: - A function that takes `request: HttpRequest | None, *args: Any, key: Key | None, **kwargs: Any` + A function that takes `request: HttpRequest | None, *args: Any, key: Key | None, **kwargs: Any` \ and returns a ReactPy component. """ @@ -172,9 +172,9 @@ def django_css(static_path: str, key: Key | None = None): """Fetches a CSS static file for use within ReactPy. This allows for deferred CSS loading. Args: - static_path: The path to the static file. This path is identical to what you would - use on a `static` template tag. - key: A key to uniquely identify this component which is unique amongst a component's + static_path: The path to the static file. This path is identical to what you would \ + use on Django's `{% static %}` template tag + key: A key to uniquely identify this component which is unique amongst a component's \ immediate siblings """ @@ -190,9 +190,9 @@ def django_js(static_path: str, key: Key | None = None): """Fetches a JS static file for use within ReactPy. This allows for deferred JS loading. Args: - static_path: The path to the static file. This path is identical to what you would + static_path: The path to the static file. This path is identical to what you would \ use on a `static` template tag. - key: A key to uniquely identify this component which is unique amongst a component's + key: A key to uniquely identify this component which is unique amongst a component's \ immediate siblings """ diff --git a/src/reactpy_django/decorators.py b/src/reactpy_django/decorators.py index fc24fdfd..4f3befe2 100644 --- a/src/reactpy_django/decorators.py +++ b/src/reactpy_django/decorators.py @@ -19,8 +19,8 @@ def auth_required( This decorator can be used with or without parentheses. Args: - auth_attribute: The value to check within the user object. - This is checked in the form of `UserModel.