filesystem.py 2.7 KB

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