Skip to content

Commit cdf870f

Browse files
authored
Handle case where input is a directory better (#433)
If a user configures a directory and not a simple file as the state store location, the error message produced is not very easy to understand. On windows in particular, it results in a "permission denied" error. This adds a more descriptive error message
1 parent eaffda2 commit cdf870f

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

cognite/extractorutils/configtools/elements.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from datetime import timedelta
1919
from enum import Enum
2020
from logging.handlers import TimedRotatingFileHandler
21+
from pathlib import Path
2122
from time import sleep
2223
from typing import Any
2324
from urllib.parse import urljoin, urlparse
@@ -649,7 +650,7 @@ class LocalStateStoreConfig:
649650
Configuration of a state store using a local JSON file
650651
"""
651652

652-
path: str
653+
path: Path
653654
save_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
654655

655656

@@ -695,8 +696,11 @@ def create_state_store(
695696
)
696697

697698
if self.local:
699+
if self.local.path.is_dir():
700+
raise ValueError(f"{self.local.path} is a directory, and not a file")
701+
698702
return LocalStateStore(
699-
file_path=self.local.path,
703+
file_path=str(self.local.path),
700704
save_interval=self.local.save_interval.seconds,
701705
cancellation_token=cancellation_token,
702706
)

tests/tests_unit/test_configtools.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
import logging
1717
import os
1818
import re
19+
from collections.abc import Generator
1920
from dataclasses import dataclass
2021
from pathlib import Path
2122

2223
import pytest
2324
import yaml
25+
from faker import Faker
2426

2527
from cognite.client import CogniteClient
2628
from cognite.client.credentials import OAuthClientCredentials
@@ -37,15 +39,18 @@
3739
AuthenticatorConfig,
3840
CastableInt,
3941
IgnorePattern,
42+
LocalStateStoreConfig,
4043
PortNumber,
4144
RegExpFlag,
45+
StateStoreConfig,
4246
)
4347
from cognite.extractorutils.configtools.loaders import (
4448
ConfigResolver,
4549
compile_patterns,
4650
)
4751
from cognite.extractorutils.configtools.validators import matches_pattern, matches_patterns
4852
from cognite.extractorutils.exceptions import InvalidConfigError
53+
from cognite.extractorutils.statestore.watermark import LocalStateStore
4954

5055

5156
@dataclass
@@ -610,3 +615,42 @@ class DbConfigCastable:
610615
assert parsed.port == 8080
611616
assert parsed.connections == 4
612617
assert parsed.batch_size == 1000
618+
619+
620+
@pytest.fixture
621+
def file_name() -> Generator[str, None, None]:
622+
name = f"{Faker().word()}.json"
623+
yield name
624+
if Path(name).exists():
625+
os.remove(name)
626+
627+
628+
def test_load_local_statestore(file_name: str) -> None:
629+
raw_config = f"""
630+
local:
631+
path: {file_name}
632+
"""
633+
634+
config = load_yaml(raw_config, StateStoreConfig)
635+
636+
assert isinstance(config.local, LocalStateStoreConfig)
637+
assert str(config.local.path) == file_name
638+
639+
state_store = config.create_state_store()
640+
assert isinstance(state_store, LocalStateStore)
641+
642+
643+
def test_load_local_directory_fails() -> None:
644+
raw_config = """
645+
local:
646+
path: cognite
647+
"""
648+
649+
config = load_yaml(raw_config, StateStoreConfig)
650+
651+
assert isinstance(config.local, LocalStateStoreConfig)
652+
653+
with pytest.raises(ValueError) as e:
654+
config.create_state_store()
655+
656+
assert "is a directory, and not a file" in str(e.value)

0 commit comments

Comments
 (0)