Nav apraksta

schema_to_enums_v201.py 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/usr/bin/env python
  2. import json
  3. import re
  4. import sys
  5. from pathlib import Path
  6. enum_types = []
  7. enum_types_names = []
  8. def create_attribute(name):
  9. """
  10. Gets an attribute name from the enum and convert it to snake_case
  11. """
  12. # Removes any hyphens or dots from the name, substituting by an underscore
  13. name_normalized = re.sub("[.]", "", name)
  14. name_normalized = re.sub("[-]", "_", name_normalized)
  15. # The following substitution will add an underscore between
  16. # any character and a word starting with a capital letter, followed by
  17. # a lowercase letters. For example:
  18. # 1) "EVConnected" -> EV_Connected
  19. # 2) "SuspendedEVSE" -> SuspendedEVSE
  20. # 3) "CSMSRootCertificate" -> CSMS_RootCertificate
  21. # For names with numbers within, this conversion does not work so well
  22. # 4) "Other1PhMax16A" -> Other1_PhMax16A
  23. name_normalized = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name_normalized)
  24. # This one will add an underscore between a word ending with non-capital
  25. # letter and one starting with a capital. It will also lowercase it.
  26. # For example:
  27. # 1) "EV_Connected" -> ev_connected
  28. # 2) "SuspendedEVSE" -> suspended_evse
  29. # 3) "CSMS_RootCertificate" -> csms_root_certificate
  30. # 4) "Other1_PhMax16A" -> other1_ph_max16a (ideally should be
  31. # other_1ph_max_16a or similar.
  32. name_converted = re.sub("([a-z])([A-Z])", r"\1_\2", name_normalized).lower()
  33. return Attribute(name, name_converted)
  34. class NormalClass:
  35. def __init__(self, name):
  36. self.name = name
  37. self.attrs = []
  38. def add_attr(self, attr):
  39. self.attrs.append(attr)
  40. def __str__(self):
  41. output = f"class {self.name}(str, Enum):\n"
  42. if len(self.attrs) == 0:
  43. return output + " pass\n"
  44. for attr in self.attrs:
  45. output += str(attr)
  46. return output
  47. class Attribute:
  48. def __init__(self, name, name_converted):
  49. self.name = name
  50. self.name_converted = name_converted
  51. def __str__(self):
  52. name = self.name
  53. if not re.match("^[a-zA-Z_]", self.name):
  54. name = "_" + self.name
  55. # The 4 spaces after the start of the string is to guarantee the proper
  56. # indentation
  57. return f' {self.name_converted} = "{name}"\n'
  58. def __repr__(self):
  59. return f"<{self.name}, {self.name_converted}> "
  60. def parse_schema(schema):
  61. with open(schema, "r") as f:
  62. schema = json.loads(f.read())
  63. try:
  64. definitions = schema["definitions"]
  65. except KeyError:
  66. print("Error: No definitions field found on the schema")
  67. return
  68. for enum_type, value in definitions.items():
  69. if "Enum" in enum_type:
  70. type_name = enum_type.replace("Enum", "")
  71. if type_name not in enum_types_names:
  72. nc = NormalClass(type_name)
  73. for enum_attr in value["enum"]:
  74. attr = create_attribute(enum_attr)
  75. nc.add_attr(attr)
  76. enum_types.append(nc)
  77. enum_types_names.append(nc.name)
  78. if __name__ == "__main__":
  79. if len(sys.argv) != 2:
  80. print("Pass path to folder with schemas")
  81. sys.exit(-1)
  82. # The second argument of argv is the path for the schemas
  83. p = Path(sys.argv[1])
  84. schemas = list(p.glob("*.json"))
  85. # This loop will update the lists enum_types and enum_types_names:
  86. # The former contains the enum objects that are later parsed to the
  87. # enum.py, using the str representation. And the latter, is used to keep
  88. # track of the already processed Enums, avoiding data duplication
  89. for schema in schemas:
  90. parse_schema(schema)
  91. with open("enums.py", "wb+") as f:
  92. f.write(b"from enum import Enum\n")
  93. for enum_type_ in sorted(enum_types, key=lambda enum_type: enum_type.name):
  94. f.write(b"\n\n")
  95. f.write(str(enum_type_).encode("utf-8"))