1
0

format.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/bin/env python
  2. # Copyright 2017 Xiaomi, Inc.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import re
  16. old_pattern = re.compile(r'%\w')
  17. new_pattern = re.compile(r'\{(\w+(\.\w+|\[\w+\])?)\}')
  18. __formaters = {}
  19. def format(text, *a, **kw):
  20. f = __formaters.get(text)
  21. if f is None:
  22. f = formater(text)
  23. __formaters[text] = f
  24. return f(*a, **kw)
  25. #return formater(text)(*a, **kw)
  26. def formater(text):
  27. """
  28. >>> format('%s %s', 3, 2, 7, a=7, id=8)
  29. '3 2'
  30. >>> format('%(a)d %(id)s', 3, 2, 7, a=7, id=8)
  31. '7 8'
  32. >>> format('{1} {id}', 3, 2, a=7, id=8)
  33. '2 8'
  34. >>> class Obj: id = 3
  35. >>> format('{obj.id} {0.id}', Obj(), obj=Obj())
  36. '3 3'
  37. """
  38. # def arg(k,a,kw):
  39. # if k.isdigit():
  40. # return a[int(k)]
  41. # return kw[k]
  42. def translator(k):
  43. if '.' in k:
  44. name,attr = k.split('.')
  45. if name.isdigit():
  46. k = int(name)
  47. return lambda *a, **kw: getattr(a[k], attr)
  48. return lambda *a, **kw: getattr(kw[name], attr)
  49. # elif '[' in k and k.endswith(']'):
  50. # name,index = k[:k.index('[')],k[k.index('[')+1:-1]
  51. # def _(*a, **kw):
  52. # if index.isdigit():
  53. # return arg(name,a,kw)[int(index)]
  54. # return arg(name,a,kw)[index]
  55. # return _
  56. else:
  57. if k.isdigit():
  58. return lambda *a, **kw: a[int(k)]
  59. return lambda *a, **kw: kw[k]
  60. args = [translator(k) for k,_1 in new_pattern.findall(text)]
  61. if args:
  62. if old_pattern.findall(text):
  63. raise Exception('mixed format is not allowed')
  64. f = new_pattern.sub('%s', text)
  65. def _(*a, **kw):
  66. return f % tuple([k(*a,**kw) for k in args])
  67. return _
  68. elif '%(' in text:
  69. return lambda *a, **kw: text % kw
  70. else:
  71. n = len(old_pattern.findall(text))
  72. return lambda *a, **kw: text % tuple(a[:n])
  73. if __name__ == '__main__':
  74. import doctest
  75. doctest.testmod()