Plain
Plain is a web framework for building products with Python.
With the core plain
package you can build an app that:
- Matches URL patterns to Python views
- Handles HTTP requests and responses
- Renders HTML templates with Jinja
- Processes user input via forms
- Has a CLI interface
- Serves static assets (CSS, JS, images)
- Can be modified with middleware
- Integrates first-party and third-party packages
- Has a preflight check system
With the official Plain ecosystem packages you can:
- Integrate a full-featured database ORM
- Use a built-in user authentication system
- Lint and format code
- Run a database-backed cache
- Send emails
- Streamline local development
- Manage feature flags
- Integrate HTMX
- Style with Tailwind CSS
- Add OAuth login and API access
- Run tests with pytest
- Run a background job worker
- Build staff tooling and admin dashboards
Learn more at plainframework.com.
1import datetime
2import decimal
3import json
4import uuid
5
6from plain.utils.duration import duration_iso_string
7from plain.utils.functional import Promise
8from plain.utils.timezone import is_aware
9
10
11class PlainJSONEncoder(json.JSONEncoder):
12 """
13 JSONEncoder subclass that knows how to encode date/time, decimal types, and
14 UUIDs.
15 """
16
17 def default(self, o):
18 # See "Date Time String Format" in the ECMA-262 specification.
19 if isinstance(o, datetime.datetime):
20 r = o.isoformat()
21 if o.microsecond:
22 r = r[:23] + r[26:]
23 if r.endswith("+00:00"):
24 r = r.removesuffix("+00:00") + "Z"
25 return r
26 elif isinstance(o, datetime.date):
27 return o.isoformat()
28 elif isinstance(o, datetime.time):
29 if is_aware(o):
30 raise ValueError("JSON can't represent timezone-aware times.")
31 r = o.isoformat()
32 if o.microsecond:
33 r = r[:12]
34 return r
35 elif isinstance(o, datetime.timedelta):
36 return duration_iso_string(o)
37 elif isinstance(o, decimal.Decimal | uuid.UUID | Promise):
38 return str(o)
39 else:
40 return super().default(o)