Skip to content

Commit 829f2aa

Browse files
Fix processing empty SQL and GraphQL files, refactor codegen (#108)
1 parent 4ee1967 commit 829f2aa

File tree

7 files changed

+148
-184
lines changed

7 files changed

+148
-184
lines changed

src/demo_hic_et_nunc/dipdup-local.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
database:
22
kind: postgres
33
host: 127.0.0.1
4-
port: 6423
4+
port: 5432
55
user: ${POSTGRES_USER:-dipdup}
66
password: ${POSTGRES_PASSWORD:-changeme}
77
database: ${POSTGRES_DB:-dipdup}

src/dipdup/codegen.py

Lines changed: 57 additions & 130 deletions
Large diffs are not rendered by default.

src/dipdup/config.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,23 @@ def merge(self, other: Optional['HTTPConfig']) -> None:
109109

110110

111111
@dataclass
112-
class ContractConfig:
112+
class NameMixin:
113+
def __post_init_post_parse__(self) -> None:
114+
self._name: Optional[str] = None
115+
116+
@property
117+
def name(self) -> str:
118+
if self._name is None:
119+
raise RuntimeError('Config is not pre-initialized')
120+
return self._name
121+
122+
@name.setter
123+
def name(self, name: str) -> None:
124+
self._name = name
125+
126+
127+
@dataclass
128+
class ContractConfig(NameMixin):
113129
"""Contract config
114130
115131
:param network: Corresponding network alias, only for sanity checks
@@ -135,22 +151,6 @@ def valid_address(cls, v):
135151
return v
136152

137153

138-
@dataclass
139-
class NameMixin:
140-
def __post_init_post_parse__(self) -> None:
141-
self._name: Optional[str] = None
142-
143-
@property
144-
def name(self) -> str:
145-
if self._name is None:
146-
raise RuntimeError('Config is not pre-initialized')
147-
return self._name
148-
149-
@name.setter
150-
def name(self, name: str) -> None:
151-
self._name = name
152-
153-
154154
@dataclass
155155
class TzktDatasourceConfig(NameMixin):
156156
"""TzKT datasource config
@@ -625,13 +625,13 @@ class BlockIndexConfig(IndexConfig):
625625

626626

627627
@dataclass
628-
class StaticTemplateConfig:
628+
class IndexTemplateConfig:
629629
kind = 'template'
630630
template: str
631631
values: Dict[str, str]
632632

633633

634-
IndexConfigT = Union[OperationIndexConfig, BigMapIndexConfig, BlockIndexConfig, StaticTemplateConfig]
634+
IndexConfigT = Union[OperationIndexConfig, BigMapIndexConfig, BlockIndexConfig, IndexTemplateConfig]
635635
IndexConfigTemplateT = Union[OperationIndexConfig, BigMapIndexConfig, BlockIndexConfig]
636636
HandlerPatternConfigT = Union[OperationHandlerOriginationPatternConfig, OperationHandlerTransactionPatternConfig]
637637

@@ -708,7 +708,7 @@ class DipDupConfig:
708708
datasources: Dict[str, DatasourceConfigT]
709709
contracts: Dict[str, ContractConfig] = Field(default_factory=dict)
710710
indexes: Dict[str, IndexConfigT] = Field(default_factory=dict)
711-
templates: Optional[Dict[str, IndexConfigTemplateT]] = None
711+
templates: Dict[str, IndexConfigTemplateT] = Field(default_factory=dict)
712712
database: Union[SqliteDatabaseConfig, PostgresDatabaseConfig] = SqliteDatabaseConfig(kind='sqlite')
713713
hasura: Optional[HasuraConfig] = None
714714
jobs: Optional[Dict[str, JobConfig]] = None
@@ -774,10 +774,10 @@ def get_configure_fn(self) -> Type:
774774
except (ModuleNotFoundError, AttributeError) as e:
775775
raise HandlerImportError(module=module_name, obj=CONFIGURE_HANDLER) from e
776776

777-
def resolve_static_templates(self) -> None:
777+
def resolve_index_templates(self) -> None:
778778
_logger.info('Substituting index templates')
779779
for index_name, index_config in self.indexes.items():
780-
if isinstance(index_config, StaticTemplateConfig):
780+
if isinstance(index_config, IndexTemplateConfig):
781781
template = self.get_template(index_config.template)
782782
raw_template = json.dumps(template, default=pydantic_encoder)
783783
for key, value in index_config.values.items():
@@ -841,10 +841,12 @@ def _pre_initialize_index(self, index_name: str, index_config: IndexConfigT) ->
841841
self._pre_initialized.append(index_name)
842842

843843
def pre_initialize(self) -> None:
844-
for name, config in self.datasources.items():
845-
config.name = name
844+
for name, contract_config in self.contracts.items():
845+
contract_config.name = name
846+
for name, datasource_config in self.datasources.items():
847+
datasource_config.name = name
846848

847-
self.resolve_static_templates()
849+
self.resolve_index_templates()
848850
for index_name, index_config in self.indexes.items():
849851
self._pre_initialize_index(index_name, index_config)
850852

@@ -942,7 +944,7 @@ def _initialize_index(self, index_name: str, index_config: IndexConfigT) -> None
942944
if index_name in self._initialized:
943945
return
944946

945-
if isinstance(index_config, StaticTemplateConfig):
947+
if isinstance(index_config, IndexTemplateConfig):
946948
raise RuntimeError('Config is not pre-initialized')
947949

948950
if isinstance(index_config, OperationIndexConfig):

src/dipdup/context.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from tortoise import Tortoise
77
from tortoise.transactions import in_transaction
88

9-
from dipdup.config import ContractConfig, DipDupConfig, PostgresDatabaseConfig, StaticTemplateConfig
9+
from dipdup.config import ContractConfig, DipDupConfig, IndexTemplateConfig, PostgresDatabaseConfig
1010
from dipdup.datasources import DatasourceT
1111
from dipdup.exceptions import ContractAlreadyExistsError, IndexAlreadyExistsError
1212
from dipdup.utils import FormattedLogger
@@ -98,7 +98,7 @@ def add_index(self, name: str, template: str, values: Dict[str, Any]) -> None:
9898
if name in self.config.indexes:
9999
raise IndexAlreadyExistsError(self, name)
100100
self.config.get_template(template)
101-
self.config.indexes[name] = StaticTemplateConfig(
101+
self.config.indexes[name] = IndexTemplateConfig(
102102
template=template,
103103
values=values,
104104
)

src/dipdup/dipdup.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22
import hashlib
33
import logging
4-
from contextlib import AsyncExitStack, asynccontextmanager
4+
from contextlib import AsyncExitStack, asynccontextmanager, suppress
55
from os import listdir
66
from os.path import join
77
from typing import Dict, List, Optional, cast
@@ -21,9 +21,9 @@
2121
DatasourceConfigT,
2222
DipDupConfig,
2323
IndexConfigTemplateT,
24+
IndexTemplateConfig,
2425
OperationIndexConfig,
2526
PostgresDatabaseConfig,
26-
StaticTemplateConfig,
2727
TzktDatasourceConfig,
2828
)
2929
from dipdup.context import DipDupContext, RollbackHandlerContext
@@ -36,7 +36,7 @@
3636
from dipdup.hasura import HasuraGateway
3737
from dipdup.index import BigMapIndex, Index, OperationIndex
3838
from dipdup.models import BigMapData, HeadBlockData, IndexType, OperationData, State
39-
from dipdup.utils import FormattedLogger, slowdown, tortoise_wrapper
39+
from dipdup.utils import FormattedLogger, iter_files, slowdown, tortoise_wrapper
4040

4141
INDEX_DISPATCHER_INTERVAL = 1.0
4242
from dipdup.scheduler import add_job, create_scheduler
@@ -83,7 +83,7 @@ async def reload_config(self) -> None:
8383
self._ctx.config.initialize()
8484

8585
for index_config in self._ctx.config.indexes.values():
86-
if isinstance(index_config, StaticTemplateConfig):
86+
if isinstance(index_config, IndexTemplateConfig):
8787
raise RuntimeError
8888
await self.add_index(index_config)
8989

@@ -336,15 +336,11 @@ async def _execute_sql_scripts(self, reindex: bool) -> None:
336336
if not exists(sql_path):
337337
return
338338
self._logger.info('Executing SQL scripts from `%s`', sql_path)
339-
for filename in sorted(listdir(sql_path)):
340-
if not filename.endswith('.sql'):
341-
continue
342-
343-
with open(join(sql_path, filename)) as file:
344-
sql = file.read()
345-
346-
self._logger.info('Executing `%s`', filename)
347-
await get_connection(None).execute_script(sql)
339+
for file in iter_files(sql_path, '.sql'):
340+
self._logger.info('Executing `%s`', file.name)
341+
sql = file.read()
342+
with suppress(AttributeError):
343+
await get_connection(None).execute_script(sql)
348344

349345
def _finish_migration(self, version: str) -> None:
350346
self._logger.warning('==================== WARNING =====================')

src/dipdup/hasura.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@
22
import importlib
33
import logging
44
from contextlib import suppress
5-
from os import listdir
65
from os.path import dirname, join
76
from typing import Any, Dict, Iterator, List, Optional, Tuple
87

98
import humps # type: ignore
109
from aiohttp import ClientConnectorError, ClientOSError
11-
from genericpath import exists
1210
from pydantic.dataclasses import dataclass
1311
from tortoise import fields
1412
from tortoise.transactions import get_connection
1513

1614
from dipdup.config import HasuraConfig, HTTPConfig, PostgresDatabaseConfig, pascal_to_snake
1715
from dipdup.exceptions import ConfigurationError
1816
from dipdup.http import HTTPGateway
19-
from dipdup.utils import iter_models
17+
from dipdup.utils import iter_files, iter_models
2018

2119

2220
@dataclass
@@ -230,14 +228,8 @@ def _iterate_graphql_queries(self) -> Iterator[Tuple[str, str]]:
230228
package = importlib.import_module(self._package)
231229
package_path = dirname(package.__file__)
232230
graphql_path = join(package_path, 'graphql')
233-
if not exists(graphql_path):
234-
return
235-
for filename in sorted(listdir(graphql_path)):
236-
if not filename.endswith('.graphql'):
237-
continue
238-
239-
with open(join(graphql_path, filename)) as file:
240-
yield filename[:-8], file.read()
231+
for file in iter_files(graphql_path, '.graphql'):
232+
yield file.name.split('/')[-1][:-8], file.read()
241233

242234
async def _generate_query_collections_metadata(self) -> List[Dict[str, Any]]:
243235
queries = []

src/dipdup/utils.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import asyncio
22
import decimal
3+
import errno
34
import importlib
45
import logging
56
import pkgutil
67
import time
78
import types
89
from contextlib import asynccontextmanager
910
from logging import Logger
10-
from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Tuple, Type
11+
from os import listdir, makedirs
12+
from os.path import dirname, exists, getsize, join
13+
from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, TextIO, Tuple, Type
1114

1215
import humps # type: ignore
1316
from tortoise import Tortoise
@@ -159,3 +162,47 @@ def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False, st
159162
if self.fmt:
160163
msg = self.fmt.format(msg)
161164
super()._log(level, msg, args, exc_info, extra, stack_info, stacklevel)
165+
166+
167+
def iter_files(path: str, ext: Optional[str] = None) -> Iterator[TextIO]:
168+
"""Iterate over files in a directory. Sort alphabetically, filter by extension, skip empty files."""
169+
if not exists(path):
170+
raise StopIteration
171+
for filename in sorted(listdir(path)):
172+
filepath = join(path, filename)
173+
if ext and not filename.endswith(ext):
174+
continue
175+
if not getsize(filepath):
176+
continue
177+
178+
with open(filepath) as file:
179+
yield file
180+
181+
182+
def mkdir_p(path: str) -> None:
183+
"""Create directory tree, ignore if already exists"""
184+
try:
185+
makedirs(path)
186+
except OSError as e:
187+
if e.errno != errno.EEXIST:
188+
raise
189+
190+
191+
def touch(path: str) -> None:
192+
"""Create empty file, ignore if already exists"""
193+
mkdir_p(dirname(path))
194+
try:
195+
open(path, 'a').close()
196+
except IOError as e:
197+
if e.errno != errno.EEXIST:
198+
raise
199+
200+
201+
def write(path: str, content: str, overwrite: bool = False) -> bool:
202+
"""Write content to file, create directory tree if necessary"""
203+
mkdir_p(dirname(path))
204+
if exists(path) and not overwrite:
205+
return False
206+
with open(path, 'w') as file:
207+
file.write(content)
208+
return True

0 commit comments

Comments
 (0)