# Path: sitetree/utils.py
# def get_tree_model() -> Type['TreeBase']:
#     """Returns the Tree model, set for the project."""
#     return get_model_class('MODEL_TREE')
# 
# def import_project_sitetree_modules() -> List[ModuleType]:
#     """Imports sitetrees modules from packages (apps).
#     Returns a list of submodules.
# 
#     """
#     submodules = []
#     for app_config in apps.app_configs.values():
#         module = import_app_sitetree_module(app_config.name)
#         if module is not None:
#             submodules.append(module)
# 
#     return submodules
# 
# Path: sitetree/settings.py
# APP_MODULE_NAME: str = getattr(settings, 'SITETREE_APP_MODULE_NAME', 'sitetrees')
# 
# Path: sitetree/sitetreeapp.py
# class Cache:
#     """Contains cache-related stuff."""
# 
#     def __init__(self):
#         self.cache: dict = {}
# 
#         cache_empty = self.empty
#         # Listen for signals from the models.
#         signals.post_save.connect(cache_empty, sender=MODEL_TREE_CLASS)
#         signals.post_save.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS)
#         signals.post_delete.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS)
#         # Listen to the changes in item permissions table.
#         signals.m2m_changed.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS.access_permissions)
# 
#         self.init()
# 
#     @classmethod
#     def reset(cls):
#         """Instructs sitetree to drop and recreate cache.
# 
#         Could be used to show up tree changes made in a different process.
# 
#         """
#         cache.set('sitetrees_reset', True)
# 
#     def init(self):
#         """Initializes local cache from Django cache."""
# 
#         # Drop cache flag set by .reset() method.
#         cache.get('sitetrees_reset') and self.empty(init=False)
# 
#         self.cache = cache.get(
#             'sitetrees', {'sitetrees': {}, 'parents': {}, 'items_by_ids': {}, 'tree_aliases': {}})
# 
#     def save(self):
#         """Saves sitetree data to Django cache."""
#         cache.set('sitetrees', self.cache, CACHE_TIMEOUT)
# 
#     def empty(self, **kwargs):
#         """Empties cached sitetree data."""
#         cache.delete('sitetrees')
#         cache.delete('sitetrees_reset')
# 
#         kwargs.get('init', True) and self.init()
# 
#     def get_entry(self, entry_name: str, key) -> Any:
#         """Returns cache entry parameter value by its name.
# 
#         :param entry_name:
#         :param key:
# 
#         """
#         return self.cache[entry_name].get(key, False)
# 
#     def update_entry_value(self, entry_name: str, key: str, value: Any):
#         """Updates cache entry parameter with new data.
# 
#         :param entry_name:
#         :param key:
#         :param value:
# 
#         """
#         if key not in self.cache[entry_name]:
#             self.cache[entry_name][key] = {}
# 
#         self.cache[entry_name][key].update(value)
# 
#     def set_entry(self, entry_name: str, key: str, value: Any):
#         """Replaces entire cache entry parameter data by its name with new data.
# 
#         :param entry_name:
#         :param key:
#         :param value:
# 
#         """
#         self.cache[entry_name][key] = value
# 
# Path: sitetree/compat.py
# class CommandOption:
#     """Command line option wrapper."""
# 
#     def __init__(self, *args, **kwargs):
#         self.args = args
#         self.kwargs = kwargs
# 
# def options_getter(command_options):
#     """Compatibility function to get rid of optparse in management commands after Django 1.10.
# 
#     :param tuple command_options: tuple with `CommandOption` objects.
# 
#     """
#     def get_options(option_func: Callable = None):
#         from optparse import make_option
# 
#         func = option_func or make_option
#         options = tuple([func(*option.args, **option.kwargs) for option in command_options])
# 
#         return [] if option_func is None else options
# 
#     return get_options


from django.core.management.base import BaseCommand
from django.db import DEFAULT_DB_ALIAS
from sitetree.utils import get_tree_model, import_project_sitetree_modules
from sitetree.settings import APP_MODULE_NAME
from sitetree.sitetreeapp import Cache
from sitetree.compat import CommandOption, options_getter
        if not tree_modules:
            self.stdout.write(f'No sitetrees found in project apps (searched in %app%/{APP_MODULE_NAME}.py).\n')

        for module in tree_modules:
            sitetrees = getattr(module, 'sitetrees', None)
            app = module.__dict__['__package__']
            if not apps or app in apps:
                if sitetrees is not None:
                    self.stdout.write(f'Sitetrees found in `{app}` app ...\n')
                    for tree in sitetrees:
                        self.stdout.write(f'  Processing `{tree.alias}` tree ...\n')
                        # Delete trees with the same name beforehand.
                        MODEL_TREE_CLASS.objects.filter(alias=tree.alias).using(using).delete()
                        # Drop id to let the DB handle it.
                        tree.id = None
                        tree.save(using=using)
                        for item in tree.dynamic_items:
                            self.stdout.write(f'    Adding `{item.title}` tree item ...\n')
                            # Drop id to let the DB handle it.
                            item.id = None
                            if item.parent is not None:
                                # Suppose parent tree object is already saved to DB.
                                item.parent_id = item.parent.id
                            item.tree = tree
                            item.save(using=using)
                            # Copy permissions to M2M field once `item`
                            # has been saved
                            if hasattr(item.access_permissions, 'set'):
                                item.access_permissions.set(item.permissions)


# Path: sitetree/utils.py
# def get_tree_model() -> Type['TreeBase']:
#     """Returns the Tree model, set for the project."""
#     return get_model_class('MODEL_TREE')
# 
# def import_project_sitetree_modules() -> List[ModuleType]:
#     """Imports sitetrees modules from packages (apps).
#     Returns a list of submodules.
# 
#     """
#     submodules = []
#     for app_config in apps.app_configs.values():
#         module = import_app_sitetree_module(app_config.name)
#         if module is not None:
#             submodules.append(module)
# 
#     return submodules
# 
# Path: sitetree/settings.py
# APP_MODULE_NAME: str = getattr(settings, 'SITETREE_APP_MODULE_NAME', 'sitetrees')
# 
# Path: sitetree/sitetreeapp.py
# class Cache:
#     """Contains cache-related stuff."""
# 
#     def __init__(self):
#         self.cache: dict = {}
# 
#         cache_empty = self.empty
#         # Listen for signals from the models.
#         signals.post_save.connect(cache_empty, sender=MODEL_TREE_CLASS)
#         signals.post_save.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS)
#         signals.post_delete.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS)
#         # Listen to the changes in item permissions table.
#         signals.m2m_changed.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS.access_permissions)
# 
#         self.init()
# 
#     @classmethod
#     def reset(cls):
#         """Instructs sitetree to drop and recreate cache.
# 
#         Could be used to show up tree changes made in a different process.
# 
#         """
#         cache.set('sitetrees_reset', True)
# 
#     def init(self):
#         """Initializes local cache from Django cache."""
# 
#         # Drop cache flag set by .reset() method.
#         cache.get('sitetrees_reset') and self.empty(init=False)
# 
#         self.cache = cache.get(
#             'sitetrees', {'sitetrees': {}, 'parents': {}, 'items_by_ids': {}, 'tree_aliases': {}})
# 
#     def save(self):
#         """Saves sitetree data to Django cache."""
#         cache.set('sitetrees', self.cache, CACHE_TIMEOUT)
# 
#     def empty(self, **kwargs):
#         """Empties cached sitetree data."""
#         cache.delete('sitetrees')
#         cache.delete('sitetrees_reset')
# 
#         kwargs.get('init', True) and self.init()
# 
#     def get_entry(self, entry_name: str, key) -> Any:
#         """Returns cache entry parameter value by its name.
# 
#         :param entry_name:
#         :param key:
# 
#         """
#         return self.cache[entry_name].get(key, False)
# 
#     def update_entry_value(self, entry_name: str, key: str, value: Any):
#         """Updates cache entry parameter with new data.
# 
#         :param entry_name:
#         :param key:
#         :param value:
# 
#         """
#         if key not in self.cache[entry_name]:
#             self.cache[entry_name][key] = {}
# 
#         self.cache[entry_name][key].update(value)
# 
#     def set_entry(self, entry_name: str, key: str, value: Any):
#         """Replaces entire cache entry parameter data by its name with new data.
# 
#         :param entry_name:
#         :param key:
#         :param value:
# 
#         """
#         self.cache[entry_name][key] = value
# 
# Path: sitetree/compat.py
# class CommandOption:
#     """Command line option wrapper."""
# 
#     def __init__(self, *args, **kwargs):
#         self.args = args
#         self.kwargs = kwargs
# 
# def options_getter(command_options):
#     """Compatibility function to get rid of optparse in management commands after Django 1.10.
# 
#     :param tuple command_options: tuple with `CommandOption` objects.
# 
#     """
#     def get_options(option_func: Callable = None):
#         from optparse import make_option
# 
#         func = option_func or make_option
#         options = tuple([func(*option.args, **option.kwargs) for option in command_options])
# 
#         return [] if option_func is None else options
# 
#     return get_options


# Path: sitetree/management/commands/sitetree_resync_apps.py
from django.core.management.base import BaseCommand
from django.db import DEFAULT_DB_ALIAS
from sitetree.utils import get_tree_model, import_project_sitetree_modules
from sitetree.settings import APP_MODULE_NAME
from sitetree.sitetreeapp import Cache
from sitetree.compat import CommandOption, options_getter

        if not tree_modules:
            self.stdout.write(f'No sitetrees found in project apps (searched in %app%/{APP_MODULE_NAME}.py).\n')

        for module in tree_modules:
            sitetrees = getattr(module, 'sitetrees', None)
            app = module.__dict__['__package__']
            if not apps or app in apps:
                if sitetrees is not None:
                    self.stdout.write(f'Sitetrees found in `{app}` app ...\n')
                    for tree in sitetrees:
                        self.stdout.write(f'  Processing `{tree.alias}` tree ...\n')
                        # Delete trees with the same name beforehand.
                        MODEL_TREE_CLASS.objects.filter(alias=tree.alias).using(using).delete()
                        # Drop id to let the DB handle it.
                        tree.id = None
                        tree.save(using=using)
                        for item in tree.dynamic_items:
                            self.stdout.write(f'    Adding `{item.title}` tree item ...\n')
                            # Drop id to let the DB handle it.
                            item.id = None
                            if item.parent is not None:
                                # Suppose parent tree object is already saved to DB.
                                item.parent_id = item.parent.id
                            item.tree = tree
                            item.save(using=using)
                            # Copy permissions to M2M field once `item`
                            # has been saved
                            if hasattr(item.access_permissions, 'set'):
                                item.access_permissions.set(item.permissions)


                            else: