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.

compat.py 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import six
  2. from django.conf import settings
  3. from django.contrib.auth import get_user_model as django_get_user_model
  4. from django.contrib.auth.models import User
  5. from django.core.exceptions import ImproperlyConfigured
  6. def get_user_model():
  7. """
  8. Return the User model.
  9. This used to live in compat to support both Django 1.4's fixed User model
  10. and custom user models introduced thereafter.
  11. Support for Django 1.4 has since been dropped in Oscar, but our
  12. get_user_model remains because code relies on us annotating the _meta class
  13. with the additional fields, and other code might rely on it as well.
  14. """
  15. model = django_get_user_model()
  16. # Test if user model has any custom fields and add attributes to the _meta
  17. # class
  18. core_fields = set([f.name for f in User._meta.fields])
  19. model_fields = set([f.name for f in model._meta.fields])
  20. new_fields = model_fields.difference(core_fields)
  21. model._meta.has_additional_fields = len(new_fields) > 0
  22. model._meta.additional_fields = new_fields
  23. return model
  24. # A setting that can be used in foreign key declarations
  25. AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
  26. # Two additional settings that are useful in South migrations when
  27. # specifying the user model in the FakeORM
  28. try:
  29. AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME = AUTH_USER_MODEL.rsplit('.', 1)
  30. except ValueError:
  31. raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form"
  32. " 'app_label.model_name'")
  33. def existing_user_fields(fields):
  34. """
  35. Starting with Django 1.6, the User model can be overridden and it is no
  36. longer safe to assume the User model has certain fields. This helper
  37. function assists in writing portable forms Meta.fields definitions
  38. when those contain fields on the User model
  39. Usage:
  40. class UserForm(forms.Form):
  41. ...
  42. class Meta:
  43. # won't break if first_name is not defined on User model
  44. fields = existing_user_fields(['first_name', 'last_name'])
  45. """
  46. user_fields = get_user_model()._meta.fields
  47. user_field_names = [field.name for field in user_fields]
  48. return list(set(fields) & set(user_field_names))
  49. # Python3 compatibility layer
  50. # Make backwards-compatible atomic decorator available
  51. try:
  52. from django.db.transaction import atomic as atomic_compat
  53. except ImportError:
  54. from django.db.transaction import commit_on_success as atomic_compat
  55. atomic_compat = atomic_compat
  56. """
  57. Unicode compatible wrapper for CSV reader and writer that abstracts away
  58. differences between Python 2 and 3. A package like unicodecsv would be
  59. preferable, but it's not Python 3 compatible yet.
  60. Code from http://python3porting.com/problems.html
  61. Changes:
  62. - Classes renamed to include CSV.
  63. - Unused 'codecs' import is dropped.
  64. - Added possibility to specify an open file to the writer to send as response
  65. of a view
  66. """
  67. import sys
  68. import csv
  69. PY3 = sys.version > '3'
  70. class UnicodeCSVReader:
  71. def __init__(self, filename, dialect=csv.excel,
  72. encoding="utf-8", **kw):
  73. self.filename = filename
  74. self.dialect = dialect
  75. self.encoding = encoding
  76. self.kw = kw
  77. def __enter__(self):
  78. if PY3:
  79. self.f = open(self.filename, 'rt',
  80. encoding=self.encoding, newline='')
  81. else:
  82. self.f = open(self.filename, 'rbU')
  83. self.reader = csv.reader(self.f, dialect=self.dialect,
  84. **self.kw)
  85. return self
  86. def __exit__(self, type, value, traceback):
  87. self.f.close()
  88. def next(self):
  89. row = next(self.reader)
  90. if PY3:
  91. return row
  92. return [s.decode("utf-8") for s in row]
  93. __next__ = next
  94. def __iter__(self):
  95. return self
  96. class UnicodeCSVWriter:
  97. """
  98. Python 2 and 3 compatible CSV writer. Supports two modes:
  99. * Writing to an open file or file-like object:
  100. writer = UnicodeCSVWriter(open_file=your_file)
  101. ...
  102. your_file.close()
  103. * Writing to a new file:
  104. with UnicodeCSVWriter(filename=filename) as writer:
  105. ...
  106. """
  107. def __init__(self, filename=None, open_file=None, dialect=csv.excel,
  108. encoding="utf-8", **kw):
  109. if filename is open_file is None:
  110. raise ImproperlyConfigured(
  111. "You need to specify either a filename or an open file")
  112. self.filename = filename
  113. self.f = open_file
  114. self.dialect = dialect
  115. self.encoding = encoding
  116. self.kw = kw
  117. self.writer = None
  118. def __enter__(self):
  119. assert self.filename is not None
  120. if PY3:
  121. self.f = open(self.filename, 'wt',
  122. encoding=self.encoding, newline='')
  123. else:
  124. self.f = open(self.filename, 'wb')
  125. def __exit__(self, type, value, traceback):
  126. assert self.filename is not None
  127. if self.filename is not None:
  128. self.f.close()
  129. def writerow(self, row):
  130. if self.writer is None:
  131. self.writer = csv.writer(self.f, dialect=self.dialect, **self.kw)
  132. if not PY3:
  133. row = [six.text_type(s).encode(self.encoding) for s in row]
  134. self.writer.writerow(list(row))
  135. def writerows(self, rows):
  136. for row in rows:
  137. self.writerow(row)