Skip to content

Commit 1471bdc

Browse files
committed
Working on docs
1 parent 81ffc53 commit 1471bdc

File tree

28 files changed

+389
-155
lines changed

28 files changed

+389
-155
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Plain
22

3-
Plain is a web framework for building products with Python.
3+
**A web framework for building products with Python.**
4+
5+
The Plain framework consists of a core `plain` package, and a collection of additional first-party packages that can be installed by choice.
6+
7+
The quickest way to get started is to clone one of the [starter kits](https://plainframework.com/start/), but you can always install `plain` directly from [PyPI](https://pypi.org/project/plain/) and start from scratch.
48

59
With the core `plain` package you can build an app that:
610

@@ -26,7 +30,7 @@ With the official Plain ecosystem packages you can:
2630
- Integrate [HTMX](https://plainframework.com/docs/plain-htmx/)
2731
- Style with [Tailwind CSS](https://plainframework.com/docs/plain-tailwind/)
2832
- Add [OAuth login](https://plainframework.com/docs/plain-oauth/) and API access
29-
- Run tests with [pytest](https://plainframework.com/docs/plain-test/)
33+
- Run tests with [pytest](https://plainframework.com/docs/plain-pytest/)
3034
- Run a [background job worker](https://plainframework.com/docs/plain-worker/)
3135
- Build [admin dashboard and tools](https://plainframework.com/docs/plain-admin/)
3236

plain-admin/plain/admin/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ INSTALLED_PACKAGES += [
113113
114114
```html
115115
<!-- base.template.html -->
116+
116117
{% load toolbar %}
118+
117119
<!doctype html>
118120
<html lang="en">
119121
<head>
@@ -148,7 +150,6 @@ module.exports = {
148150

149151
If you aren't using Tailwind, and don't intend to, open an issue to discuss other options.
150152

151-
152153
# plain.requestlog
153154

154155
The request log stores a local history of HTTP requests and responses during `plain work` (Django runserver).
@@ -213,7 +214,6 @@ module.exports = {
213214

214215
If you aren't using Tailwind, and don't intend to, open an issue to discuss other options.
215216

216-
217217
# plain.impersonate
218218

219219
See what your users see.
@@ -254,7 +254,8 @@ urlpatterns = [
254254

255255
By default, all admin users can impersonate other users.
256256

257-
```python
257+
````python
258258
# settings.py
259259
IMPERSONATE_ALLOWED = lambda user: user.is_admin
260260
``` -->
261+
````

plain-admin/plain/admin/querystats/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ you can add the querystats to your frontend templates with this include:
4343
{% include "querystats/button.html" %}
4444
```
4545

46-
*Note that you will likely want to surround this with an if `DEBUG` or `is_admin` check.*
46+
_Note that you will likely want to surround this with an if `DEBUG` or `is_admin` check._
4747

4848
To view querystats you need to send a POST request to `?querystats=store` (i.e. via a `<form>`),
4949
and the template include is the easiest way to do that.
@@ -69,7 +69,6 @@ module.exports = {
6969

7070
If you aren't using Tailwind, and don't intend to, open an issue to discuss other options.
7171

72-
7372
# plain.toolbar
7473

7574
The admin toolbar is enabled for every user who `is_admin`.
@@ -125,7 +124,6 @@ module.exports = {
125124

126125
If you aren't using Tailwind, and don't intend to, open an issue to discuss other options.
127126

128-
129127
# plain.requestlog
130128

131129
The request log stores a local history of HTTP requests and responses during `plain work` (Django runserver).

plain-auth/plain/auth/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ urlpatterns = [
6666
]
6767
```
6868

69-
7069
## Checking if a user is logged in
7170

7271
A `request.user` will either be `None` or point to an instance of a your `AUTH_USER_MODEL`.
@@ -90,7 +89,6 @@ else:
9089
print("You are not logged in.")
9190
```
9291

93-
9492
## Restricting views
9593

9694
Use the `AuthViewMixin` to restrict views to logged in users, admin users, or custom logic.

plain-dev/plain/dev/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A single command that runs everything you need for local development.
44

55
![Plain dev command example](https://github.com/dropseed/plain/assets/649496/3643bb64-a99b-4a8e-adab-8c6b81791ea9)
66

7-
The `plain.dev` package can be [installed from PyPI](https://pypi.org/project/plain.dev/), and does *not* need to be added to `INSTALLED_PACKAGES`.
7+
The `plain.dev` package can be [installed from PyPI](https://pypi.org/project/plain.dev/), and does _not_ need to be added to `INSTALLED_PACKAGES`.
88

99
- [`plain dev`](#plain-dev)
1010
- [`plain dev services`](#plain-dev-services)
@@ -26,7 +26,7 @@ The `plain dev` command does several things:
2626

2727
### Services
2828

29-
Use services to define databases or other processes that your app *needs* to be functional. The services will be started automatically in `plain dev`, but also in `plain pre-commit` (so preflight and tests have a database).
29+
Use services to define databases or other processes that your app _needs_ to be functional. The services will be started automatically in `plain dev`, but also in `plain pre-commit` (so preflight and tests have a database).
3030

3131
Ultimately, how you run your development database is up to you. But a recommended starting point is to use Docker:
3232

@@ -38,7 +38,7 @@ postgres = {cmd = "docker run --name app-postgres --rm -p 54321:5432 -v $(pwd)/.
3838

3939
### Custom processes
4040

41-
Unlike [services](#services), custom processes are *only* run during `plain dev`. This is a good place to run something like [ngrok](https://ngrok.com/) or a [Plain worker](../../../plain-worker), which you might need to use your local site, but don't need running for executing tests, for example.
41+
Unlike [services](#services), custom processes are _only_ run during `plain dev`. This is a good place to run something like [ngrok](https://ngrok.com/) or a [Plain worker](../../../plain-worker), which you might need to use your local site, but don't need running for executing tests, for example.
4242

4343
```toml
4444
# pyproject.toml

plain-htmx/plain/htmx/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ INSTALLED_PACKAGES = [
5252

5353
An `{% htmxfragment %}` can be used to render a specific part of your template in HTMX responses.
5454
When you use a fragment, all `hx-get`, `hx-post`, etc. elements inside that fragment will automatically send a request to the current URL,
55-
render *only* the updated content for the fragment,
55+
render _only_ the updated content for the fragment,
5656
and swap out the fragment.
5757

5858
Here's an example:
@@ -306,7 +306,7 @@ And then subsequent HTMX requests/actions on individual items can be handled by
306306
</div>
307307
```
308308

309-
*If* you need a URL to render an individual item, you can simply include the same template fragment in most cases:
309+
_If_ you need a URL to render an individual item, you can simply include the same template fragment in most cases:
310310

311311
```html
312312
<!-- pullrequests/pullrequest_detail.html -->

plain-htmx/plain/htmx/assets/htmx/src/ext/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ These are legacy extensions for htmx 1.x and are **NOT** actively maintained or
44
They are here because we unfortunately linked to unversioned unpkg URLs in the installation guides for them
55
in 1.x, so we need to keep them here to preserve those URLs and not break existing users functionality.
66

7-
If you are looking for extensions for htmx 2.x, please see the [htmx 2.0 extensions site](https://htmx.org/extensions),
7+
If you are looking for extensions for htmx 2.x, please see the [htmx 2.0 extensions site](https://htmx.org/extensions),
88
which has links to the new extensions repos (They have all been moved to their own NPM projects and URLs, like
99
they should have been from the start!)

plain-oauth/plain/oauth/README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ There are three OAuth flows that it makes possible:
1515
2. Login via OAuth (existing user, existing OAuth connection)
1616
3. Connect/disconnect OAuth accounts to a user (existing user, new OAuth connection)
1717

18-
1918
## Usage
2019

2120
Install the package from PyPi:
@@ -142,7 +141,7 @@ That's pretty much it!
142141
The most common error you'll run into is if an existing user clicks a login button,
143142
but they haven't yet connected that provider to their account.
144143
For security reasons,
145-
the required flow here is that the user actually logs in with another method (however they signed up) and then *connects* the OAuth provider from a settings page.
144+
the required flow here is that the user actually logs in with another method (however they signed up) and then _connects_ the OAuth provider from a settings page.
146145

147146
For this error (and a couple others),
148147
there is an error template that is rendered.
@@ -236,7 +235,7 @@ response = requests.get(...)
236235

237236
### Using the Django system check
238237

239-
This library comes with a Django system check to ensure you don't *remove* a provider from `settings.py` that is still in use in your database.
238+
This library comes with a Django system check to ensure you don't _remove_ a provider from `settings.py` that is still in use in your database.
240239
You do need to specify the `--database` for this to run when using the check command by itself:
241240

242241
```sh
@@ -247,7 +246,7 @@ python manage.py check --database default
247246

248247
### How is this different from [Django OAuth libraries](https://djangopackages.org/grids/g/oauth/)?
249248

250-
The short answer is that *it does less*.
249+
The short answer is that _it does less_.
251250

252251
In [django-allauth](https://github.com/pennersr/django-allauth)
253252
(maybe the most popular alternative)
@@ -262,7 +261,7 @@ Personally, I don't like the way that your OAuth settings are stored in the data
262261
and the implications for doing it one way or another.
263262

264263
The other popular OAuth libraries have similar issues,
265-
and I think their *weight* outweighs their usefulness for 80% of the use cases.
264+
and I think their _weight_ outweighs their usefulness for 80% of the use cases.
266265

267266
### Why aren't providers included in the library itself?
268267

@@ -281,7 +280,7 @@ Just copy that code and paste it in your project.
281280
Tweak as necessary!
282281

283282
This might sound strange at first.
284-
But in the long run we think it's actually *much* more maintainable for both us (as library authors) and you (as app author).
283+
But in the long run we think it's actually _much_ more maintainable for both us (as library authors) and you (as app author).
285284
If something breaks with a provider, you can fix it immediately!
286285
You don't need to try to run changes through us or wait for an upstream update.
287286
You're welcome to contribute an example to this repo,

plain-pageviews/plain/pageviews/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ class UserAdmin(AdminViewset):
2727

2828
### Why not use server-side middleware?
2929

30-
Originally this was the idea. It turns out that tracking from the backend, while powerful, also means you have to identify all kinds of requests *not* to track (assets, files, API calls, etc.). In the end, a simple client-side tracking script naturally accomplishes what we're looking for in a more straightforward way.
30+
Originally this was the idea. It turns out that tracking from the backend, while powerful, also means you have to identify all kinds of requests _not_ to track (assets, files, API calls, etc.). In the end, a simple client-side tracking script naturally accomplishes what we're looking for in a more straightforward way.

plain/plain/README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,60 @@
11
# Plain
2+
3+
- pep 420 https://peps.python.org/pep-0420/
4+
5+
## Core Modules
6+
7+
The `plain` package includes everything you need to start handling web requests with Python:
8+
9+
- [assets](assets/README.md) - Serve static files and assets.
10+
- [cli](cli/README.md) - The `plain` CLI, powered by Click.
11+
- [csrf](csrf/README.md) - Cross-Site Request Forgery protection.
12+
- [forms](forms/README.md) - HTML forms and form validation.
13+
- [http](http/README.md) - HTTP request and response handling.
14+
- [logs](logs/README.md) - Logging configuration and utilities.
15+
- [preflight](preflight/README.md) - Preflight checks for your app.
16+
- [runtime](runtime/README.md) - Runtime settings and configuration.
17+
- [templates](templates/README.md) - Jinja2 templates and rendering.
18+
- [test](test/README.md) - Test utilities and fixtures.
19+
- [urls](urls/README.md) - URL routing and request dispatching.
20+
- [views](views/README.md) - Class-based views and request handlers.
21+
22+
## Foundational Packages
23+
24+
- [plain.models](/plain-models/README.md) - Define and interact with your database models.
25+
- [plain.cache](/plain-cache/README.md) - A database-driven general purpose cache.
26+
- [plain.mail](/plain-mail/README.md) - Send emails with SMTP or custom backends.
27+
- [plain.sessions](/plain-sessions/README.md) - User sessions and cookies.
28+
- [plain.worker](/plain-worker/README.md) - Backgrounb jobs stored in the database.
29+
- [plain.api](/plain-api/README.md) - Build APIs with Plain views.
30+
31+
## Auth Packages
32+
33+
- [plain.auth](/plain-auth/README.md) - User authentication and authorization.
34+
- [plain.oauth](/plain-oauth/README.md) - OAuth authentication and API access.
35+
- [plain.passwords](/plain-passwords/README.md) - Password-based login and registration.
36+
- [plain.loginlink](/plain-loginlink/README.md) - Login links for passwordless authentication.
37+
38+
## Admin Packages
39+
40+
- [plain.admin](/plain-admin/README.md) - An admin interface for back-office tasks.
41+
- [plain.flags](/plain-flags/README.md) - Feature flags.
42+
- [plain.support](/plain-support/README.md) - Customer support forms.
43+
- [plain.redirection](/plain-redirection/README.md) - Redirects managed in the database.
44+
- [plain.pageviews](/plain-pageviews/README.md) - Basic self-hosted page view tracking and reporting.
45+
46+
## Dev Packages
47+
48+
- [plain.dev](/plain-dev/README.md) - A single command for local development.
49+
- [plain.pytest](/plain-pytest/README.md) - Pytest fixtures and helpers.
50+
- [plain.code](/plain-code/README.md) - Code formatting and linting.
51+
- [plain.tunnel](/plain-tunnel/README.md) - Expose your local server to the internet.
52+
53+
## Frontend Packages
54+
55+
- [plain.tailwind](/plain-tailwind/README.md) - Tailwind CSS integration without Node.js.
56+
- [plain.htmx](/plain-htmx/README.md) - HTMX integrated into views and templates.
57+
- [plain.elements](/plain-elements/README.md) - Server-side HTML components.
58+
- [plain.pages](/plain-pages/README.md) - Static pages with Markdown and Jinja2.
59+
- [plain.esbuild](/plain-esbuild/README.md) - Simple JavaScript bundling and minification.
60+
- [plain.vendor](/plain-vendor/README.md) - Vendor JavaScript and CSS libraries.

plain/plain/assets/README.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
# Assets
22

3-
Serve static assets (CSS, JS, images, etc.) directly from your app.
4-
3+
**Serve static assets (CSS, JS, images, etc.) directly or from a CDN.**
54

65
## Usage
76

87
To serve assets, put them in `app/assets` or `app/{package}/assets`.
98

10-
Then include the `plain.assets.urls` in your `urls.py`:
9+
Then include the `AssetsRouter` in your own router, typically under the `assets/` path.
1110

1211
```python
1312
# app/urls.py
14-
from plain.urls import include, path
15-
import plain.assets.urls
13+
from plain.assets.urls import AssetsRouter
14+
from plain.urls import include, Router
1615

1716

18-
urlpatterns = [
19-
path("assets/", include(plain.assets.urls)),
20-
# ...
21-
]
17+
class AppRouter(Router):
18+
namespace = ""
19+
urls = [
20+
include("assets/", AssetsRouter),
21+
# your other routes here...
22+
]
2223
```
2324

24-
Now in your template you can use the `asset()` function to get the URL:
25+
Now in your template you can use the `asset()` function to get the URL, which will output the fully compiled and fingerprinted URL.
2526

2627
```html
2728
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
2829
```
2930

30-
3131
## Local development
3232

3333
When you're working with `settings.DEBUG = True`, the assets will be served directly from their original location. You don't need to run `plain build` or configure anything else.
3434

35-
3635
## Production deployment
3736

3837
In production, one of your deployment steps should be to compile the assets.
@@ -41,11 +40,10 @@ In production, one of your deployment steps should be to compile the assets.
4140
plain build
4241
```
4342

44-
By default, this generates "fingerprinted" and compressed versions of the assets, which are then served by your app. This means that a file like `main.css` will result in two new files, like `main.d0db67b.css` and `main.d0db67b.css.gz`.
43+
By default, this [generates "fingerprinted" and compressed versions of the assets](fingerprints.py#get_file_fingerprint), which are then served by your app. This means that a file like `main.css` will result in two new files, like `main.d0db67b.css` and `main.d0db67b.css.gz`.
4544

4645
The purpose of fingerprinting the assets is to allow the browser to cache them indefinitely. When the content of the file changes, the fingerprint will change, and the browser will use the newer file. This cuts down on the number of requests that your app has to handle related to assets.
4746

48-
4947
## FAQs
5048

5149
### How do you reference assets in Python code?
@@ -67,10 +65,16 @@ mv .plain/assets/compiled /path/to/your/static
6765

6866
### How do I upload the assets to a CDN?
6967

70-
The steps for this will vary, but the general idea is to compile them, and then upload the compiled assets.
68+
The steps for this will vary, but the general idea is to compile them, and then upload the compiled assets from their [compiled location](compile.py#get_compiled_path).
7169

7270
```bash
71+
# Compile the assets
7372
plain build
73+
74+
# List the newly compiled files
75+
ls .plain/assets/compiled
76+
77+
# Upload the files to your CDN
7478
./example-upload-to-cdn-script
7579
```
7680

@@ -81,14 +85,10 @@ Use the `ASSETS_BASE_URL` setting to tell the `{{ asset() }}` template function
8185
ASSETS_BASE_URL = "https://cdn.example.com/"
8286
```
8387

84-
8588
### Why aren't the originals copied to the compiled directory?
8689

8790
The default behavior is to fingerprint assets, which is an exact copy of the original file but with a different filename. The originals aren't copied over because you should generally always use this fingerprinted path (that automatically uses longer-lived caching).
8891

8992
If you need the originals for any reason, you can use `plain build --keep-original`, though this will typically be combined with `--no-fingerprint` otherwise the fingerprinted files will still get priority in `{{ asset() }}` template calls.
9093

91-
92-
### What about source maps or imported css files?
93-
94-
TODO
94+
Note that by default, the `ASSETS_REDIRECT_ORIGINAL` setting is `True`, which will redirect requests for the original file to the fingerprinted file.

0 commit comments

Comments
 (0)