filesystem.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # -*- coding: utf-8 -*-
  2. """
  3. ``celery.backends.filesystem``
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. File-system result store backend.
  6. """
  7. from __future__ import absolute_import, unicode_literals
  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 file-system backend does not
  23. work correctly, please make sure that it exists and has
  24. the correct permissions.\
  25. """
  26. class FilesystemBackend(KeyValueStoreBackend):
  27. """File-system 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 separator (to join the directory with the key)
  33. :param encoding: encoding used on the file-system
  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 separator 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 not url:
  49. raise ImproperlyConfigured(
  50. 'You need to configure a path for the File-system backend')
  51. if url is not None and url.startswith('file:///'):
  52. return url[7:]
  53. def _do_directory_test(self, key):
  54. try:
  55. self.set(key, b'test value')
  56. assert self.get(key) == b'test value'
  57. self.delete(key)
  58. except IOError:
  59. raise ImproperlyConfigured(E_PATH_INVALID)
  60. def _filename(self, key):
  61. return self.sep.join((self.path, key))
  62. def get(self, key):
  63. try:
  64. with self.open(self._filename(key), 'rb') as infile:
  65. return infile.read()
  66. except FileNotFoundError:
  67. pass
  68. def set(self, key, value):
  69. with self.open(self._filename(key), 'wb') as outfile:
  70. outfile.write(ensure_bytes(value))
  71. def mget(self, keys):
  72. for key in keys:
  73. yield self.get(key)
  74. def delete(self, key):
  75. self.unlink(self._filename(key))