nodestream icon indicating copy to clipboard operation
nodestream copied to clipboard

[REQUEST] Provide Friendlier Errors for `MissingFromRegistryError`s and `KeyError`s

Open zprobst opened this issue 1 year ago • 0 comments

Is your feature request related to a problem? Please describe. Its not obvious from this error message what is not found and what the pipeline is trying to load that it can.


  KeyError

  None

  at ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\subclass_registry.py:60 in get
       56│
       57│     def get(self, name):
       58│         """Get a subclass by name."""
       59│         try:
    →  60│             return self.registry[name]
       61│         except KeyError:
       62│             raise MissingFromRegistryError(name)
       63│
       64│     @property

The following error occurred when trying to handle this error:


  Stack trace:

  24  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\cleo\application.py:327 in run
       325│
       326│             try:
     → 327│                 exit_code = self._run(io)
       328│             except BrokenPipeError:
       329│                 # If we are piped to another process, it may close early and send a

  23  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\cleo\application.py:431 in _run
       429│             io.input.interactive(interactive)
       430│
     → 431│         exit_code = self._run_command(command, io)
       432│         self._running_command = None
       433│

  22  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\cleo\application.py:438 in _run_command
       436│     def _run_command(self, command: Command, io: IO) -> int:
       437│         if self._event_dispatcher is None:
     → 438│             return command.run(io)
       439│
       440│         # Bind before the console.command event,

  21  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\cleo\commands\base_command.py:119 in run
       117│         io.input.validate()
       118│
     → 119│         status_code = self.execute(io)
       120│
       121│         if status_code is None:

  20  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\cleo\commands\command.py:62 in execute
        60│
        61│         try:
     →  62│             return self.handle()
        63│         except KeyboardInterrupt:
        64│             return 1

  19  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\cli\commands\nodestream_command.py:21 in handle
        19│
        20│     def handle(self):
     →  21│         return asyncio.run(self.handle_async())
        22│
        23│     async def handle_async(self):

  18  ~\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py:190 in run
       188│
       189│     with Runner(debug=debug) as runner:
     → 190│         return runner.run(main)
       191│
       192│

  17  ~\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py:118 in run
       116│         self._interrupt_count = 0
       117│         try:
     → 118│             return self._loop.run_until_complete(task)
       119│         except exceptions.CancelledError:
       120│             if self._interrupt_count > 0:

  16  ~\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py:653 in run_until_complete
        651│             raise RuntimeError('Event loop stopped before Future completed.')
        652│
     →  653│         return future.result()
        654│
        655│     def stop(self):

  15  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\cli\commands\run.py:41 in handle_async
        39│         await self.run_operation(InitializeLogger())
        40│         project = await self.run_operation(InitializeProject())
     →  41│         await self.run_operation(RunPipeline(project))
        42│

  14  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\cli\commands\nodestream_command.py:30 in run_operation
        28│             f"Running: {operation.name}", verbosity=Verbosity.VERBOSE
        29│         )
     →  30│         return await operation.perform(self)
        31│
        32│     def get_project_path(self) -> Path:

  13  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\cli\operations\run_pipeline.py:32 in perform
        30│         for pipeline_name in self.get_pipelines_to_run(command):
        31│             request = self.make_run_request(command, pipeline_name)
     →  32│             pipelines_ran += await self.project.run(request)
        33│
        34│         if pipelines_ran == 0:

  12  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\project\project.py:122 in run
       120│         pipelines_ran = 0
       121│         for scope in self.scopes_by_name.values():
     → 122│             pipelines_ran += await scope.run_request(request)
       123│         return pipelines_ran
       124│

  11  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\project\pipeline_scope.py:85 in run_request
        83│             return 0
        84│
     →  85│         await run_request.execute_with_definition(self[name], self.config)
        86│         return 1
        87│

  10  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\project\run_request.py:59 in execute_with_definition
        57│         """
        58│         with start_context(self.pipeline_name):
     →  59│             pipeline = definition.initialize(self.initialization_arguments, config)
        60│             await pipeline.run(self.progress_reporter)
        61│

   9  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\project\pipeline_definition.py:91 in initialize
        89│         self, init_args: PipelineInitializationArguments, config: ScopeConfig = None
        90│     ) -> Pipeline:
     →  91│         return PipelineFileLoader(self.file_path).load_pipeline(init_args, config)
        92│
        93│     def remove_file(self, missing_ok: bool = True):

   8  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\pipeline\pipeline_file_loader.py:118 in load_pipeline
       116│     ) -> Pipeline:
       117│         init_args = init_args or PipelineInitializationArguments()
     → 118│         return self.load_pipeline_from_file_data(
       119│             self.load_pipeline_file_data(config), init_args
       120│         )

   7  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\pipeline\pipeline_file_loader.py:130 in load_pipeline_from_file_data
       128│             )
       129│
     → 130│         return init_args.initialize_from_file_data(file_data)
       131│
       132│     def load_pipeline_file_data(self, config: ScopeConfig = None):

   6  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\pipeline\pipeline_file_loader.py:74 in initialize_from_file_data
        72│     def initialize_from_file_data(self, file_data: List[dict]):
        73│         return Pipeline(
     →  74│             steps=self.load_steps(ClassLoader(Step), file_data),
        75│             step_outbox_size=self.step_outbox_size,
        76│         )

   5  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\pipeline\pipeline_file_loader.py:82 in load_steps
        80│         if self.on_effective_configuration_resolved:
        81│             self.on_effective_configuration_resolved(file_data)
     →  82│         return [class_loader.load_class(**step_data) for step_data in effective]
        83│
        84│     def get_effective_configuration(self, file_data):

   4  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\pipeline\pipeline_file_loader.py:82 in <listcomp>
        80│         if self.on_effective_configuration_resolved:
        81│             self.on_effective_configuration_resolved(file_data)
     →  82│         return [class_loader.load_class(**step_data) for step_data in effective]
        83│
        84│     def get_effective_configuration(self, file_data):

   3  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\pipeline\class_loader.py:62 in load_class
        60│         initializer = self.find_class_initializer(implementation, factory)
        61│         try:
     →  62│             result = initializer(**arguments)
        63│         except TypeError as e:
        64│             raise PipelineComponentInitializationError(initializer, arguments) from e

   2  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\databases\writer.py:21 in from_file_data
        19│         # Import all query executors so that they can register themselves
        20│         DatabaseConnector.import_all()
     →  21│         connector = DatabaseConnector.from_database_args(
        22│             database=database, **database_args
        23│         )

   1  ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\databases\database_connector.py:19 in from_database_args
        17│         cls, database: str = "neo4j", **database_args
        18│     ) -> "DatabaseConnector":
     →  19│         return DATABASE_CONNECTOR_SUBCLASS_REGISTRY.get(database).from_file_data(
        20│             **database_args
        21│         )

  MissingFromRegistryError

  None is not in the subclass registry

  at ~\AppData\Local\pypoetry\Cache\virtualenvs\test1-WxuTdTEg-py3.11\Lib\site-packages\nodestream\subclass_registry.py:62 in get
       58│         """Get a subclass by name."""
       59│         try:
       60│             return self.registry[name]
       61│         except KeyError:
    →  62│             raise MissingFromRegistryError(name)
       63│
       64│     @property
       65│     def all_subclasses(self):
       66│         return self.registry.values()

Describe the solution you'd like I think we should catch and re-raise these errors better to provide a better indicator as to what is wrong.

Describe alternatives you've considered n/a

Additional context n/a

zprobst avatar Nov 15 '23 21:11 zprobst