Skip to content

Commit 7fe291b

Browse files
Merge pull request #195 from ZeroIntensity/reactpy
This is going to break a lot of things, and basically all CI is going to fail. That's OK--this is an alpha library anyway. For now, we just want to focus on getting all this code on main so we can start working on fixing the C code.
2 parents e586143 + f933736 commit 7fe291b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+8154
-6595
lines changed

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DisableFormat: true

.github/workflows/build.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
name: CI
1+
name: Build
22

33
on:
44
push:
55
tags:
66
- v*
7-
pull_request:
8-
branches:
9-
- master
107

118
concurrency:
129
group: build-${{ github.head_ref }}
1310
cancel-in-progress: true
1411

1512
env:
13+
SKBUILD_CMAKE_BUILD_TYPE: "Release"
1614
CIBW_SKIP: >
1715
pp*
1816

.github/workflows/memory_check.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Memory Check
1+
name: Memory Problems
22

33
on:
44
push:
@@ -12,10 +12,13 @@ env:
1212
PYTHONUNBUFFERED: "1"
1313
FORCE_COLOR: "1"
1414
PYTHONIOENCODING: "utf8"
15+
PYTHONMALLOC: "malloc"
16+
PYTHONDEVMODE: "1"
17+
HATCH_VERBOSE: "1"
1518

1619
jobs:
1720
run:
18-
name: Valgrind on Ubuntu
21+
name: Run memory tests on Ubuntu
1922
runs-on: ubuntu-latest
2023

2124
steps:
@@ -26,16 +29,19 @@ jobs:
2629
with:
2730
python-version: 3.12
2831

29-
- name: Install PyTest
32+
- name: Install Pytest
3033
run: |
31-
pip install pytest pytest-asyncio
34+
pip install pytest pytest-asyncio pytest-memray
3235
shell: bash
3336

34-
- name: Build project
37+
- name: Build view.py
3538
run: pip install .[full]
3639

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

4043
- name: Run tests with Valgrind
41-
run: valgrind --suppressions=valgrind-python.supp --error-exitcode=1 pytest -x
44+
run: valgrind --error-exitcode=1 pytest
45+
46+
- name: Run tests with Memray
47+
run: pytest --enable-leak-tracking

.github/workflows/tests.yml

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ env:
1616
PYTHONUNBUFFERED: "1"
1717
FORCE_COLOR: "1"
1818
PYTHONIOENCODING: "utf8"
19+
PYTHONDEVMODE: "1"
20+
HATCH_VERBOSE: "1"
1921

2022
jobs:
2123
run:
@@ -24,8 +26,8 @@ jobs:
2426
strategy:
2527
fail-fast: false
2628
matrix:
27-
os: [ubuntu-latest, windows-latest, macos-12]
28-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
29+
os: [ubuntu-latest, windows-latest, macos-latest]
30+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
2931

3032
steps:
3133
- uses: actions/checkout@v2
@@ -35,23 +37,11 @@ jobs:
3537
with:
3638
python-version: ${{ matrix.python-version }}
3739

38-
- name: Install PyTest
39-
run: |
40-
if [ "$RUNNER_OS" == "Windows" ]; then
41-
pip install pytest pytest-asyncio
42-
else
43-
pip install pytest pytest-asyncio pytest-memray
44-
fi
45-
shell: bash
46-
47-
- name: Build project
40+
- name: Install Pytest
41+
run: pip install pytest pytest-asyncio
42+
43+
- name: Build view.py
4844
run: pip install .[full]
4945

50-
- name: Run tests
51-
run: |
52-
if [ "$RUNNER_OS" == "Windows" ]; then
53-
pytest
54-
else
55-
pytest --memray
56-
fi
57-
shell: bash
46+
- name: Run tests
47+
run: pytest -x

.gitignore

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,47 @@
1+
# Python
12
__pycache__/
23
.venv/
3-
ext/
4-
test.py
5-
sample.py
4+
38venv/
5+
39venv/
6+
311venv/
7+
8+
# LSP
9+
.vscode/
610
compile_flags.txt
11+
pyawaitable.h
12+
13+
# View Configurations
714
view.toml
815
view.json
916
view_config.py
10-
/app.py
17+
18+
# Testing Files
19+
*.test
20+
test.py
1121
a.py
22+
.coverage
23+
.pytest-cache/
24+
.ruff-cache/
25+
.cache/
26+
27+
# Logs
1228
*.log
29+
vgcore.*
30+
valgrind.txt*
31+
32+
# JavaScript
1333
node_modules/
1434
*.lock
15-
site/
1635
benchmark.py
36+
package-lock.json
37+
client.js
38+
.next/
39+
40+
# Builds
41+
site/
1742
dist/
18-
*.egg-info
1943
build/
20-
*.so
44+
*.egg-info/
2145
html/dist.css
22-
38venv
23-
39venv
24-
311venv
46+
*.so
2547
a.md
26-
new_app/
27-
vgcore.*
28-
.vscode/
29-
*.test

CHANGELOG.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Added support for coroutines in `PyAwaitable` (vendored)
1414
- Finished websocket implementation
1515
- Added the `custom` loader
16-
- Added support for returning `bytes` objects in the body.
16+
- Added support for returning `bytes` objects in the body
17+
- Added `nosanitize` and `repr` to the `ref` attribute of `<view>` tags in view template rendering
18+
- `WebSocketDisconnect` is now raised instead of `WebSocketHandshakeError` in an unexpected WebSocket disconnect
19+
- Added many, _many_, more docstrings
20+
- Added the `app` attribute to `Context`
21+
- Switched to PyMalloc under the hood
22+
- Deprecated the `run()` utility
23+
- Added support for asynchronous `__view_result__` functions
24+
- Removed unstable `components` functions from top-level `view` module
25+
- Added native support for `ReactPy` component routes
26+
- Added the `expect_errors` utility
27+
- Added the `HeaderDict` class
28+
- Changed the `headers` attribute on `Context` to a `HeaderDict` instance of a `dict`
29+
- Added the `call_result` utility
30+
- Added the `ctx` parameter to `to_response`
31+
- Removed broken hint when forgetting to call `load()`
32+
- Added support for `isinstance` to `SupportsViewResult`
33+
- Moved `to_response` to the `view.utils` module
34+
- Added the `force` parameter to `run`
35+
- Added the `view dev` command (live reload)
36+
- Fixed redirection and disabling of HTTP server logging
37+
- C API is now compliant with [PEP 7](https://peps.python.org/pep-0007/)
38+
- Added `-g3` and `-O3` flag to the `_view` extension module (debugging information and optimizations)
39+
- Removed use of Rich `escape()` in the message shown when a dependency is needed
40+
- Query string client errors are now displayed during development mode
41+
- `KeyboardInterrupt` is swallowed by the server coroutine, and a log message is now issued
42+
- Typecode API now raises exceptions indicating a validation error (and now it's sent as a response with a query or body parse failure)
43+
- `hatchling` and `scikit-build-core` are now used for build instead of `setuptools`
44+
- Renamed the `view-admin` command to `view-py`
45+
- **Breaking Change:** Renamed `Error` to `HTTPError`
46+
- **Breaking Change:** `__view_result__` is now given a `Context` parameter
47+
- **Breaking Change:** `to_response` is now asynchronous
48+
- **Breaking Change:** Renamed `Response._custom` to `Response.translate_body`
1749
- **Breaking Change:** Removed the `hijack` configuration setting
18-
- **Breaking Change:** Removed the `post_init` parameter from `new_app`, as well as renamed the `store_address` parameter to `store`.
50+
- **Breaking Change:** Removed the `post_init` parameter from `new_app`, as well as renamed the `store_address` parameter to `store`
1951
- **Breaking Change:** `load()` now takes routes via variadic arguments, instead of a list of routes.
2052

2153
## [1.0.0-alpha10] - 2024-5-26

CMakeLists.txt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
cmake_minimum_required(VERSION 3.15...3.26)
2+
project(${SKBUILD_PROJECT_NAME} LANGUAGES C)
3+
4+
message(STATUS "CMAKE_BUILD_TYPE set to '${CMAKE_BUILD_TYPE}'")
5+
6+
# Source code
7+
file(GLOB _view_SRC
8+
${CMAKE_CURRENT_SOURCE_DIR}/src/_view/*.c
9+
)
10+
MESSAGE(DEBUG ${_view_SRC})
11+
12+
# Find Python
13+
find_package(
14+
Python
15+
COMPONENTS Interpreter Development.Module
16+
REQUIRED)
17+
18+
# Link Python
19+
python_add_library(_view MODULE ${_view_SRC} WITH_SOABI)
20+
21+
# Settings
22+
add_compile_definitions(PYAWAITABLE_PYAPI)
23+
24+
# Add include directories
25+
target_include_directories(_view PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/)
26+
target_include_directories(_view PUBLIC $ENV{PYAWAITABLE_INCLUDE_DIR})
27+
28+
MESSAGE(STATUS "Everything looks good, let's install!")
29+
# Install extension module
30+
install(TARGETS _view DESTINATION .)

CONTRIBUTING.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ $ pip install .
2020

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

23+
Note that this cannot be an editable install (the `-e` flag), as `scikit-build-core` does not support it.
24+
2325
## Workflow
2426

2527
First, you should create a new branch:
2628

2729
```
28-
$ git branch my_cool_feature
29-
$ git checkout my_cool_feature
30+
$ git switch -c my-cool-feature
3031
```
3132

3233
All of your code should be contained on this branch.
@@ -72,7 +73,7 @@ fancy = false
7273
server_logger = true
7374
```
7475

75-
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.
76+
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.
7677

7778
## Writing Tests
7879

MANIFEST.in

Lines changed: 0 additions & 3 deletions
This file was deleted.

_view.pyi

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# flake8: noqa
2-
# NOTE: anything in this file that is defined solely for typing purposes should be
3-
# prefixed with __ to tell the developer that its not an actual symbol defined by
4-
# the extension module
2+
3+
"""
4+
_view - Type stubs for the view.py extension module.
5+
6+
Anything in this file that is defined solely for typing purposes should be
7+
prefixed with __ to tell the developer that its not an actual symbol defined by
8+
the extension module.
9+
"""
510

611
from ipaddress import IPv4Address as __IPv4Address
712
from ipaddress import IPv6Address as __IPv6Address
@@ -14,6 +19,7 @@ from typing import Literal as __Literal
1419
from typing import NoReturn as __NoReturn
1520
from typing import TypeVar as __TypeVar
1621

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

122-
def test_awaitable(coro: __Coroutine[__Any, __Any, __T], /) -> __Awaitable[__T]: ...
128+
def test_awaitable(
129+
coro: __Coroutine[__Any, __Any, __T], /
130+
) -> __Awaitable[__T]: ...
123131

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

135+
app: App
127136
cookies: dict[str, str]
128-
headers: dict[str, str]
137+
headers: HeaderDict
129138
client: __IPv4Address | __IPv6Address | None
130139
server: __IPv4Address | __IPv6Address | None
131140
method: __StrMethodASGI
@@ -152,5 +161,14 @@ class ViewWebSocket:
152161
class InvalidStatusError(RuntimeError): ...
153162
class WebSocketHandshakeError(RuntimeError): ...
154163

155-
def setup_route_log(func: __Callable[[int | str, str, str], None]) -> None: ...
156-
def register_ws_cls(tp: type[__Any]) -> None: ...
164+
def setup_route_log(func: __Callable[[int | str, str, str], None], warn: __Callable[[str], None], /) -> None: ...
165+
def register_ws_cls(
166+
tp: type[__Any], ws_handshake_err: type[__Any], ws_err: type[__Any], /,
167+
) -> None: ...
168+
169+
class HeaderDict:
170+
def __init__(self) -> __NoReturn: ...
171+
def __setitem__(self, key: str, value: str, /) -> None: ...
172+
def __getitem__(self, key: str, /) -> str | list[str]: ...
173+
174+
def dummy_context(app: ViewApp | None) -> Context: ...

client/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<view ref="prerender_head" nosanitize />
4+
<script src="src/reactpy.tsx" type="module"></script>
5+
<p hidden id="_view-route-hook">
6+
<view ref="hook" />
7+
</p>
8+
<view ref="prerender_body" nosanitize />
9+
10+
</html>

client/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"private": true,
3+
"type": "module",
4+
"scripts": {
5+
"dev": "vite",
6+
"build": "tsc && vite build",
7+
"preview": "vite preview"
8+
},
9+
"devDependencies": {
10+
"@types/react": "^18.3.3",
11+
"@types/react-dom": "^18.3.0",
12+
"typescript": "^5.4.5",
13+
"vite": "^5.2.0",
14+
"vite-plugin-singlefile": "^2.0.1"
15+
},
16+
"dependencies": {
17+
"@reactpy/client": "^0.3.1",
18+
"react": "^18.3.1",
19+
"react-dom": "^18.3.1"
20+
}
21+
}

0 commit comments

Comments
 (0)