Skip to content

Commit 2e62839

Browse files
committed
fix tests
1 parent a69c19e commit 2e62839

File tree

11 files changed

+135
-69
lines changed

11 files changed

+135
-69
lines changed

extensions/positron-python/python_files/posit/positron/tests/test_convert.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from .conftest import DummyComm, PositronShell
2121
from .test_data_explorer import (
2222
COMPARE_OPS,
23+
SIMPLE_DATA,
2324
SIMPLE_PANDAS_DF,
2425
DataExplorerFixture,
2526
_between_filter,
@@ -42,8 +43,13 @@
4243
except ImportError:
4344
has_sqlalchemy = False
4445

46+
try:
47+
import pyarrow
4548

46-
SIMPLE_POLARS_DF = pl.DataFrame(SIMPLE_PANDAS_DF.drop(columns=["f"]))
49+
SIMPLE_POLARS_DF = pl.DataFrame(SIMPLE_PANDAS_DF.drop(columns=["f"]))
50+
except ImportError:
51+
pyarrow = None
52+
SIMPLE_POLARS_DF = pl.DataFrame({k: v for k, v in SIMPLE_DATA.items() if k != "f"})
4753

4854

4955
# ruff: noqa: E712
@@ -655,7 +661,7 @@ def test_convert_polars_filter_compare(dxf: DataExplorerConvertFixture):
655661
def test_convert_polars_filter_datetimetz(dxf: DataExplorerConvertFixture):
656662
test_df = pl.DataFrame(
657663
{
658-
"date": pd.date_range("2000-01-01", periods=5, tz="US/Eastern"),
664+
"date": pd.date_range("2000-01-01", periods=5, tz="US/Eastern").to_list(),
659665
}
660666
)
661667
tz = pytz.timezone("US/Eastern")
@@ -692,6 +698,7 @@ def test_convert_polars_sort_and_filter(dxf: DataExplorerConvertFixture):
692698
)
693699

694700

701+
@pytest.mark.skipif(pyarrow is None, reason="pyarrow is not installed")
695702
def test_convert_polars_sort_to_pandas(dxf: DataExplorerConvertFixture):
696703
# Test that we can convert a sort operation to pandas
697704
test_df = SIMPLE_POLARS_DF

extensions/positron-python/python_files/posit/positron/tests/test_data_explorer.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from io import StringIO
1515
from typing import Any, Dict, List, Optional, Type, cast
1616

17-
import ibis
1817
import numpy as np
1918
import pandas as pd
2019
import polars as pl
@@ -59,6 +58,11 @@
5958
from .test_variables import BIG_ARRAY_LENGTH, _assign_variables
6059
from .utils import dummy_rpc_request, json_rpc_notification, json_rpc_request
6160

61+
try:
62+
import ibis
63+
except ImportError:
64+
ibis = None
65+
6266
TARGET_NAME = "positron.dataExplorer"
6367

6468

@@ -122,7 +126,7 @@ def __repr__(self):
122126
"a": [1, 2, 3, 4, 5],
123127
"b": [True, False, True, None, True],
124128
"c": ["foo", "bar", None, "bar", "None"],
125-
"d": [0, 1.2, -4.5, 6, np.nan],
129+
"d": [0.0, 1.2, -4.5, 6, np.nan],
126130
"e": pd.to_datetime(
127131
[
128132
"2024-01-01 00:00:00",
@@ -139,13 +143,16 @@ def __repr__(self):
139143

140144
SIMPLE_PANDAS_DF = pd.DataFrame(SIMPLE_DATA)
141145

142-
SIMPLE_IBIS_DF = ibis.memtable(
143-
{
144-
"a": [1, 2, 3, 4, 5],
145-
"b": [True, False, True, None, True],
146-
"c": ["foo", "bar", None, "bar", "None"],
147-
}
148-
)
146+
if ibis:
147+
SIMPLE_IBIS_DF = ibis.memtable(
148+
{
149+
"a": [1, 2, 3, 4, 5],
150+
"b": [True, False, True, None, True],
151+
"c": ["foo", "bar", None, "bar", "None"],
152+
}
153+
)
154+
else:
155+
SIMPLE_IBIS_DF = None
149156

150157

151158
def test_service_properties(de_service: DataExplorerService):
@@ -4211,6 +4218,7 @@ def test_polars_profile_summary_stats(dxf: DataExplorerFixture):
42114218
assert_summary_stats_equal(stats["type_display"], stats, ex_result)
42124219

42134220

4221+
@pytest.mark.skipif(ibis is None, reason="ibis is not available")
42144222
def test_ibis_supported_features(dxf: DataExplorerFixture):
42154223
dxf.register_table("example", SIMPLE_IBIS_DF)
42164224
features = dxf.get_state("example")["supported_features"]

extensions/positron-python/python_files/posit/positron/tests/test_inspectors.py

Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,11 @@
99
import types
1010
from typing import Any, Callable, Iterable, Optional, Tuple
1111

12-
import geopandas
1312
import numpy as np
1413
import pandas as pd
1514
import polars as pl
1615
import pytest
17-
import torch
1816
from fastcore.foundation import L
19-
from shapely.geometry import Polygon
2017

2118
from positron import inspectors
2219
from positron.inspectors import _get_simplified_qualname, get_inspector
@@ -37,6 +34,23 @@
3734
)
3835
from .utils import get_type_as_str
3936

37+
try:
38+
import geopandas
39+
from shapely.geometry import Polygon
40+
except ImportError:
41+
geopandas = None
42+
Polygon = None
43+
44+
try:
45+
import torch
46+
except ImportError:
47+
torch = None
48+
49+
try:
50+
import ibis
51+
except ImportError:
52+
ibis = None
53+
4054

4155
def verify_inspector(
4256
*,
@@ -627,6 +641,7 @@ def mutate(x):
627641
)
628642

629643

644+
@pytest.mark.skipif(geopandas is None, reason="geopandas is not available")
630645
def test_inspect_geopandas_dataframe() -> None:
631646
p1 = Polygon([(0, 0), (1, 0), (1, 1)])
632647
p2 = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
@@ -708,19 +723,15 @@ def mutate(x):
708723
)
709724

710725

711-
@pytest.mark.parametrize(
712-
"value",
713-
[
714-
geopandas.GeoSeries(
715-
[
716-
Polygon([(0, 0), (1, 0), (1, 1)]),
717-
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
718-
Polygon([(2, 0), (3, 0), (3, 1), (2, 1)]),
719-
]
720-
),
721-
],
722-
)
723-
def test_inspect_geopandas_series(value: geopandas.GeoSeries) -> None:
726+
@pytest.mark.skipif(geopandas is None, reason="geopandas is not available")
727+
def test_inspect_geopandas_series() -> None:
728+
value = geopandas.GeoSeries(
729+
[
730+
Polygon([(0, 0), (1, 0), (1, 1)]),
731+
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
732+
Polygon([(2, 0), (3, 0), (3, 1), (2, 1)]),
733+
]
734+
)
724735
(rows,) = value.shape
725736

726737
def mutate(x):
@@ -875,9 +886,8 @@ def test_get_child(value: Any, key: Any, expected: Any) -> None:
875886

876887

877888
@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires Python 3.10 or higher")
889+
@pytest.mark.skipif(ibis is None, reason="ibis not available")
878890
def test_inspect_ibis_exprs() -> None:
879-
import ibis
880-
881891
# Make sure we don't return an executed repr
882892
ibis.options.interactive = True
883893

@@ -921,16 +931,21 @@ def test_inspect_ibis_exprs() -> None:
921931
@pytest.mark.parametrize(
922932
("value", "expected"),
923933
[
924-
(np.array([[1, 2, 3], [4, 5, 6]], dtype="int64"), 48),
925-
(torch.Tensor([[1, 2, 3], [4, 5, 6]]), 24),
926-
(pd.Series([1, 2, 3, 4]), 32),
927-
(pl.Series([1, 2, 3, 4]), 32),
928-
(pd.DataFrame({"a": [1, 2], "b": ["3", "4"]}), 4),
929-
(pl.DataFrame({"a": [1, 2], "b": ["3", "4"]}), 4),
930-
(pd.Index([0, 1]), 16),
934+
(lambda: np.array([[1, 2, 3], [4, 5, 6]], dtype="int64"), 48),
935+
pytest.param(
936+
lambda: torch.Tensor([[1, 2, 3], [4, 5, 6]]),
937+
24,
938+
marks=pytest.mark.skipif(torch is None, reason="torch not available"),
939+
),
940+
(lambda: pd.Series([1, 2, 3, 4]), 32),
941+
(lambda: pl.Series([1, 2, 3, 4]), 32),
942+
(lambda: pd.DataFrame({"a": [1, 2], "b": ["3", "4"]}), 4),
943+
(lambda: pl.DataFrame({"a": [1, 2], "b": ["3", "4"]}), 4),
944+
(lambda: pd.Index([0, 1]), 16),
931945
],
932946
)
933-
def test_arrays_maps_get_size(value: Any, expected: int) -> None:
947+
def test_arrays_maps_get_size(value: Callable, expected: int) -> None:
948+
value = value()
934949
if value is None:
935950
return
936951
inspector = get_inspector(value)
@@ -944,43 +959,53 @@ class VeryLongClassNameThatShouldDefinitelyBeTruncatedBecauseItIsWayTooLong:
944959
@pytest.mark.parametrize(
945960
"value",
946961
[
947-
pytest.param("The quick brown fox jumps over the lazy dog", id="string"),
948-
pytest.param(sys.maxsize * 100, id="int"),
949-
pytest.param(sys.float_info.max, id="float"),
950-
pytest.param(complex(sys.float_info.min, sys.float_info.max), id="complex"),
962+
pytest.param(lambda: "The quick brown fox jumps over the lazy dog", id="string"),
963+
pytest.param(lambda: sys.maxsize * 100, id="int"),
964+
pytest.param(lambda: sys.float_info.max, id="float"),
965+
pytest.param(lambda: complex(sys.float_info.min, sys.float_info.max), id="complex"),
951966
pytest.param(
952-
VeryLongClassNameThatShouldDefinitelyBeTruncatedBecauseItIsWayTooLong, id="class"
967+
lambda: VeryLongClassNameThatShouldDefinitelyBeTruncatedBecauseItIsWayTooLong,
968+
id="class",
953969
),
954-
pytest.param(b"The quick brown fox jumps over the lazy dog", id="bytes"),
955-
pytest.param(bytearray(b"The quick brown fox jumps over the lazy dog"), id="bytearray"),
956-
pytest.param(set(range(20)), id="set"),
957-
pytest.param(frozenset(range(20)), id="frozenset"),
958-
pytest.param(list(range(20)), id="list"),
959-
pytest.param(LIST_WITH_CYCLE, id="list_cycle"),
960-
pytest.param(range(12345678901), id="range"),
961-
pytest.param(L(range(20)), id="fastcore_list"),
962-
pytest.param(FASTCORE_LIST_WITH_CYCLE, id="fastcore_list_cycle"),
963-
pytest.param({str(i): i for i in range(20)}, id="map"),
964-
pytest.param(MAP_WITH_CYCLE, id="map_cycle"),
970+
pytest.param(lambda: b"The quick brown fox jumps over the lazy dog", id="bytes"),
965971
pytest.param(
966-
datetime.datetime(2021, 1, 1, 1, 23, 45, tzinfo=datetime.timezone.utc),
972+
lambda: bytearray(b"The quick brown fox jumps over the lazy dog"), id="bytearray"
973+
),
974+
pytest.param(lambda: set(range(20)), id="set"),
975+
pytest.param(lambda: frozenset(range(20)), id="frozenset"),
976+
pytest.param(lambda: list(range(20)), id="list"),
977+
pytest.param(lambda: LIST_WITH_CYCLE, id="list_cycle"),
978+
pytest.param(lambda: range(12345678901), id="range"),
979+
pytest.param(lambda: L(range(20)), id="fastcore_list"),
980+
pytest.param(lambda: FASTCORE_LIST_WITH_CYCLE, id="fastcore_list_cycle"),
981+
pytest.param(lambda: {str(i): i for i in range(20)}, id="map"),
982+
pytest.param(lambda: MAP_WITH_CYCLE, id="map_cycle"),
983+
pytest.param(
984+
lambda: datetime.datetime(2021, 1, 1, 1, 23, 45, tzinfo=datetime.timezone.utc),
967985
id="timestamp_datetime",
968986
),
969-
pytest.param(pd.Timestamp("2021-01-01 01:23:45"), id="timestamp_pandas"),
970-
pytest.param(pd.Index(list(range(20))), id="pandas_index"),
971-
pytest.param(pd.Series(list(range(20))), id="pandas_series"),
987+
pytest.param(lambda: pd.Timestamp("2021-01-01 01:23:45"), id="timestamp_pandas"),
988+
pytest.param(lambda: pd.Index(list(range(20))), id="pandas_index"),
989+
pytest.param(lambda: pd.Series(list(range(20))), id="pandas_series"),
990+
pytest.param(
991+
lambda: pd.DataFrame({"a": list(range(20)), "b": list(range(20))}),
992+
id="pandas_dataframe",
993+
),
994+
pytest.param(lambda: pl.Series(list(range(20))), id="polars_series"),
972995
pytest.param(
973-
pd.DataFrame({"a": list(range(20)), "b": list(range(20))}), id="pandas_dataframe"
996+
lambda: pl.DataFrame({"a": list(range(20)), "b": list(range(20))}),
997+
id="polars_dataframe",
974998
),
975-
pytest.param(pl.Series(list(range(20))), id="polars_series"),
999+
pytest.param(lambda: np.ones((20, 20)), id="numpy_array"),
9761000
pytest.param(
977-
pl.DataFrame({"a": list(range(20)), "b": list(range(20))}), id="polars_dataframe"
1001+
lambda: torch.ones((20, 20)),
1002+
id="torch_tensor",
1003+
marks=pytest.mark.skipif(torch is None, reason="torch not available"),
9781004
),
979-
pytest.param(np.ones((20, 20)), id="numpy_array"),
980-
pytest.param(torch.ones((20, 20)), id="torch_tensor"),
9811005
],
9821006
)
9831007
def test_truncated_display_value(value, snapshot, monkeypatch) -> None:
1008+
value = value()
9841009
# Patch the maximum string length for faster and more readable tests.
9851010
monkeypatch.setattr(inspectors, "MAX_ITEMS_BY_LEVEL", (20, 10))
9861011
monkeypatch.setattr(inspectors, "MAX_CHARACTERS", 20)

extensions/positron-python/python_files/posit/positron/tests/test_patch/test_haystack.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
# Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
44
#
55

6+
import sys
67
from typing import Any, Dict
78
from unittest.mock import patch
89

10+
import pytest
11+
912
from positron.positron_ipkernel import PositronShell
1013

1114

15+
@pytest.mark.skipif(
16+
sys.version_info >= (3, 14), reason="haystack is not installed at all on 3.14 yet"
17+
)
1218
def test_haystack_patch_automatically_applied(shell: PositronShell):
1319
"""
1420
Test that the haystack is_in_jupyter function is automatically patched to return True.

extensions/positron-python/python_files/posit/positron/tests/test_positron_ipkernel.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
from .conftest import PositronShell
2525
from .utils import assert_register_table_called
2626

27+
try:
28+
import lightning
29+
except ImportError:
30+
lightning = None
31+
2732
# The idea for these tests is to mock out communications with Positron
2833
# via our various comms, and only test IPython interactions. For
2934
# example, in testing the %view magic, we assert that running a cell
@@ -420,6 +425,7 @@ def test_console_warning_logger(shell: PositronShell, caplog, warning_kwargs):
420425
assert "this is a warning" in caplog.text
421426

422427

428+
@pytest.mark.skipif(lightning is None, reason="lightning is not installed")
423429
def test_import_lightning_and_torch_dynamo(shell: PositronShell) -> None:
424430
# See: https://github.com/posit-dev/positron/issues/5879
425431
shell.run_cell("import lightning").raise_error()

extensions/positron-python/python_files/posit/positron/tests/test_ui.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
)
3030

3131
try:
32-
import torch # type: ignore [reportMissingImports] for 3.12
32+
import torch
3333
except ImportError:
3434
torch = None
3535

@@ -104,7 +104,8 @@ def test_set_console_width(ui_comm: DummyComm) -> None:
104104
assert np.get_printoptions()["linewidth"] == width
105105
assert pd.get_option("display.width") is None
106106
assert pl.Config.state()["POLARS_TABLE_WIDTH"] == str(width)
107-
assert torch._tensor_str.PRINT_OPTS.linewidth == width # type: ignore[reportGeneralTypeIssues] # noqa: SLF001
107+
if torch is not None:
108+
assert torch._tensor_str.PRINT_OPTS.linewidth == width # noqa: SLF001
108109

109110

110111
def test_open_editor(ui_service: UiService, ui_comm: DummyComm) -> None:

extensions/positron-python/src/client/common/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export const UseProposedApi = Symbol('USE_VSC_PROPOSED_API');
157157
export const IPYKERNEL_VERSION = '>=6.19.1';
158158
// We support versions where MINIMUM_PYTHON_VERSION <= version < MAXIMUM_PYTHON_VERSION_EXCLUSIVE.
159159
export const MINIMUM_PYTHON_VERSION = { major: 3, minor: 9, patch: 0, raw: '3.9.0' } as PythonVersion;
160-
export const MAXIMUM_PYTHON_VERSION_EXCLUSIVE = { major: 3, minor: 14, patch: 0, raw: '3.14.0' } as PythonVersion;
160+
export const MAXIMUM_PYTHON_VERSION_EXCLUSIVE = { major: 3, minor: 15, patch: 0, raw: '3.15.0' } as PythonVersion;
161161
export const INTERPRETERS_INCLUDE_SETTING_KEY = 'interpreters.include';
162162
export const INTERPRETERS_EXCLUDE_SETTING_KEY = 'interpreters.exclude';
163163
export const INTERPRETERS_OVERRIDE_SETTING_KEY = 'interpreters.override';

extensions/positron-python/src/client/positron/ipykernel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export async function getIpykernelBundle(
4949

5050
// Check if ipykernel is bundled for the interpreter version.
5151
// (defined in scripts/pip-compile-ipykernel.py).
52-
if (interpreter.version?.major !== 3 || ![9, 10, 11, 12, 13].includes(interpreter.version?.minor)) {
52+
if (interpreter.version?.major !== 3 || ![9, 10, 11, 12, 13, 14].includes(interpreter.version?.minor)) {
5353
return { disabledReason: `unsupported interpreter version: ${interpreter.version?.raw}` };
5454
}
5555

extensions/positron-python/src/client/pythonEnvironments/creation/provider/uvUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { CancellationToken, QuickPickItem } from 'vscode';
77
import { showQuickPickWithBack } from '../../../common/vscodeApis/windowApis';
88
import { CreateEnv } from '../../../common/utils/localize';
99

10-
const SUPPORTED_UV_PYTHON_VERSIONS = ['3.14', '3.13', '3.12', '3.11', '3.10', '3.9'];
10+
const SUPPORTED_UV_PYTHON_VERSIONS = ['3.13', '3.12', '3.11', '3.10', '3.9', '3.14'];
1111

1212
export function getUvPythonVersions(): { versions: string[] } {
1313
return {
@@ -18,7 +18,7 @@ export function getUvPythonVersions(): { versions: string[] } {
1818
export async function pickPythonVersion(token?: CancellationToken): Promise<string | undefined> {
1919
const items: QuickPickItem[] = SUPPORTED_UV_PYTHON_VERSIONS.map((v) => ({
2020
label: 'Python',
21-
description: v,
21+
description: v === '3.14' ? `${v} (preview)` : v,
2222
}));
2323
const selection = await showQuickPickWithBack(
2424
items,

0 commit comments

Comments
 (0)