filesystem.py 2.7 KB

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