1010from enum import Enum
1111from os import environ as env
1212from os .path import dirname
13- from typing import Any , Callable , Dict , List , Optional , Sequence , Type , Union , cast
13+ from typing import Any , Callable , Dict , List , Optional , Sequence , Set , Type , Union , cast
1414from urllib .parse import urlparse
1515
1616from pydantic import Field , validator
@@ -285,6 +285,24 @@ def initialize_storage_cls(self, package: str, module_name: str) -> None:
285285 self .storage_type_cls = storage_type_cls
286286
287287
288+ @dataclass
289+ class ParentMixin :
290+ """`parent` field for index and template configs"""
291+
292+ def __post_init_post_parse__ (self ):
293+ self ._parent : Optional ['IndexConfig' ] = None
294+
295+ @property
296+ def parent (self ) -> Optional ['IndexConfig' ]:
297+ return self ._parent
298+
299+ @parent .setter
300+ def parent (self , config : 'IndexConfig' ) -> None :
301+ if self ._parent :
302+ raise RuntimeError ('Can\' t unset parent once set' )
303+ self ._parent = config
304+
305+
288306@dataclass
289307class ParameterTypeMixin :
290308 """`parameter_type_cls` field"""
@@ -459,10 +477,11 @@ def originated_contract_config(self) -> ContractConfig:
459477
460478
461479@dataclass
462- class HandlerConfig :
480+ class HandlerConfig ( NameMixin ) :
463481 callback : str
464482
465483 def __post_init_post_parse__ (self ):
484+ super ().__post_init_post_parse__ ()
466485 self ._callback_fn = None
467486 if self .callback in (ROLLBACK_HANDLER , CONFIGURE_HANDLER ):
468487 raise ConfigurationError (f'`{ self .callback } ` callback name is reserved' )
@@ -509,12 +528,13 @@ def template_values(self, value: Dict[str, str]) -> None:
509528
510529
511530@dataclass
512- class IndexConfig (TemplateValuesMixin , NameMixin ):
531+ class IndexConfig (TemplateValuesMixin , NameMixin , ParentMixin ):
513532 datasource : Union [str , TzktDatasourceConfig ]
514533
515534 def __post_init_post_parse__ (self ) -> None :
516535 TemplateValuesMixin .__post_init_post_parse__ (self )
517536 NameMixin .__post_init_post_parse__ (self )
537+ ParentMixin .__post_init_post_parse__ (self )
518538
519539 def hash (self ) -> str :
520540 config_json = json .dumps (self , default = pydantic_encoder )
@@ -532,10 +552,11 @@ def datasource_config(self) -> TzktDatasourceConfig:
532552class OperationIndexConfig (IndexConfig ):
533553 """Operation index config
534554
535- :param datasource: Alias of datasource in `datasources` block
536- :param contract: Alias of contract to fetch operations for
537- :param first_block: First block to process
538- :param last_block: Last block to process
555+ :param datasource: Alias of index datasource in `datasources` section
556+ :param contracts: Aliases of contracts being indexed in `contracts` section
557+ :param stateless: Makes index dynamic. DipDup will synchronize index from the first block on every run
558+ :param first_block: First block to process (use with `--oneshot` run argument)
559+ :param last_block: Last block to process (use with `--oneshot` run argument)
539560 :param handlers: List of indexer handlers
540561 """
541562
@@ -557,6 +578,15 @@ def contract_configs(self) -> List[ContractConfig]:
557578 raise RuntimeError ('Config is not initialized' )
558579 return cast (List [ContractConfig ], self .contracts )
559580
581+ @property
582+ def entrypoints (self ) -> Set [str ]:
583+ entrypoints = set ()
584+ for handler in self .handlers :
585+ for pattern in handler .pattern :
586+ if isinstance (pattern , OperationHandlerTransactionPatternConfig ) and pattern .entrypoint :
587+ entrypoints .add (pattern .entrypoint )
588+ return entrypoints
589+
560590
561591@dataclass
562592class BigMapHandlerConfig (HandlerConfig ):
@@ -611,7 +641,7 @@ def contracts(self) -> List[ContractConfig]:
611641
612642
613643@dataclass
614- class IndexTemplateConfig :
644+ class IndexTemplateConfig ( ParentMixin ) :
615645 kind = 'template'
616646 template : str
617647 values : Dict [str , str ]
@@ -692,12 +722,12 @@ class DipDupConfig:
692722 spec_version : str
693723 package : str
694724 datasources : Dict [str , DatasourceConfigT ]
725+ database : Union [SqliteDatabaseConfig , PostgresDatabaseConfig ] = SqliteDatabaseConfig (kind = 'sqlite' )
695726 contracts : Dict [str , ContractConfig ] = Field (default_factory = dict )
696727 indexes : Dict [str , IndexConfigT ] = Field (default_factory = dict )
697728 templates : Dict [str , IndexConfigTemplateT ] = Field (default_factory = dict )
698- database : Union [ SqliteDatabaseConfig , PostgresDatabaseConfig ] = SqliteDatabaseConfig ( kind = 'sqlite' )
729+ jobs : Dict [ str , JobConfig ] = Field ( default_factory = dict )
699730 hasura : Optional [HasuraConfig ] = None
700- jobs : Optional [Dict [str , JobConfig ]] = None
701731 sentry : Optional [SentryConfig ] = None
702732
703733 def __post_init_post_parse__ (self ):
@@ -721,20 +751,27 @@ def validate(self) -> None:
721751 raise ConfigurationError ('SQLite DB engine is not supported by Hasura' )
722752
723753 def get_contract (self , name : str ) -> ContractConfig :
754+ if name .startswith ('<' ) and name .endswith ('>' ):
755+ raise ConfigurationError (f'`{ name } ` variable of index template is not set' )
756+
724757 try :
725758 return self .contracts [name ]
726759 except KeyError as e :
727760 raise ConfigurationError (f'Contract `{ name } ` not found in `contracts` config section' ) from e
728761
729762 def get_datasource (self , name : str ) -> DatasourceConfigT :
763+ if name .startswith ('<' ) and name .endswith ('>' ):
764+ raise ConfigurationError (f'`{ name } ` variable of index template is not set' )
765+
730766 try :
731767 return self .datasources [name ]
732768 except KeyError as e :
733769 raise ConfigurationError (f'Datasource `{ name } ` not found in `datasources` config section' ) from e
734770
735771 def get_template (self , name : str ) -> IndexConfigTemplateT :
736- if not self .templates :
737- raise ConfigurationError ('`templates` section is missing' )
772+ if name .startswith ('<' ) and name .endswith ('>' ):
773+ raise ConfigurationError (f'`{ name } ` variable of index template is not set' )
774+
738775 try :
739776 return self .templates [name ]
740777 except KeyError as e :
@@ -772,6 +809,7 @@ def resolve_index_templates(self) -> None:
772809 json_template = json .loads (raw_template )
773810 new_index_config = template .__class__ (** json_template )
774811 new_index_config .template_values = index_config .values
812+ new_index_config .parent = index_config .parent
775813 self .indexes [index_name ] = new_index_config
776814
777815 def _pre_initialize_index (self , index_name : str , index_config : IndexConfigT ) -> None :
@@ -831,6 +869,8 @@ def pre_initialize(self) -> None:
831869 contract_config .name = name
832870 for name , datasource_config in self .datasources .items ():
833871 datasource_config .name = name
872+ for name , job_config in self .jobs .items ():
873+ job_config .name = name
834874
835875 self .resolve_index_templates ()
836876 for index_name , index_config in self .indexes .items ():
0 commit comments