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.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. try:
  57. import urlparse as _urlparse
  58. except ImportError:
  59. from urllib import parse as _urlparse # NOQA
  60. urlparse = _urlparse
  61. """
  62. Unicode compatible wrapper for CSV reader and writer that abstracts away
  63. differences between Python 2 and 3. A package like unicodecsv would be
  64. preferable, but it's not Python 3 compatible yet.
  65. Code from http://python3porting.com/problems.html
  66. Changes:
  67. - Classes renamed to include CSV.
  68. - Unused 'codecs' import is dropped.
  69. - Added possibility to specify an open file to the writer to send as response
  70. of a view
  71. """
  72. import sys
  73. import csv
  74. PY3 = sys.version > '3'
  75. class UnicodeCSVReader:
  76. def __init__(self, filename, dialect=csv.excel,
  77. encoding="utf-8", **kw):
  78. self.filename = filename
  79. self.dialect = dialect
  80. self.encoding = encoding
  81. self.kw = kw
  82. def __enter__(self):
  83. if PY3:
  84. self.f = open(self.filename, 'rt',
  85. encoding=self.encoding, newline='')
  86. else:
  87. self.f = open(self.filename, 'rbU')
  88. self.reader = csv.reader(self.f, dialect=self.dialect,
  89. **self.kw)
  90. return self
  91. def __exit__(self, type, value, traceback):
  92. self.f.close()
  93. def next(self):
  94. row = next(self.reader)
  95. if PY3:
  96. return row
  97. return [s.decode("utf-8") for s in row]
  98. __next__ = next
  99. def __iter__(self):
  100. return self
  101. class UnicodeCSVWriter:
  102. """
  103. Python 2 and 3 compatible CSV writer. Supports two modes:
  104. * Writing to an open file or file-like object:
  105. writer = UnicodeCSVWriter(open_file=your_file)
  106. ...
  107. your_file.close()
  108. * Writing to a new file:
  109. with UnicodeCSVWriter(filename=filename) as writer:
  110. ...
  111. """
  112. def __init__(self, filename=None, open_file=None, dialect=csv.excel,
  113. encoding="utf-8", **kw):
  114. if filename is open_file is None:
  115. raise ImproperlyConfigured(
  116. "You need to specify either a filename or an open file")
  117. self.filename = filename
  118. self.f = open_file
  119. self.dialect = dialect
  120. self.encoding = encoding
  121. self.kw = kw
  122. self.writer = None
  123. def __enter__(self):
  124. assert self.filename is not None
  125. if PY3:
  126. self.f = open(self.filename, 'wt',
  127. encoding=self.encoding, newline='')
  128. else:
  129. self.f = open(self.filename, 'wb')
  130. def __exit__(self, type, value, traceback):
  131. assert self.filename is not None
  132. if self.filename is not None:
  133. self.f.close()
  134. def writerow(self, row):
  135. if self.writer is None:
  136. self.writer = csv.writer(self.f, dialect=self.dialect, **self.kw)
  137. if not PY3:
  138. row = [six.text_type(s).encode(self.encoding) for s in row]
  139. self.writer.writerow(list(row))
  140. def writerows(self, rows):
  141. for row in rows:
  142. self.writerow(row)