Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions .github/workflows/test_be.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
dependencies: ["core", "core,optional"]
python-version: ["3.9"]
python-version: ["3.10"]
include:
- os: ubuntu-latest
python-version: "3.10"
dependencies: "core"
dependencies: "minimal"
- os: ubuntu-latest
python-version: "3.11"
dependencies: "core"
Expand All @@ -74,8 +74,8 @@ jobs:
python-version: "3.13"
dependencies: "core"
- os: ubuntu-latest
python-version: "3.9"
dependencies: "core,optional"
python-version: "3.14"
dependencies: "core"
- os: ubuntu-latest
python-version: "3.10"
dependencies: "core,optional"
Expand All @@ -88,9 +88,7 @@ jobs:
- os: ubuntu-latest
python-version: "3.13"
dependencies: "core,optional"
- os: ubuntu-latest
python-version: "3.9"
dependencies: "minimal"
# TODO: Add in 3.14 optional once there is broader wheel support
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/[email protected]
Expand All @@ -115,6 +113,11 @@ jobs:
if: ${{ matrix.python-version == '3.12' }}
run: hatch run typecheck:check

# Required since python3.14 not pulled automatically for now.
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

# Test with base dependencies
- name: Test with base dependencies
if: ${{ matrix.dependencies == 'core' }}
Expand Down
2 changes: 1 addition & 1 deletion marimo/_messaging/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ class ColumnPreview(msgspec.Struct):


# We shouldn't need to make table_name and column_name have default values.
# We can use kw_only=True once we drop support for Python 3.9.
# We can use kw_only=True once we drop support for Python 3.9 (25-11-01).
class DataColumnPreview(Op, ColumnPreview, tag="data-column-preview"):
"""Preview of a column in a dataset."""

Expand Down
2 changes: 1 addition & 1 deletion marimo/_plugins/ui/_core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

T = TypeVar("T")

# Recursive types don't support | or dict[] in py3.8/3.9
# Recursive types don't support | or dict[] in py3.8/3.9 (25-11-01)
LensValue: TypeAlias = Union[T, dict[str, "LensValue[T]"]]


Expand Down
6 changes: 3 additions & 3 deletions pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies = [
# Pinned to specific version for introduction of codeblock handling.
"pymdown-extensions>=10.15,<11",
# syntax highlighting of code in markdown
"pygments>=2.13,<3",
"pygments>=2.19,<3",
# for reading, writing configs
"tomlkit>= 0.12.0",
# for managing frontmatter headers in markdown
Expand All @@ -36,7 +36,7 @@ dependencies = [
# websockets for use with starlette, and for lsp
"websockets >= 14.2.0",
# loro for collaborative editing
"loro>=1.5.0; python_version >= '3.11'",
"loro>=1.5.0; python_version >= '3.11' and python_version < '3.14'",
# python <=3.10 compatibility
"typing_extensions>=4.4.0; python_version < '3.11'",
# for rst parsing; lowerbound determined by awscli requiring < 0.17,
Expand Down Expand Up @@ -68,6 +68,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3 :: Only",
]

Expand Down Expand Up @@ -195,18 +196,21 @@ extra-dependencies = [
"hypothesis~=6.102.1",
# For server testing
"httpx~=0.27.0",
"matplotlib~=3.9.2",
"urllib3~=2.5.0",
"matplotlib~=3.10.7",
# Forced for modern matplotlib.
"pillow>=9",
"pytest~=8.3.4",
"pytest-timeout~=2.3.1",
"pytest-codecov~=0.6.1",
"pytest-codecov~=0.7.0",
"pytest-rerunfailures~=15.1",
"pytest-asyncio~=0.26.0",
"pytest-picked>=0.5.1",
"inline-snapshot~=0.29.0",
]

[[tool.hatch.envs.test.matrix]]
python = ["3.9", "3.10", "3.11", "3.12", "3.13"]
python = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

[tool.hatch.envs.test.scripts]
test = "pytest{env:HATCH_TEST_ARGS:} {args:tests}"
Expand Down Expand Up @@ -284,7 +288,7 @@ extra-dependencies = [
]

[[tool.hatch.envs.test-optional.matrix]]
python = ["3.9", "3.10", "3.11", "3.12", "3.13"]
python = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

[tool.hatch.envs.docs]
dependencies = [
Expand Down
12 changes: 9 additions & 3 deletions tests/_server/api/endpoints/test_ws_rtc.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def rtc_enabled(config: UserConfigManager):
ws_2_sync = "/ws_sync?session_id=456&access_token=fake-token"


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_loro_sync(client: TestClient) -> None:
"""Test that Loro-CRDT sync works between multiple clients"""

Expand Down Expand Up @@ -147,7 +149,9 @@ async def test_loro_sync(client: TestClient) -> None:
client.post("/api/kernel/shutdown", headers=HEADERS)


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_loro_cleanup_on_session_close(
client: TestClient,
) -> None:
Expand Down Expand Up @@ -192,7 +196,9 @@ async def test_loro_cleanup_on_session_close(
client.post("/api/kernel/shutdown", headers=HEADERS)


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_loro_persistence(client: TestClient) -> None:
"""Test that cell content persists between connections"""
from loro import ExportMode, LoroDoc
Expand Down
40 changes: 29 additions & 11 deletions tests/_server/rtc/test_rtc_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from marimo._server.rtc.doc import LoroDocManager
from marimo._types.ids import CellId_t

if sys.version_info >= (3, 11):
if sys.version_info >= (3, 11) and sys.version_info < (3, 14):
from loro import LoroDoc, LoroText

doc_manager = LoroDocManager()
Expand All @@ -29,7 +29,9 @@ async def setup_doc_manager() -> AsyncGenerator[None, None]:
doc_manager.loro_docs_cleaners.clear()


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_quick_reconnection(setup_doc_manager: None) -> None:
"""Test that quick reconnection properly handles cleanup task cancellation"""
del setup_doc_manager
Expand Down Expand Up @@ -65,7 +67,9 @@ async def test_quick_reconnection(setup_doc_manager: None) -> None:
) # Original client + reconnected client


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_two_users_sync(setup_doc_manager: None) -> None:
"""Test that two users can connect and sync text properly without duplicates"""
del setup_doc_manager
Expand Down Expand Up @@ -111,7 +115,9 @@ async def test_two_users_sync(setup_doc_manager: None) -> None:
assert lang_text_typed.to_string() == "python"


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_concurrent_doc_creation(setup_doc_manager: None) -> None:
"""Test concurrent doc creation doesn't cause issues"""
del setup_doc_manager
Expand All @@ -130,7 +136,9 @@ async def test_concurrent_doc_creation(setup_doc_manager: None) -> None:
assert len(doc_manager.loro_docs) == 1


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_concurrent_client_operations(
setup_doc_manager: None,
) -> None:
Expand All @@ -157,7 +165,9 @@ async def client_operation(queue: asyncio.Queue[bytes]) -> None:
assert len(doc_manager.loro_docs_clients[file_key]) == 0


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_cleanup_task_management(setup_doc_manager: None) -> None:
"""Test cleanup task management and cancellation"""
del setup_doc_manager
Expand Down Expand Up @@ -189,7 +199,9 @@ async def test_cleanup_task_management(setup_doc_manager: None) -> None:
await doc_manager.remove_client(file_key, new_queue)


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_broadcast_update(setup_doc_manager: None) -> None:
"""Test broadcast update functionality"""
del setup_doc_manager
Expand All @@ -215,7 +227,9 @@ async def test_broadcast_update(setup_doc_manager: None) -> None:
assert await queue.get() == message


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_remove_nonexistent_doc(setup_doc_manager: None) -> None:
"""Test removing a doc that doesn't exist"""
del setup_doc_manager
Expand All @@ -226,7 +240,9 @@ async def test_remove_nonexistent_doc(setup_doc_manager: None) -> None:
assert file_key not in doc_manager.loro_docs_cleaners


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_remove_nonexistent_client(setup_doc_manager: None) -> None:
"""Test removing a client that doesn't exist"""
del setup_doc_manager
Expand All @@ -236,7 +252,9 @@ async def test_remove_nonexistent_client(setup_doc_manager: None) -> None:
assert file_key not in doc_manager.loro_docs_clients


@pytest.mark.skipif("sys.version_info < (3, 11)")
@pytest.mark.skipif(
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_concurrent_doc_removal(setup_doc_manager: None) -> None:
"""Test concurrent doc removal doesn't cause issues"""
del setup_doc_manager
Expand All @@ -255,7 +273,7 @@ async def test_concurrent_doc_removal(setup_doc_manager: None) -> None:


@pytest.mark.skipif(
sys.version_info < (3, 11), reason="Python 3.10+ required for Barrier"
"sys.version_info < (3, 11) or sys.version_info >= (3, 14)"
)
async def test_prevent_lock_deadlock(setup_doc_manager: None) -> None:
"""Test that our deadlock prevention measures work correctly.
Expand Down
Loading