openedx-learning 0.27.0__tar.gz → 0.27.1__tar.gz

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 (174) hide show
  1. {openedx_learning-0.27.0/openedx_learning.egg-info → openedx_learning-0.27.1}/PKG-INFO +5 -5
  2. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/__init__.py +1 -1
  3. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/api/authoring.py +1 -0
  4. openedx_learning-0.27.1/openedx_learning/apps/authoring/backup_restore/api.py +15 -0
  5. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py +0 -1
  6. openedx_learning-0.27.1/openedx_learning/apps/authoring/backup_restore/toml.py +75 -0
  7. openedx_learning-0.27.1/openedx_learning/apps/authoring/backup_restore/zipper.py +53 -0
  8. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/apps.py +2 -2
  9. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/api.py +41 -8
  10. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/apps.py +2 -2
  11. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/publishable_entity.py +7 -3
  12. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/api.py +6 -1
  13. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/apps.py +2 -2
  14. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/api.py +6 -1
  15. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/apps.py +2 -2
  16. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/api.py +6 -1
  17. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/apps.py +2 -2
  18. {openedx_learning-0.27.0 → openedx_learning-0.27.1/openedx_learning.egg-info}/PKG-INFO +5 -5
  19. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning.egg-info/SOURCES.txt +1 -0
  20. openedx_learning-0.27.0/openedx_learning/apps/authoring/backup_restore/api.py +0 -25
  21. openedx_learning-0.27.0/openedx_learning/apps/authoring/backup_restore/toml.py +0 -72
  22. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/CHANGELOG.rst +0 -0
  23. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/LICENSE.txt +0 -0
  24. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/MANIFEST.in +0 -0
  25. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/README.rst +0 -0
  26. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/api/__init__.py +0 -0
  27. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/api/authoring_models.py +0 -0
  28. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/__init__.py +0 -0
  29. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/__init__.py +0 -0
  30. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/__init__.py +0 -0
  31. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/admin.py +0 -0
  32. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/apps.py +0 -0
  33. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/management/__init__.py +0 -0
  34. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/management/commands/__init__.py +0 -0
  35. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/migrations/__init__.py +0 -0
  36. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/backup_restore/models.py +0 -0
  37. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/__init__.py +0 -0
  38. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/admin.py +0 -0
  39. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/api.py +0 -0
  40. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/apps.py +0 -0
  41. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/migrations/0001_initial.py +0 -0
  42. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/migrations/0002_remove_collection_name_collection_created_by_and_more.py +0 -0
  43. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/migrations/0003_collection_entities.py +0 -0
  44. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/migrations/0004_collection_key.py +0 -0
  45. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/migrations/0005_alter_collection_options_alter_collection_enabled.py +0 -0
  46. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/migrations/__init__.py +0 -0
  47. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/collections/models.py +0 -0
  48. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/__init__.py +0 -0
  49. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/admin.py +0 -0
  50. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/api.py +0 -0
  51. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/management/__init__.py +0 -0
  52. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/management/commands/__init__.py +0 -0
  53. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/management/commands/add_assets_to_component.py +0 -0
  54. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/migrations/0001_initial.py +0 -0
  55. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/migrations/0002_alter_componentversioncontent_key.py +0 -0
  56. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/migrations/0003_remove_componentversioncontent_learner_downloadable.py +0 -0
  57. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/migrations/__init__.py +0 -0
  58. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/components/models.py +0 -0
  59. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/__init__.py +0 -0
  60. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/admin.py +0 -0
  61. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/api.py +0 -0
  62. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/apps.py +0 -0
  63. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/migrations/0001_initial.py +0 -0
  64. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/migrations/__init__.py +0 -0
  65. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/contents/models.py +0 -0
  66. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/__init__.py +0 -0
  67. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/admin.py +0 -0
  68. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/contextmanagers.py +0 -0
  69. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0001_initial.py +0 -0
  70. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0002_alter_learningpackage_key_and_more.py +0 -0
  71. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0003_containers.py +0 -0
  72. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0004_publishableentity_can_stand_alone.py +0 -0
  73. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0005_alter_entitylistrow_options.py +0 -0
  74. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0006_draftchangelog.py +0 -0
  75. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0007_bootstrap_draftchangelog.py +0 -0
  76. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/0008_alter_draftchangelogrecord_options_and_more.py +0 -0
  77. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/migrations/__init__.py +0 -0
  78. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/__init__.py +0 -0
  79. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/container.py +0 -0
  80. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/draft_log.py +0 -0
  81. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/entity_list.py +0 -0
  82. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/learning_package.py +0 -0
  83. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/publishing/models/publish_log.py +0 -0
  84. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/__init__.py +0 -0
  85. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/admin.py +0 -0
  86. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/migrations/0001_initial.py +0 -0
  87. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/migrations/__init__.py +0 -0
  88. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/sections/models.py +0 -0
  89. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/__init__.py +0 -0
  90. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/admin.py +0 -0
  91. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/migrations/0001_initial.py +0 -0
  92. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/migrations/__init__.py +0 -0
  93. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/subsections/models.py +0 -0
  94. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/__init__.py +0 -0
  95. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/admin.py +0 -0
  96. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/migrations/0001_initial.py +0 -0
  97. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/migrations/__init__.py +0 -0
  98. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/apps/authoring/units/models.py +0 -0
  99. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/contrib/__init__.py +0 -0
  100. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/contrib/media_server/__init__.py +0 -0
  101. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/contrib/media_server/apps.py +0 -0
  102. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/contrib/media_server/urls.py +0 -0
  103. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/contrib/media_server/views.py +0 -0
  104. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/__init__.py +0 -0
  105. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/admin_utils.py +0 -0
  106. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/cache.py +0 -0
  107. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/collations.py +0 -0
  108. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/fields.py +0 -0
  109. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/managers.py +0 -0
  110. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/test_utils.py +0 -0
  111. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/lib/validators.py +0 -0
  112. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning/py.typed +0 -0
  113. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning.egg-info/dependency_links.txt +0 -0
  114. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning.egg-info/not-zip-safe +0 -0
  115. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning.egg-info/requires.txt +4 -4
  116. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_learning.egg-info/top_level.txt +0 -0
  117. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/__init__.py +0 -0
  118. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/__init__.py +0 -0
  119. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/__init__.py +0 -0
  120. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/admin.py +0 -0
  121. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/api.py +0 -0
  122. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/apps.py +0 -0
  123. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/data.py +0 -0
  124. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/__init__.py +0 -0
  125. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/actions.py +0 -0
  126. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/api.py +0 -0
  127. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/exceptions.py +0 -0
  128. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/import_plan.py +0 -0
  129. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/parsers.py +0 -0
  130. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/tasks.py +0 -0
  131. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/template.csv +0 -0
  132. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/import_export/template.json +0 -0
  133. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0001_initial.py +0 -0
  134. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0001_squashed.py +0 -0
  135. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0002_auto_20230718_2026.py +0 -0
  136. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0003_auto_20230721_1238.py +0 -0
  137. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0004_auto_20230723_2001.py +0 -0
  138. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py +0 -0
  139. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0006_alter_objecttag_unique_together.py +0 -0
  140. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0006_auto_20230802_1631.py +0 -0
  141. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0007_tag_import_task_log_null_fix.py +0 -0
  142. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0008_taxonomy_description_not_null.py +0 -0
  143. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0009_alter_objecttag_object_id.py +0 -0
  144. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0010_cleanups.py +0 -0
  145. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0011_remove_required.py +0 -0
  146. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py +0 -0
  147. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0013_tag_parent_blank.py +0 -0
  148. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0014_minor_fixes.py +0 -0
  149. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0015_taxonomy_export_id.py +0 -0
  150. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0016_object_tag_export_id.py +0 -0
  151. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0017_alter_tagimporttask_status.py +0 -0
  152. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/0018_objecttag_is_copied.py +0 -0
  153. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/migrations/__init__.py +0 -0
  154. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/models/__init__.py +0 -0
  155. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/models/base.py +0 -0
  156. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/models/import_export.py +0 -0
  157. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/models/system_defined.py +0 -0
  158. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/models/utils.py +0 -0
  159. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/__init__.py +0 -0
  160. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/paginators.py +0 -0
  161. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/urls.py +0 -0
  162. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/utils.py +0 -0
  163. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/v1/__init__.py +0 -0
  164. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/v1/permissions.py +0 -0
  165. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/v1/serializers.py +0 -0
  166. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/v1/urls.py +0 -0
  167. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/v1/views.py +0 -0
  168. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rest_api/v1/views_import.py +0 -0
  169. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/rules.py +0 -0
  170. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/core/tagging/urls.py +0 -0
  171. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/openedx_tagging/py.typed +0 -0
  172. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/requirements/base.in +0 -0
  173. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/setup.cfg +0 -0
  174. {openedx_learning-0.27.0 → openedx_learning-0.27.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openedx-learning
3
- Version: 0.27.0
3
+ Version: 0.27.1
4
4
  Summary: Open edX Learning Core and Tagging.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -19,13 +19,13 @@ Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.11
21
21
  License-File: LICENSE.txt
22
- Requires-Dist: Django
23
- Requires-Dist: rules<4.0
24
- Requires-Dist: celery
25
22
  Requires-Dist: djangorestframework<4.0
26
- Requires-Dist: attrs
27
23
  Requires-Dist: tomlkit
24
+ Requires-Dist: celery
25
+ Requires-Dist: Django
26
+ Requires-Dist: attrs
28
27
  Requires-Dist: edx-drf-extensions
28
+ Requires-Dist: rules<4.0
29
29
  Dynamic: author
30
30
  Dynamic: author-email
31
31
  Dynamic: classifier
@@ -2,4 +2,4 @@
2
2
  Open edX Learning ("Learning Core").
3
3
  """
4
4
 
5
- __version__ = "0.27.0"
5
+ __version__ = "0.27.1"
@@ -9,6 +9,7 @@ APIs.
9
9
  """
10
10
  # These wildcard imports are okay because these api modules declare __all__.
11
11
  # pylint: disable=wildcard-import
12
+ from ..apps.authoring.backup_restore.api import *
12
13
  from ..apps.authoring.collections.api import *
13
14
  from ..apps.authoring.components.api import *
14
15
  from ..apps.authoring.contents.api import *
@@ -0,0 +1,15 @@
1
+ """
2
+ Backup Restore API
3
+ """
4
+ from openedx_learning.apps.authoring.backup_restore.zipper import LearningPackageZipper
5
+ from openedx_learning.apps.authoring.publishing.api import get_learning_package_by_key
6
+
7
+
8
+ def create_zip_file(lp_key: str, path: str) -> None:
9
+ """
10
+ Creates a zip file with a toml file so far (WIP)
11
+
12
+ Can throw a NotFoundError at get_learning_package_by_key
13
+ """
14
+ learning_package = get_learning_package_by_key(lp_key)
15
+ LearningPackageZipper(learning_package).create_zip(path)
@@ -33,7 +33,6 @@ class Command(BaseCommand):
33
33
  self.stdout.write(self.style.SUCCESS(message))
34
34
  except LearningPackage.DoesNotExist as exc:
35
35
  message = f"Learning package with key {lp_key} not found"
36
- logger.exception(message)
37
36
  raise CommandError(message) from exc
38
37
  except Exception as e:
39
38
  message = f"Failed to export learning package '{lp_key}': {e}"
@@ -0,0 +1,75 @@
1
+ """
2
+ TOML serialization for learning packages and publishable entities.
3
+ """
4
+
5
+ from datetime import datetime
6
+
7
+ import tomlkit
8
+
9
+ from openedx_learning.apps.authoring.publishing.models import PublishableEntity, PublishableEntityVersion
10
+ from openedx_learning.apps.authoring.publishing.models.learning_package import LearningPackage
11
+
12
+
13
+ def toml_learning_package(learning_package: LearningPackage) -> str:
14
+ """Create a TOML representation of the learning package."""
15
+ doc = tomlkit.document()
16
+ doc.add(tomlkit.comment(f"Datetime of the export: {datetime.now()}"))
17
+ section = tomlkit.table()
18
+ section.add("title", learning_package.title)
19
+ section.add("key", learning_package.key)
20
+ section.add("description", learning_package.description)
21
+ section.add("created", learning_package.created)
22
+ section.add("updated", learning_package.updated)
23
+ doc.add("learning_package", section)
24
+ return tomlkit.dumps(doc)
25
+
26
+
27
+ def toml_publishable_entity(entity: PublishableEntity) -> str:
28
+ """Create a TOML representation of a publishable entity."""
29
+
30
+ current_draft_version = getattr(entity, "draft", None)
31
+ current_published_version = getattr(entity, "published", None)
32
+
33
+ doc = tomlkit.document()
34
+ entity_table = tomlkit.table()
35
+ entity_table.add("uuid", str(entity.uuid))
36
+ entity_table.add("can_stand_alone", entity.can_stand_alone)
37
+
38
+ if current_draft_version:
39
+ draft_table = tomlkit.table()
40
+ draft_table.add("version_num", current_draft_version.version.version_num)
41
+ entity_table.add("draft", draft_table)
42
+
43
+ published_table = tomlkit.table()
44
+ if current_published_version:
45
+ published_table.add("version_num", current_published_version.version.version_num)
46
+ else:
47
+ published_table.add(tomlkit.comment("unpublished: no published_version_num"))
48
+ entity_table.add("published", published_table)
49
+
50
+ doc.add("entity", entity_table)
51
+ doc.add(tomlkit.nl())
52
+ doc.add(tomlkit.comment("### Versions"))
53
+
54
+ for entity_version in entity.versions.all():
55
+ version = tomlkit.aot()
56
+ version_table = toml_publishable_entity_version(entity_version)
57
+ version.append(version_table)
58
+ doc.add("version", version)
59
+
60
+ return tomlkit.dumps(doc)
61
+
62
+
63
+ def toml_publishable_entity_version(version: PublishableEntityVersion) -> tomlkit.items.Table:
64
+ """Create a TOML representation of a publishable entity version."""
65
+ version_table = tomlkit.table()
66
+ version_table.add("title", version.title)
67
+ version_table.add("uuid", str(version.uuid))
68
+ version_table.add("version_num", version.version_num)
69
+ container_table = tomlkit.table()
70
+ container_table.add("children", [])
71
+ unit_table = tomlkit.table()
72
+ unit_table.add("graded", True)
73
+ container_table.add("unit", unit_table)
74
+ version_table.add("container", container_table)
75
+ return version_table # For use in AoT
@@ -0,0 +1,53 @@
1
+ """
2
+ This module provides functionality to create a zip file containing the learning package data,
3
+ including a TOML representation of the learning package and its entities.
4
+ """
5
+ import zipfile
6
+ from pathlib import Path
7
+
8
+ from openedx_learning.apps.authoring.backup_restore.toml import toml_learning_package, toml_publishable_entity
9
+ from openedx_learning.apps.authoring.publishing import api as publishing_api
10
+ from openedx_learning.apps.authoring.publishing.models.learning_package import LearningPackage
11
+
12
+ TOML_PACKAGE_NAME = "package.toml"
13
+
14
+
15
+ class LearningPackageZipper:
16
+ """
17
+ A class to handle the zipping of learning content for backup and restore.
18
+ """
19
+
20
+ def __init__(self, learning_package: LearningPackage):
21
+ self.learning_package = learning_package
22
+
23
+ def create_zip(self, path: str) -> None:
24
+ """
25
+ Creates a zip file containing the learning package data.
26
+ Args:
27
+ path (str): The path where the zip file will be created.
28
+ Raises:
29
+ Exception: If the learning package cannot be found or if the zip creation fails.
30
+ """
31
+ package_toml_content: str = toml_learning_package(self.learning_package)
32
+
33
+ with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zipf:
34
+ # Add the package.toml string
35
+ zipf.writestr(TOML_PACKAGE_NAME, package_toml_content)
36
+
37
+ # Add the entities directory
38
+ entities_folder = Path("entities")
39
+ zip_info = zipfile.ZipInfo(str(entities_folder) + "/") # Ensure trailing slash
40
+ zipf.writestr(zip_info, "") # Add explicit empty directory entry
41
+
42
+ # Add the collections directory
43
+ collections_folder = Path("collections")
44
+ collections_info = zipfile.ZipInfo(str(collections_folder) + "/") # Ensure trailing slash
45
+ zipf.writestr(collections_info, "") # Add explicit empty directory
46
+
47
+ # Add each entity's TOML file
48
+ for entity in publishing_api.get_entities(self.learning_package.pk):
49
+ # Create a TOML representation of the entity
50
+ entity_toml_content: str = toml_publishable_entity(entity)
51
+ entity_toml_filename = f"{entity.key}.toml"
52
+ entity_toml_path = entities_folder / entity_toml_filename
53
+ zipf.writestr(str(entity_toml_path), entity_toml_content)
@@ -18,7 +18,7 @@ class ComponentsConfig(AppConfig):
18
18
  """
19
19
  Register Component and ComponentVersion.
20
20
  """
21
- from ..publishing.api import register_content_models # pylint: disable=import-outside-toplevel
21
+ from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel
22
22
  from .models import Component, ComponentVersion # pylint: disable=import-outside-toplevel
23
23
 
24
- register_content_models(Component, ComponentVersion)
24
+ register_publishable_models(Component, ComponentVersion)
@@ -60,6 +60,7 @@ __all__ = [
60
60
  "get_publishable_entity_by_key",
61
61
  "get_last_publish",
62
62
  "get_all_drafts",
63
+ "get_entities",
63
64
  "get_entities_with_unpublished_changes",
64
65
  "get_entities_with_unpublished_deletes",
65
66
  "publish_all_drafts",
@@ -69,7 +70,7 @@ __all__ = [
69
70
  "set_draft_version",
70
71
  "soft_delete_draft",
71
72
  "reset_drafts_to_published",
72
- "register_content_models",
73
+ "register_publishable_models",
73
74
  "filter_publishable_entities",
74
75
  # 🛑 UNSTABLE: All APIs related to containers are unstable until we've figured
75
76
  # out our approach to dynamic content (randomized, A/B tests, etc.)
@@ -261,6 +262,13 @@ def get_all_drafts(learning_package_id: int, /) -> QuerySet[Draft]:
261
262
  )
262
263
 
263
264
 
265
+ def get_entities(learning_package_id: int, /) -> QuerySet[PublishableEntity]:
266
+ """
267
+ Get all entities in a learning package.
268
+ """
269
+ return PublishableEntity.objects.filter(learning_package_id=learning_package_id)
270
+
271
+
264
272
  def get_entities_with_unpublished_changes(
265
273
  learning_package_id: int,
266
274
  /,
@@ -789,7 +797,7 @@ def reset_drafts_to_published(
789
797
  set_draft_version(draft, published_version_id)
790
798
 
791
799
 
792
- def register_content_models(
800
+ def register_publishable_models(
793
801
  content_model_cls: type[PublishableEntityMixin],
794
802
  content_version_model_cls: type[PublishableEntityVersionMixin],
795
803
  ) -> PublishableContentModelRegistry:
@@ -805,10 +813,10 @@ def register_content_models(
805
813
  method. For example, in the components app, this looks like:
806
814
 
807
815
  def ready(self):
808
- from ..publishing.api import register_content_models
816
+ from ..publishing.api import register_publishable_models
809
817
  from .models import Component, ComponentVersion
810
818
 
811
- register_content_models(Component, ComponentVersion)
819
+ register_publishable_models(Component, ComponentVersion)
812
820
 
813
821
  There may be a more clever way to introspect this information from the model
814
822
  metadata, but this is simple and explicit.
@@ -1275,6 +1283,7 @@ def get_entities_in_container(
1275
1283
  container: Container,
1276
1284
  *,
1277
1285
  published: bool,
1286
+ select_related_version: str | None = None,
1278
1287
  ) -> list[ContainerEntityListEntry]:
1279
1288
  """
1280
1289
  [ 🛑 UNSTABLE ]
@@ -1285,14 +1294,35 @@ def get_entities_in_container(
1285
1294
  container: The Container, e.g. returned by `get_container()`
1286
1295
  published: `True` if we want the published version of the container, or
1287
1296
  `False` for the draft version.
1297
+ select_related_version: An optional optimization; specify a relationship
1298
+ on ContainerVersion, like `componentversion` or `containerversion__x`
1299
+ to preload via select_related.
1288
1300
  """
1289
1301
  assert isinstance(container, Container)
1290
- container_version = container.versioning.published if published else container.versioning.draft
1302
+ if published:
1303
+ # Very minor optimization: reload the container with related 1:1 entities
1304
+ container = Container.objects.select_related(
1305
+ "publishable_entity__published__version__containerversion__entity_list").get(pk=container.pk)
1306
+ container_version = container.versioning.published
1307
+ select_related = ["entity__published__version"]
1308
+ if select_related_version:
1309
+ select_related.append(f"entity__published__version__{select_related_version}")
1310
+ else:
1311
+ # Very minor optimization: reload the container with related 1:1 entities
1312
+ container = Container.objects.select_related(
1313
+ "publishable_entity__draft__version__containerversion__entity_list").get(pk=container.pk)
1314
+ container_version = container.versioning.draft
1315
+ select_related = ["entity__draft__version"]
1316
+ if select_related_version:
1317
+ select_related.append(f"entity__draft__version__{select_related_version}")
1291
1318
  if container_version is None:
1292
1319
  raise ContainerVersion.DoesNotExist # This container has not been published yet, or has been deleted.
1293
1320
  assert isinstance(container_version, ContainerVersion)
1294
- entity_list = []
1295
- for row in container_version.entity_list.entitylistrow_set.order_by("order_num"):
1321
+ entity_list: list[ContainerEntityListEntry] = []
1322
+ for row in container_version.entity_list.entitylistrow_set.select_related(
1323
+ "entity_version",
1324
+ *select_related,
1325
+ ).order_by("order_num"):
1296
1326
  entity_version = row.entity_version # This will be set if pinned
1297
1327
  if not entity_version: # If this entity is "unpinned", use the latest published/draft version:
1298
1328
  entity_version = row.entity.published.version if published else row.entity.draft.version
@@ -1385,7 +1415,10 @@ def get_containers_with_entity(
1385
1415
  qs = Container.objects.filter(
1386
1416
  publishable_entity__draft__version__containerversion__entity_list__entitylistrow__entity_id=publishable_entity_pk, # pylint: disable=line-too-long # noqa: E501
1387
1417
  )
1388
- return qs.order_by("pk").distinct() # Ordering is mostly for consistent test cases.
1418
+ return qs.select_related(
1419
+ "publishable_entity__draft__version__containerversion",
1420
+ "publishable_entity__published__version__containerversion",
1421
+ ).order_by("pk").distinct() # Ordering is mostly for consistent test cases.
1389
1422
 
1390
1423
 
1391
1424
  def get_container_children_count(
@@ -19,7 +19,7 @@ class PublishingConfig(AppConfig):
19
19
  """
20
20
  Register Container and ContainerVersion.
21
21
  """
22
- from .api import register_content_models # pylint: disable=import-outside-toplevel
22
+ from .api import register_publishable_models # pylint: disable=import-outside-toplevel
23
23
  from .models import Container, ContainerVersion # pylint: disable=import-outside-toplevel
24
24
 
25
- register_content_models(Container, ContainerVersion)
25
+ register_publishable_models(Container, ContainerVersion)
@@ -272,7 +272,7 @@ class PublishableEntityMixin(models.Model):
272
272
  Please see docstring for PublishableEntity for more details.
273
273
 
274
274
  If you use this class, you *MUST* also use PublishableEntityVersionMixin and
275
- the publishing app's api.register_content_models (see its docstring for
275
+ the publishing app's api.register_publishable_models (see its docstring for
276
276
  details).
277
277
  """
278
278
  # select these related entities by default for all queries
@@ -294,6 +294,10 @@ class PublishableEntityMixin(models.Model):
294
294
  def uuid(self) -> str:
295
295
  return self.publishable_entity.uuid
296
296
 
297
+ @property
298
+ def can_stand_alone(self) -> bool:
299
+ return self.publishable_entity.can_stand_alone
300
+
297
301
  @property
298
302
  def key(self) -> str:
299
303
  return self.publishable_entity.key
@@ -551,7 +555,7 @@ class PublishableEntityVersionMixin(models.Model):
551
555
  Please see docstring for PublishableEntityVersion for more details.
552
556
 
553
557
  If you use this class, you *MUST* also use PublishableEntityMixin and the
554
- publishing app's api.register_content_models (see its docstring for
558
+ publishing app's api.register_publishable_models (see its docstring for
555
559
  details).
556
560
  """
557
561
 
@@ -609,7 +613,7 @@ class PublishableContentModelRegistry:
609
613
  Register what content model maps to what content version model.
610
614
 
611
615
  If you want to call this from another app, please use the
612
- ``register_content_models`` function in this app's ``api`` module
616
+ ``register_publishable_models`` function in this app's ``api`` module
613
617
  instead.
614
618
  """
615
619
  if not issubclass(content_model_cls, PublishableEntityMixin):
@@ -257,7 +257,12 @@ def get_subsections_in_section(
257
257
  """
258
258
  assert isinstance(section, Section)
259
259
  subsections = []
260
- for entry in publishing_api.get_entities_in_container(section, published=published):
260
+ entries = publishing_api.get_entities_in_container(
261
+ section,
262
+ published=published,
263
+ select_related_version="containerversion__subsectionversion",
264
+ )
265
+ for entry in entries:
261
266
  # Convert from generic PublishableEntityVersion to SubsectionVersion:
262
267
  subsection_version = entry.entity_version.containerversion.subsectionversion
263
268
  assert isinstance(subsection_version, SubsectionVersion)
@@ -19,7 +19,7 @@ class SectionsConfig(AppConfig):
19
19
  """
20
20
  Register Section and SectionVersion.
21
21
  """
22
- from ..publishing.api import register_content_models # pylint: disable=import-outside-toplevel
22
+ from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel
23
23
  from .models import Section, SectionVersion # pylint: disable=import-outside-toplevel
24
24
 
25
- register_content_models(Section, SectionVersion)
25
+ register_publishable_models(Section, SectionVersion)
@@ -256,7 +256,12 @@ def get_units_in_subsection(
256
256
  """
257
257
  assert isinstance(subsection, Subsection)
258
258
  units = []
259
- for entry in publishing_api.get_entities_in_container(subsection, published=published):
259
+ entries = publishing_api.get_entities_in_container(
260
+ subsection,
261
+ published=published,
262
+ select_related_version="containerversion__unitversion",
263
+ )
264
+ for entry in entries:
260
265
  # Convert from generic PublishableEntityVersion to UnitVersion:
261
266
  unit_version = entry.entity_version.containerversion.unitversion
262
267
  assert isinstance(unit_version, UnitVersion)
@@ -19,7 +19,7 @@ class SubsectionsConfig(AppConfig):
19
19
  """
20
20
  Register Subsection and SubsectionVersion.
21
21
  """
22
- from ..publishing.api import register_content_models # pylint: disable=import-outside-toplevel
22
+ from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel
23
23
  from .models import Subsection, SubsectionVersion # pylint: disable=import-outside-toplevel
24
24
 
25
- register_content_models(Subsection, SubsectionVersion)
25
+ register_publishable_models(Subsection, SubsectionVersion)
@@ -257,7 +257,12 @@ def get_components_in_unit(
257
257
  """
258
258
  assert isinstance(unit, Unit)
259
259
  components = []
260
- for entry in publishing_api.get_entities_in_container(unit, published=published):
260
+ entries = publishing_api.get_entities_in_container(
261
+ unit,
262
+ published=published,
263
+ select_related_version="componentversion",
264
+ )
265
+ for entry in entries:
261
266
  # Convert from generic PublishableEntityVersion to ComponentVersion:
262
267
  component_version = entry.entity_version.componentversion
263
268
  assert isinstance(component_version, ComponentVersion)
@@ -19,7 +19,7 @@ class UnitsConfig(AppConfig):
19
19
  """
20
20
  Register Unit and UnitVersion.
21
21
  """
22
- from ..publishing.api import register_content_models # pylint: disable=import-outside-toplevel
22
+ from ..publishing.api import register_publishable_models # pylint: disable=import-outside-toplevel
23
23
  from .models import Unit, UnitVersion # pylint: disable=import-outside-toplevel
24
24
 
25
- register_content_models(Unit, UnitVersion)
25
+ register_publishable_models(Unit, UnitVersion)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openedx-learning
3
- Version: 0.27.0
3
+ Version: 0.27.1
4
4
  Summary: Open edX Learning Core and Tagging.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -19,13 +19,13 @@ Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.11
21
21
  License-File: LICENSE.txt
22
- Requires-Dist: Django
23
- Requires-Dist: rules<4.0
24
- Requires-Dist: celery
25
22
  Requires-Dist: djangorestframework<4.0
26
- Requires-Dist: attrs
27
23
  Requires-Dist: tomlkit
24
+ Requires-Dist: celery
25
+ Requires-Dist: Django
26
+ Requires-Dist: attrs
28
27
  Requires-Dist: edx-drf-extensions
28
+ Requires-Dist: rules<4.0
29
29
  Dynamic: author
30
30
  Dynamic: author-email
31
31
  Dynamic: classifier
@@ -23,6 +23,7 @@ openedx_learning/apps/authoring/backup_restore/api.py
23
23
  openedx_learning/apps/authoring/backup_restore/apps.py
24
24
  openedx_learning/apps/authoring/backup_restore/models.py
25
25
  openedx_learning/apps/authoring/backup_restore/toml.py
26
+ openedx_learning/apps/authoring/backup_restore/zipper.py
26
27
  openedx_learning/apps/authoring/backup_restore/management/__init__.py
27
28
  openedx_learning/apps/authoring/backup_restore/management/commands/__init__.py
28
29
  openedx_learning/apps/authoring/backup_restore/management/commands/lp_dump.py
@@ -1,25 +0,0 @@
1
- """
2
- Backup Restore API
3
- """
4
- import zipfile
5
-
6
- from openedx_learning.apps.authoring.publishing.api import get_learning_package_by_key
7
-
8
- from .toml import TOMLLearningPackageFile
9
-
10
- TOML_PACKAGE_NAME = "package.toml"
11
-
12
-
13
- def create_zip_file(lp_key: str, path: str) -> None:
14
- """
15
- Creates a zip file with a toml file so far (WIP)
16
-
17
- Can throw a NotFoundError at get_learning_package_by_key
18
- """
19
- learning_package = get_learning_package_by_key(lp_key)
20
- toml_file = TOMLLearningPackageFile(learning_package)
21
- toml_file.create()
22
- toml_content: str = toml_file.get()
23
- with zipfile.ZipFile(path, "w", compression=zipfile.ZIP_DEFLATED) as zipf:
24
- # Add the TOML string as a file in the ZIP
25
- zipf.writestr(TOML_PACKAGE_NAME, toml_content)
@@ -1,72 +0,0 @@
1
- """
2
- Utilities for backup and restore app
3
- """
4
-
5
- from datetime import datetime
6
- from typing import Any, Dict
7
-
8
- from tomlkit import comment, document, dumps, nl, table
9
- from tomlkit.items import Table
10
-
11
- from openedx_learning.apps.authoring.publishing.models.learning_package import LearningPackage
12
-
13
-
14
- class TOMLLearningPackageFile():
15
- """
16
- Class to create a .toml representation of a LearningPackage instance.
17
-
18
- This class builds a structured TOML document using `tomlkit` with metadata and fields
19
- extracted from a `LearningPackage` object. The output can later be saved to a file or used elsewhere.
20
- """
21
-
22
- def __init__(self, learning_package: LearningPackage):
23
- self.doc = document()
24
- self.learning_package = learning_package
25
-
26
- def _create_header(self) -> None:
27
- """
28
- Adds a comment with the current datetime to indicate when the export occurred.
29
- This helps with traceability and file versioning.
30
- """
31
- self.doc.add(comment(f"Datetime of the export: {datetime.now()}"))
32
- self.doc.add(nl())
33
-
34
- def _create_table(self, params: Dict[str, Any]) -> Table:
35
- """
36
- Builds a TOML table section from a dictionary of key-value pairs.
37
-
38
- Args:
39
- params (Dict[str, Any]): A dictionary containing keys and values to include in the TOML table.
40
-
41
- Returns:
42
- Table: A TOML table populated with the provided keys and values.
43
- """
44
- section = table()
45
- for key, value in params.items():
46
- section.add(key, value)
47
- return section
48
-
49
- def create(self) -> None:
50
- """
51
- Populates the TOML document with a header and a table containing
52
- metadata from the LearningPackage instance.
53
-
54
- This method must be called before calling `get()`, otherwise the document will be empty.
55
- """
56
- self._create_header()
57
- section = self._create_table({
58
- "title": self.learning_package.title,
59
- "key": self.learning_package.key,
60
- "description": self.learning_package.description,
61
- "created": self.learning_package.created,
62
- "updated": self.learning_package.updated
63
- })
64
- self.doc.add("learning_package", section)
65
-
66
- def get(self) -> str:
67
- """
68
- Returns:
69
- str: The string representation of the generated TOML document.
70
- Ensure `create()` has been called beforehand to get meaningful output.
71
- """
72
- return dumps(self.doc)