Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow arguments of type pathlib.Path for file I/O methods #228

16 changes: 8 additions & 8 deletions src/safeds/data/image/containers/_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ class Image:
"""

@staticmethod
def from_jpeg_file(path: str) -> Image:
def from_jpeg_file(path: str | Path) -> Image:
"""
Create an image from a JPEG file.

Parameters
----------
path : str
path : str | Path
The path to the JPEG file.

Returns
Expand All @@ -41,13 +41,13 @@ def from_jpeg_file(path: str) -> Image:
)

@staticmethod
def from_png_file(path: str) -> Image:
def from_png_file(path: str | Path) -> Image:
"""
Create an image from a PNG file.

Parameters
----------
path : str
path : str | Path
The path to the PNG file.

Returns
Expand Down Expand Up @@ -86,25 +86,25 @@ def format(self) -> ImageFormat:
# Conversion
# ------------------------------------------------------------------------------------------------------------------

def to_jpeg_file(self, path: str) -> None:
def to_jpeg_file(self, path: str | Path) -> None:
"""
Save the image as a JPEG file.

Parameters
----------
path : str
path : str | Path
The path to the JPEG file.
"""
Path(path).parent.mkdir(parents=True, exist_ok=True)
self._image.save(path, format="jpeg")

def to_png_file(self, path: str) -> None:
def to_png_file(self, path: str | Path) -> None:
"""
Save the image as a PNG file.

Parameters
----------
path : str
path : str | Path
The path to the PNG file.
"""
Path(path).parent.mkdir(parents=True, exist_ok=True)
Expand Down
16 changes: 8 additions & 8 deletions src/safeds/data/tabular/containers/_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ class Table:
# ------------------------------------------------------------------------------------------------------------------

@staticmethod
def from_csv_file(path: str) -> Table:
def from_csv_file(path: str | Path) -> Table:
"""
Read data from a CSV file into a table.

Parameters
----------
path : str
path : str | Path
The path to the CSV file.

Returns
Expand All @@ -87,13 +87,13 @@ def from_csv_file(path: str) -> Table:
raise FileNotFoundError(f'File "{path}" does not exist') from exception

@staticmethod
def from_json_file(path: str) -> Table:
def from_json_file(path: str | Path) -> Table:
"""
Read data from a JSON file into a table.

Parameters
----------
path : str
path : str | Path
The path to the JSON file.

Returns
Expand Down Expand Up @@ -1200,7 +1200,7 @@ def plot_scatterplot(self, x_column_name: str, y_column_name: str) -> Image:
# Conversion
# ------------------------------------------------------------------------------------------------------------------

def to_csv_file(self, path: str) -> None:
def to_csv_file(self, path: str | Path) -> None:
"""
Write the data from the table into a CSV file.

Expand All @@ -1209,15 +1209,15 @@ def to_csv_file(self, path: str) -> None:

Parameters
----------
path : str
path : str | Path
The path to the output file.
"""
Path(path).parent.mkdir(parents=True, exist_ok=True)
data_to_csv = self._data.copy()
data_to_csv.columns = self._schema.column_names
data_to_csv.to_csv(path, index=False)

def to_json_file(self, path: str) -> None:
def to_json_file(self, path: str | Path) -> None:
"""
Write the data from the table into a JSON file.

Expand All @@ -1226,7 +1226,7 @@ def to_json_file(self, path: str) -> None:

Parameters
----------
path : str
path : str | Path
The path to the output file.
"""
Path(path).parent.mkdir(parents=True, exist_ok=True)
Expand Down
4 changes: 2 additions & 2 deletions tests/helpers/_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
_resources_root = Path(__file__).parent / ".." / "resources"


def resolve_resource_path(resource_path: str) -> str:
def resolve_resource_path(resource_path: str | Path) -> str:
"""
Resolve a path relative to the `resources` directory to an absolute path.

Parameters
----------
resource_path : str
resource_path : str | Path
The path to the resource relative to the `resources` directory.

Returns
Expand Down
52 changes: 42 additions & 10 deletions tests/safeds/data/image/containers/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,33 @@
class TestFromJpegFile:
@pytest.mark.parametrize(
"path",
["image/white_square.jpg"],
["image/white_square.jpg", Path("image/white_square.jpg")],
)
def test_should_load_jpeg_file(self, path: str) -> None:
def test_should_load_jpeg_file(self, path: str | Path) -> None:
Image.from_jpeg_file(resolve_resource_path(path))

@pytest.mark.parametrize(
"path",
["image/missing_file.jpg"],
["image/missing_file.jpg", Path("image/missing_file.jpg")],
)
def test_should_raise_if_file_not_found(self, path: str) -> None:
def test_should_raise_if_file_not_found(self, path: str | Path) -> None:
with pytest.raises(FileNotFoundError):
Image.from_jpeg_file(resolve_resource_path(path))


class TestFromPngFile:
@pytest.mark.parametrize(
"path",
["image/white_square.png"],
["image/white_square.png", Path("image/white_square.png")],
)
def test_should_load_png_file(self, path: str) -> None:
def test_should_load_png_file(self, path: str | Path) -> None:
Image.from_png_file(resolve_resource_path(path))

@pytest.mark.parametrize(
"path",
["image/missing_file.png"],
["image/missing_file.png", Path("image/missing_file.png")],
)
def test_should_raise_if_file_not_found(self, path: str) -> None:
def test_should_raise_if_file_not_found(self, path: str | Path) -> None:
with pytest.raises(FileNotFoundError):
Image.from_png_file(resolve_resource_path(path))

Expand All @@ -59,7 +59,7 @@ class TestToJpegFile:
"path",
["image/white_square.jpg"],
)
def test_should_save_jpeg_file(self, path: str) -> None:
def test_should_save_jpeg_file_by_str(self, path: str) -> None:
image = Image.from_jpeg_file(resolve_resource_path(path))

with NamedTemporaryFile() as tmp_file:
Expand All @@ -71,13 +71,29 @@ def test_should_save_jpeg_file(self, path: str) -> None:

assert image._image.tobytes() == image_read_back._image.tobytes()

@pytest.mark.parametrize(
"path",
["image/white_square.jpg"],
)
def test_should_save_jpeg_file_by_path(self, path: str) -> None:
image = Image.from_jpeg_file(resolve_resource_path(path))

with NamedTemporaryFile() as tmp_file:
tmp_file.close()
with Path(tmp_file.name).open("wb") as tmp_write_file:
image.to_jpeg_file(Path(tmp_write_file.name))
with Path(tmp_file.name).open("rb") as tmp_read_file:
image_read_back = Image.from_jpeg_file(tmp_read_file.name)

assert image._image.tobytes() == image_read_back._image.tobytes()


class TestToPngFile:
@pytest.mark.parametrize(
"path",
["image/white_square.png"],
)
def test_should_save_png_file(self, path: str) -> None:
def test_should_save_png_file_by_str(self, path: str) -> None:
image = Image.from_png_file(resolve_resource_path(path))

with NamedTemporaryFile() as tmp_file:
Expand All @@ -89,6 +105,22 @@ def test_should_save_png_file(self, path: str) -> None:

assert image._image.tobytes() == image_read_back._image.tobytes()

@pytest.mark.parametrize(
"path",
["image/white_square.png"],
)
def test_should_save_png_file_by_path(self, path: str) -> None:
image = Image.from_png_file(resolve_resource_path(path))

with NamedTemporaryFile() as tmp_file:
tmp_file.close()
with Path(tmp_file.name).open("wb") as tmp_write_file:
image.to_png_file(Path(tmp_write_file.name))
with Path(tmp_file.name).open("rb") as tmp_read_file:
image_read_back = Image.from_png_file(tmp_read_file.name)

assert image._image.tobytes() == image_read_back._image.tobytes()


class TestReprJpeg:
@pytest.mark.parametrize(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
from pathlib import Path

import pytest
from safeds.data.tabular.containers import Table

from tests.helpers import resolve_resource_path


def test_from_csv_file_valid() -> None:
table = Table.from_csv_file(resolve_resource_path("table.csv"))
@pytest.mark.parametrize(
"path",
["table.csv", Path("table.csv")],
)
def test_from_csv_file_valid(path: str | Path) -> None:
table = Table.from_csv_file(resolve_resource_path(path))
assert table.get_column("A").get_value(0) == 1
assert table.get_column("B").get_value(0) == 2


def test_from_csv_file_invalid() -> None:
@pytest.mark.parametrize(
"path",
["test_table_from_csv_file_invalid.csv", Path("test_table_from_csv_file_invalid.csv")],
)
def test_from_csv_file_invalid(path: str | Path) -> None:
with pytest.raises(FileNotFoundError):
Table.from_csv_file(resolve_resource_path("test_table_from_csv_file_invalid.csv"))
Table.from_csv_file(resolve_resource_path(path))
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
from pathlib import Path

import pytest
from safeds.data.tabular.containers import Table

from tests.helpers import resolve_resource_path


def test_from_json_file_valid() -> None:
table = Table.from_json_file(resolve_resource_path("table.json"))
@pytest.mark.parametrize(
"path",
["table.json", Path("table.json")],
)
def test_from_json_file_valid(path: str | Path) -> None:
table = Table.from_json_file(resolve_resource_path(path))
assert table.get_column("A").get_value(0) == 1
assert table.get_column("B").get_value(0) == 2


def test_from_json_file_invalid() -> None:
@pytest.mark.parametrize(
"path",
["test_table_from_json_file_invalid.json", Path("test_table_from_json_file_invalid.json")],
)
def test_from_json_file_invalid(path: str | Path) -> None:
with pytest.raises(FileNotFoundError):
Table.from_json_file(resolve_resource_path("test_table_from_json_file_invalid.json"))
Table.from_json_file(resolve_resource_path(path))
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from safeds.data.tabular.containers import Table


def test_to_csv_file() -> None:
def test_to_csv_file_by_str() -> None:
table = Table.from_dict({"col1": ["col1_1"], "col2": ["col2_1"]})
with NamedTemporaryFile() as tmp_table_file:
tmp_table_file.close()
Expand All @@ -13,3 +13,14 @@ def test_to_csv_file() -> None:
with Path(tmp_table_file.name).open("r", encoding="utf-8") as tmp_file:
table_r = Table.from_csv_file(tmp_file.name)
assert table == table_r


def test_to_csv_file_by_path() -> None:
table = Table.from_dict({"col1": ["col1_1"], "col2": ["col2_1"]})
with NamedTemporaryFile() as tmp_table_file:
tmp_table_file.close()
with Path(tmp_table_file.name).open("w", encoding="utf-8") as tmp_file:
table.to_csv_file(Path(tmp_file.name))
with Path(tmp_table_file.name).open("r", encoding="utf-8") as tmp_file:
table_r = Table.from_csv_file(Path(tmp_file.name))
assert table == table_r
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from safeds.data.tabular.containers import Table


def test_to_json_file() -> None:
def test_to_json_file_by_str() -> None:
table = Table.from_dict({"col1": ["col1_1"], "col2": ["col2_1"]})
with NamedTemporaryFile() as tmp_table_file:
tmp_table_file.close()
Expand All @@ -13,3 +13,14 @@ def test_to_json_file() -> None:
with Path(tmp_table_file.name).open("r", encoding="utf-8") as tmp_file:
table_r = Table.from_json_file(tmp_file.name)
assert table == table_r


def test_to_json_file_by_path() -> None:
table = Table.from_dict({"col1": ["col1_1"], "col2": ["col2_1"]})
with NamedTemporaryFile() as tmp_table_file:
tmp_table_file.close()
with Path(tmp_table_file.name).open("w", encoding="utf-8") as tmp_file:
table.to_json_file(Path(tmp_file.name))
with Path(tmp_table_file.name).open("r", encoding="utf-8") as tmp_file:
table_r = Table.from_json_file(Path(tmp_file.name))
assert table == table_r