Skip to content

Commit da9874a

Browse files
committed
Merge branch 'main' into closure-tables
2 parents ebcd3ed + 6817fc1 commit da9874a

Some content is hidden

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

71 files changed

+3579
-1186
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ jobs:
8888
# Opt in to LDAPAuthenticator tests.
8989
TILED_TEST_LDAP: 1
9090

91+
- name: Upload coverage to Codecov
92+
uses: codecov/codecov-action@v4
93+
with:
94+
name: ${{ inputs.python-version }}/${{ inputs.runs-on }}
95+
files: cov.xml
96+
env:
97+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
98+
9199
windows_checks:
92100
name: Test on Windows
93101
runs-on: windows-latest

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ docs/source/reference/generated/
1616
# pytest
1717
.pytest_cache/
1818

19+
# Unit test / coverage reports
20+
htmlcov/
21+
.tox/
22+
.coverage
23+
.cache
24+
nosetests.xml
25+
coverage.xml
26+
cover/*
27+
1928
# PyBuilder
2029
target/
2130

CHANGELOG.md

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,115 @@
22
Write the date in place of the "Unreleased" in the case a new version is released. -->
33
# Changelog
44

5+
## 0.1.0-b27 (2025-05-08)
56

6-
## Unreleased
7+
_This release requires a database migration of the catalog database._
8+
9+
```none
10+
tiled catalog upgrade-database [postgresql://.. | sqlite:///...]
11+
```
12+
13+
### Added
14+
15+
- New access policy `TagBasedAccessPolicy` which introduces more robust
16+
authorization based on the concept of tagging. When this policy is used,
17+
access to data is controlled by the node's `access_blob` (i.e the tags applied
18+
to that node).
19+
- Added new `access_blob` column to catalog database, in support of the new
20+
authorization. This blob typically contains one of: resource owner (creator),
21+
or a list of access tags.
22+
- Added new filter type `AccessBlobFilter` which filters nodes based upon their
23+
`access_blob` contents. In support of the new authorization.
24+
25+
### Changed
26+
- Tiled now accepts a single `access_control` configuraton for the entire
27+
server, only. Access policies are now a server-wide singleton used for
28+
all access requests. Access control can no longer be specified on
29+
individual trees.
30+
- Removed `path_parts` arg from access policy signatures and related.
31+
- Effective scopes for the principal (from authN) are now threaded into
32+
access policies and related.
33+
- Removed `access_policy` from `MapAdapter` and `CatalogAdapter`; accesss policies
34+
are now set server-wide only.
35+
36+
## 0.1.0-b26 (2025-05-07)
37+
38+
### Added
39+
40+
- New query parameter `drop_revision` on endpoints `PUT /metadata/{path}`
41+
and `PATCH /metadata/{path}`. If set to true, the version replaced by
42+
the update is _not_ saved as a revision. This is exposed in the Python
43+
client via a new keyword-only argument `drop_revision` in
44+
`update_metadata`, `patch_metadata`, and `replace_metadata`.
45+
46+
### Fixed
47+
48+
- A critical bug in the `mount_node` feature introduced in the
49+
previous release prohibited the server from starting when
50+
`mount_node` was used with a PostgreSQL database.
51+
52+
## 0.1.0-b25 (2025-05-06)
53+
54+
### Added
55+
56+
- New optional parameter to catalog configuration, `mount_node`
57+
enables mounting different sub-trees of one catalog database
58+
at different prefixes. This is an advanced feature to facilitate
59+
migration from many catalogs to one. See
60+
`tiled/_tests/test_mount_node.py` for usage.
61+
62+
## 0.1.0-b24 (2025-05-06)
63+
64+
### Added
65+
66+
- Support for reading numpy's on-disk format, `.npy` files.
67+
68+
### Changed
69+
70+
- In server configuration, `writable_storage` now takes a list of URIs,
71+
given in order of decreasing priority.
72+
- Adapters should implement a `supported_storage` attribute, as specified
73+
in `tiled.adapters.protocols.BaseAdapter`. This is optional, for
74+
backward-compatiblity with existing Adapters, which are assumed to
75+
use file-based storage.
76+
77+
### Fixed
78+
79+
- When using SQL-backed storage and file-backed storage, Tiled treated SQLite
80+
or DuckDB files as if they were directories of readable files, and
81+
included them superfluously in a check on whether assets were situated
82+
in a readable area.
83+
- Update data_sources in the client after receiving a response from the server.
84+
Removed the (unused) `data_source` parameter from the `PUT /data_source/`
85+
endpoint; the id of the updated data source must be included in the structure
86+
within the body of the request.
87+
88+
## 0.1.0-b23 (2025-04-24)
89+
90+
### Added
91+
92+
- New query type `Like` enables partial string match using SQL `LIKE`
93+
condition.
94+
95+
### Changed
96+
97+
- Exposed `Session.state` information from database to enhance custom access
98+
control developments.
99+
100+
## 0.1.0-b22 (2025-04-21)
101+
102+
### Added
103+
104+
- Tiled now retries HTTP requests that fail due to server-side (`5XX`) or
105+
connection-level problems.
106+
- Support for `async` streaming serializers (exporters)
107+
108+
### Changed
109+
110+
- Iteration over a `Composite` client yields its (flattened) keys, not its
111+
internal parts. This makes `__iter__` and `__getitem__` consistent.
112+
113+
## 0.1.0-b21 (2025-04-15)
7114

8115
### Added
9116

@@ -15,15 +122,17 @@ Write the date in place of the "Unreleased" in the case a new version is release
15122

16123
- Adjust arguments of `print_admin_api_key_if_generated` and rename `print_server_info`
17124
- Allow `SQLAdapter.append_partition` to accept `pyarrow.Table` as its argument
125+
- Fix streaming serialization of tables keeping the dtypes of individual columns
18126

19127
### Maintenance
20128

21129
- Extract API key handling
22130
- Extract scope fetching and checking
23131
- Refactor router construction
24132
- Adjust environment loading
25-
- This is a breaking change if setting TILED_SERVER_SECRET_KEYS or TILED_ALLOW_ORIGINS,
26-
TILED_SERVER_SECRET_KEYS is now TILED_SECRET_KEYS and these fields now require passing a json
133+
- This is a breaking change if setting `TILED_SERVER_SECRET_KEYS` or
134+
`TILED_ALLOW_ORIGINS`. `TILED_SERVER_SECRET_KEYS` is now
135+
`TILED_SECRET_KEYS` and these fields now require passing a json
27136
list e.g. ``TILED_SECRET_KEYS='["one", "two"]'``
28137
- More type hinting
29138
- Refactor authentication router construction

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: "3.2"
22
services:
33
tiled:
4-
image: ghcr.io/bluesky/tiled:0.1.0-b20
4+
image: ghcr.io/bluesky/tiled:0.1.0-b27
55
environment:
66
- TILED_SINGLE_USER_API_KEY=${TILED_SINGLE_USER_API_KEY}
77
ports:

docs/source/explanations/access-control.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ class PASSAccessPolicy:
102102
f"Its identities are: {principal.identities}"
103103
)
104104

105-
def allowed_scopes(self, node, principal, path_parts):
105+
def allowed_scopes(self, node, principal, authn_scopes):
106106
return PUBLIC_SCOPES
107107

108-
def filters(self, node, principal, scopes, path_parts):
108+
def filters(self, node, principal, authn_scopes, scopes):
109109
queries = []
110110
id = self._get_id(principal)
111111
if not scopes.issubset(PUBLIC_SCOPES):

docs/source/how-to/retries.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Control Retries
2+
3+
Tiled uses the library [stamina](https://stamina.hynek.me/en/stable/) to
4+
implement HTTP retries. Retries are essential for making distributed systems
5+
resilient. See the
6+
[Motivation](https://stamina.hynek.me/en/stable/motivation.html) section of the
7+
stamina documentation for more.
8+
9+
Tiled retries requests that fail to garner a response (e.g. due to connection
10+
problems) or receive a response indicating a server-side problem (HTTP
11+
status code `5XX`). By default, it retries for 10 attempts or 45 seconds,
12+
whichever it reaches first. These defaults can be tuned by setting
13+
environment variables:
14+
15+
```
16+
TILED_RETRY_ATTEMPTS # max number of attempts
17+
TILED_RETRY_TIMEOUT # max total seconds
18+
```
19+
20+
See following examples to control retry behavior in the context of development
21+
or testing.
22+
23+
```python
24+
import stamina
25+
26+
# Disable retries globally.
27+
stamina.set_active(False)
28+
29+
# Check whether retries are active.
30+
stamina.is_active()
31+
32+
# Disable delay between attempts
33+
stamina.set_testing(True, attempts=1)
34+
35+
# Check whether test mode is enabled.
36+
stamina.is_testing()
37+
```

docs/source/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ how-to/metrics
3333
how-to/direct-client
3434
how-to/tiled-authn-database
3535
how-to/register
36+
how-to/retries
3637
```
3738

3839
```{toctree}

docs/source/reference/queries.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Follow the links in the table below for examples specific to each query.
2020
tiled.queries.NotEq
2121
tiled.queries.FullText
2222
tiled.queries.In
23+
tiled.queries.Like
2324
tiled.queries.NotIn
2425
tiled.queries.Regex
2526
tiled.queries.SpecQuery

pyproject.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ all = [
9595
"rich",
9696
"sparse",
9797
"sqlalchemy[asyncio] >=2",
98+
"stamina",
9899
"starlette >=0.38.0",
99100
"tifffile",
100101
"uvicorn[standard]",
@@ -122,6 +123,7 @@ client = [
122123
"pyarrow",
123124
"rich",
124125
"sparse",
126+
"stamina",
125127
"watchfiles",
126128
"xarray",
127129
"zstandard",
@@ -175,6 +177,7 @@ formats = [
175177
minimal-client = [
176178
"entrypoints",
177179
"rich",
180+
"stamina",
178181
"watchfiles",
179182
]
180183
# These are the requirements needed for basic server functionality.
@@ -304,3 +307,12 @@ exclude = '''
304307
| web-frontend
305308
)
306309
'''
310+
311+
[tool.coverage.run]
312+
data_file = "/tmp/tiled.coverage"
313+
314+
[tool.coverage.report]
315+
exclude_lines = ["if __name__ == '__main__':"]
316+
317+
[tool.coverage.paths]
318+
source = ["."]

tiled/_tests/adapters/test_arrow.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import pytest
55

66
from tiled.adapters.arrow import ArrowAdapter
7+
from tiled.storage import FileStorage
78
from tiled.structures.core import StructureFamily
8-
from tiled.structures.data_source import DataSource, Management, Storage
9+
from tiled.structures.data_source import DataSource, Management
910
from tiled.structures.table import TableStructure
1011

1112
names = ["f0", "f1", "f2"]
@@ -38,7 +39,7 @@ def data_source_from_init_storage() -> DataSource[TableStructure]:
3839
structure=structure,
3940
assets=[],
4041
)
41-
storage = Storage(filesystem=data_uri, sql=None)
42+
storage = FileStorage(data_uri)
4243
return ArrowAdapter.init_storage(
4344
data_source=data_source, storage=storage, path_parts=[]
4445
)

0 commit comments

Comments
 (0)