init.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # coding:utf-8
  2. #!/usr/bin/python
  3. #
  4. # Copyright (c) Contributors to the Open 3D Engine Project.
  5. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  6. #
  7. # SPDX-License-Identifier: Apache-2.0 OR MIT
  8. #
  9. # -------------------------------------------------------------------------
  10. """! @brief
  11. <DCCsi>/azpy/shared/utils/__init__.py
  12. This module moves some utility methods out of __init__ files so we can reuse
  13. and reduce boiler plate code copied across modules.
  14. """
  15. # --------------------------------------------------------------------------
  16. # standard imports
  17. import sys
  18. import errno
  19. import os
  20. import site
  21. import os.path
  22. from pathlib import Path
  23. import logging as _logging
  24. # -------------------------------------------------------------------------
  25. # There are many __init__ files throughout the dccsi that need to be refactored
  26. # and updated to share this module for common utils.
  27. # -------------------------------------------------------------------------
  28. # Global Scope
  29. _MODULENAME = 'azpy.shared.utils.init'
  30. _LOGGER = _logging.getLogger(_MODULENAME)
  31. _LOGGER.debug('Initializing: {}.'.format({_MODULENAME}))
  32. __all__ = ['makedirs',
  33. 'FileExistsError',
  34. 'initialize_logger',
  35. 'test_imports']
  36. # to refactor things into this module, some of this was brought along
  37. # and this could be streamlined in a future refactor pass to slim down
  38. # we need to set up basic access to the DCCsi
  39. _MODULE_PATH = os.path.realpath(__file__) # To Do: what if frozen?
  40. _PATH_DCCSIG = os.path.normpath(os.path.join(_MODULE_PATH, '../..'))
  41. _PATH_DCCSIG = os.getenv('PATH_DCCSIG', _PATH_DCCSIG)
  42. site.addsitedir(_PATH_DCCSIG)
  43. import azpy.constants as constants
  44. # For now, use dccsi as the default project location6
  45. # This could be improved by deriving the project from o3de and/or managed settings
  46. _PATH_O3DE_PROJECT = Path(os.getenv(constants.ENVAR_PATH_O3DE_PROJECT, _PATH_DCCSIG))
  47. _LOGGER.debug('Default PATH_O3DE_PROJECT" {}'.format(_PATH_O3DE_PROJECT.resolve()))
  48. from azpy.config_utils import ENVAR_DCCSI_GDEBUG
  49. from azpy.env_bool import env_bool
  50. _DCCSI_GDEBUG = env_bool(ENVAR_DCCSI_GDEBUG, False)
  51. # project cache log dir path
  52. from azpy.constants import TAG_DCCSI_NICKNAME
  53. from azpy.constants import PATH_DCCSI_LOG_PATH
  54. _DCCSI_LOG_PATH = Path(PATH_DCCSI_LOG_PATH.format(PATH_O3DE_PROJECT=_PATH_O3DE_PROJECT.resolve(),
  55. TAG_DCCSI_NICKNAME=TAG_DCCSI_NICKNAME))
  56. # -------------------------------------------------------------------------
  57. # -------------------------------------------------------------------------
  58. # This method could be updated for py3+ to use pathlib
  59. def makedirs(folder, *args, **kwargs):
  60. """a makedirs for py2.7 support"""
  61. try:
  62. return os.makedirs(folder, exist_ok=True, *args, **kwargs)
  63. except TypeError:
  64. # Unexpected arguments encountered
  65. pass
  66. try:
  67. # Should work is TypeError was caused by exist_ok, eg., Py2
  68. return os.makedirs(folder, *args, **kwargs)
  69. except OSError as e:
  70. if e.errno != errno.EEXIST:
  71. raise
  72. if os.path.isfile(folder):
  73. # folder is a file, raise OSError just like os.makedirs() in Py3
  74. raise
  75. # -------------------------------------------------------------------------
  76. # -------------------------------------------------------------------------
  77. class FileExistsError(Exception):
  78. """Implements a stand-in Exception for py2.7"""
  79. def __init__(self, message, errors):
  80. # Call the base class constructor with the parameters it needs
  81. super(FileExistsError, self).__init__(message)
  82. # Now for your custom code...
  83. self.errors = errors
  84. if sys.version_info.major < 3:
  85. FileExistsError = FileExistsError
  86. # -------------------------------------------------------------------------
  87. # -------------------------------------------------------------------------
  88. # This method we intend to replace with a logging class/module in the future
  89. def initialize_logger(name,
  90. log_to_file=False,
  91. default_log_level=_logging.NOTSET,
  92. propagate=False):
  93. """Start a azpy logger"""
  94. _logger = _logging.getLogger(name)
  95. _logger.propagate = propagate
  96. if not _logger.handlers:
  97. _log_level = int(os.getenv('DCCSI_LOGLEVEL', default_log_level))
  98. if _DCCSI_GDEBUG:
  99. _log_level = int(10) # force when debugging
  100. print('_log_level: {}'.format(_log_level))
  101. if _log_level:
  102. ch = _logging.StreamHandler(sys.stdout)
  103. ch.setLevel(_log_level)
  104. formatter = _logging.Formatter(constants.FRMT_LOG_LONG)
  105. ch.setFormatter(formatter)
  106. _logger.addHandler(ch)
  107. _logger.setLevel(_log_level)
  108. else:
  109. _logger.addHandler(_logging.NullHandler())
  110. # optionally add the log file handler (off by default)
  111. if log_to_file:
  112. _logger.info('DCCSI_LOG_PATH: {}'.format(_DCCSI_LOG_PATH))
  113. if not _DCCSI_LOG_PATH.exists():
  114. try:
  115. os.makedirs(_DCCSI_LOG_PATH.as_posix())
  116. except FileExistsError:
  117. # except FileExistsError: doesn't exist in py2.7
  118. _logger.debug("Folder is already there")
  119. else:
  120. _logger.debug("Folder was created")
  121. _log_filepath = Path(_DCCSI_LOG_PATH, '{}.log'.format(name))
  122. try:
  123. _log_filepath.touch(mode=0o666, exist_ok=True)
  124. except FileExistsError:
  125. _logger.debug("Log file is already there: {}".format(_log_filepath))
  126. else:
  127. _logger.debug("Log file was created: {}".format(_log_filepath))
  128. if _log_filepath.exists():
  129. file_formatter = _logging.Formatter(constants.FRMT_LOG_LONG)
  130. file_handler = _logging.FileHandler(str(_log_filepath))
  131. file_handler.setLevel(_logging.DEBUG)
  132. file_handler.setFormatter(file_formatter)
  133. _logger.addHandler(file_handler)
  134. return _logger
  135. # -------------------------------------------------------------------------
  136. # -------------------------------------------------------------------------
  137. def test_imports(_all=__all__, _pkg=_MODULENAME, _logger=_LOGGER):
  138. # If in dev mode this will test imports of __all__
  139. _logger.debug("~ Import triggered from: {}".format(_pkg))
  140. import importlib
  141. for mod_str in _all:
  142. try:
  143. # this is py2.7 compatible
  144. # in py3.5+, we can use importlib.util instead
  145. importlib.import_module('.{}'.format(mod_str), _pkg)
  146. _logger.info("~ Imported module: {0}.{1}".format(_pkg, mod_str))
  147. except Exception as e:
  148. _logger.warning('~ {}'.format(e))
  149. _logger.warning("~ {0}.{1} :: ImportFail".format(_pkg, mod_str))
  150. return False
  151. return True
  152. # -------------------------------------------------------------------------