filesystem.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # -*- coding: utf-8 -*-
  2. """
  3. celery.backends.filesystem
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. Filesystem result store backend.
  6. """
  7. from __future__ import absolute_import
  8. from kombu.utils.encoding import ensure_bytes
  9. from celery.exceptions import ImproperlyConfigured
  10. from celery.backends.base import KeyValueStoreBackend
  11. from celery.utils import uuid
  12. import os
  13. import locale
  14. default_encoding = locale.getpreferredencoding(False)
  15. # Python 2 does not have FileNotFoundError and IsADirectoryError
  16. try:
  17. FileNotFoundError
  18. except NameError:
  19. FileNotFoundError = IOError
  20. IsADirectoryError = IOError
  21. E_PATH_INVALID = """\
  22. The configured path for the Filesystem backend does not
  23. work correctly, please make sure that it exists and has
  24. the correct permissions.\
  25. """
  26. class FilesystemBackend(KeyValueStoreBackend):
  27. """Filesystem result backend.
  28. Keyword arguments (in addition to those of KeyValueStoreBackend):
  29. :param url: URL to the directory we should use
  30. :param open: open function to use when opening files
  31. :param unlink: unlink function to use when deleting files
  32. :param sep: directory seperator (to join the directory with the key)
  33. :param encoding: encoding used on the filesystem
  34. """
  35. def __init__(self, url=None, open=open, unlink=os.unlink, sep=os.sep,
  36. encoding=default_encoding, *args, **kwargs):
  37. super(FilesystemBackend, self).__init__(*args, **kwargs)
  38. self.url = url
  39. path = self._find_path(url)
  40. # We need the path and seperator as bytes objects
  41. self.path = path.encode(encoding)
  42. self.sep = sep.encode(encoding)
  43. self.open = open
  44. self.unlink = unlink
  45. # Lets verify that we have everything setup right
  46. self._do_directory_test(b'.fs-backend-' + uuid().encode(encoding))
  47. def _find_path(self, url):
  48. if url is not None and url.startswith('file:///'):
  49. return url[7:]
  50. path = self.app.conf.result_fspath
  51. if not path:
  52. raise ImproperlyConfigured(
  53. 'You need to configure a path for the Filesystem backend')
  54. return path
  55. def _do_directory_test(self, key):
  56. try:
  57. self.set(key, b'test value')
  58. assert self.get(key) == b'test value'
  59. self.delete(key)
  60. except IOError:
  61. raise ImproperlyConfigured(E_PATH_INVALID)
  62. def _filename(self, key):
  63. return self.sep.join((self.path, key))
  64. def get(self, key):
  65. try:
  66. with self.open(self._filename(key), 'rb') as infile:
  67. return infile.read()
  68. except FileNotFoundError:
  69. pass
  70. def set(self, key, value):
  71. with self.open(self._filename(key), 'wb') as outfile:
  72. outfile.write(ensure_bytes(value))
  73. def mget(self, keys):
  74. for key in keys:
  75. yield self.get(key)
  76. def delete(self, key):
  77. self.unlink(self._filename(key))