appm 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (769) hide show
  1. appm/.mypy_cache/.gitignore +2 -0
  2. appm/.mypy_cache/3.10/@plugins_snapshot.json +1 -0
  3. appm/.mypy_cache/3.10/__future__.data.json +1 -0
  4. appm/.mypy_cache/3.10/__future__.meta.json +1 -0
  5. appm/.mypy_cache/3.10/_ast.data.json +1 -0
  6. appm/.mypy_cache/3.10/_ast.meta.json +1 -0
  7. appm/.mypy_cache/3.10/_bz2.data.json +1 -0
  8. appm/.mypy_cache/3.10/_bz2.meta.json +1 -0
  9. appm/.mypy_cache/3.10/_codecs.data.json +1 -0
  10. appm/.mypy_cache/3.10/_codecs.meta.json +1 -0
  11. appm/.mypy_cache/3.10/_collections_abc.data.json +1 -0
  12. appm/.mypy_cache/3.10/_collections_abc.meta.json +1 -0
  13. appm/.mypy_cache/3.10/_compression.data.json +1 -0
  14. appm/.mypy_cache/3.10/_compression.meta.json +1 -0
  15. appm/.mypy_cache/3.10/_contextvars.data.json +1 -0
  16. appm/.mypy_cache/3.10/_contextvars.meta.json +1 -0
  17. appm/.mypy_cache/3.10/_decimal.data.json +1 -0
  18. appm/.mypy_cache/3.10/_decimal.meta.json +1 -0
  19. appm/.mypy_cache/3.10/_frozen_importlib.data.json +1 -0
  20. appm/.mypy_cache/3.10/_frozen_importlib.meta.json +1 -0
  21. appm/.mypy_cache/3.10/_frozen_importlib_external.data.json +1 -0
  22. appm/.mypy_cache/3.10/_frozen_importlib_external.meta.json +1 -0
  23. appm/.mypy_cache/3.10/_io.data.json +1 -0
  24. appm/.mypy_cache/3.10/_io.meta.json +1 -0
  25. appm/.mypy_cache/3.10/_operator.data.json +1 -0
  26. appm/.mypy_cache/3.10/_operator.meta.json +1 -0
  27. appm/.mypy_cache/3.10/_pickle.data.json +1 -0
  28. appm/.mypy_cache/3.10/_pickle.meta.json +1 -0
  29. appm/.mypy_cache/3.10/_sitebuiltins.data.json +1 -0
  30. appm/.mypy_cache/3.10/_sitebuiltins.meta.json +1 -0
  31. appm/.mypy_cache/3.10/_typeshed/__init__.data.json +1 -0
  32. appm/.mypy_cache/3.10/_typeshed/__init__.meta.json +1 -0
  33. appm/.mypy_cache/3.10/_typeshed/importlib.data.json +1 -0
  34. appm/.mypy_cache/3.10/_typeshed/importlib.meta.json +1 -0
  35. appm/.mypy_cache/3.10/_warnings.data.json +1 -0
  36. appm/.mypy_cache/3.10/_warnings.meta.json +1 -0
  37. appm/.mypy_cache/3.10/_weakref.data.json +1 -0
  38. appm/.mypy_cache/3.10/_weakref.meta.json +1 -0
  39. appm/.mypy_cache/3.10/_weakrefset.data.json +1 -0
  40. appm/.mypy_cache/3.10/_weakrefset.meta.json +1 -0
  41. appm/.mypy_cache/3.10/abc.data.json +1 -0
  42. appm/.mypy_cache/3.10/abc.meta.json +1 -0
  43. appm/.mypy_cache/3.10/annotated_types/__init__.data.json +1 -0
  44. appm/.mypy_cache/3.10/annotated_types/__init__.meta.json +1 -0
  45. appm/.mypy_cache/3.10/appm/__version__.data.json +1 -0
  46. appm/.mypy_cache/3.10/appm/__version__.meta.json +1 -0
  47. appm/.mypy_cache/3.10/appm/exceptions.data.json +1 -0
  48. appm/.mypy_cache/3.10/appm/exceptions.meta.json +1 -0
  49. appm/.mypy_cache/3.10/appm/utils.data.json +1 -0
  50. appm/.mypy_cache/3.10/appm/utils.meta.json +1 -0
  51. appm/.mypy_cache/3.10/ast.data.json +1 -0
  52. appm/.mypy_cache/3.10/ast.meta.json +1 -0
  53. appm/.mypy_cache/3.10/base64.data.json +1 -0
  54. appm/.mypy_cache/3.10/base64.meta.json +1 -0
  55. appm/.mypy_cache/3.10/builtins.data.json +1 -0
  56. appm/.mypy_cache/3.10/builtins.meta.json +1 -0
  57. appm/.mypy_cache/3.10/bz2.data.json +1 -0
  58. appm/.mypy_cache/3.10/bz2.meta.json +1 -0
  59. appm/.mypy_cache/3.10/codecs.data.json +1 -0
  60. appm/.mypy_cache/3.10/codecs.meta.json +1 -0
  61. appm/.mypy_cache/3.10/collections/__init__.data.json +1 -0
  62. appm/.mypy_cache/3.10/collections/__init__.meta.json +1 -0
  63. appm/.mypy_cache/3.10/collections/abc.data.json +1 -0
  64. appm/.mypy_cache/3.10/collections/abc.meta.json +1 -0
  65. appm/.mypy_cache/3.10/colorsys.data.json +1 -0
  66. appm/.mypy_cache/3.10/colorsys.meta.json +1 -0
  67. appm/.mypy_cache/3.10/contextlib.data.json +1 -0
  68. appm/.mypy_cache/3.10/contextlib.meta.json +1 -0
  69. appm/.mypy_cache/3.10/contextvars.data.json +1 -0
  70. appm/.mypy_cache/3.10/contextvars.meta.json +1 -0
  71. appm/.mypy_cache/3.10/copy.data.json +1 -0
  72. appm/.mypy_cache/3.10/copy.meta.json +1 -0
  73. appm/.mypy_cache/3.10/dataclasses.data.json +1 -0
  74. appm/.mypy_cache/3.10/dataclasses.meta.json +1 -0
  75. appm/.mypy_cache/3.10/datetime.data.json +1 -0
  76. appm/.mypy_cache/3.10/datetime.meta.json +1 -0
  77. appm/.mypy_cache/3.10/decimal.data.json +1 -0
  78. appm/.mypy_cache/3.10/decimal.meta.json +1 -0
  79. appm/.mypy_cache/3.10/dis.data.json +1 -0
  80. appm/.mypy_cache/3.10/dis.meta.json +1 -0
  81. appm/.mypy_cache/3.10/email/__init__.data.json +1 -0
  82. appm/.mypy_cache/3.10/email/__init__.meta.json +1 -0
  83. appm/.mypy_cache/3.10/email/_policybase.data.json +1 -0
  84. appm/.mypy_cache/3.10/email/_policybase.meta.json +1 -0
  85. appm/.mypy_cache/3.10/email/charset.data.json +1 -0
  86. appm/.mypy_cache/3.10/email/charset.meta.json +1 -0
  87. appm/.mypy_cache/3.10/email/contentmanager.data.json +1 -0
  88. appm/.mypy_cache/3.10/email/contentmanager.meta.json +1 -0
  89. appm/.mypy_cache/3.10/email/errors.data.json +1 -0
  90. appm/.mypy_cache/3.10/email/errors.meta.json +1 -0
  91. appm/.mypy_cache/3.10/email/header.data.json +1 -0
  92. appm/.mypy_cache/3.10/email/header.meta.json +1 -0
  93. appm/.mypy_cache/3.10/email/message.data.json +1 -0
  94. appm/.mypy_cache/3.10/email/message.meta.json +1 -0
  95. appm/.mypy_cache/3.10/email/policy.data.json +1 -0
  96. appm/.mypy_cache/3.10/email/policy.meta.json +1 -0
  97. appm/.mypy_cache/3.10/enum.data.json +1 -0
  98. appm/.mypy_cache/3.10/enum.meta.json +1 -0
  99. appm/.mypy_cache/3.10/functools.data.json +1 -0
  100. appm/.mypy_cache/3.10/functools.meta.json +1 -0
  101. appm/.mypy_cache/3.10/genericpath.data.json +1 -0
  102. appm/.mypy_cache/3.10/genericpath.meta.json +1 -0
  103. appm/.mypy_cache/3.10/gzip.data.json +1 -0
  104. appm/.mypy_cache/3.10/gzip.meta.json +1 -0
  105. appm/.mypy_cache/3.10/importlib/__init__.data.json +1 -0
  106. appm/.mypy_cache/3.10/importlib/__init__.meta.json +1 -0
  107. appm/.mypy_cache/3.10/importlib/_abc.data.json +1 -0
  108. appm/.mypy_cache/3.10/importlib/_abc.meta.json +1 -0
  109. appm/.mypy_cache/3.10/importlib/_bootstrap.data.json +1 -0
  110. appm/.mypy_cache/3.10/importlib/_bootstrap.meta.json +1 -0
  111. appm/.mypy_cache/3.10/importlib/_bootstrap_external.data.json +1 -0
  112. appm/.mypy_cache/3.10/importlib/_bootstrap_external.meta.json +1 -0
  113. appm/.mypy_cache/3.10/importlib/abc.data.json +1 -0
  114. appm/.mypy_cache/3.10/importlib/abc.meta.json +1 -0
  115. appm/.mypy_cache/3.10/importlib/machinery.data.json +1 -0
  116. appm/.mypy_cache/3.10/importlib/machinery.meta.json +1 -0
  117. appm/.mypy_cache/3.10/importlib/metadata/__init__.data.json +1 -0
  118. appm/.mypy_cache/3.10/importlib/metadata/__init__.meta.json +1 -0
  119. appm/.mypy_cache/3.10/importlib/metadata/_meta.data.json +1 -0
  120. appm/.mypy_cache/3.10/importlib/metadata/_meta.meta.json +1 -0
  121. appm/.mypy_cache/3.10/importlib/readers.data.json +1 -0
  122. appm/.mypy_cache/3.10/importlib/readers.meta.json +1 -0
  123. appm/.mypy_cache/3.10/inspect.data.json +1 -0
  124. appm/.mypy_cache/3.10/inspect.meta.json +1 -0
  125. appm/.mypy_cache/3.10/io.data.json +1 -0
  126. appm/.mypy_cache/3.10/io.meta.json +1 -0
  127. appm/.mypy_cache/3.10/ipaddress.data.json +1 -0
  128. appm/.mypy_cache/3.10/ipaddress.meta.json +1 -0
  129. appm/.mypy_cache/3.10/itertools.data.json +1 -0
  130. appm/.mypy_cache/3.10/itertools.meta.json +1 -0
  131. appm/.mypy_cache/3.10/json/__init__.data.json +1 -0
  132. appm/.mypy_cache/3.10/json/__init__.meta.json +1 -0
  133. appm/.mypy_cache/3.10/json/decoder.data.json +1 -0
  134. appm/.mypy_cache/3.10/json/decoder.meta.json +1 -0
  135. appm/.mypy_cache/3.10/json/encoder.data.json +1 -0
  136. appm/.mypy_cache/3.10/json/encoder.meta.json +1 -0
  137. appm/.mypy_cache/3.10/keyword.data.json +1 -0
  138. appm/.mypy_cache/3.10/keyword.meta.json +1 -0
  139. appm/.mypy_cache/3.10/math.data.json +1 -0
  140. appm/.mypy_cache/3.10/math.meta.json +1 -0
  141. appm/.mypy_cache/3.10/numbers.data.json +1 -0
  142. appm/.mypy_cache/3.10/numbers.meta.json +1 -0
  143. appm/.mypy_cache/3.10/opcode.data.json +1 -0
  144. appm/.mypy_cache/3.10/opcode.meta.json +1 -0
  145. appm/.mypy_cache/3.10/operator.data.json +1 -0
  146. appm/.mypy_cache/3.10/operator.meta.json +1 -0
  147. appm/.mypy_cache/3.10/os/__init__.data.json +1 -0
  148. appm/.mypy_cache/3.10/os/__init__.meta.json +1 -0
  149. appm/.mypy_cache/3.10/os/path.data.json +1 -0
  150. appm/.mypy_cache/3.10/os/path.meta.json +1 -0
  151. appm/.mypy_cache/3.10/pathlib.data.json +1 -0
  152. appm/.mypy_cache/3.10/pathlib.meta.json +1 -0
  153. appm/.mypy_cache/3.10/pickle.data.json +1 -0
  154. appm/.mypy_cache/3.10/pickle.meta.json +1 -0
  155. appm/.mypy_cache/3.10/posixpath.data.json +1 -0
  156. appm/.mypy_cache/3.10/posixpath.meta.json +1 -0
  157. appm/.mypy_cache/3.10/pydantic/__init__.data.json +1 -0
  158. appm/.mypy_cache/3.10/pydantic/__init__.meta.json +1 -0
  159. appm/.mypy_cache/3.10/pydantic/_internal/__init__.data.json +1 -0
  160. appm/.mypy_cache/3.10/pydantic/_internal/__init__.meta.json +1 -0
  161. appm/.mypy_cache/3.10/pydantic/_internal/_config.data.json +1 -0
  162. appm/.mypy_cache/3.10/pydantic/_internal/_config.meta.json +1 -0
  163. appm/.mypy_cache/3.10/pydantic/_internal/_core_metadata.data.json +1 -0
  164. appm/.mypy_cache/3.10/pydantic/_internal/_core_metadata.meta.json +1 -0
  165. appm/.mypy_cache/3.10/pydantic/_internal/_core_utils.data.json +1 -0
  166. appm/.mypy_cache/3.10/pydantic/_internal/_core_utils.meta.json +1 -0
  167. appm/.mypy_cache/3.10/pydantic/_internal/_dataclasses.data.json +1 -0
  168. appm/.mypy_cache/3.10/pydantic/_internal/_dataclasses.meta.json +1 -0
  169. appm/.mypy_cache/3.10/pydantic/_internal/_decorators.data.json +1 -0
  170. appm/.mypy_cache/3.10/pydantic/_internal/_decorators.meta.json +1 -0
  171. appm/.mypy_cache/3.10/pydantic/_internal/_decorators_v1.data.json +1 -0
  172. appm/.mypy_cache/3.10/pydantic/_internal/_decorators_v1.meta.json +1 -0
  173. appm/.mypy_cache/3.10/pydantic/_internal/_discriminated_union.data.json +1 -0
  174. appm/.mypy_cache/3.10/pydantic/_internal/_discriminated_union.meta.json +1 -0
  175. appm/.mypy_cache/3.10/pydantic/_internal/_fields.data.json +1 -0
  176. appm/.mypy_cache/3.10/pydantic/_internal/_fields.meta.json +1 -0
  177. appm/.mypy_cache/3.10/pydantic/_internal/_forward_ref.data.json +1 -0
  178. appm/.mypy_cache/3.10/pydantic/_internal/_forward_ref.meta.json +1 -0
  179. appm/.mypy_cache/3.10/pydantic/_internal/_generate_schema.data.json +1 -0
  180. appm/.mypy_cache/3.10/pydantic/_internal/_generate_schema.meta.json +1 -0
  181. appm/.mypy_cache/3.10/pydantic/_internal/_generics.data.json +1 -0
  182. appm/.mypy_cache/3.10/pydantic/_internal/_generics.meta.json +1 -0
  183. appm/.mypy_cache/3.10/pydantic/_internal/_internal_dataclass.data.json +1 -0
  184. appm/.mypy_cache/3.10/pydantic/_internal/_internal_dataclass.meta.json +1 -0
  185. appm/.mypy_cache/3.10/pydantic/_internal/_known_annotated_metadata.data.json +1 -0
  186. appm/.mypy_cache/3.10/pydantic/_internal/_known_annotated_metadata.meta.json +1 -0
  187. appm/.mypy_cache/3.10/pydantic/_internal/_mock_val_ser.data.json +1 -0
  188. appm/.mypy_cache/3.10/pydantic/_internal/_mock_val_ser.meta.json +1 -0
  189. appm/.mypy_cache/3.10/pydantic/_internal/_model_construction.data.json +1 -0
  190. appm/.mypy_cache/3.10/pydantic/_internal/_model_construction.meta.json +1 -0
  191. appm/.mypy_cache/3.10/pydantic/_internal/_repr.data.json +1 -0
  192. appm/.mypy_cache/3.10/pydantic/_internal/_repr.meta.json +1 -0
  193. appm/.mypy_cache/3.10/pydantic/_internal/_schema_generation_shared.data.json +1 -0
  194. appm/.mypy_cache/3.10/pydantic/_internal/_schema_generation_shared.meta.json +1 -0
  195. appm/.mypy_cache/3.10/pydantic/_internal/_std_types_schema.data.json +1 -0
  196. appm/.mypy_cache/3.10/pydantic/_internal/_std_types_schema.meta.json +1 -0
  197. appm/.mypy_cache/3.10/pydantic/_internal/_typing_extra.data.json +1 -0
  198. appm/.mypy_cache/3.10/pydantic/_internal/_typing_extra.meta.json +1 -0
  199. appm/.mypy_cache/3.10/pydantic/_internal/_utils.data.json +1 -0
  200. appm/.mypy_cache/3.10/pydantic/_internal/_utils.meta.json +1 -0
  201. appm/.mypy_cache/3.10/pydantic/_internal/_validate_call.data.json +1 -0
  202. appm/.mypy_cache/3.10/pydantic/_internal/_validate_call.meta.json +1 -0
  203. appm/.mypy_cache/3.10/pydantic/_internal/_validators.data.json +1 -0
  204. appm/.mypy_cache/3.10/pydantic/_internal/_validators.meta.json +1 -0
  205. appm/.mypy_cache/3.10/pydantic/_migration.data.json +1 -0
  206. appm/.mypy_cache/3.10/pydantic/_migration.meta.json +1 -0
  207. appm/.mypy_cache/3.10/pydantic/annotated_handlers.data.json +1 -0
  208. appm/.mypy_cache/3.10/pydantic/annotated_handlers.meta.json +1 -0
  209. appm/.mypy_cache/3.10/pydantic/color.data.json +1 -0
  210. appm/.mypy_cache/3.10/pydantic/color.meta.json +1 -0
  211. appm/.mypy_cache/3.10/pydantic/config.data.json +1 -0
  212. appm/.mypy_cache/3.10/pydantic/config.meta.json +1 -0
  213. appm/.mypy_cache/3.10/pydantic/dataclasses.data.json +1 -0
  214. appm/.mypy_cache/3.10/pydantic/dataclasses.meta.json +1 -0
  215. appm/.mypy_cache/3.10/pydantic/deprecated/__init__.data.json +1 -0
  216. appm/.mypy_cache/3.10/pydantic/deprecated/__init__.meta.json +1 -0
  217. appm/.mypy_cache/3.10/pydantic/deprecated/class_validators.data.json +1 -0
  218. appm/.mypy_cache/3.10/pydantic/deprecated/class_validators.meta.json +1 -0
  219. appm/.mypy_cache/3.10/pydantic/deprecated/config.data.json +1 -0
  220. appm/.mypy_cache/3.10/pydantic/deprecated/config.meta.json +1 -0
  221. appm/.mypy_cache/3.10/pydantic/deprecated/copy_internals.data.json +1 -0
  222. appm/.mypy_cache/3.10/pydantic/deprecated/copy_internals.meta.json +1 -0
  223. appm/.mypy_cache/3.10/pydantic/deprecated/json.data.json +1 -0
  224. appm/.mypy_cache/3.10/pydantic/deprecated/json.meta.json +1 -0
  225. appm/.mypy_cache/3.10/pydantic/deprecated/parse.data.json +1 -0
  226. appm/.mypy_cache/3.10/pydantic/deprecated/parse.meta.json +1 -0
  227. appm/.mypy_cache/3.10/pydantic/deprecated/tools.data.json +1 -0
  228. appm/.mypy_cache/3.10/pydantic/deprecated/tools.meta.json +1 -0
  229. appm/.mypy_cache/3.10/pydantic/errors.data.json +1 -0
  230. appm/.mypy_cache/3.10/pydantic/errors.meta.json +1 -0
  231. appm/.mypy_cache/3.10/pydantic/fields.data.json +1 -0
  232. appm/.mypy_cache/3.10/pydantic/fields.meta.json +1 -0
  233. appm/.mypy_cache/3.10/pydantic/functional_serializers.data.json +1 -0
  234. appm/.mypy_cache/3.10/pydantic/functional_serializers.meta.json +1 -0
  235. appm/.mypy_cache/3.10/pydantic/functional_validators.data.json +1 -0
  236. appm/.mypy_cache/3.10/pydantic/functional_validators.meta.json +1 -0
  237. appm/.mypy_cache/3.10/pydantic/json_schema.data.json +1 -0
  238. appm/.mypy_cache/3.10/pydantic/json_schema.meta.json +1 -0
  239. appm/.mypy_cache/3.10/pydantic/main.data.json +1 -0
  240. appm/.mypy_cache/3.10/pydantic/main.meta.json +1 -0
  241. appm/.mypy_cache/3.10/pydantic/networks.data.json +1 -0
  242. appm/.mypy_cache/3.10/pydantic/networks.meta.json +1 -0
  243. appm/.mypy_cache/3.10/pydantic/plugin/__init__.data.json +1 -0
  244. appm/.mypy_cache/3.10/pydantic/plugin/__init__.meta.json +1 -0
  245. appm/.mypy_cache/3.10/pydantic/plugin/_schema_validator.data.json +1 -0
  246. appm/.mypy_cache/3.10/pydantic/plugin/_schema_validator.meta.json +1 -0
  247. appm/.mypy_cache/3.10/pydantic/root_model.data.json +1 -0
  248. appm/.mypy_cache/3.10/pydantic/root_model.meta.json +1 -0
  249. appm/.mypy_cache/3.10/pydantic/type_adapter.data.json +1 -0
  250. appm/.mypy_cache/3.10/pydantic/type_adapter.meta.json +1 -0
  251. appm/.mypy_cache/3.10/pydantic/types.data.json +1 -0
  252. appm/.mypy_cache/3.10/pydantic/types.meta.json +1 -0
  253. appm/.mypy_cache/3.10/pydantic/validate_call.data.json +1 -0
  254. appm/.mypy_cache/3.10/pydantic/validate_call.meta.json +1 -0
  255. appm/.mypy_cache/3.10/pydantic/validators.data.json +1 -0
  256. appm/.mypy_cache/3.10/pydantic/validators.meta.json +1 -0
  257. appm/.mypy_cache/3.10/pydantic/version.data.json +1 -0
  258. appm/.mypy_cache/3.10/pydantic/version.meta.json +1 -0
  259. appm/.mypy_cache/3.10/pydantic/warnings.data.json +1 -0
  260. appm/.mypy_cache/3.10/pydantic/warnings.meta.json +1 -0
  261. appm/.mypy_cache/3.10/pydantic_core/__init__.data.json +1 -0
  262. appm/.mypy_cache/3.10/pydantic_core/__init__.meta.json +1 -0
  263. appm/.mypy_cache/3.10/pydantic_core/_pydantic_core.data.json +1 -0
  264. appm/.mypy_cache/3.10/pydantic_core/_pydantic_core.meta.json +1 -0
  265. appm/.mypy_cache/3.10/pydantic_core/core_schema.data.json +1 -0
  266. appm/.mypy_cache/3.10/pydantic_core/core_schema.meta.json +1 -0
  267. appm/.mypy_cache/3.10/re.data.json +1 -0
  268. appm/.mypy_cache/3.10/re.meta.json +1 -0
  269. appm/.mypy_cache/3.10/resource.data.json +1 -0
  270. appm/.mypy_cache/3.10/resource.meta.json +1 -0
  271. appm/.mypy_cache/3.10/shutil.data.json +1 -0
  272. appm/.mypy_cache/3.10/shutil.meta.json +1 -0
  273. appm/.mypy_cache/3.10/sre_compile.data.json +1 -0
  274. appm/.mypy_cache/3.10/sre_compile.meta.json +1 -0
  275. appm/.mypy_cache/3.10/sre_constants.data.json +1 -0
  276. appm/.mypy_cache/3.10/sre_constants.meta.json +1 -0
  277. appm/.mypy_cache/3.10/sre_parse.data.json +1 -0
  278. appm/.mypy_cache/3.10/sre_parse.meta.json +1 -0
  279. appm/.mypy_cache/3.10/subprocess.data.json +1 -0
  280. appm/.mypy_cache/3.10/subprocess.meta.json +1 -0
  281. appm/.mypy_cache/3.10/sys/__init__.data.json +1 -0
  282. appm/.mypy_cache/3.10/sys/__init__.meta.json +1 -0
  283. appm/.mypy_cache/3.10/tarfile.data.json +1 -0
  284. appm/.mypy_cache/3.10/tarfile.meta.json +1 -0
  285. appm/.mypy_cache/3.10/time.data.json +1 -0
  286. appm/.mypy_cache/3.10/time.meta.json +1 -0
  287. appm/.mypy_cache/3.10/types.data.json +1 -0
  288. appm/.mypy_cache/3.10/types.meta.json +1 -0
  289. appm/.mypy_cache/3.10/typing.data.json +1 -0
  290. appm/.mypy_cache/3.10/typing.meta.json +1 -0
  291. appm/.mypy_cache/3.10/typing_extensions.data.json +1 -0
  292. appm/.mypy_cache/3.10/typing_extensions.meta.json +1 -0
  293. appm/.mypy_cache/3.10/uuid.data.json +1 -0
  294. appm/.mypy_cache/3.10/uuid.meta.json +1 -0
  295. appm/.mypy_cache/3.10/warnings.data.json +1 -0
  296. appm/.mypy_cache/3.10/warnings.meta.json +1 -0
  297. appm/.mypy_cache/3.10/weakref.data.json +1 -0
  298. appm/.mypy_cache/3.10/weakref.meta.json +1 -0
  299. appm/.mypy_cache/3.10/zipfile/__init__.data.json +1 -0
  300. appm/.mypy_cache/3.10/zipfile/__init__.meta.json +1 -0
  301. appm/.mypy_cache/3.10/zlib.data.json +1 -0
  302. appm/.mypy_cache/3.10/zlib.meta.json +1 -0
  303. appm/.mypy_cache/3.13/@plugins_snapshot.json +1 -0
  304. appm/.mypy_cache/3.13/__future__.data.json +1 -0
  305. appm/.mypy_cache/3.13/__future__.meta.json +1 -0
  306. appm/.mypy_cache/3.13/_ast.data.json +1 -0
  307. appm/.mypy_cache/3.13/_ast.meta.json +1 -0
  308. appm/.mypy_cache/3.13/_bz2.data.json +1 -0
  309. appm/.mypy_cache/3.13/_bz2.meta.json +1 -0
  310. appm/.mypy_cache/3.13/_codecs.data.json +1 -0
  311. appm/.mypy_cache/3.13/_codecs.meta.json +1 -0
  312. appm/.mypy_cache/3.13/_collections_abc.data.json +1 -0
  313. appm/.mypy_cache/3.13/_collections_abc.meta.json +1 -0
  314. appm/.mypy_cache/3.13/_compression.data.json +1 -0
  315. appm/.mypy_cache/3.13/_compression.meta.json +1 -0
  316. appm/.mypy_cache/3.13/_contextvars.data.json +1 -0
  317. appm/.mypy_cache/3.13/_contextvars.meta.json +1 -0
  318. appm/.mypy_cache/3.13/_decimal.data.json +1 -0
  319. appm/.mypy_cache/3.13/_decimal.meta.json +1 -0
  320. appm/.mypy_cache/3.13/_frozen_importlib.data.json +1 -0
  321. appm/.mypy_cache/3.13/_frozen_importlib.meta.json +1 -0
  322. appm/.mypy_cache/3.13/_frozen_importlib_external.data.json +1 -0
  323. appm/.mypy_cache/3.13/_frozen_importlib_external.meta.json +1 -0
  324. appm/.mypy_cache/3.13/_io.data.json +1 -0
  325. appm/.mypy_cache/3.13/_io.meta.json +1 -0
  326. appm/.mypy_cache/3.13/_operator.data.json +1 -0
  327. appm/.mypy_cache/3.13/_operator.meta.json +1 -0
  328. appm/.mypy_cache/3.13/_pickle.data.json +1 -0
  329. appm/.mypy_cache/3.13/_pickle.meta.json +1 -0
  330. appm/.mypy_cache/3.13/_sitebuiltins.data.json +1 -0
  331. appm/.mypy_cache/3.13/_sitebuiltins.meta.json +1 -0
  332. appm/.mypy_cache/3.13/_typeshed/__init__.data.json +1 -0
  333. appm/.mypy_cache/3.13/_typeshed/__init__.meta.json +1 -0
  334. appm/.mypy_cache/3.13/_typeshed/importlib.data.json +1 -0
  335. appm/.mypy_cache/3.13/_typeshed/importlib.meta.json +1 -0
  336. appm/.mypy_cache/3.13/_warnings.data.json +1 -0
  337. appm/.mypy_cache/3.13/_warnings.meta.json +1 -0
  338. appm/.mypy_cache/3.13/_weakref.data.json +1 -0
  339. appm/.mypy_cache/3.13/_weakref.meta.json +1 -0
  340. appm/.mypy_cache/3.13/_weakrefset.data.json +1 -0
  341. appm/.mypy_cache/3.13/_weakrefset.meta.json +1 -0
  342. appm/.mypy_cache/3.13/abc.data.json +1 -0
  343. appm/.mypy_cache/3.13/abc.meta.json +1 -0
  344. appm/.mypy_cache/3.13/annotated_types/__init__.data.json +1 -0
  345. appm/.mypy_cache/3.13/annotated_types/__init__.meta.json +1 -0
  346. appm/.mypy_cache/3.13/appm/__version__.data.json +1 -0
  347. appm/.mypy_cache/3.13/appm/__version__.meta.json +1 -0
  348. appm/.mypy_cache/3.13/appm/default.data.json +1 -0
  349. appm/.mypy_cache/3.13/appm/default.meta.json +1 -0
  350. appm/.mypy_cache/3.13/appm/exceptions.data.json +1 -0
  351. appm/.mypy_cache/3.13/appm/exceptions.meta.json +1 -0
  352. appm/.mypy_cache/3.13/appm/utils.data.json +1 -0
  353. appm/.mypy_cache/3.13/appm/utils.meta.json +1 -0
  354. appm/.mypy_cache/3.13/ast.data.json +1 -0
  355. appm/.mypy_cache/3.13/ast.meta.json +1 -0
  356. appm/.mypy_cache/3.13/base64.data.json +1 -0
  357. appm/.mypy_cache/3.13/base64.meta.json +1 -0
  358. appm/.mypy_cache/3.13/binascii.data.json +1 -0
  359. appm/.mypy_cache/3.13/binascii.meta.json +1 -0
  360. appm/.mypy_cache/3.13/builtins.data.json +1 -0
  361. appm/.mypy_cache/3.13/builtins.meta.json +1 -0
  362. appm/.mypy_cache/3.13/bz2.data.json +1 -0
  363. appm/.mypy_cache/3.13/bz2.meta.json +1 -0
  364. appm/.mypy_cache/3.13/codecs.data.json +1 -0
  365. appm/.mypy_cache/3.13/codecs.meta.json +1 -0
  366. appm/.mypy_cache/3.13/collections/__init__.data.json +1 -0
  367. appm/.mypy_cache/3.13/collections/__init__.meta.json +1 -0
  368. appm/.mypy_cache/3.13/collections/abc.data.json +1 -0
  369. appm/.mypy_cache/3.13/collections/abc.meta.json +1 -0
  370. appm/.mypy_cache/3.13/colorsys.data.json +1 -0
  371. appm/.mypy_cache/3.13/colorsys.meta.json +1 -0
  372. appm/.mypy_cache/3.13/contextlib.data.json +1 -0
  373. appm/.mypy_cache/3.13/contextlib.meta.json +1 -0
  374. appm/.mypy_cache/3.13/contextvars.data.json +1 -0
  375. appm/.mypy_cache/3.13/contextvars.meta.json +1 -0
  376. appm/.mypy_cache/3.13/copy.data.json +1 -0
  377. appm/.mypy_cache/3.13/copy.meta.json +1 -0
  378. appm/.mypy_cache/3.13/copyreg.data.json +1 -0
  379. appm/.mypy_cache/3.13/copyreg.meta.json +1 -0
  380. appm/.mypy_cache/3.13/dataclasses.data.json +1 -0
  381. appm/.mypy_cache/3.13/dataclasses.meta.json +1 -0
  382. appm/.mypy_cache/3.13/datetime.data.json +1 -0
  383. appm/.mypy_cache/3.13/datetime.meta.json +1 -0
  384. appm/.mypy_cache/3.13/decimal.data.json +1 -0
  385. appm/.mypy_cache/3.13/decimal.meta.json +1 -0
  386. appm/.mypy_cache/3.13/dis.data.json +1 -0
  387. appm/.mypy_cache/3.13/dis.meta.json +1 -0
  388. appm/.mypy_cache/3.13/email/__init__.data.json +1 -0
  389. appm/.mypy_cache/3.13/email/__init__.meta.json +1 -0
  390. appm/.mypy_cache/3.13/email/_policybase.data.json +1 -0
  391. appm/.mypy_cache/3.13/email/_policybase.meta.json +1 -0
  392. appm/.mypy_cache/3.13/email/charset.data.json +1 -0
  393. appm/.mypy_cache/3.13/email/charset.meta.json +1 -0
  394. appm/.mypy_cache/3.13/email/contentmanager.data.json +1 -0
  395. appm/.mypy_cache/3.13/email/contentmanager.meta.json +1 -0
  396. appm/.mypy_cache/3.13/email/errors.data.json +1 -0
  397. appm/.mypy_cache/3.13/email/errors.meta.json +1 -0
  398. appm/.mypy_cache/3.13/email/header.data.json +1 -0
  399. appm/.mypy_cache/3.13/email/header.meta.json +1 -0
  400. appm/.mypy_cache/3.13/email/message.data.json +1 -0
  401. appm/.mypy_cache/3.13/email/message.meta.json +1 -0
  402. appm/.mypy_cache/3.13/email/policy.data.json +1 -0
  403. appm/.mypy_cache/3.13/email/policy.meta.json +1 -0
  404. appm/.mypy_cache/3.13/enum.data.json +1 -0
  405. appm/.mypy_cache/3.13/enum.meta.json +1 -0
  406. appm/.mypy_cache/3.13/fractions.data.json +1 -0
  407. appm/.mypy_cache/3.13/fractions.meta.json +1 -0
  408. appm/.mypy_cache/3.13/functools.data.json +1 -0
  409. appm/.mypy_cache/3.13/functools.meta.json +1 -0
  410. appm/.mypy_cache/3.13/genericpath.data.json +1 -0
  411. appm/.mypy_cache/3.13/genericpath.meta.json +1 -0
  412. appm/.mypy_cache/3.13/glob.data.json +1 -0
  413. appm/.mypy_cache/3.13/glob.meta.json +1 -0
  414. appm/.mypy_cache/3.13/gzip.data.json +1 -0
  415. appm/.mypy_cache/3.13/gzip.meta.json +1 -0
  416. appm/.mypy_cache/3.13/importlib/__init__.data.json +1 -0
  417. appm/.mypy_cache/3.13/importlib/__init__.meta.json +1 -0
  418. appm/.mypy_cache/3.13/importlib/_abc.data.json +1 -0
  419. appm/.mypy_cache/3.13/importlib/_abc.meta.json +1 -0
  420. appm/.mypy_cache/3.13/importlib/_bootstrap.data.json +1 -0
  421. appm/.mypy_cache/3.13/importlib/_bootstrap.meta.json +1 -0
  422. appm/.mypy_cache/3.13/importlib/_bootstrap_external.data.json +1 -0
  423. appm/.mypy_cache/3.13/importlib/_bootstrap_external.meta.json +1 -0
  424. appm/.mypy_cache/3.13/importlib/abc.data.json +1 -0
  425. appm/.mypy_cache/3.13/importlib/abc.meta.json +1 -0
  426. appm/.mypy_cache/3.13/importlib/machinery.data.json +1 -0
  427. appm/.mypy_cache/3.13/importlib/machinery.meta.json +1 -0
  428. appm/.mypy_cache/3.13/importlib/metadata/__init__.data.json +1 -0
  429. appm/.mypy_cache/3.13/importlib/metadata/__init__.meta.json +1 -0
  430. appm/.mypy_cache/3.13/importlib/metadata/_meta.data.json +1 -0
  431. appm/.mypy_cache/3.13/importlib/metadata/_meta.meta.json +1 -0
  432. appm/.mypy_cache/3.13/importlib/readers.data.json +1 -0
  433. appm/.mypy_cache/3.13/importlib/readers.meta.json +1 -0
  434. appm/.mypy_cache/3.13/importlib/resources/__init__.data.json +1 -0
  435. appm/.mypy_cache/3.13/importlib/resources/__init__.meta.json +1 -0
  436. appm/.mypy_cache/3.13/importlib/resources/_common.data.json +1 -0
  437. appm/.mypy_cache/3.13/importlib/resources/_common.meta.json +1 -0
  438. appm/.mypy_cache/3.13/importlib/resources/_functional.data.json +1 -0
  439. appm/.mypy_cache/3.13/importlib/resources/_functional.meta.json +1 -0
  440. appm/.mypy_cache/3.13/importlib/resources/abc.data.json +1 -0
  441. appm/.mypy_cache/3.13/importlib/resources/abc.meta.json +1 -0
  442. appm/.mypy_cache/3.13/inspect.data.json +1 -0
  443. appm/.mypy_cache/3.13/inspect.meta.json +1 -0
  444. appm/.mypy_cache/3.13/io.data.json +1 -0
  445. appm/.mypy_cache/3.13/io.meta.json +1 -0
  446. appm/.mypy_cache/3.13/ipaddress.data.json +1 -0
  447. appm/.mypy_cache/3.13/ipaddress.meta.json +1 -0
  448. appm/.mypy_cache/3.13/itertools.data.json +1 -0
  449. appm/.mypy_cache/3.13/itertools.meta.json +1 -0
  450. appm/.mypy_cache/3.13/json/__init__.data.json +1 -0
  451. appm/.mypy_cache/3.13/json/__init__.meta.json +1 -0
  452. appm/.mypy_cache/3.13/json/decoder.data.json +1 -0
  453. appm/.mypy_cache/3.13/json/decoder.meta.json +1 -0
  454. appm/.mypy_cache/3.13/json/encoder.data.json +1 -0
  455. appm/.mypy_cache/3.13/json/encoder.meta.json +1 -0
  456. appm/.mypy_cache/3.13/keyword.data.json +1 -0
  457. appm/.mypy_cache/3.13/keyword.meta.json +1 -0
  458. appm/.mypy_cache/3.13/math.data.json +1 -0
  459. appm/.mypy_cache/3.13/math.meta.json +1 -0
  460. appm/.mypy_cache/3.13/numbers.data.json +1 -0
  461. appm/.mypy_cache/3.13/numbers.meta.json +1 -0
  462. appm/.mypy_cache/3.13/opcode.data.json +1 -0
  463. appm/.mypy_cache/3.13/opcode.meta.json +1 -0
  464. appm/.mypy_cache/3.13/operator.data.json +1 -0
  465. appm/.mypy_cache/3.13/operator.meta.json +1 -0
  466. appm/.mypy_cache/3.13/os/__init__.data.json +1 -0
  467. appm/.mypy_cache/3.13/os/__init__.meta.json +1 -0
  468. appm/.mypy_cache/3.13/os/path.data.json +1 -0
  469. appm/.mypy_cache/3.13/os/path.meta.json +1 -0
  470. appm/.mypy_cache/3.13/pathlib.data.json +1 -0
  471. appm/.mypy_cache/3.13/pathlib.meta.json +1 -0
  472. appm/.mypy_cache/3.13/pickle.data.json +1 -0
  473. appm/.mypy_cache/3.13/pickle.meta.json +1 -0
  474. appm/.mypy_cache/3.13/posixpath.data.json +1 -0
  475. appm/.mypy_cache/3.13/posixpath.meta.json +1 -0
  476. appm/.mypy_cache/3.13/pydantic/__init__.data.json +1 -0
  477. appm/.mypy_cache/3.13/pydantic/__init__.meta.json +1 -0
  478. appm/.mypy_cache/3.13/pydantic/_internal/__init__.data.json +1 -0
  479. appm/.mypy_cache/3.13/pydantic/_internal/__init__.meta.json +1 -0
  480. appm/.mypy_cache/3.13/pydantic/_internal/_config.data.json +1 -0
  481. appm/.mypy_cache/3.13/pydantic/_internal/_config.meta.json +1 -0
  482. appm/.mypy_cache/3.13/pydantic/_internal/_core_metadata.data.json +1 -0
  483. appm/.mypy_cache/3.13/pydantic/_internal/_core_metadata.meta.json +1 -0
  484. appm/.mypy_cache/3.13/pydantic/_internal/_core_utils.data.json +1 -0
  485. appm/.mypy_cache/3.13/pydantic/_internal/_core_utils.meta.json +1 -0
  486. appm/.mypy_cache/3.13/pydantic/_internal/_dataclasses.data.json +1 -0
  487. appm/.mypy_cache/3.13/pydantic/_internal/_dataclasses.meta.json +1 -0
  488. appm/.mypy_cache/3.13/pydantic/_internal/_decorators.data.json +1 -0
  489. appm/.mypy_cache/3.13/pydantic/_internal/_decorators.meta.json +1 -0
  490. appm/.mypy_cache/3.13/pydantic/_internal/_decorators_v1.data.json +1 -0
  491. appm/.mypy_cache/3.13/pydantic/_internal/_decorators_v1.meta.json +1 -0
  492. appm/.mypy_cache/3.13/pydantic/_internal/_discriminated_union.data.json +1 -0
  493. appm/.mypy_cache/3.13/pydantic/_internal/_discriminated_union.meta.json +1 -0
  494. appm/.mypy_cache/3.13/pydantic/_internal/_docs_extraction.data.json +1 -0
  495. appm/.mypy_cache/3.13/pydantic/_internal/_docs_extraction.meta.json +1 -0
  496. appm/.mypy_cache/3.13/pydantic/_internal/_fields.data.json +1 -0
  497. appm/.mypy_cache/3.13/pydantic/_internal/_fields.meta.json +1 -0
  498. appm/.mypy_cache/3.13/pydantic/_internal/_forward_ref.data.json +1 -0
  499. appm/.mypy_cache/3.13/pydantic/_internal/_forward_ref.meta.json +1 -0
  500. appm/.mypy_cache/3.13/pydantic/_internal/_generate_schema.data.json +1 -0
  501. appm/.mypy_cache/3.13/pydantic/_internal/_generate_schema.meta.json +1 -0
  502. appm/.mypy_cache/3.13/pydantic/_internal/_generics.data.json +1 -0
  503. appm/.mypy_cache/3.13/pydantic/_internal/_generics.meta.json +1 -0
  504. appm/.mypy_cache/3.13/pydantic/_internal/_import_utils.data.json +1 -0
  505. appm/.mypy_cache/3.13/pydantic/_internal/_import_utils.meta.json +1 -0
  506. appm/.mypy_cache/3.13/pydantic/_internal/_internal_dataclass.data.json +1 -0
  507. appm/.mypy_cache/3.13/pydantic/_internal/_internal_dataclass.meta.json +1 -0
  508. appm/.mypy_cache/3.13/pydantic/_internal/_known_annotated_metadata.data.json +1 -0
  509. appm/.mypy_cache/3.13/pydantic/_internal/_known_annotated_metadata.meta.json +1 -0
  510. appm/.mypy_cache/3.13/pydantic/_internal/_mock_val_ser.data.json +1 -0
  511. appm/.mypy_cache/3.13/pydantic/_internal/_mock_val_ser.meta.json +1 -0
  512. appm/.mypy_cache/3.13/pydantic/_internal/_model_construction.data.json +1 -0
  513. appm/.mypy_cache/3.13/pydantic/_internal/_model_construction.meta.json +1 -0
  514. appm/.mypy_cache/3.13/pydantic/_internal/_namespace_utils.data.json +1 -0
  515. appm/.mypy_cache/3.13/pydantic/_internal/_namespace_utils.meta.json +1 -0
  516. appm/.mypy_cache/3.13/pydantic/_internal/_repr.data.json +1 -0
  517. appm/.mypy_cache/3.13/pydantic/_internal/_repr.meta.json +1 -0
  518. appm/.mypy_cache/3.13/pydantic/_internal/_schema_gather.data.json +1 -0
  519. appm/.mypy_cache/3.13/pydantic/_internal/_schema_gather.meta.json +1 -0
  520. appm/.mypy_cache/3.13/pydantic/_internal/_schema_generation_shared.data.json +1 -0
  521. appm/.mypy_cache/3.13/pydantic/_internal/_schema_generation_shared.meta.json +1 -0
  522. appm/.mypy_cache/3.13/pydantic/_internal/_serializers.data.json +1 -0
  523. appm/.mypy_cache/3.13/pydantic/_internal/_serializers.meta.json +1 -0
  524. appm/.mypy_cache/3.13/pydantic/_internal/_signature.data.json +1 -0
  525. appm/.mypy_cache/3.13/pydantic/_internal/_signature.meta.json +1 -0
  526. appm/.mypy_cache/3.13/pydantic/_internal/_typing_extra.data.json +1 -0
  527. appm/.mypy_cache/3.13/pydantic/_internal/_typing_extra.meta.json +1 -0
  528. appm/.mypy_cache/3.13/pydantic/_internal/_utils.data.json +1 -0
  529. appm/.mypy_cache/3.13/pydantic/_internal/_utils.meta.json +1 -0
  530. appm/.mypy_cache/3.13/pydantic/_internal/_validate_call.data.json +1 -0
  531. appm/.mypy_cache/3.13/pydantic/_internal/_validate_call.meta.json +1 -0
  532. appm/.mypy_cache/3.13/pydantic/_internal/_validators.data.json +1 -0
  533. appm/.mypy_cache/3.13/pydantic/_internal/_validators.meta.json +1 -0
  534. appm/.mypy_cache/3.13/pydantic/_migration.data.json +1 -0
  535. appm/.mypy_cache/3.13/pydantic/_migration.meta.json +1 -0
  536. appm/.mypy_cache/3.13/pydantic/aliases.data.json +1 -0
  537. appm/.mypy_cache/3.13/pydantic/aliases.meta.json +1 -0
  538. appm/.mypy_cache/3.13/pydantic/annotated_handlers.data.json +1 -0
  539. appm/.mypy_cache/3.13/pydantic/annotated_handlers.meta.json +1 -0
  540. appm/.mypy_cache/3.13/pydantic/color.data.json +1 -0
  541. appm/.mypy_cache/3.13/pydantic/color.meta.json +1 -0
  542. appm/.mypy_cache/3.13/pydantic/config.data.json +1 -0
  543. appm/.mypy_cache/3.13/pydantic/config.meta.json +1 -0
  544. appm/.mypy_cache/3.13/pydantic/dataclasses.data.json +1 -0
  545. appm/.mypy_cache/3.13/pydantic/dataclasses.meta.json +1 -0
  546. appm/.mypy_cache/3.13/pydantic/deprecated/__init__.data.json +1 -0
  547. appm/.mypy_cache/3.13/pydantic/deprecated/__init__.meta.json +1 -0
  548. appm/.mypy_cache/3.13/pydantic/deprecated/class_validators.data.json +1 -0
  549. appm/.mypy_cache/3.13/pydantic/deprecated/class_validators.meta.json +1 -0
  550. appm/.mypy_cache/3.13/pydantic/deprecated/config.data.json +1 -0
  551. appm/.mypy_cache/3.13/pydantic/deprecated/config.meta.json +1 -0
  552. appm/.mypy_cache/3.13/pydantic/deprecated/copy_internals.data.json +1 -0
  553. appm/.mypy_cache/3.13/pydantic/deprecated/copy_internals.meta.json +1 -0
  554. appm/.mypy_cache/3.13/pydantic/deprecated/json.data.json +1 -0
  555. appm/.mypy_cache/3.13/pydantic/deprecated/json.meta.json +1 -0
  556. appm/.mypy_cache/3.13/pydantic/deprecated/parse.data.json +1 -0
  557. appm/.mypy_cache/3.13/pydantic/deprecated/parse.meta.json +1 -0
  558. appm/.mypy_cache/3.13/pydantic/deprecated/tools.data.json +1 -0
  559. appm/.mypy_cache/3.13/pydantic/deprecated/tools.meta.json +1 -0
  560. appm/.mypy_cache/3.13/pydantic/errors.data.json +1 -0
  561. appm/.mypy_cache/3.13/pydantic/errors.meta.json +1 -0
  562. appm/.mypy_cache/3.13/pydantic/fields.data.json +1 -0
  563. appm/.mypy_cache/3.13/pydantic/fields.meta.json +1 -0
  564. appm/.mypy_cache/3.13/pydantic/functional_serializers.data.json +1 -0
  565. appm/.mypy_cache/3.13/pydantic/functional_serializers.meta.json +1 -0
  566. appm/.mypy_cache/3.13/pydantic/functional_validators.data.json +1 -0
  567. appm/.mypy_cache/3.13/pydantic/functional_validators.meta.json +1 -0
  568. appm/.mypy_cache/3.13/pydantic/json_schema.data.json +1 -0
  569. appm/.mypy_cache/3.13/pydantic/json_schema.meta.json +1 -0
  570. appm/.mypy_cache/3.13/pydantic/main.data.json +1 -0
  571. appm/.mypy_cache/3.13/pydantic/main.meta.json +1 -0
  572. appm/.mypy_cache/3.13/pydantic/networks.data.json +1 -0
  573. appm/.mypy_cache/3.13/pydantic/networks.meta.json +1 -0
  574. appm/.mypy_cache/3.13/pydantic/plugin/__init__.data.json +1 -0
  575. appm/.mypy_cache/3.13/pydantic/plugin/__init__.meta.json +1 -0
  576. appm/.mypy_cache/3.13/pydantic/plugin/_schema_validator.data.json +1 -0
  577. appm/.mypy_cache/3.13/pydantic/plugin/_schema_validator.meta.json +1 -0
  578. appm/.mypy_cache/3.13/pydantic/root_model.data.json +1 -0
  579. appm/.mypy_cache/3.13/pydantic/root_model.meta.json +1 -0
  580. appm/.mypy_cache/3.13/pydantic/type_adapter.data.json +1 -0
  581. appm/.mypy_cache/3.13/pydantic/type_adapter.meta.json +1 -0
  582. appm/.mypy_cache/3.13/pydantic/types.data.json +1 -0
  583. appm/.mypy_cache/3.13/pydantic/types.meta.json +1 -0
  584. appm/.mypy_cache/3.13/pydantic/v1/__init__.data.json +1 -0
  585. appm/.mypy_cache/3.13/pydantic/v1/__init__.meta.json +1 -0
  586. appm/.mypy_cache/3.13/pydantic/v1/annotated_types.data.json +1 -0
  587. appm/.mypy_cache/3.13/pydantic/v1/annotated_types.meta.json +1 -0
  588. appm/.mypy_cache/3.13/pydantic/v1/class_validators.data.json +1 -0
  589. appm/.mypy_cache/3.13/pydantic/v1/class_validators.meta.json +1 -0
  590. appm/.mypy_cache/3.13/pydantic/v1/color.data.json +1 -0
  591. appm/.mypy_cache/3.13/pydantic/v1/color.meta.json +1 -0
  592. appm/.mypy_cache/3.13/pydantic/v1/config.data.json +1 -0
  593. appm/.mypy_cache/3.13/pydantic/v1/config.meta.json +1 -0
  594. appm/.mypy_cache/3.13/pydantic/v1/dataclasses.data.json +1 -0
  595. appm/.mypy_cache/3.13/pydantic/v1/dataclasses.meta.json +1 -0
  596. appm/.mypy_cache/3.13/pydantic/v1/datetime_parse.data.json +1 -0
  597. appm/.mypy_cache/3.13/pydantic/v1/datetime_parse.meta.json +1 -0
  598. appm/.mypy_cache/3.13/pydantic/v1/decorator.data.json +1 -0
  599. appm/.mypy_cache/3.13/pydantic/v1/decorator.meta.json +1 -0
  600. appm/.mypy_cache/3.13/pydantic/v1/env_settings.data.json +1 -0
  601. appm/.mypy_cache/3.13/pydantic/v1/env_settings.meta.json +1 -0
  602. appm/.mypy_cache/3.13/pydantic/v1/error_wrappers.data.json +1 -0
  603. appm/.mypy_cache/3.13/pydantic/v1/error_wrappers.meta.json +1 -0
  604. appm/.mypy_cache/3.13/pydantic/v1/errors.data.json +1 -0
  605. appm/.mypy_cache/3.13/pydantic/v1/errors.meta.json +1 -0
  606. appm/.mypy_cache/3.13/pydantic/v1/fields.data.json +1 -0
  607. appm/.mypy_cache/3.13/pydantic/v1/fields.meta.json +1 -0
  608. appm/.mypy_cache/3.13/pydantic/v1/json.data.json +1 -0
  609. appm/.mypy_cache/3.13/pydantic/v1/json.meta.json +1 -0
  610. appm/.mypy_cache/3.13/pydantic/v1/main.data.json +1 -0
  611. appm/.mypy_cache/3.13/pydantic/v1/main.meta.json +1 -0
  612. appm/.mypy_cache/3.13/pydantic/v1/networks.data.json +1 -0
  613. appm/.mypy_cache/3.13/pydantic/v1/networks.meta.json +1 -0
  614. appm/.mypy_cache/3.13/pydantic/v1/parse.data.json +1 -0
  615. appm/.mypy_cache/3.13/pydantic/v1/parse.meta.json +1 -0
  616. appm/.mypy_cache/3.13/pydantic/v1/schema.data.json +1 -0
  617. appm/.mypy_cache/3.13/pydantic/v1/schema.meta.json +1 -0
  618. appm/.mypy_cache/3.13/pydantic/v1/tools.data.json +1 -0
  619. appm/.mypy_cache/3.13/pydantic/v1/tools.meta.json +1 -0
  620. appm/.mypy_cache/3.13/pydantic/v1/types.data.json +1 -0
  621. appm/.mypy_cache/3.13/pydantic/v1/types.meta.json +1 -0
  622. appm/.mypy_cache/3.13/pydantic/v1/typing.data.json +1 -0
  623. appm/.mypy_cache/3.13/pydantic/v1/typing.meta.json +1 -0
  624. appm/.mypy_cache/3.13/pydantic/v1/utils.data.json +1 -0
  625. appm/.mypy_cache/3.13/pydantic/v1/utils.meta.json +1 -0
  626. appm/.mypy_cache/3.13/pydantic/v1/validators.data.json +1 -0
  627. appm/.mypy_cache/3.13/pydantic/v1/validators.meta.json +1 -0
  628. appm/.mypy_cache/3.13/pydantic/v1/version.data.json +1 -0
  629. appm/.mypy_cache/3.13/pydantic/v1/version.meta.json +1 -0
  630. appm/.mypy_cache/3.13/pydantic/validate_call_decorator.data.json +1 -0
  631. appm/.mypy_cache/3.13/pydantic/validate_call_decorator.meta.json +1 -0
  632. appm/.mypy_cache/3.13/pydantic/version.data.json +1 -0
  633. appm/.mypy_cache/3.13/pydantic/version.meta.json +1 -0
  634. appm/.mypy_cache/3.13/pydantic/warnings.data.json +1 -0
  635. appm/.mypy_cache/3.13/pydantic/warnings.meta.json +1 -0
  636. appm/.mypy_cache/3.13/pydantic_core/__init__.data.json +1 -0
  637. appm/.mypy_cache/3.13/pydantic_core/__init__.meta.json +1 -0
  638. appm/.mypy_cache/3.13/pydantic_core/_pydantic_core.data.json +1 -0
  639. appm/.mypy_cache/3.13/pydantic_core/_pydantic_core.meta.json +1 -0
  640. appm/.mypy_cache/3.13/pydantic_core/core_schema.data.json +1 -0
  641. appm/.mypy_cache/3.13/pydantic_core/core_schema.meta.json +1 -0
  642. appm/.mypy_cache/3.13/re.data.json +1 -0
  643. appm/.mypy_cache/3.13/re.meta.json +1 -0
  644. appm/.mypy_cache/3.13/resource.data.json +1 -0
  645. appm/.mypy_cache/3.13/resource.meta.json +1 -0
  646. appm/.mypy_cache/3.13/ruamel/yaml/__init__.data.json +1 -0
  647. appm/.mypy_cache/3.13/ruamel/yaml/__init__.meta.json +1 -0
  648. appm/.mypy_cache/3.13/ruamel/yaml/anchor.data.json +1 -0
  649. appm/.mypy_cache/3.13/ruamel/yaml/anchor.meta.json +1 -0
  650. appm/.mypy_cache/3.13/ruamel/yaml/comments.data.json +1 -0
  651. appm/.mypy_cache/3.13/ruamel/yaml/comments.meta.json +1 -0
  652. appm/.mypy_cache/3.13/ruamel/yaml/compat.data.json +1 -0
  653. appm/.mypy_cache/3.13/ruamel/yaml/compat.meta.json +1 -0
  654. appm/.mypy_cache/3.13/ruamel/yaml/composer.data.json +1 -0
  655. appm/.mypy_cache/3.13/ruamel/yaml/composer.meta.json +1 -0
  656. appm/.mypy_cache/3.13/ruamel/yaml/constructor.data.json +1 -0
  657. appm/.mypy_cache/3.13/ruamel/yaml/constructor.meta.json +1 -0
  658. appm/.mypy_cache/3.13/ruamel/yaml/cyaml.data.json +1 -0
  659. appm/.mypy_cache/3.13/ruamel/yaml/cyaml.meta.json +1 -0
  660. appm/.mypy_cache/3.13/ruamel/yaml/docinfo.data.json +1 -0
  661. appm/.mypy_cache/3.13/ruamel/yaml/docinfo.meta.json +1 -0
  662. appm/.mypy_cache/3.13/ruamel/yaml/dumper.data.json +1 -0
  663. appm/.mypy_cache/3.13/ruamel/yaml/dumper.meta.json +1 -0
  664. appm/.mypy_cache/3.13/ruamel/yaml/emitter.data.json +1 -0
  665. appm/.mypy_cache/3.13/ruamel/yaml/emitter.meta.json +1 -0
  666. appm/.mypy_cache/3.13/ruamel/yaml/error.data.json +1 -0
  667. appm/.mypy_cache/3.13/ruamel/yaml/error.meta.json +1 -0
  668. appm/.mypy_cache/3.13/ruamel/yaml/events.data.json +1 -0
  669. appm/.mypy_cache/3.13/ruamel/yaml/events.meta.json +1 -0
  670. appm/.mypy_cache/3.13/ruamel/yaml/loader.data.json +1 -0
  671. appm/.mypy_cache/3.13/ruamel/yaml/loader.meta.json +1 -0
  672. appm/.mypy_cache/3.13/ruamel/yaml/main.data.json +1 -0
  673. appm/.mypy_cache/3.13/ruamel/yaml/main.meta.json +1 -0
  674. appm/.mypy_cache/3.13/ruamel/yaml/nodes.data.json +1 -0
  675. appm/.mypy_cache/3.13/ruamel/yaml/nodes.meta.json +1 -0
  676. appm/.mypy_cache/3.13/ruamel/yaml/parser.data.json +1 -0
  677. appm/.mypy_cache/3.13/ruamel/yaml/parser.meta.json +1 -0
  678. appm/.mypy_cache/3.13/ruamel/yaml/reader.data.json +1 -0
  679. appm/.mypy_cache/3.13/ruamel/yaml/reader.meta.json +1 -0
  680. appm/.mypy_cache/3.13/ruamel/yaml/representer.data.json +1 -0
  681. appm/.mypy_cache/3.13/ruamel/yaml/representer.meta.json +1 -0
  682. appm/.mypy_cache/3.13/ruamel/yaml/resolver.data.json +1 -0
  683. appm/.mypy_cache/3.13/ruamel/yaml/resolver.meta.json +1 -0
  684. appm/.mypy_cache/3.13/ruamel/yaml/scalarbool.data.json +1 -0
  685. appm/.mypy_cache/3.13/ruamel/yaml/scalarbool.meta.json +1 -0
  686. appm/.mypy_cache/3.13/ruamel/yaml/scalarfloat.data.json +1 -0
  687. appm/.mypy_cache/3.13/ruamel/yaml/scalarfloat.meta.json +1 -0
  688. appm/.mypy_cache/3.13/ruamel/yaml/scalarint.data.json +1 -0
  689. appm/.mypy_cache/3.13/ruamel/yaml/scalarint.meta.json +1 -0
  690. appm/.mypy_cache/3.13/ruamel/yaml/scalarstring.data.json +1 -0
  691. appm/.mypy_cache/3.13/ruamel/yaml/scalarstring.meta.json +1 -0
  692. appm/.mypy_cache/3.13/ruamel/yaml/scanner.data.json +1 -0
  693. appm/.mypy_cache/3.13/ruamel/yaml/scanner.meta.json +1 -0
  694. appm/.mypy_cache/3.13/ruamel/yaml/serializer.data.json +1 -0
  695. appm/.mypy_cache/3.13/ruamel/yaml/serializer.meta.json +1 -0
  696. appm/.mypy_cache/3.13/ruamel/yaml/tag.data.json +1 -0
  697. appm/.mypy_cache/3.13/ruamel/yaml/tag.meta.json +1 -0
  698. appm/.mypy_cache/3.13/ruamel/yaml/timestamp.data.json +1 -0
  699. appm/.mypy_cache/3.13/ruamel/yaml/timestamp.meta.json +1 -0
  700. appm/.mypy_cache/3.13/ruamel/yaml/tokens.data.json +1 -0
  701. appm/.mypy_cache/3.13/ruamel/yaml/tokens.meta.json +1 -0
  702. appm/.mypy_cache/3.13/ruamel/yaml/util.data.json +1 -0
  703. appm/.mypy_cache/3.13/ruamel/yaml/util.meta.json +1 -0
  704. appm/.mypy_cache/3.13/ruamel.data.json +1 -0
  705. appm/.mypy_cache/3.13/ruamel.meta.json +1 -0
  706. appm/.mypy_cache/3.13/shutil.data.json +1 -0
  707. appm/.mypy_cache/3.13/shutil.meta.json +1 -0
  708. appm/.mypy_cache/3.13/sre_compile.data.json +1 -0
  709. appm/.mypy_cache/3.13/sre_compile.meta.json +1 -0
  710. appm/.mypy_cache/3.13/sre_constants.data.json +1 -0
  711. appm/.mypy_cache/3.13/sre_constants.meta.json +1 -0
  712. appm/.mypy_cache/3.13/sre_parse.data.json +1 -0
  713. appm/.mypy_cache/3.13/sre_parse.meta.json +1 -0
  714. appm/.mypy_cache/3.13/subprocess.data.json +1 -0
  715. appm/.mypy_cache/3.13/subprocess.meta.json +1 -0
  716. appm/.mypy_cache/3.13/sys/__init__.data.json +1 -0
  717. appm/.mypy_cache/3.13/sys/__init__.meta.json +1 -0
  718. appm/.mypy_cache/3.13/sys/_monitoring.data.json +1 -0
  719. appm/.mypy_cache/3.13/sys/_monitoring.meta.json +1 -0
  720. appm/.mypy_cache/3.13/tarfile.data.json +1 -0
  721. appm/.mypy_cache/3.13/tarfile.meta.json +1 -0
  722. appm/.mypy_cache/3.13/textwrap.data.json +1 -0
  723. appm/.mypy_cache/3.13/textwrap.meta.json +1 -0
  724. appm/.mypy_cache/3.13/time.data.json +1 -0
  725. appm/.mypy_cache/3.13/time.meta.json +1 -0
  726. appm/.mypy_cache/3.13/traceback.data.json +1 -0
  727. appm/.mypy_cache/3.13/traceback.meta.json +1 -0
  728. appm/.mypy_cache/3.13/types.data.json +1 -0
  729. appm/.mypy_cache/3.13/types.meta.json +1 -0
  730. appm/.mypy_cache/3.13/typing.data.json +1 -0
  731. appm/.mypy_cache/3.13/typing.meta.json +1 -0
  732. appm/.mypy_cache/3.13/typing_extensions.data.json +1 -0
  733. appm/.mypy_cache/3.13/typing_extensions.meta.json +1 -0
  734. appm/.mypy_cache/3.13/typing_inspection/__init__.data.json +1 -0
  735. appm/.mypy_cache/3.13/typing_inspection/__init__.meta.json +1 -0
  736. appm/.mypy_cache/3.13/typing_inspection/introspection.data.json +1 -0
  737. appm/.mypy_cache/3.13/typing_inspection/introspection.meta.json +1 -0
  738. appm/.mypy_cache/3.13/typing_inspection/typing_objects.data.json +1 -0
  739. appm/.mypy_cache/3.13/typing_inspection/typing_objects.meta.json +1 -0
  740. appm/.mypy_cache/3.13/uuid.data.json +1 -0
  741. appm/.mypy_cache/3.13/uuid.meta.json +1 -0
  742. appm/.mypy_cache/3.13/warnings.data.json +1 -0
  743. appm/.mypy_cache/3.13/warnings.meta.json +1 -0
  744. appm/.mypy_cache/3.13/weakref.data.json +1 -0
  745. appm/.mypy_cache/3.13/weakref.meta.json +1 -0
  746. appm/.mypy_cache/3.13/zipfile/__init__.data.json +1 -0
  747. appm/.mypy_cache/3.13/zipfile/__init__.meta.json +1 -0
  748. appm/.mypy_cache/3.13/zipfile/_path/__init__.data.json +1 -0
  749. appm/.mypy_cache/3.13/zipfile/_path/__init__.meta.json +1 -0
  750. appm/.mypy_cache/3.13/zlib.data.json +1 -0
  751. appm/.mypy_cache/3.13/zlib.meta.json +1 -0
  752. appm/.mypy_cache/3.13/zoneinfo/__init__.data.json +1 -0
  753. appm/.mypy_cache/3.13/zoneinfo/__init__.meta.json +1 -0
  754. appm/.mypy_cache/3.13/zoneinfo/_common.data.json +1 -0
  755. appm/.mypy_cache/3.13/zoneinfo/_common.meta.json +1 -0
  756. appm/.mypy_cache/3.13/zoneinfo/_tzpath.data.json +1 -0
  757. appm/.mypy_cache/3.13/zoneinfo/_tzpath.meta.json +1 -0
  758. appm/.mypy_cache/CACHEDIR.TAG +3 -0
  759. appm/__version__.py +1 -1
  760. appm/default.py +36 -0
  761. appm/exceptions.py +6 -0
  762. appm/manager.py +118 -121
  763. appm/model.py +261 -30
  764. appm/utils.py +45 -0
  765. appm-0.0.4.dist-info/METADATA +76 -0
  766. appm-0.0.4.dist-info/RECORD +769 -0
  767. appm-0.0.2.dist-info/METADATA +0 -9
  768. appm-0.0.2.dist-info/RECORD +0 -10
  769. {appm-0.0.2.dist-info → appm-0.0.4.dist-info}/WHEEL +0 -0
appm/manager.py CHANGED
@@ -1,68 +1,25 @@
1
1
  from __future__ import annotations
2
2
 
3
- import re
4
3
  import shutil
5
- from collections.abc import Mapping
4
+ from copy import deepcopy
6
5
  from pathlib import Path
7
- from typing import Any, Sequence, overload
6
+ from typing import Any
8
7
 
9
- from ruamel.yaml import YAML, CommentedMap, CommentedSeq
8
+ from ruamel.yaml import YAML
10
9
 
11
10
  from appm.__version__ import __version__
11
+ from appm.default import DEFAULT_TEMPLATE
12
12
  from appm.exceptions import (
13
- FileFormatMismatch,
14
- MetadataFileNotFoundErr,
15
- ProjectNotFoundErr,
16
13
  UnsupportedFileExtension,
17
14
  )
18
- from appm.model import ExtDecl, ProjectMetadata
15
+ from appm.model import Project
16
+ from appm.utils import to_flow_style, validate_path
19
17
 
20
18
  yaml = YAML()
21
19
  yaml.indent(mapping=2, sequence=4, offset=2)
22
20
  yaml.preserve_quotes = True # optional, if you want to preserve quotes
23
21
 
24
22
 
25
- def to_flow_style(obj: Any) -> Any:
26
- """Recursively convert dict/list to ruamel structures with ALL lists using flow-style."""
27
- if isinstance(obj, Mapping):
28
- cm = CommentedMap()
29
- for k, v in obj.items():
30
- cm[k] = to_flow_style(v)
31
- return cm
32
- if isinstance(obj, Sequence) and not isinstance(obj, str):
33
- cs = CommentedSeq()
34
- for item in obj:
35
- cs.append(to_flow_style(item))
36
- cs.fa.set_flow_style()
37
- return cs
38
- return obj
39
-
40
-
41
- class ExtManager:
42
- def __init__(self, ext: str, decl: ExtDecl) -> None:
43
- self.ext = ext
44
- self.decl = decl
45
-
46
- @property
47
- def pattern(self) -> str:
48
- return (
49
- r"^"
50
- + self.decl.sep.join([f"({p})" for _, p in self.decl.format])
51
- + r"(.*)$"
52
- )
53
-
54
- def match(self, name: str) -> dict[str, str]:
55
- match = re.match(self.pattern, name)
56
- if not match:
57
- raise FileFormatMismatch(f"Name: {name}. Pattern: {self.pattern}")
58
- groups = match.groups()
59
- result = {}
60
- for i, (field, _) in enumerate(self.decl.format):
61
- result[field] = groups[i]
62
- result["*"] = groups[-1]
63
- return result
64
-
65
-
66
23
  class ProjectManager:
67
24
  METADATA_NAME: str = "metadata.yaml"
68
25
 
@@ -72,30 +29,68 @@ class ProjectManager:
72
29
  root: str | Path,
73
30
  ) -> None:
74
31
  self.root = Path(root)
75
- self.metadata = ProjectMetadata.model_validate(metadata)
76
- self.handlers = {
77
- ext: ExtManager(ext, ext_decl)
78
- for ext, ext_decl in self.metadata.file.items()
79
- }
32
+ self.metadata = Project.model_validate(metadata)
33
+ self.handlers = {ext: handler for ext, handler in self.metadata.file.items()}
34
+
35
+ @property
36
+ def location(self) -> Path:
37
+ return self.root / self.metadata.project_name
80
38
 
81
- def match(self, name: str) -> dict[str, str]:
39
+ def match(self, name: str) -> dict[str, str | None]:
40
+ """Match a file name and separate into format defined field components
41
+
42
+ The result contains a * which captures all non-captured values.
43
+
44
+ Args:
45
+ name (str): file name
46
+
47
+ Raises:
48
+ UnsupportedFileExtension: the metadata does not define an
49
+ extension declaration for the file's extension.
50
+
51
+ Returns:
52
+ dict[str, str]: key value dictionary of the field component
53
+ defined using the format field.
54
+ """
82
55
  ext = name.split(".")[-1]
83
- if ext not in self.handlers:
84
- raise UnsupportedFileExtension(ext)
85
- return self.handlers[ext].match(name)
56
+ if ext in self.handlers:
57
+ return self.handlers[ext].match(name)
58
+ if "*" in self.handlers:
59
+ return self.handlers["*"].match(name)
60
+ raise UnsupportedFileExtension(str(ext))
86
61
 
87
62
  def get_file_placement(self, name: str) -> str:
88
- layout = self.metadata.layout
63
+ """Find location where a file should be placed.
64
+
65
+ Determination is based on the metadata's layout field,
66
+ the file extension format definition, and the file name.
67
+ More concretely, field component - values are matched using the
68
+ RegEx defined in format. Fields that match layout values will be
69
+ extracted and path-appended in the order they appear in layout.
70
+
71
+ Args:
72
+ name (str): file name
73
+
74
+ Returns:
75
+ str: file placement directory
76
+ """
77
+ layout = self.metadata.parsed_layout
89
78
  groups = self.match(name)
90
- values = [groups[component] for component in layout]
91
- return "/".join(values)
79
+ return layout.get_path(groups)
92
80
 
93
81
  def init_project(self) -> None:
94
- self.root.mkdir(exist_ok=True, parents=True)
82
+ """Create a project:
83
+
84
+ - Determine the project's name from nameing_convention and metadata
85
+ - Create a folder based on project's root and project name
86
+ - Create a metadata file in the project's location
87
+ """
88
+ self.location.mkdir(exist_ok=True, parents=True)
95
89
  self.save_metadata()
96
90
 
97
91
  def save_metadata(self) -> None:
98
- metadata_path = self.root / self.METADATA_NAME
92
+ """Save the current metadata to the project location"""
93
+ metadata_path = self.location / self.METADATA_NAME
99
94
  with metadata_path.open("w") as file:
100
95
  data = self.metadata.model_dump(mode="json")
101
96
  data["version"] = __version__
@@ -104,84 +99,86 @@ class ProjectManager:
104
99
  file,
105
100
  )
106
101
 
107
- def copy_file(self, src_path: Path) -> None:
108
- if src_path.exists():
109
- raise FileNotFoundError(str(src_path))
110
- location = self.get_file_placement(src_path.name)
111
- dst_path = self.root / location
102
+ def copy_file(self, src_path: str | Path) -> None:
103
+ """Copy a file located at `src_path` to an appropriate
104
+ location in the project.
105
+
106
+ Args:
107
+ src_path (str | Path): path to where src data is found
108
+ """
109
+ src_path = validate_path(src_path)
110
+ dst_path = self.location / self.get_file_placement(src_path.name)
112
111
  dst_path.mkdir(parents=True, exist_ok=True)
113
112
  shutil.copy2(src_path, dst_path)
114
113
 
115
- @overload
116
114
  @classmethod
117
- def from_metadata(
115
+ def from_template(
118
116
  cls,
119
117
  root: str | Path,
120
- metadata: str | Path,
121
118
  year: int,
122
119
  summary: str,
123
120
  internal: bool = True,
124
- researcher: str | None = None,
125
- organisation: str | None = None,
126
- ) -> ProjectManager: ...
127
-
128
- @overload
129
- @classmethod
130
- def from_metadata(
131
- cls,
132
- root: str | Path,
133
- metadata: dict[str, Any],
134
- year: int,
135
- summary: str,
136
- internal: bool = True,
137
- researcher: str | None = None,
138
- organisation: str | None = None,
139
- ) -> ProjectManager: ...
140
-
141
- @classmethod
142
- def from_metadata(
143
- cls,
144
- root: str | Path,
145
- metadata: str | Path | dict[str, Any],
146
- year: int,
147
- summary: str,
148
- internal: bool = True,
149
- researcher: str | None = None,
150
- organisation: str | None = None,
121
+ template: str | Path | dict[str, Any] | None = None,
122
+ researcherName: str | None = None,
123
+ organisationName: str | None = None,
151
124
  ) -> ProjectManager:
152
- if isinstance(metadata, str | Path):
153
- metadata = Path(metadata)
154
- if not metadata.exists():
155
- raise MetadataFileNotFoundErr(str(metadata))
156
- with metadata.open("r") as file:
157
- _metadata = yaml.load(file)
125
+ """Create a ProjectManager based on template and meta information
126
+
127
+ Args:
128
+ root (str | Path): parent directory - where project is stored
129
+ template (str | Path | dict[str, Any]): path to template file or the template content.
130
+ year (int): meta information - year
131
+ summary (str): meta information - summary
132
+ internal (bool, optional): meta information - internal. Defaults to True.
133
+ researcher (str | None, optional): meta information - researcherName. Defaults to None.
134
+ organisation (str | None, optional): meta information - organisationName. Defaults to None.
135
+
136
+ Returns:
137
+ ProjectManager: ProjectManager object
138
+ """
139
+ if isinstance(template, str | Path):
140
+ metadata_path = Path(template)
141
+ metadata_path = validate_path(template)
142
+ with metadata_path.open("r") as file:
143
+ metadata = yaml.load(file)
144
+ elif isinstance(template, dict):
145
+ metadata = template
146
+ elif not template:
147
+ metadata = deepcopy(DEFAULT_TEMPLATE)
158
148
  else:
159
- _metadata = metadata
160
- _metadata.update(
161
- {
162
- "year": year,
163
- "summary": summary,
164
- "internal": internal,
165
- "researcher": researcher,
166
- "organisation": organisation,
167
- }
168
- )
169
- return cls(root=root, metadata=_metadata)
149
+ raise TypeError(
150
+ f"Unexpected type for template: {type(template)}. Accepts str, dict or None"
151
+ )
152
+ metadata["meta"] = {
153
+ "year": year,
154
+ "summary": summary,
155
+ "internal": internal,
156
+ "researcherName": researcherName,
157
+ "organisationName": organisationName,
158
+ }
159
+ return cls(root=root, metadata=metadata)
170
160
 
171
161
  @classmethod
172
162
  def load_project(
173
163
  cls, project_path: Path | str, metadata_name: str | None = None
174
164
  ) -> ProjectManager:
175
- project_path = Path(project_path)
176
- if not project_path.exists():
177
- raise ProjectNotFoundErr(str(project_path))
165
+ """Load a project from project's path
166
+
167
+ Args:
168
+ project_path (Path | str): path to project to open
169
+ metadata_name (str | None, optional): name for metadata file. If not provided, use "metadata.yaml". Defaults to None.
170
+
171
+ Returns:
172
+ ProjectManager: ProjectManager object
173
+ """
174
+ project_path = validate_path(project_path)
178
175
  metadata_path = (
179
176
  project_path / cls.METADATA_NAME
180
177
  if not metadata_name
181
178
  else project_path / metadata_name
182
179
  )
183
- if not metadata_path.exists():
184
- raise MetadataFileNotFoundErr(str(metadata_path))
180
+ metadata_path = validate_path(metadata_path)
181
+
185
182
  with metadata_path.open("r") as file:
186
183
  metadata = yaml.load(file)
187
- return cls(metadata=metadata, root=project_path)
184
+ return cls(metadata=metadata, root=project_path.parent)
appm/model.py CHANGED
@@ -1,28 +1,231 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from collections import Counter
1
5
  from typing import Self
2
6
 
3
7
  from pydantic import BaseModel, model_validator
8
+ from ruamel.yaml import YAML
4
9
 
5
10
  from appm.__version__ import __version__
11
+ from appm.exceptions import FileFormatMismatch
6
12
  from appm.utils import slugify
7
13
 
8
- STRUCTURES = {"year", "summary", "internal", "researcher", "organisation"}
14
+ yaml = YAML()
9
15
 
16
+ STRUCTURES = {"year", "summary", "internal", "researcherName", "organisationName"}
10
17
 
11
- class ExtDecl(BaseModel):
12
- sep: str = "_"
13
- format: list[tuple[str, str]]
18
+
19
+ class Field(BaseModel):
20
+ name: str
21
+ pattern: str
22
+ required: bool = True
23
+
24
+ @property
25
+ def regex(self) -> str:
26
+ return f"(?P<{self.name}>{self.pattern})"
27
+
28
+ @classmethod
29
+ def from_tuple(cls, value: tuple[str, str] | list[str]) -> Field:
30
+ assert len(value) == 2
31
+ return Field(name=value[0], pattern=value[1])
32
+
33
+
34
+ class Group(BaseModel):
35
+ components: list[tuple[str, str] | Field | Group]
36
+ sep: str = "-"
37
+
38
+ def validate_components(self) -> Self:
39
+ if not self.components:
40
+ raise ValueError(f"Components cannot be empty: {self.components}")
41
+ self._fields: list[Field | Group] = []
42
+ self._normalised_fields: list[Field] = []
43
+ for field in self.components:
44
+ if isinstance(field, tuple | list):
45
+ f = Field.from_tuple(field)
46
+ self._fields.append(f)
47
+ self._normalised_fields.append(f)
48
+ elif isinstance(field, Field):
49
+ self._fields.append(field)
50
+ self._normalised_fields.append(field)
51
+ else:
52
+ self._fields.append(field)
53
+ self._normalised_fields.extend(field.normalised_fields)
54
+ return self
55
+
56
+ def validate_names(self) -> Self:
57
+ self._names: list[str] = []
58
+ self._optional_names: set[str] = set()
59
+ for field in self.fields:
60
+ if isinstance(field, Field):
61
+ self._names.append(field.name)
62
+ if not field.required:
63
+ self._optional_names.add(field.name)
64
+ else:
65
+ self._names.extend(field.names)
66
+ self._optional_names.update(field.optional_names)
67
+ return self
68
+
69
+ def validate_regex(self) -> Self:
70
+ regex_str = []
71
+ for i, field in enumerate(self.fields):
72
+ is_optional = isinstance(field, Field) and not field.required
73
+ pattern = field.regex
74
+
75
+ if i == 0:
76
+ if is_optional:
77
+ # First field, no separator; make only field optional
78
+ regex_str.append(f"(?:{pattern})?")
79
+ else:
80
+ regex_str.append(pattern)
81
+ else:
82
+ if is_optional:
83
+ # Wrap separator + field together as optional
84
+ regex_str.append(f"(?:{self.sep}{pattern})?")
85
+ else:
86
+ regex_str.append(f"{self.sep}{pattern}")
87
+ self._regex = "".join(regex_str)
88
+ return self
89
+
90
+ @model_validator(mode="after")
91
+ def validate_group(self) -> Self:
92
+ return self.validate_components().validate_names().validate_regex()
93
+
94
+ @property
95
+ def normalised_fields(self) -> list[Field]:
96
+ return self._normalised_fields
97
+
98
+ @property
99
+ def fields(self) -> list[Field | Group]:
100
+ return self._fields
101
+
102
+ @property
103
+ def names(self) -> list[str]:
104
+ return self._names
105
+
106
+ @property
107
+ def optional_names(self) -> set[str]:
108
+ return self._optional_names
109
+
110
+ @property
111
+ def regex(self) -> str:
112
+ return self._regex
113
+
114
+
115
+ class Extension(Group):
116
+ default: dict[str, str] | None = None
14
117
 
15
118
  @property
16
- def fields(self) -> set[str]:
17
- return {item[0] for item in self.format}
119
+ def default_names(self) -> set[str]:
120
+ return set() if not self.default else set(self.default.keys())
18
121
 
122
+ @property
123
+ def all_names(self) -> set[str]:
124
+ return set(self.names) | self.default_names
125
+
126
+ def validate_regex(self) -> Self:
127
+ self = super().validate_regex()
128
+ self._regex = f"^{self._regex}(?P<rest>.*)$"
129
+ return self
130
+
131
+ def validate_unique_names(self) -> Self:
132
+ count = Counter(self.names)
133
+ non_uniques = {k: v for k, v in count.items() if v > 1}
134
+ if non_uniques:
135
+ raise ValueError(f"Non-unique field name: {non_uniques}")
136
+ return self
137
+
138
+ def validate_reserved_name(self) -> Self:
139
+ if "rest" in self.names:
140
+ raise ValueError("Field component must not contain reserved key: rest")
141
+ return self
19
142
 
20
- class NamingConventionDecl(BaseModel):
143
+ def validate_first_field_must_be_required(self) -> Self:
144
+ if not (field := self.normalised_fields[0]).required:
145
+ raise ValueError(f"First component must be required: {field.name}")
146
+ return self
147
+
148
+ @model_validator(mode="after")
149
+ def validate_extension(self) -> Self:
150
+ return (
151
+ self.validate_components()
152
+ .validate_names()
153
+ .validate_regex()
154
+ .validate_unique_names()
155
+ .validate_reserved_name()
156
+ .validate_first_field_must_be_required()
157
+ )
158
+
159
+ def match(self, name: str) -> dict[str, str | None]:
160
+ m = re.match(self.regex, name)
161
+ if not m:
162
+ raise FileFormatMismatch(f"Name: {name}. Pattern: {self.regex}")
163
+ result = m.groupdict()
164
+ if self.default:
165
+ for k, v in self.default.items():
166
+ if result.get(k) is None:
167
+ result[k] = v
168
+ return result
169
+
170
+
171
+ type File = dict[str, Extension]
172
+
173
+
174
+ class Layout(BaseModel):
175
+ structure: list[str]
176
+ mapping: dict[str, dict[str, str]] | None = None
177
+
178
+ @classmethod
179
+ def from_list(cls, value: list[str]) -> Layout:
180
+ return cls(structure=value)
181
+
182
+ @property
183
+ def structure_set(self) -> set[str]:
184
+ return self._structure_set
185
+
186
+ @model_validator(mode="after")
187
+ def validate_layout(self) -> Self:
188
+ self._structure_set = set(self.structure)
189
+ if self.mapping:
190
+ if not set(self.mapping.keys()).issubset(self._structure_set):
191
+ raise ValueError(
192
+ f"Mapping keys must be a subset of structure. Mapping keys: {set(self.mapping.keys())}, structure: {self.structure}"
193
+ )
194
+ return self
195
+
196
+ def get_path(self, components: dict[str, str | None]) -> str:
197
+ result: list[str] = []
198
+ for key in self.structure:
199
+ value = components.get(key, None)
200
+ if self.mapping and key in self.mapping and value in self.mapping[key]:
201
+ value = self.mapping[key][value]
202
+ if value is None:
203
+ raise ValueError(
204
+ f"None value for key: {key}. Either set a default for Extension definition, change Extension pattern to capture key value, or rename file."
205
+ )
206
+ result.append(value)
207
+ return "/".join(result)
208
+
209
+
210
+ class NamingConv(BaseModel):
21
211
  sep: str = "_"
22
- structure: list[str] = ["year", "summary", "internal", "researcher", "organisation"]
212
+ structure: list[str] = [
213
+ "year",
214
+ "summary",
215
+ "internal",
216
+ "researcherName",
217
+ "organisationName",
218
+ ]
23
219
 
24
220
  @model_validator(mode="after")
25
- def validate_structure_values(self) -> Self:
221
+ def validate_naming_convention(self) -> Self:
222
+ """Validate structure value
223
+
224
+ structure:
225
+ - cannot be empty
226
+ - cannot have repeated component(s)
227
+ - cannot have a field component that is not one of the metadata fields.
228
+ """
26
229
  counter: dict[str, int] = {}
27
230
  if len(self.structure) == 0:
28
231
  raise ValueError("Invalid naming structure - empty structure")
@@ -37,40 +240,68 @@ class NamingConventionDecl(BaseModel):
37
240
  return self
38
241
 
39
242
 
40
- class ProjectDecl(BaseModel):
41
- layout: list[str]
42
- file: dict[str, ExtDecl]
43
- naming_convention: NamingConventionDecl = NamingConventionDecl()
243
+ class Template(BaseModel):
244
+ layout: Layout | list[str]
245
+ file: File
246
+ naming_convention: NamingConv = NamingConv()
247
+ version: str = __version__
44
248
 
45
- @property
46
- def layout_set(self) -> set[str]:
47
- return set(self.layout)
249
+ def validate_layout(self) -> Self:
250
+ if isinstance(self.layout, list):
251
+ self._layout = Layout.from_list(self.layout)
252
+ else:
253
+ self._layout = self.layout
254
+ return self
48
255
 
49
- @model_validator(mode="after")
50
- def validate_format_and_layout(self) -> Self:
256
+ def validate_file_non_empty(self) -> Self:
257
+ if not self.file:
258
+ raise ValueError("Empty extension")
259
+ return self
260
+
261
+ def validate_file_name_subset_layout(self) -> Self:
51
262
  for ext, decl in self.file.items():
52
- if not self.layout_set.issubset(decl.fields):
53
- raise ValueError(
54
- f"""Format fields must be a superset of layout fields.
55
- Extension: {ext}. Format fields: {decl.fields}. Layout fields: {self.layout_set}"""
56
- )
263
+ for field in self.parsed_layout.structure_set:
264
+ if field not in decl.all_names:
265
+ raise ValueError(
266
+ f"Component fields must be a superset of layout fields: {field}. Ext: {ext}"
267
+ )
268
+ if field in decl.optional_names and field not in decl.default_names:
269
+ raise ValueError(
270
+ f"Optional field that is also a layout field must have a default value: {field}. Ext: {ext}"
271
+ )
57
272
  return self
58
273
 
274
+ @property
275
+ def parsed_layout(self) -> Layout:
276
+ return self._layout
277
+
278
+ @model_validator(mode="after")
279
+ def validate_template(self) -> Self:
280
+ return (
281
+ self.validate_layout()
282
+ .validate_file_non_empty()
283
+ .validate_file_name_subset_layout()
284
+ )
285
+
59
286
 
60
- class ProjectMetadata(ProjectDecl):
287
+ class Metadata(BaseModel):
61
288
  year: int
62
289
  summary: str
63
- internal: bool
64
- researcher: str | None = None
65
- organisation: str | None = None
66
- version: str | None = __version__
290
+ internal: bool = True
291
+ researcherName: str | None = None
292
+ organisationName: str | None = None
293
+
294
+
295
+ class Project(Template):
296
+ meta: Metadata
67
297
 
68
298
  @property
69
- def name(self) -> str:
299
+ def project_name(self) -> str:
300
+ """Project name based on metadata and naming convention definiton"""
70
301
  fields = self.naming_convention.structure
71
302
  name: list[str] = []
72
303
  for field in fields:
73
- value = getattr(self, field)
304
+ value = getattr(self.meta, field)
74
305
  if value is not None:
75
306
  if isinstance(value, str):
76
307
  name.append(slugify(value))
appm/utils.py CHANGED
@@ -1,4 +1,11 @@
1
1
  import re
2
+ from collections.abc import Mapping, Sequence
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from ruamel.yaml import CommentedMap, CommentedSeq
7
+
8
+ from appm.exceptions import NotAFileErr, NotFoundErr
2
9
 
3
10
 
4
11
  def slugify(text: str) -> str:
@@ -25,3 +32,41 @@ def slugify(text: str) -> str:
25
32
  # Replace spaces with hyphens
26
33
  text = re.sub(r"[\s\-]+", "-", text)
27
34
  return text.strip("-")
35
+
36
+
37
+ def to_flow_style(obj: Any) -> Any:
38
+ """Recursively convert dict/list to ruamel structures with ALL lists using flow-style."""
39
+ if isinstance(obj, Mapping):
40
+ cm = CommentedMap()
41
+ for k, v in obj.items():
42
+ cm[k] = to_flow_style(v)
43
+ return cm
44
+ if isinstance(obj, Sequence) and not isinstance(obj, str):
45
+ cs = CommentedSeq()
46
+ for item in obj:
47
+ cs.append(to_flow_style(item))
48
+ cs.fa.set_flow_style()
49
+ return cs
50
+ return obj
51
+
52
+
53
+ def validate_path(path: str | Path, is_file: bool = False) -> Path:
54
+ """Verify that path describes an existing file/folder
55
+
56
+ Args:
57
+ path (str | Path): path to validate
58
+ is_file (bool): whether path is a file. Defaults to False.
59
+
60
+ Raises:
61
+ NotFoundErr: path item doesnt exist
62
+ NotAFileErr: path doesn't describe a file
63
+
64
+ Returns:
65
+ Path: validated path
66
+ """
67
+ _path = Path(path)
68
+ if not _path.exists():
69
+ raise NotFoundErr(str(path))
70
+ if is_file and not _path.is_file():
71
+ raise NotAFileErr(str(path))
72
+ return _path