Skip to content

Commit

Permalink
Synchronize entity dynamic imports (#1794)
Browse files Browse the repository at this point in the history
Co-authored-by: Arkadii Yakovets <ark@cho.red>
  • Loading branch information
Izzette and arkid15r committed May 22, 2024
1 parent 35cbb44 commit 94371ef
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 1 deletion.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Heikki Orsila
Henrik Sozzi
Hugh McNamara
Hugo van Kemenade
Isabelle COWAN-BERGMAN
Jacky Han
Jacob Punter
Jaemin Kim
Expand Down
11 changes: 10 additions & 1 deletion holidays/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# License: MIT (see LICENSE file)

import importlib
from threading import RLock
from typing import Any, Dict, Iterable, Optional, Tuple, Union

from holidays.holiday_base import HolidayBase
Expand Down Expand Up @@ -178,6 +179,11 @@
"ny_stock_exchange": ("NewYorkStockExchange", "NYSE", "XNYS"),
}

# A re-entrant lock. Once a thread has acquired a re-entrant lock,
# the same thread may acquire it again without blocking.
# https://docs.python.org/3/library/threading.html#rlock-objects
IMPORT_LOCK = RLock()


class EntityLoader:
"""Country and financial holidays entities lazy loader."""
Expand Down Expand Up @@ -223,7 +229,10 @@ def __str__(self) -> str:
def get_entity(self) -> Optional[HolidayBase]:
"""Return lazy-loaded entity."""
if self.entity is None:
self.entity = getattr(importlib.import_module(self.module_name), self.entity_name)
# Avoid deadlock due to importlib.import_module not being thread-safe by caching all
# the first imports in a dedicated thread.
with IMPORT_LOCK:
self.entity = getattr(importlib.import_module(self.module_name), self.entity_name)

return self.entity

Expand Down

0 comments on commit 94371ef

Please sign in to comment.