You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

registry.py 3.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. from itertools import chain
  2. from django.utils.itercompat import is_iterable
  3. class Tags:
  4. """
  5. Built-in tags for internal checks.
  6. """
  7. admin = 'admin'
  8. caches = 'caches'
  9. compatibility = 'compatibility'
  10. database = 'database'
  11. models = 'models'
  12. security = 'security'
  13. signals = 'signals'
  14. templates = 'templates'
  15. translation = 'translation'
  16. urls = 'urls'
  17. class CheckRegistry:
  18. def __init__(self):
  19. self.registered_checks = set()
  20. self.deployment_checks = set()
  21. def register(self, check=None, *tags, **kwargs):
  22. """
  23. Can be used as a function or a decorator. Register given function
  24. `f` labeled with given `tags`. The function should receive **kwargs
  25. and return list of Errors and Warnings.
  26. Example::
  27. registry = CheckRegistry()
  28. @registry.register('mytag', 'anothertag')
  29. def my_check(apps, **kwargs):
  30. # ... perform checks and collect `errors` ...
  31. return errors
  32. # or
  33. registry.register(my_check, 'mytag', 'anothertag')
  34. """
  35. def inner(check):
  36. check.tags = tags
  37. checks = self.deployment_checks if kwargs.get('deploy') else self.registered_checks
  38. checks.add(check)
  39. return check
  40. if callable(check):
  41. return inner(check)
  42. else:
  43. if check:
  44. tags += (check,)
  45. return inner
  46. def run_checks(self, app_configs=None, tags=None, include_deployment_checks=False):
  47. """
  48. Run all registered checks and return list of Errors and Warnings.
  49. """
  50. errors = []
  51. checks = self.get_checks(include_deployment_checks)
  52. if tags is not None:
  53. checks = [check for check in checks if not set(check.tags).isdisjoint(tags)]
  54. else:
  55. # By default, 'database'-tagged checks are not run as they do more
  56. # than mere static code analysis.
  57. checks = [check for check in checks if Tags.database not in check.tags]
  58. for check in checks:
  59. new_errors = check(app_configs=app_configs)
  60. assert is_iterable(new_errors), (
  61. "The function %r did not return a list. All functions registered "
  62. "with the checks registry must return a list." % check)
  63. errors.extend(new_errors)
  64. return errors
  65. def tag_exists(self, tag, include_deployment_checks=False):
  66. return tag in self.tags_available(include_deployment_checks)
  67. def tags_available(self, deployment_checks=False):
  68. return set(chain.from_iterable(
  69. check.tags for check in self.get_checks(deployment_checks)
  70. ))
  71. def get_checks(self, include_deployment_checks=False):
  72. checks = list(self.registered_checks)
  73. if include_deployment_checks:
  74. checks.extend(self.deployment_checks)
  75. return checks
  76. registry = CheckRegistry()
  77. register = registry.register
  78. run_checks = registry.run_checks
  79. tag_exists = registry.tag_exists