Skip to content
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

ReactPy Support #195

Merged
merged 100 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
2475d18
needs polishing
ZeroIntensity Jun 15, 2024
d3e60e3
remove program.prof
ZeroIntensity Jun 15, 2024
7391c0a
add some error handling shenanigans
ZeroIntensity Jun 15, 2024
342ed91
add test.py for testing purposes
ZeroIntensity Jun 16, 2024
7fe9286
add many docstrings
ZeroIntensity Jun 16, 2024
542d7b0
even more docstrings
ZeroIntensity Jun 16, 2024
1a75cdf
fix circular imports
ZeroIntensity Jun 16, 2024
9f6efdf
c api changes
ZeroIntensity Jun 16, 2024
55fb261
remove dead html folder
ZeroIntensity Jun 16, 2024
94645da
fix redef
ZeroIntensity Jun 16, 2024
c3ce6b7
add pth file
ZeroIntensity Jun 16, 2024
55b7f54
nevermind it doesn't work
ZeroIntensity Jun 16, 2024
87bd1be
working reactpy support
ZeroIntensity Jun 16, 2024
cc49d45
run formatter
ZeroIntensity Jun 16, 2024
90f1315
remove test.py
ZeroIntensity Jun 16, 2024
cc110a5
finish reactpy integration
ZeroIntensity Jun 16, 2024
13cf4ed
add some c api docstrings
ZeroIntensity Jun 17, 2024
affe5bf
broken as of now
ZeroIntensity Jun 17, 2024
da12deb
still a bit broken
ZeroIntensity Jun 17, 2024
5773ea6
literally like all tests failing
ZeroIntensity Jun 17, 2024
f50ab89
add expect_errors for fun
ZeroIntensity Jun 17, 2024
5a05d20
run formatter
ZeroIntensity Jun 17, 2024
b119d6f
i hate the vscode c formatter
ZeroIntensity Jun 17, 2024
0bde2da
fix is_http with error responses
ZeroIntensity Jun 18, 2024
a07dfdc
refactor c api
ZeroIntensity Jun 18, 2024
6c7e261
more c api docstrings
ZeroIntensity Jun 18, 2024
783e183
docstrings galore
ZeroIntensity Jun 18, 2024
84bd92f
they call me docstring hudson
ZeroIntensity Jun 18, 2024
db3bef2
add map docstrings
ZeroIntensity Jun 19, 2024
c0671c4
guess what
ZeroIntensity Jun 19, 2024
ae7b574
bugfixes for new features
ZeroIntensity Jun 19, 2024
ce03fa7
fix import
ZeroIntensity Jun 19, 2024
25401ce
fix response
ZeroIntensity Jun 19, 2024
2839b68
fix cookies
ZeroIntensity Jun 19, 2024
fbcfec4
actually fix cookies
ZeroIntensity Jun 19, 2024
74e2881
trying to get live reload working
ZeroIntensity Jun 19, 2024
1aa1ac6
fix server logging
ZeroIntensity Jun 19, 2024
434e44e
Add module slots
ZeroIntensity Jun 22, 2024
b2f6db1
Implement #186 - use a PEP 7 compliant uncrustify configuration
ZeroIntensity Jun 22, 2024
67fb206
Update changelog with C API reformat
ZeroIntensity Jun 22, 2024
c3e7e0c
Add -g3 flag to _view
ZeroIntensity Jun 22, 2024
5db8792
Clean up .gitignore
ZeroIntensity Jun 22, 2024
bfc1f94
Remove dead ext/ folder
ZeroIntensity Jun 22, 2024
5d0ced5
Add NULL check for PyModule_Create
ZeroIntensity Jun 22, 2024
c5a3d27
Remove module slots, since they don't work on PyModule_Create
ZeroIntensity Jun 22, 2024
8e29aab
Remove escape() from needs_dep()
ZeroIntensity Jun 22, 2024
ee081e5
Fix reference leak in handle_result
ZeroIntensity Jun 23, 2024
6bfd080
Fix PyDict_Next position in PyTuple_SET_ITEM
ZeroIntensity Jun 23, 2024
958d17c
Fix cookie parsing
ZeroIntensity Jun 23, 2024
e0c485b
Upgrade PyAwaitable vendor and fix reference leaks
ZeroIntensity Jun 25, 2024
6b421b5
There's a tornado nearby so I have to commit in case my laptop gets d…
ZeroIntensity Jun 26, 2024
30c0eb9
Update changelog and update log messages
ZeroIntensity Jun 26, 2024
16cd310
Partial implementation of #51
ZeroIntensity Jun 26, 2024
5ce5d21
Fix reference and leak and only use -O3 in release builds
ZeroIntensity Jun 27, 2024
a52123c
Fix header iterable containing strings instead of bytes
ZeroIntensity Jun 27, 2024
10dfc82
Add new except clause to public Typecode API
ZeroIntensity Jun 27, 2024
f596e66
Fix missing pos initializer for PyDict_Next
ZeroIntensity Jun 27, 2024
c3536b7
Add debugging information to workflows
ZeroIntensity Jun 27, 2024
bcdf65f
Fix missing exception in cast_from_typecodes
ZeroIntensity Jun 27, 2024
3389b04
Fix test segfaults
ZeroIntensity Jun 27, 2024
0f42894
Switch to PyErr_Clear() to fix union support
ZeroIntensity Jun 27, 2024
1ddbddc
Fix parameter mismatch in build_data_inputs()
ZeroIntensity Jun 27, 2024
8cf1fc6
Add backport.h to route implementation.
ZeroIntensity Jul 8, 2024
e7ec43c
Update CHANGELOG
ZeroIntensity Jul 10, 2024
a9806ea
Add test for isinstance() on a type that supports __view_result__
ZeroIntensity Jul 10, 2024
5f602d2
Add test for call_result()
ZeroIntensity Jul 10, 2024
1c7658e
Add ctx parameter to the call_result() test
ZeroIntensity Jul 10, 2024
609801a
Fix context data reference counting.
ZeroIntensity Jul 11, 2024
c83fdbd
Fix some more reference problems.
ZeroIntensity Jul 12, 2024
b71512b
Switch to Hatch (#190)
ZeroIntensity Jul 14, 2024
7aadb2b
Remove coverage file.
ZeroIntensity Jul 14, 2024
4a45f6f
Update workflows to build with Hatch.
ZeroIntensity Jul 14, 2024
5f4924d
Fix TOML formatting.
ZeroIntensity Jul 14, 2024
1c570fe
Fix stolen reference problem with PyErr_GetRaisedException()
ZeroIntensity Jul 15, 2024
7405d12
Merge branch 'master' into reactpy
ZeroIntensity Jul 16, 2024
e657129
I made these changes a while ago so I don't remember.
ZeroIntensity Jul 29, 2024
191deb8
Update contributors file.
ZeroIntensity Aug 3, 2024
252d5d6
Update the classifiers.
ZeroIntensity Aug 3, 2024
f34bb82
Switch to PyAwaitable PyPI build.
ZeroIntensity Aug 4, 2024
775a162
Add PYAWAITABLE_THIS_FILE_INIT define.
ZeroIntensity Aug 4, 2024
6f3bfb6
Update testing workflow.
ZeroIntensity Aug 5, 2024
9c20364
Shenanigans.
ZeroIntensity Aug 5, 2024
b9b43de
Still broken.
ZeroIntensity Aug 8, 2024
2555575
Fix merge conflicts.
ZeroIntensity Aug 23, 2024
e9501b2
Fix failing build.
ZeroIntensity Aug 23, 2024
4489e18
Temporarily fix failing build.
ZeroIntensity Aug 23, 2024
dc484c7
Reformat code.
ZeroIntensity Aug 24, 2024
c8a89dd
Change build type to RelWithDebInfo
ZeroIntensity Aug 24, 2024
4061dda
Remove useless build script.
ZeroIntensity Aug 24, 2024
2e3d47a
Run formatter.
ZeroIntensity Aug 24, 2024
54284f4
Shenanigans.
ZeroIntensity Sep 21, 2024
bb8b82c
Run formatter.
ZeroIntensity Sep 22, 2024
8700413
Check for Pydantic 2.0 sentinel in typecodes.
ZeroIntensity Oct 26, 2024
d241d3e
Changes to build steps.
ZeroIntensity Oct 26, 2024
218064e
Remove valgrind shenanigans.
ZeroIntensity Oct 26, 2024
ac6be1c
Remove suppressions.
ZeroIntensity Oct 26, 2024
dd5e0f0
Fix docs.
ZeroIntensity Oct 26, 2024
74ac546
Bump classifiers and PyAwaitable version.
ZeroIntensity Oct 31, 2024
c2da1c6
Switch to multi phase init
ZeroIntensity Nov 4, 2024
f933736
Break the rest of the code.
ZeroIntensity Nov 5, 2024
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
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DisableFormat: true
6 changes: 2 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
name: CI
name: Build

on:
push:
tags:
- v*
pull_request:
branches:
- master

concurrency:
group: build-${{ github.head_ref }}
cancel-in-progress: true

env:
SKBUILD_CMAKE_BUILD_TYPE: "Release"
CIBW_SKIP: >
pp*

Expand Down
18 changes: 12 additions & 6 deletions .github/workflows/memory_check.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Memory Check
name: Memory Problems

on:
push:
Expand All @@ -12,10 +12,13 @@ env:
PYTHONUNBUFFERED: "1"
FORCE_COLOR: "1"
PYTHONIOENCODING: "utf8"
PYTHONMALLOC: "malloc"
PYTHONDEVMODE: "1"
HATCH_VERBOSE: "1"

jobs:
run:
name: Valgrind on Ubuntu
name: Run memory tests on Ubuntu
runs-on: ubuntu-latest

steps:
Expand All @@ -26,16 +29,19 @@ jobs:
with:
python-version: 3.12

- name: Install PyTest
- name: Install Pytest
run: |
pip install pytest pytest-asyncio
pip install pytest pytest-asyncio pytest-memray
shell: bash

- name: Build project
- name: Build view.py
run: pip install .[full]

- name: Install Valgrind
run: sudo apt-get update && sudo apt-get -y install valgrind

- name: Run tests with Valgrind
run: valgrind --suppressions=valgrind-python.supp --error-exitcode=1 pytest -x
run: valgrind --error-exitcode=1 pytest

- name: Run tests with Memray
run: pytest --enable-leak-tracking
30 changes: 10 additions & 20 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ env:
PYTHONUNBUFFERED: "1"
FORCE_COLOR: "1"
PYTHONIOENCODING: "utf8"
PYTHONDEVMODE: "1"
HATCH_VERBOSE: "1"

jobs:
run:
Expand All @@ -24,8 +26,8 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-12]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v2
Expand All @@ -35,23 +37,11 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install PyTest
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
pip install pytest pytest-asyncio
else
pip install pytest pytest-asyncio pytest-memray
fi
shell: bash

- name: Build project
- name: Install Pytest
run: pip install pytest pytest-asyncio

- name: Build view.py
run: pip install .[full]

- name: Run tests
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
pytest
else
pytest --memray
fi
shell: bash
- name: Run tests
run: pytest -x
46 changes: 32 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
# Python
__pycache__/
.venv/
ext/
test.py
sample.py
38venv/
39venv/
311venv/

# LSP
.vscode/
compile_flags.txt
pyawaitable.h

# View Configurations
view.toml
view.json
view_config.py
/app.py

# Testing Files
*.test
test.py
a.py
.coverage
.pytest-cache/
.ruff-cache/
.cache/

# Logs
*.log
vgcore.*
valgrind.txt*

# JavaScript
node_modules/
*.lock
site/
benchmark.py
package-lock.json
client.js
.next/

# Builds
site/
dist/
*.egg-info
build/
*.so
*.egg-info/
html/dist.css
38venv
39venv
311venv
*.so
a.md
new_app/
vgcore.*
.vscode/
*.test
36 changes: 34 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for coroutines in `PyAwaitable` (vendored)
- Finished websocket implementation
- Added the `custom` loader
- Added support for returning `bytes` objects in the body.
- Added support for returning `bytes` objects in the body
- Added `nosanitize` and `repr` to the `ref` attribute of `<view>` tags in view template rendering
- `WebSocketDisconnect` is now raised instead of `WebSocketHandshakeError` in an unexpected WebSocket disconnect
- Added many, _many_, more docstrings
- Added the `app` attribute to `Context`
- Switched to PyMalloc under the hood
- Deprecated the `run()` utility
- Added support for asynchronous `__view_result__` functions
- Removed unstable `components` functions from top-level `view` module
- Added native support for `ReactPy` component routes
- Added the `expect_errors` utility
- Added the `HeaderDict` class
- Changed the `headers` attribute on `Context` to a `HeaderDict` instance of a `dict`
- Added the `call_result` utility
- Added the `ctx` parameter to `to_response`
- Removed broken hint when forgetting to call `load()`
- Added support for `isinstance` to `SupportsViewResult`
- Moved `to_response` to the `view.utils` module
- Added the `force` parameter to `run`
- Added the `view dev` command (live reload)
- Fixed redirection and disabling of HTTP server logging
- C API is now compliant with [PEP 7](https://peps.python.org/pep-0007/)
- Added `-g3` and `-O3` flag to the `_view` extension module (debugging information and optimizations)
- Removed use of Rich `escape()` in the message shown when a dependency is needed
- Query string client errors are now displayed during development mode
- `KeyboardInterrupt` is swallowed by the server coroutine, and a log message is now issued
- Typecode API now raises exceptions indicating a validation error (and now it's sent as a response with a query or body parse failure)
- `hatchling` and `scikit-build-core` are now used for build instead of `setuptools`
- Renamed the `view-admin` command to `view-py`
- **Breaking Change:** Renamed `Error` to `HTTPError`
- **Breaking Change:** `__view_result__` is now given a `Context` parameter
- **Breaking Change:** `to_response` is now asynchronous
- **Breaking Change:** Renamed `Response._custom` to `Response.translate_body`
- **Breaking Change:** Removed the `hijack` configuration setting
- **Breaking Change:** Removed the `post_init` parameter from `new_app`, as well as renamed the `store_address` parameter to `store`.
- **Breaking Change:** Removed the `post_init` parameter from `new_app`, as well as renamed the `store_address` parameter to `store`
- **Breaking Change:** `load()` now takes routes via variadic arguments, instead of a list of routes.

## [1.0.0-alpha10] - 2024-5-26
Expand Down
30 changes: 30 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.15...3.26)
project(${SKBUILD_PROJECT_NAME} LANGUAGES C)

message(STATUS "CMAKE_BUILD_TYPE set to '${CMAKE_BUILD_TYPE}'")

# Source code
file(GLOB _view_SRC
${CMAKE_CURRENT_SOURCE_DIR}/src/_view/*.c
)
MESSAGE(DEBUG ${_view_SRC})

# Find Python
find_package(
Python
COMPONENTS Interpreter Development.Module
REQUIRED)

# Link Python
python_add_library(_view MODULE ${_view_SRC} WITH_SOABI)

# Settings
add_compile_definitions(PYAWAITABLE_PYAPI)

# Add include directories
target_include_directories(_view PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/)
target_include_directories(_view PUBLIC $ENV{PYAWAITABLE_INCLUDE_DIR})

MESSAGE(STATUS "Everything looks good, let's install!")
# Install extension module
install(TARGETS _view DESTINATION .)
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ $ pip install .

Congratulations, you have just started your development with view.py!

Note that this cannot be an editable install (the `-e` flag), as `scikit-build-core` does not support it.

## Workflow

First, you should create a new branch:

```
$ git branch my_cool_feature
$ git checkout my_cool_feature
$ git switch -c my-cool-feature
```

All of your code should be contained on this branch.
Expand Down Expand Up @@ -72,7 +73,7 @@ fancy = false
server_logger = true
```

These settings will stop view.py's fancy output from showing, as well as stopping the hijack of the ASGI logger, and you'll get the raw output.
These settings will stop view.py's fancy output from showing, as well as stopping the hijack of the server's logger, and you'll get the raw server output.

## Writing Tests

Expand Down
3 changes: 0 additions & 3 deletions MANIFEST.in

This file was deleted.

32 changes: 25 additions & 7 deletions _view.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# flake8: noqa
# NOTE: anything in this file that is defined solely for typing purposes should be
# prefixed with __ to tell the developer that its not an actual symbol defined by
# the extension module

"""
_view - Type stubs for the view.py extension module.

Anything in this file that is defined solely for typing purposes should be
prefixed with __ to tell the developer that its not an actual symbol defined by
the extension module.
"""

from ipaddress import IPv4Address as __IPv4Address
from ipaddress import IPv6Address as __IPv6Address
Expand All @@ -14,6 +19,7 @@ from typing import Literal as __Literal
from typing import NoReturn as __NoReturn
from typing import TypeVar as __TypeVar

from view.app import App
from view.routing import RouteData as __RouteData
from view.typing import AsgiDict as __AsgiDict
from view.typing import AsgiReceive as __AsgiReceive
Expand Down Expand Up @@ -119,13 +125,16 @@ class ViewApp:
def _supply_parsers(self, query: __Parser, json: __Parser, /) -> None: ...
def _register_error(self, error: type, /) -> None: ...

def test_awaitable(coro: __Coroutine[__Any, __Any, __T], /) -> __Awaitable[__T]: ...
def test_awaitable(
coro: __Coroutine[__Any, __Any, __T], /
) -> __Awaitable[__T]: ...

class Context:
def __init__(self) -> __NoReturn: ...

app: App
cookies: dict[str, str]
headers: dict[str, str]
headers: HeaderDict
client: __IPv4Address | __IPv6Address | None
server: __IPv4Address | __IPv6Address | None
method: __StrMethodASGI
Expand All @@ -152,5 +161,14 @@ class ViewWebSocket:
class InvalidStatusError(RuntimeError): ...
class WebSocketHandshakeError(RuntimeError): ...

def setup_route_log(func: __Callable[[int | str, str, str], None]) -> None: ...
def register_ws_cls(tp: type[__Any]) -> None: ...
def setup_route_log(func: __Callable[[int | str, str, str], None], warn: __Callable[[str], None], /) -> None: ...
def register_ws_cls(
tp: type[__Any], ws_handshake_err: type[__Any], ws_err: type[__Any], /,
) -> None: ...

class HeaderDict:
def __init__(self) -> __NoReturn: ...
def __setitem__(self, key: str, value: str, /) -> None: ...
def __getitem__(self, key: str, /) -> str | list[str]: ...

def dummy_context(app: ViewApp | None) -> Context: ...
10 changes: 10 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<view ref="prerender_head" nosanitize />
<script src="src/reactpy.tsx" type="module"></script>
<p hidden id="_view-route-hook">
<view ref="hook" />
</p>
<view ref="prerender_body" nosanitize />

</html>
21 changes: 21 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"typescript": "^5.4.5",
"vite": "^5.2.0",
"vite-plugin-singlefile": "^2.0.1"
},
"dependencies": {
"@reactpy/client": "^0.3.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
}
Loading
Loading