mirror of
https://github.com/simonw/datasette.git
synced 2026-10-15 22:06:57 +02:00
parent
cf113a5985
commit
e1a4e03635
16 changed files with 24 additions and 47 deletions
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.10'
|
||||
python-version: '3.11'
|
||||
cache: pip
|
||||
cache-dependency-path: pyproject.toml
|
||||
- name: Install dependencies
|
||||
|
|
|
|||
4
.github/workflows/test-pyodide.yml
vendored
4
.github/workflows/test-pyodide.yml
vendored
|
|
@ -19,10 +19,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Set up Python 3.10
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: "3.11"
|
||||
cache: 'pip'
|
||||
cache-dependency-path: '**/pyproject.toml'
|
||||
- name: Cache Playwright browsers
|
||||
|
|
|
|||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
|
||||
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
|
||||
include:
|
||||
- python-version: "3.14"
|
||||
coverage: true
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ You can also install it using `pip` or `pipx`:
|
|||
|
||||
pip install datasette
|
||||
|
||||
Datasette requires Python 3.10 or higher. We also have [detailed installation instructions](https://docs.datasette.io/en/stable/installation.html) covering other options such as Docker.
|
||||
Datasette requires Python 3.11 or higher. We also have [detailed installation instructions](https://docs.datasette.io/en/stable/installation.html) covering other options such as Docker.
|
||||
|
||||
## Basic usage
|
||||
|
||||
|
|
|
|||
|
|
@ -2212,7 +2212,7 @@ ORDER BY allowed.parent, allowed.child
|
|||
|
||||
# Log every check (including cache hits) for the debug page,
|
||||
# dependencies before the actions that required them
|
||||
when = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
when = datetime.datetime.now(datetime.UTC).isoformat()
|
||||
for name in reversed(expanded):
|
||||
self._permission_checks.append(
|
||||
PermissionCheck(
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ logger = logging.getLogger("datasette.background_tasks")
|
|||
|
||||
|
||||
def _utcnow_iso() -> str:
|
||||
return datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
return datetime.datetime.now(datetime.UTC).isoformat()
|
||||
|
||||
|
||||
def _function_path(func: Callable) -> str:
|
||||
|
|
|
|||
|
|
@ -25,12 +25,9 @@ def now(key, request):
|
|||
if key == "epoch":
|
||||
return int(time.time())
|
||||
elif key == "date_utc":
|
||||
return datetime.datetime.now(datetime.timezone.utc).date().isoformat()
|
||||
return datetime.datetime.now(datetime.UTC).date().isoformat()
|
||||
elif key == "datetime_utc":
|
||||
return (
|
||||
datetime.datetime.now(datetime.timezone.utc).strftime(r"%Y-%m-%dT%H:%M:%S")
|
||||
+ "Z"
|
||||
)
|
||||
return datetime.datetime.now(datetime.UTC).strftime(r"%Y-%m-%dT%H:%M:%S") + "Z"
|
||||
else:
|
||||
raise KeyError
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from abc import ABC, abstractproperty
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from datasette.hookspecs import hookimpl
|
||||
|
||||
|
|
@ -11,9 +11,7 @@ class Event(ABC):
|
|||
def name(self):
|
||||
pass
|
||||
|
||||
created: datetime = field(
|
||||
init=False, default_factory=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
created: datetime = field(init=False, default_factory=lambda: datetime.now(UTC))
|
||||
actor: dict | None
|
||||
|
||||
def properties(self):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import sys
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
|
|
@ -193,20 +192,6 @@ _AUTHORIZER_ACTION_NAMES = {
|
|||
}
|
||||
|
||||
|
||||
def _allow_authorizer_action(*args):
|
||||
return sqlite3.SQLITE_OK
|
||||
|
||||
|
||||
def _disable_authorizer(conn):
|
||||
# Python 3.11 added support for unregistering an authorizer using None.
|
||||
# On Python 3.10, None is installed as the callback instead, and the next
|
||||
# statement fails with "not authorized" when sqlite3 tries to call it.
|
||||
if sys.version_info >= (3, 11):
|
||||
conn.set_authorizer(None)
|
||||
else:
|
||||
conn.set_authorizer(_allow_authorizer_action)
|
||||
|
||||
|
||||
def analyze_sql_tables(
|
||||
conn,
|
||||
sql: str,
|
||||
|
|
@ -451,9 +436,7 @@ def analyze_sql_tables(
|
|||
explain_rows = conn.execute(
|
||||
"EXPLAIN " + sql, params if params is not None else {}
|
||||
).fetchall()
|
||||
# Passing None before these lookups leaves a failing callback installed
|
||||
# on Python 3.10, so use a permissive callback until they are complete.
|
||||
conn.set_authorizer(_allow_authorizer_action)
|
||||
conn.set_authorizer(None)
|
||||
|
||||
if not operations:
|
||||
vacuum_row = next((row for row in explain_rows if row[1] == "Vacuum"), None)
|
||||
|
|
@ -495,7 +478,7 @@ def analyze_sql_tables(
|
|||
conn, key.table, schema=key.sqlite_schema
|
||||
)
|
||||
finally:
|
||||
_disable_authorizer(conn)
|
||||
conn.set_authorizer(None)
|
||||
|
||||
has_schema_operation = any(
|
||||
key.target_type in {"table", "index", "view", "trigger", "virtual-table"}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ General guidelines
|
|||
Setting up a development environment
|
||||
------------------------------------
|
||||
|
||||
If you have Python 3.10 or higher installed on your computer (on OS X the quickest way to do this `is using homebrew <https://docs.python-guide.org/starting/install3/osx/>`__) you can install an editable copy of Datasette using the following steps.
|
||||
If you have Python 3.11 or higher installed on your computer (on OS X the quickest way to do this `is using homebrew <https://docs.python-guide.org/starting/install3/osx/>`__) you can install an editable copy of Datasette using the following steps.
|
||||
|
||||
If you want to use GitHub to publish your changes, first `create a fork of datasette <https://github.com/simonw/datasette/fork>`__ under your own GitHub account.
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ If the latest packaged release of Datasette has not yet been made available thro
|
|||
Using pip
|
||||
---------
|
||||
|
||||
Datasette requires Python 3.10 or higher. The `Python.org Python For Beginners <https://www.python.org/about/gettingstarted/>`__ page has instructions for getting started.
|
||||
Datasette requires Python 3.11 or higher. The `Python.org Python For Beginners <https://www.python.org/about/gettingstarted/>`__ page has instructions for getting started.
|
||||
|
||||
You can install Datasette and its dependencies using ``pip``::
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ Use ``which datasette`` to confirm that ``datasette`` will run that version. The
|
|||
|
||||
/usr/local/opt/datasette/bin/datasette
|
||||
|
||||
If you get a different location here such as ``/Library/Frameworks/Python.framework/Versions/3.10/bin/datasette`` you can run the following command to cause ``datasette`` to execute the Homebrew version instead::
|
||||
If you get a different location here such as ``/Library/Frameworks/Python.framework/Versions/3.11/bin/datasette`` you can run the following command to cause ``datasette`` to execute the Homebrew version instead::
|
||||
|
||||
alias datasette=$(echo $(brew --prefix datasette)/bin/datasette)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ authors = [
|
|||
{ name = "Simon Willison" },
|
||||
]
|
||||
license = "Apache-2.0"
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.11"
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Framework :: Datasette",
|
||||
|
|
@ -15,11 +15,11 @@ classifiers = [
|
|||
"Intended Audience :: Science/Research",
|
||||
"Intended Audience :: End Users/Desktop",
|
||||
"Topic :: Database",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
"Programming Language :: Python :: 3.15",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
line-length = 160
|
||||
target-version = "py310"
|
||||
target-version = "py311"
|
||||
|
||||
[lint.flake8-bugbear]
|
||||
# from_extra() returns a dataclasses.field(), so it is safe as a dataclass
|
||||
# default - ruff cannot see through the wrapper (RUF009)
|
||||
extend-immutable-calls = ["datasette.views.from_extra"]
|
||||
extend-immutable-calls = ["datasette.views.from_extra"]
|
||||
|
|
|
|||
|
|
@ -1727,7 +1727,7 @@ async def test_hook_track_event():
|
|||
# Should have a recent created as well
|
||||
created = event.created
|
||||
assert isinstance(created, datetime.datetime)
|
||||
assert created.tzinfo == datetime.timezone.utc
|
||||
assert created.tzinfo == datetime.UTC
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -455,5 +455,4 @@ def test_analyze_disables_authorizer_on_error():
|
|||
with pytest.raises(sqlite3.OperationalError):
|
||||
analyze_sql_tables(conn, "bad SQL")
|
||||
|
||||
final_authorizer = conn.authorizers[-1]
|
||||
assert final_authorizer is None or final_authorizer() == sqlite3.SQLITE_OK
|
||||
assert conn.authorizers[-1] is None
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ async def test_write_wrapper_set_authorizer(datasette, actor, table, should_deny
|
|||
try:
|
||||
yield
|
||||
finally:
|
||||
conn.set_authorizer(lambda *args: sqlite3.SQLITE_OK)
|
||||
conn.set_authorizer(None)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue