diff --git a/pyproject.toml b/pyproject.toml index 0a9573be8..6c418e3d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ authors = [ ] readme = "README.md" repository = "https://github.com/dipdup-net/dipdup-py" -homepage = "https://pytezos.org" +homepage = "https://dipdup.net/" keywords = ['tezos', 'blockchain', 'sdk', 'michelson', 'indexers', 'tzkt', 'cryptocurrencies', 'smart-contracts'] classifiers = [ "Programming Language :: Python :: 3", diff --git a/src/dipdup/codegen.py b/src/dipdup/codegen.py index 9f934daa5..7ed9007c5 100644 --- a/src/dipdup/codegen.py +++ b/src/dipdup/codegen.py @@ -21,6 +21,7 @@ TzktDatasourceConfig, ) from dipdup.datasources.tzkt.datasource import TzktDatasource +from dipdup.exceptions import ConfigurationError from dipdup.utils import camel_to_snake, snake_to_camel _logger = logging.getLogger(__name__) @@ -107,9 +108,17 @@ async def fetch_schemas(config: DipDupConfig): with suppress(FileExistsError): mkdir(parameter_schemas_path) - entrypoint_schema = next( - ep['parameterSchema'] for ep in contract_schemas['entrypoints'] if ep['name'] == operation_pattern_config.entrypoint - ) + try: + entrypoint_schema = next( + ep['parameterSchema'] + for ep in contract_schemas['entrypoints'] + if ep['name'] == operation_pattern_config.entrypoint + ) + except StopIteration as e: + raise ConfigurationError( + f'Contract `{contract_config.address}` has no entrypoint `{operation_pattern_config.entrypoint}`' + ) from e + entrypoint_schema_path = join(parameter_schemas_path, f'{operation_pattern_config.entrypoint}.json') if not exists(entrypoint_schema_path): diff --git a/src/dipdup/config.py b/src/dipdup/config.py index b396c86c6..8bf007bc7 100644 --- a/src/dipdup/config.py +++ b/src/dipdup/config.py @@ -395,7 +395,10 @@ def __post_init_post_parse__(self): _logger.info('Substituting index templates') for index_name, index_config in self.indexes.items(): if isinstance(index_config, IndexTemplateConfig): - template = self.templates[index_config.template] + try: + template = self.templates[index_config.template] + except KeyError as e: + raise ConfigurationError(f'Template `{index_config.template}` not found in `templates` config section') from e raw_template = json.dumps(template, default=pydantic_encoder) for key, value in index_config.values.items(): value_regex = r'<[ ]*' + key + r'[ ]*>' @@ -410,17 +413,26 @@ def __post_init_post_parse__(self): for index_config in self.indexes.values(): if isinstance(index_config, OperationIndexConfig): if isinstance(index_config.datasource, str): - index_config.datasource = self.datasources[index_config.datasource] + try: + index_config.datasource = self.datasources[index_config.datasource] + except KeyError as e: + raise ConfigurationError(f'Datasource `{index_config.datasource}` not found in `datasources` config section') from e for i, contract in enumerate(index_config.contracts): if isinstance(contract, str): - index_config.contracts[i] = self.contracts[contract] + try: + index_config.contracts[i] = self.contracts[contract] + except KeyError as e: + raise ConfigurationError(f'Contract `{contract}` not found in `contracts` config section') from e for handler in index_config.handlers: callback_patterns[handler.callback].append(handler.pattern) for pattern in handler.pattern: if isinstance(pattern.destination, str): - pattern.destination = self.contracts[pattern.destination] + try: + pattern.destination = self.contracts[pattern.destination] + except KeyError as e: + raise ConfigurationError(f'Contract `{pattern.destination}` not found in `contracts` config section') from e elif isinstance(index_config, BigMapIndexConfig): if isinstance(index_config.datasource, str): @@ -430,7 +442,10 @@ def __post_init_post_parse__(self): callback_patterns[handler.callback].append(handler.pattern) for pattern in handler.pattern: if isinstance(pattern.contract, str): - pattern.contract = self.contracts[pattern.contract] + try: + pattern.contract = self.contracts[pattern.contract] + except KeyError as e: + raise ConfigurationError(f'Contract `{pattern.contract}` not found in `contracts` config section') from e else: raise NotImplementedError(f'Index kind `{index_config.kind}` is not supported') @@ -474,6 +489,8 @@ def load( for match in re.finditer(ENV_VARIABLE_REGEX, raw_config): variable, default_value = match.group(1), match.group(2) value = env.get(variable) + if not default_value and not value: + raise ConfigurationError(f'Environment variable `{variable}` is not set') placeholder = '${' + variable + ':-' + default_value + '}' raw_config = raw_config.replace(placeholder, value or default_value) diff --git a/src/dipdup/dipdup.py b/src/dipdup/dipdup.py index cad689b73..f8409b186 100644 --- a/src/dipdup/dipdup.py +++ b/src/dipdup/dipdup.py @@ -19,6 +19,7 @@ TzktDatasourceConfig, ) from dipdup.datasources.tzkt.datasource import TzktDatasource +from dipdup.exceptions import ConfigurationError from dipdup.hasura import configure_hasura from dipdup.models import IndexType, State from dipdup.utils import reindex, tortoise_wrapper @@ -40,7 +41,11 @@ async def run(self) -> None: url = self._config.database.connection_string cache = isinstance(self._config.database, SqliteDatabaseConfig) models = f'{self._config.package}.models' - rollback_fn = getattr(importlib.import_module(f'{self._config.package}.handlers.{ROLLBACK_HANDLER}'), ROLLBACK_HANDLER) + + try: + rollback_fn = getattr(importlib.import_module(f'{self._config.package}.handlers.{ROLLBACK_HANDLER}'), ROLLBACK_HANDLER) + except ModuleNotFoundError as e: + raise ConfigurationError(f'Package `{self._config.package}` not found. Have you forgot to call `init`?') from e async with tortoise_wrapper(url, models): await self.initialize_database()