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: ✨ add path_*() functions (with their verify_*()'ers) #730

Merged
merged 22 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
029ea53
feat: :sparkles: add path_*() functions with utils
signekb Sep 24, 2024
fe6f3d2
test: :white_check_mark: add tests for `path_*()` functions with utils
signekb Sep 24, 2024
786fc9d
feat: :sparkles: add path functions to core module init file
signekb Sep 25, 2024
a132fea
refactor: :recycle: update imports to path functions
signekb Sep 25, 2024
a6cd9bd
refactor: :recycle: rename file from `path_utils` to `path_error_cont…
signekb Sep 25, 2024
700efd3
refactor: update imports to reflect renaming of `path_error_context`
signekb Sep 25, 2024
141ab20
refactor: :recycle: rename file `path_test_utils` -> `directory_struc…
signekb Sep 25, 2024
c2e5d40
refactor: update imports to reflect renaming of `directory_structure_…
signekb Sep 25, 2024
8aaa7b8
Merge branch 'main' into feat/add-path-functions
signekb Sep 25, 2024
2379675
docs: update todo item
signekb Sep 25, 2024
b704ae2
Merge branch 'main' into feat/add-path-functions
signekb Sep 25, 2024
4222404
fix: apply suggestions from code review
signekb Sep 26, 2024
857050d
refactor: :recycle: simplify code by reusing path functions internally
signekb Sep 26, 2024
14ba245
refactor: :recycle: simplify by returning tmp_path directly in fixture
signekb Sep 26, 2024
9c45a33
fix: :art: remove unused import
signekb Sep 26, 2024
c716559
Merge branch 'main' into feat/add-path-functions
lwjohnst86 Sep 30, 2024
a0f8eae
chore: :truck: rename to match content
lwjohnst86 Sep 30, 2024
af08d28
refactor: :recycle: use two simpler verify functions rather than one …
lwjohnst86 Sep 30, 2024
9ad6b48
refactor: :recycle: update verify functions in path functions
lwjohnst86 Sep 30, 2024
d387eed
refactor: :recycle: need to verify it is a file too
lwjohnst86 Sep 30, 2024
f1abda7
refactor: :art: ran Ruff formatter
lwjohnst86 Sep 30, 2024
e4029a8
fix: :bug: should be `verify_is_dir()` instead
lwjohnst86 Oct 2, 2024
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
38 changes: 22 additions & 16 deletions sprout/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,19 @@
# from .delete_resource_properties import *
# Path -----
# TODO: Consider having all these in one module.
# from .path_resources import *
# from .path_resource import *
# from .path_resource_raw import *
# from .path_resource_raw_files import *
# from .path_resource_data import *
# from .path_properties import *
# from .path_package_database import *
# from .path_package import *
from .path_package_functions import (
path_package,
path_package_database,
path_package_properties,
path_packages,
)
from .path_resource_functions import (
path_resource,
path_resource_data,
path_resource_raw,
path_resource_raw_files,
path_resources,
)
from .path_sprout_root import path_sprout_root
from .properties import (
ConstraintsProperties,
Expand Down Expand Up @@ -92,14 +97,15 @@
# "delete_resource_data",
# "delete_resource_properties",
# Path -----
# "path_resources",
# "path_resource",
# "path_resource_raw",
# "path_resource_raw_files",
# "path_resource_data",
# "path_properties",
# "path_package_database",
# "path_package",
"path_package",
"path_package_database",
"path_package_properties",
"path_packages",
"path_resource",
"path_resource_data",
"path_resource_raw",
"path_resource_raw_files",
"path_resources",
"path_sprout_root",
# Helpers -----
# "pretty_json",
Expand Down
49 changes: 49 additions & 0 deletions sprout/core/path_error_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from pathlib import Path

from sprout.core.get_ids import get_ids
from sprout.core.verify_is_dir import verify_is_dir
from sprout.core.verify_is_file import verify_is_file


def verify_is_dir_or_raise_error_with_id_context(path: Path, ids_path: Path):
"""Verifies if path is a directory or raises error with existing ids.

Args:
path: Path to verify.
ids_path: Path to find existing ID's.
signekb marked this conversation as resolved.
Show resolved Hide resolved

Returns:
Path, if path is a directory.

Raises:
NotADirectoryError: If the path is not a directory. The error message
includes existing ID's.
"""
try:
verify_is_dir(path)
return path
signekb marked this conversation as resolved.
Show resolved Hide resolved
except NotADirectoryError as e:
existing_ids = get_ids(ids_path)
raise NotADirectoryError(f"Existing ID's are {existing_ids}") from e


def verify_is_file_or_raise_error_with_id_context(path: Path, ids_path: Path):
"""Verifies if path is a file or raises error with existing ids.

Args:
path: Path to verify.
ids_path: Path to find existing ID's.

Returns:
Path, if path is a file.

Raises:
FileNotFoundError: If the path is not a file. The error message
includes existing ID's.
"""
try:
verify_is_file(path)
return path
except FileNotFoundError as e:
existing_ids = get_ids(ids_path)
raise FileNotFoundError(f"Existing ID's are {existing_ids}") from e
63 changes: 63 additions & 0 deletions sprout/core/path_package_functions.py
lwjohnst86 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from pathlib import Path

from sprout.core.path_error_context import (
verify_is_dir_or_raise_error_with_id_context,
verify_is_file_or_raise_error_with_id_context,
)
from sprout.core.path_sprout_root import path_sprout_root
from sprout.core.verify_is_dir import verify_is_dir


def path_package(package_id: int) -> Path:
"""Gets the absolute path to the specific package folder.

Args:
package_id: The ID of the package to get the folder path for.

Returns:
The absolute path to the package folder.
"""
path = path_sprout_root() / "packages" / str(package_id)
signekb marked this conversation as resolved.
Show resolved Hide resolved
return verify_is_dir_or_raise_error_with_id_context(path=path, ids_path=path.parent)


def path_package_database(package_id: int) -> Path:
"""Gets the absolute path to a given package's SQL database.

Args:
package_id: ID of the package.

Returns:
A Path to the package's database.
"""
path = path_sprout_root() / "packages" / str(package_id) / "database.sql"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
path = path_sprout_root() / "packages" / str(package_id) / "database.sql"
path = path_package(package_id) / "database.sql"

return verify_is_file_or_raise_error_with_id_context(
path=path, ids_path=path.parent.parent
)


def path_package_properties(package_id: int) -> Path:
"""Gets the absolute path to a given package's properties file.

Args:
package_id: ID of the package.

Returns:
A Path to the properties file.
"""
path = path_sprout_root() / "packages" / str(package_id) / "datapackage.json"
signekb marked this conversation as resolved.
Show resolved Hide resolved
return verify_is_file_or_raise_error_with_id_context(
path=path, ids_path=path.parent.parent
)


def path_packages() -> Path:
"""Gets the absolute path to the packages folder.

Returns:
A Path to the packages folder.

Raises:
NotADirectoryError: If the packages folder doesn't exist.
"""
return verify_is_dir(path_sprout_root() / "packages")
120 changes: 120 additions & 0 deletions sprout/core/path_resource_functions.py
signekb marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from pathlib import Path

from sprout.core.get_ids import get_ids
from sprout.core.path_error_context import (
verify_is_dir_or_raise_error_with_id_context,
verify_is_file_or_raise_error_with_id_context,
)
from sprout.core.path_sprout_root import path_sprout_root
from sprout.core.verify_is_dir import verify_is_dir


def path_resource(package_id: int, resource_id: int) -> Path:
"""Gets the absolute path to a given resource of a given package.

Args:
package_id: ID of the package.
resource_id: ID of the resource.

Returns:
A Path to the resource.
"""
path = (
path_sprout_root()
/ "packages"
/ str(package_id)
/ "resources"
/ str(resource_id)
)
return verify_is_dir_or_raise_error_with_id_context(path=path, ids_path=path.parent)


def path_resource_data(package_id: int, resource_id: int) -> Path:
"""Gets the absolute path to a given resource's data (i.e., parquet) file.

Args:
package_id: ID of the package.
resource_id: ID of the resource.

Returns:
A Path to the resource's data file.
"""
path = (
path_sprout_root()
/ "packages"
/ str(package_id)
/ "resources"
/ str(resource_id)
/ "data.parquet"
)
return verify_is_file_or_raise_error_with_id_context(
path=path, ids_path=path.parent.parent
)


def path_resource_raw(package_id: int, resource_id: int) -> Path:
"""Gets the absolute path to a given resource's raw folder.

Args:
package_id: ID of the package.
resource_id: ID of the resource.

Returns:
A Path to the resource's raw folder.
"""
path = (
path_sprout_root()
/ "packages"
/ str(package_id)
/ "resources"
/ str(resource_id)
/ "raw"
)
return verify_is_dir_or_raise_error_with_id_context(
path=path, ids_path=path.parent.parent
)


def path_resource_raw_files(package_id: int, resource_id: int) -> list[Path]:
"""Gets the absolute path to the raw files of a resource.

Args:
package_id: ID of the package.
resource_id: ID of the resource.

Returns:
A list of Paths to the raw files of the resource.

Raises:
NotADirectoryError: If the package_id doesn't exist or the resource_id doesn't
exist within the package.
"""
path = (
path_sprout_root()
/ "packages"
/ str(package_id)
/ "resources"
/ str(resource_id)
/ "raw"
)

try:
verify_is_dir(path)
return [file for file in path.iterdir()]
signekb marked this conversation as resolved.
Show resolved Hide resolved
except NotADirectoryError as e:
raise NotADirectoryError(
f"Existing ID's are {get_ids(path.parent.parent)}"
) from e


def path_resources(package_id: int) -> Path:
"""Gets the absolute path to resources of a given package.

Args:
package_id: ID of the package to get the resource path from."

Returns:
A Path to the resources within the package.
"""
path = path_sprout_root() / "packages" / str(package_id) / "resources"
return verify_is_dir_or_raise_error_with_id_context(path, path.parent.parent)
47 changes: 47 additions & 0 deletions tests/core/directory_structure_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from pathlib import Path

from sprout.core.create_resource_structure import create_resource_structure


def create_test_package_structure(root_path: Path, package_id: int) -> Path:
"""Creates a package file structure (with empty files) for path function tests.

Args:
root_path: Root path to create the package structure.
package_id: ID of the package to create.

Returns:
Path of package.
"""
# TODO: Use `create_package_structure()` function here when it's implemented.
signekb marked this conversation as resolved.
Show resolved Hide resolved
path_package = root_path / "packages" / str(package_id)
path_package.mkdir(parents=True)
(path_package / "datapackage.json").touch()
(path_package / "database.sql").touch()

return path_package


def create_test_resource_structure(
path_package: Path, raw_files: str | list[str]
) -> list[Path]:
"""Creates a resource file structure (with empty files) for path function tests.

Args:
path_package: Path to package.$
signekb marked this conversation as resolved.
Show resolved Hide resolved
resource_id: ID of the resource to create.
raw_files: Name(s) of raw file(s).

Returns:
List with two Paths: one to the resource, one to it's raw directory.
signekb marked this conversation as resolved.
Show resolved Hide resolved
"""
path_resources = path_package / "resources"
if not (path_resources).exists():
path_resources.mkdir(parents=True)
signekb marked this conversation as resolved.
Show resolved Hide resolved

path_list_resource = create_resource_structure(path_resources)
(path_list_resource[0] / "data.parquet").touch()
for raw_file in raw_files:
(path_list_resource[1] / raw_file).touch()

return path_list_resource
Loading