mirror of
https://github.com/simonw/datasette.git
synced 2026-05-28 21:06:18 +02:00
Switch to ruff and fix all lint errors, refs #2630
This commit is contained in:
parent
b0436faa5e
commit
66d2a033f8
21 changed files with 44 additions and 101 deletions
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -35,6 +35,8 @@ jobs:
|
|||
tests/test_datasette_https_server.sh
|
||||
- name: Black
|
||||
run: black --check .
|
||||
- name: Ruff
|
||||
run: ruff check datasette tests
|
||||
- name: Check if cog needs to be run
|
||||
run: |
|
||||
cog --check docs/*.rst
|
||||
|
|
|
|||
12
Justfile
12
Justfile
|
|
@ -17,12 +17,16 @@ export DATASETTE_SECRET := "not_a_secret"
|
|||
uv run codespell datasette -S datasette/static --ignore-words docs/codespell-ignore-words.txt
|
||||
uv run codespell tests --ignore-words docs/codespell-ignore-words.txt
|
||||
|
||||
# Run linters: black, flake8, mypy, cog
|
||||
# Run linters: black, ruff, cog
|
||||
@lint: codespell
|
||||
uv run black . --check
|
||||
uv run flake8
|
||||
uv run black datasette tests --check
|
||||
uv run ruff check datasette tests
|
||||
uv run cog --check README.md docs/*.rst
|
||||
|
||||
# Apply ruff fixes
|
||||
@fix:
|
||||
uv run ruff check --fix datasette tests
|
||||
|
||||
# Rebuild docs with cog
|
||||
@cog:
|
||||
uv run cog -r README.md docs/*.rst
|
||||
|
|
@ -37,7 +41,7 @@ export DATASETTE_SECRET := "not_a_secret"
|
|||
|
||||
# Apply Black
|
||||
@black:
|
||||
uv run black .
|
||||
uv run black datasette tests
|
||||
|
||||
# Apply blacken-docs
|
||||
@blacken-docs:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import contextvars
|
|||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from datasette.permissions import AllowedResource, Resource
|
||||
from datasette.permissions import Resource
|
||||
import asgi_csrf
|
||||
import collections
|
||||
import dataclasses
|
||||
|
|
@ -1144,7 +1144,7 @@ class Datasette:
|
|||
|
||||
# Validate that resource is a Resource object or None
|
||||
if resource is not None and not isinstance(resource, Resource):
|
||||
raise TypeError(f"resource must be a Resource subclass instance or None.")
|
||||
raise TypeError("resource must be a Resource subclass instance or None.")
|
||||
|
||||
# Check if actor can see it
|
||||
if not await self.allowed(action=action, resource=resource, actor=actor):
|
||||
|
|
|
|||
|
|
@ -26,18 +26,18 @@ from datasette import hookimpl
|
|||
|
||||
# Re-export all hooks and public utilities
|
||||
from .restrictions import (
|
||||
actor_restrictions_sql,
|
||||
restrictions_allow_action,
|
||||
ActorRestrictions,
|
||||
actor_restrictions_sql as actor_restrictions_sql,
|
||||
restrictions_allow_action as restrictions_allow_action,
|
||||
ActorRestrictions as ActorRestrictions,
|
||||
)
|
||||
from .root import root_user_permissions_sql
|
||||
from .config import config_permissions_sql
|
||||
from .root import root_user_permissions_sql as root_user_permissions_sql
|
||||
from .config import config_permissions_sql as config_permissions_sql
|
||||
from .defaults import (
|
||||
default_allow_sql_check,
|
||||
default_action_permissions_sql,
|
||||
DEFAULT_ALLOW_ACTIONS,
|
||||
default_allow_sql_check as default_allow_sql_check,
|
||||
default_action_permissions_sql as default_action_permissions_sql,
|
||||
DEFAULT_ALLOW_ACTIONS as DEFAULT_ALLOW_ACTIONS,
|
||||
)
|
||||
from .tokens import actor_from_signed_api_token
|
||||
from .tokens import actor_from_signed_api_token as actor_from_signed_api_token
|
||||
|
||||
|
||||
@hookimpl
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import asyncio
|
||||
import csv
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ dev = [
|
|||
"pytest-timeout>=1.4.2",
|
||||
"trustme>=0.7",
|
||||
"cogapp>=3.3.0",
|
||||
"ruff>=0.9",
|
||||
# docs
|
||||
"Sphinx==7.4.7",
|
||||
"furo==2025.9.25",
|
||||
|
|
@ -94,5 +95,9 @@ datasette = ["templates/*.html"]
|
|||
[tool.setuptools.dynamic]
|
||||
version = {attr = "datasette.version.__version__"}
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 160
|
||||
select = ["E", "F", "W"]
|
||||
|
||||
[tool.uv]
|
||||
package = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,2 @@
|
|||
[aliases]
|
||||
test=pytest
|
||||
|
||||
[flake8]
|
||||
max-line-length = 160
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ async def test_tables_endpoint_database_restriction(test_ds):
|
|||
|
||||
# Bob should only see analytics tables
|
||||
analytics_tables = [m for m in result if m["name"].startswith("analytics/")]
|
||||
production_tables = [m for m in result if m["name"].startswith("production/")]
|
||||
|
||||
assert len(analytics_tables) == 3
|
||||
table_names = {m["name"] for m in analytics_tables}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,7 @@
|
|||
from datasette.app import Datasette
|
||||
from datasette.plugins import DEFAULT_PLUGINS
|
||||
from datasette.version import __version__
|
||||
from .fixtures import ( # noqa
|
||||
app_client,
|
||||
app_client_no_files,
|
||||
app_client_with_dot,
|
||||
app_client_shorter_time_limit,
|
||||
app_client_two_attached_databases_one_immutable,
|
||||
app_client_larger_cache_size,
|
||||
app_client_with_cors,
|
||||
app_client_two_attached_databases,
|
||||
app_client_conflicting_database_names,
|
||||
app_client_immutable_and_inspect_file,
|
||||
make_app_client,
|
||||
EXPECTED_PLUGINS,
|
||||
METADATA,
|
||||
)
|
||||
from .fixtures import make_app_client, EXPECTED_PLUGINS
|
||||
import pathlib
|
||||
import pytest
|
||||
import sys
|
||||
|
|
@ -815,14 +801,14 @@ def test_databases_json(app_client_two_attached_databases_one_immutable):
|
|||
assert 2 == len(databases)
|
||||
extra_database, fixtures_database = databases
|
||||
assert "extra database" == extra_database["name"]
|
||||
assert None == extra_database["hash"]
|
||||
assert True == extra_database["is_mutable"]
|
||||
assert False == extra_database["is_memory"]
|
||||
assert extra_database["hash"] is None
|
||||
assert extra_database["is_mutable"] is True
|
||||
assert extra_database["is_memory"] is False
|
||||
|
||||
assert "fixtures" == fixtures_database["name"]
|
||||
assert fixtures_database["hash"] is not None
|
||||
assert False == fixtures_database["is_mutable"]
|
||||
assert False == fixtures_database["is_memory"]
|
||||
assert fixtures_database["is_mutable"] is False
|
||||
assert fixtures_database["is_memory"] is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ def test_invalid_settings(config_dir):
|
|||
)
|
||||
try:
|
||||
with pytest.raises(StartupError) as ex:
|
||||
ds = Datasette([], config_dir=config_dir)
|
||||
Datasette([], config_dir=config_dir)
|
||||
assert ex.value.args[0] == "Invalid setting 'invalid' in config file"
|
||||
finally:
|
||||
(config_dir / "datasette.json").write_text(previous, "utf-8")
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ def test_crossdb_attached_database_list_display(
|
|||
):
|
||||
app_client = app_client_two_attached_databases_crossdb_enabled
|
||||
response = app_client.get("/_memory")
|
||||
response2 = app_client.get("/")
|
||||
app_client.get("/")
|
||||
for fragment in (
|
||||
"databases are attached to this connection",
|
||||
"<li><strong>fixtures</strong> - ",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
from datasette.app import Datasette
|
||||
from bs4 import BeautifulSoup as Soup
|
||||
import pytest
|
||||
from .fixtures import ( # noqa
|
||||
app_client,
|
||||
app_client_csv_max_mb_one,
|
||||
app_client_with_cors,
|
||||
app_client_with_trace,
|
||||
)
|
||||
import urllib.parse
|
||||
|
||||
EXPECTED_TABLE_CSV = """id,content
|
||||
|
|
|
|||
|
|
@ -103,27 +103,6 @@ async def test_through_filters_from_request(ds_client):
|
|||
assert filter_args.extra_context == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_through_filters_from_request(ds_client):
|
||||
request = Request.fake(
|
||||
'/?_through={"table":"roadside_attraction_characteristics","column":"characteristic_id","value":"1"}'
|
||||
)
|
||||
filter_args = await through_filters(
|
||||
request=request,
|
||||
datasette=ds_client.ds,
|
||||
table="roadside_attractions",
|
||||
database="fixtures",
|
||||
)()
|
||||
assert filter_args.where_clauses == [
|
||||
"pk in (select attraction_id from roadside_attraction_characteristics where characteristic_id = :p0)"
|
||||
]
|
||||
assert filter_args.params == {"p0": "1"}
|
||||
assert filter_args.human_descriptions == [
|
||||
'roadside_attraction_characteristics.characteristic_id = "1"'
|
||||
]
|
||||
assert filter_args.extra_context == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_where_filters_from_request(ds_client):
|
||||
await ds_client.ds.invoke_startup()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,7 @@
|
|||
from bs4 import BeautifulSoup as Soup
|
||||
from datasette.app import Datasette
|
||||
from datasette.utils import allowed_pragmas
|
||||
from .fixtures import ( # noqa
|
||||
app_client,
|
||||
app_client_base_url_prefix,
|
||||
app_client_shorter_time_limit,
|
||||
app_client_two_attached_databases,
|
||||
make_app_client,
|
||||
METADATA,
|
||||
)
|
||||
from .fixtures import make_app_client
|
||||
from .utils import assert_footer_links, inner_html
|
||||
import copy
|
||||
import json
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ def test_datasette_error_if_string_not_list(tmpdir):
|
|||
# https://github.com/simonw/datasette/issues/1985
|
||||
db_path = str(tmpdir / "data.db")
|
||||
with pytest.raises(ValueError):
|
||||
ds = Datasette(db_path)
|
||||
Datasette(db_path)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import collections
|
|||
from datasette.app import Datasette
|
||||
from datasette.cli import cli
|
||||
from datasette.default_permissions import restrictions_allow_action
|
||||
from .fixtures import app_client, assert_permissions_checked, make_app_client
|
||||
from .fixtures import assert_permissions_checked, make_app_client
|
||||
from click.testing import CliRunner
|
||||
from bs4 import BeautifulSoup as Soup
|
||||
import copy
|
||||
|
|
@ -1481,7 +1481,6 @@ async def test_actor_restrictions_view_instance_only(perms_ds):
|
|||
assert response.status_code == 200
|
||||
|
||||
# But no databases should be visible (no view-database permission)
|
||||
data = response.json()
|
||||
# The instance is visible but databases list should be empty or minimal
|
||||
# Actually, let's check via allowed_resources
|
||||
page = await perms_ds.allowed_resources("view-database", actor)
|
||||
|
|
|
|||
|
|
@ -1172,8 +1172,6 @@ async def test_hook_filters_from_request(ds_client):
|
|||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("extra_metadata", (False, True))
|
||||
async def test_hook_register_actions(extra_metadata):
|
||||
from datasette.permissions import Action
|
||||
from datasette.resources import DatabaseResource, InstanceResource
|
||||
|
||||
ds = Datasette(
|
||||
config=(
|
||||
|
|
@ -1527,7 +1525,7 @@ async def test_hook_register_events():
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hook_register_actions():
|
||||
async def test_hook_register_actions_view_collection():
|
||||
datasette = Datasette(memory=True, plugins_dir=PLUGINS_DIR)
|
||||
await datasette.invoke_startup()
|
||||
# Check that the custom action from my_plugin.py is registered
|
||||
|
|
@ -1545,7 +1543,7 @@ async def test_hook_register_actions_with_custom_resources():
|
|||
- A parent-level action (DocumentCollectionResource)
|
||||
- A child-level action (DocumentResource)
|
||||
"""
|
||||
from datasette.permissions import Resource, Action
|
||||
from datasette.permissions import Resource
|
||||
|
||||
# Define custom Resource classes
|
||||
class DocumentCollectionResource(Resource):
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ async def test_also_requires_with_restrictions():
|
|||
"""
|
||||
ds = Datasette()
|
||||
await ds.invoke_startup()
|
||||
db1 = ds.add_memory_database("db1_also_requires")
|
||||
db2 = ds.add_memory_database("db2_also_requires")
|
||||
ds.add_memory_database("db1_also_requires")
|
||||
ds.add_memory_database("db2_also_requires")
|
||||
await ds._refresh_schemas()
|
||||
|
||||
# Actor restricted to only db1_also_requires for view-database
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import asyncio
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from datasette.app import Datasette
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
from datasette.utils import detect_json1
|
||||
from datasette.utils.sqlite import sqlite_version
|
||||
from .fixtures import ( # noqa
|
||||
app_client,
|
||||
app_client_with_trace,
|
||||
app_client_returned_rows_matches_page_size,
|
||||
generate_compound_rows,
|
||||
generate_sortable_rows,
|
||||
make_app_client,
|
||||
)
|
||||
from .fixtures import generate_compound_rows, generate_sortable_rows, make_app_client
|
||||
import json
|
||||
import pytest
|
||||
import urllib
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
from datasette.app import Datasette
|
||||
from bs4 import BeautifulSoup as Soup
|
||||
from .fixtures import ( # noqa
|
||||
app_client,
|
||||
make_app_client,
|
||||
app_client_with_dot,
|
||||
)
|
||||
from .fixtures import make_app_client
|
||||
import pathlib
|
||||
import pytest
|
||||
import urllib.parse
|
||||
|
|
@ -1263,7 +1259,7 @@ async def test_foreign_key_labels_obey_permissions(config):
|
|||
"insert or replace into b (id, name, a_id) values (1, 'world', 1)"
|
||||
)
|
||||
# Anonymous user can see table b but not table a
|
||||
blah = await ds.client.get("/foreign_key_labels.json")
|
||||
await ds.client.get("/foreign_key_labels.json")
|
||||
anon_a = await ds.client.get("/foreign_key_labels/a.json?_labels=on")
|
||||
assert anon_a.status_code == 403
|
||||
anon_b = await ds.client.get("/foreign_key_labels/b.json?_labels=on")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue