Development of an internal social media platform with personalised dashboards for students
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.

arguments.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. from django import template
  2. from django.core.exceptions import ImproperlyConfigured
  3. from classytags.exceptions import InvalidFlag
  4. from classytags.utils import NULL
  5. from classytags.utils import TemplateConstant
  6. from classytags.utils import mixin
  7. from classytags.values import ChoiceValue
  8. from classytags.values import DictValue
  9. from classytags.values import IntegerValue
  10. from classytags.values import ListValue
  11. from classytags.values import StrictStringValue
  12. from classytags.values import StringValue
  13. class Argument(object):
  14. """
  15. A basic single value argument.
  16. """
  17. value_class = StringValue
  18. def __init__(self, name, default=None, required=True, resolve=True):
  19. self.name = name
  20. self.default = default
  21. self.required = required
  22. self.resolve = resolve
  23. def __repr__(self): # pragma: no cover
  24. return '<%s: %s>' % (self.__class__.__name__, self.name)
  25. def get_default(self):
  26. """
  27. Get the default value
  28. """
  29. return TemplateConstant(self.default)
  30. def parse_token(self, parser, token):
  31. if self.resolve:
  32. return parser.compile_filter(token)
  33. else:
  34. return TemplateConstant(token)
  35. def parse(self, parser, token, tagname, kwargs):
  36. """
  37. Parse a token.
  38. """
  39. if self.name in kwargs:
  40. return False
  41. else:
  42. value = self.parse_token(parser, token)
  43. kwargs[self.name] = self.value_class(value)
  44. return True
  45. class StringArgument(Argument):
  46. value_class = StrictStringValue
  47. class KeywordArgument(Argument):
  48. """
  49. A single 'key=value' argument
  50. """
  51. wrapper_class = DictValue
  52. def __init__(self, name, default=None, required=True, resolve=True,
  53. defaultkey=None, splitter='='):
  54. super(KeywordArgument, self).__init__(name, default, required, resolve)
  55. self.defaultkey = defaultkey
  56. self.splitter = splitter
  57. def get_default(self):
  58. if self.defaultkey:
  59. return self.wrapper_class({
  60. self.defaultkey: TemplateConstant(self.default)
  61. })
  62. else:
  63. return self.wrapper_class({})
  64. def parse_token(self, parser, token):
  65. if self.splitter in token:
  66. key, raw_value = token.split(self.splitter, 1)
  67. value = super(KeywordArgument, self).parse_token(parser, raw_value)
  68. else:
  69. key = self.defaultkey
  70. value = super(KeywordArgument, self).parse_token(parser, token)
  71. return key, self.value_class(value)
  72. def parse(self, parser, token, tagname, kwargs):
  73. if self.name in kwargs: # pragma: no cover
  74. return False
  75. else:
  76. key, value = self.parse_token(parser, token)
  77. kwargs[self.name] = self.wrapper_class({
  78. key: value
  79. })
  80. return True
  81. class IntegerArgument(Argument):
  82. """
  83. Same as Argument but converts the value to integers.
  84. """
  85. value_class = IntegerValue
  86. class ChoiceArgument(Argument):
  87. """
  88. An Argument which checks if it's value is in a predefined list of choices.
  89. """
  90. def __init__(self, name, choices, default=None, required=True,
  91. resolve=True):
  92. super(ChoiceArgument, self).__init__(name, default, required, resolve)
  93. if default or not required:
  94. value_on_error = default
  95. else:
  96. value_on_error = choices[0]
  97. self.value_class = mixin(
  98. self.value_class,
  99. ChoiceValue,
  100. attrs={
  101. 'choices': choices,
  102. 'value_on_error': value_on_error,
  103. }
  104. )
  105. class MultiValueArgument(Argument):
  106. """
  107. An argument which allows multiple values.
  108. """
  109. sequence_class = ListValue
  110. value_class = StringValue
  111. def __init__(self, name, default=NULL, required=True, max_values=None,
  112. resolve=True):
  113. self.max_values = max_values
  114. if default is NULL:
  115. default = []
  116. else:
  117. required = False
  118. super(MultiValueArgument, self).__init__(name, default, required,
  119. resolve)
  120. def parse(self, parser, token, tagname, kwargs):
  121. """
  122. Parse a token.
  123. """
  124. value = self.value_class(self.parse_token(parser, token))
  125. if self.name in kwargs:
  126. if self.max_values and len(kwargs[self.name]) == self.max_values:
  127. return False
  128. kwargs[self.name].append(value)
  129. else:
  130. kwargs[self.name] = self.sequence_class(value)
  131. return True
  132. class MultiKeywordArgument(KeywordArgument):
  133. def __init__(self, name, default=None, required=True, resolve=True,
  134. max_values=None, splitter='='):
  135. if not default:
  136. default = {}
  137. else:
  138. default = dict(default)
  139. super(MultiKeywordArgument, self).__init__(name, default, required,
  140. resolve, NULL, splitter)
  141. self.max_values = max_values
  142. def get_default(self):
  143. items = self.default.items()
  144. return self.wrapper_class(
  145. dict([(key, TemplateConstant(value)) for key, value in items])
  146. )
  147. def parse(self, parser, token, tagname, kwargs):
  148. key, value = self.parse_token(parser, token)
  149. if key is NULL:
  150. raise template.TemplateSyntaxError(
  151. "MultiKeywordArgument arguments require key=value pairs"
  152. )
  153. if self.name in kwargs:
  154. if self.max_values and len(kwargs[self.name]) == self.max_values:
  155. return False
  156. kwargs[self.name][key] = value
  157. else:
  158. kwargs[self.name] = self.wrapper_class({
  159. key: value
  160. })
  161. return True
  162. class Flag(Argument):
  163. """
  164. A boolean flag
  165. """
  166. def __init__(self, name, default=NULL, true_values=None, false_values=None,
  167. case_sensitive=False):
  168. if default is not NULL:
  169. required = False
  170. else:
  171. required = True
  172. super(Flag, self).__init__(name, default, required)
  173. if true_values is None:
  174. true_values = []
  175. if false_values is None:
  176. false_values = []
  177. if case_sensitive:
  178. self.mod = lambda x: x
  179. else:
  180. self.mod = lambda x: str(x).lower()
  181. self.true_values = [self.mod(tv) for tv in true_values]
  182. self.false_values = [self.mod(fv) for fv in false_values]
  183. if not any([self.true_values, self.false_values]):
  184. raise ImproperlyConfigured(
  185. "Flag must specify either true_values and/or false_values"
  186. )
  187. def parse(self, parser, token, tagname, kwargs):
  188. """
  189. Parse a token.
  190. """
  191. ltoken = self.mod(token)
  192. if self.name in kwargs:
  193. return False
  194. if self.true_values and ltoken in self.true_values:
  195. kwargs[self.name] = TemplateConstant(True)
  196. elif self.false_values and ltoken in self.false_values:
  197. kwargs[self.name] = TemplateConstant(False)
  198. elif self.default is NULL:
  199. allowed_values = []
  200. if self.true_values:
  201. allowed_values += self.true_values
  202. if self.false_values:
  203. allowed_values += self.false_values
  204. raise InvalidFlag(self.name, token, allowed_values, tagname)
  205. else:
  206. kwargs[self.name] = self.get_default()
  207. return True