openedx-learning 0.9.3__py2.py3-none-any.whl → 0.9.4__py2.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.
@@ -1,4 +1,4 @@
1
1
  """
2
2
  Open edX Learning ("Learning Core").
3
3
  """
4
- __version__ = "0.9.3"
4
+ __version__ = "0.9.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openedx-learning
3
- Version: 0.9.3
3
+ Version: 0.9.4
4
4
  Summary: An experiment.
5
5
  Home-page: https://github.com/openedx/openedx-learning
6
6
  Author: David Ormsbee
@@ -19,12 +19,12 @@ Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.8
21
21
  License-File: LICENSE.txt
22
- Requires-Dist: djangorestframework <4.0
23
- Requires-Dist: Django <5.0
24
22
  Requires-Dist: edx-drf-extensions
25
- Requires-Dist: attrs
26
- Requires-Dist: celery
27
23
  Requires-Dist: rules <4.0
24
+ Requires-Dist: celery
25
+ Requires-Dist: Django <5.0
26
+ Requires-Dist: attrs
27
+ Requires-Dist: djangorestframework <4.0
28
28
 
29
29
  openedx-learning
30
30
  =============================
@@ -1,4 +1,4 @@
1
- openedx_learning/__init__.py,sha256=EfjfyOQVIjOVYMNlUo9QxJoi0su5KwN9ncFBkCrXPAk,67
1
+ openedx_learning/__init__.py,sha256=kjHnMSOx6G1q0RhcvJpPELPXo4ytbQqp3XpU6wcZb4A,67
2
2
  openedx_learning/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  openedx_learning/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  openedx_learning/contrib/media_server/__init__.py,sha256=iYijWFCl5RNR9omSu22kMl49EfponoqXBqXr0HMp4QI,56
@@ -55,10 +55,10 @@ openedx_tagging/core/tagging/data.py,sha256=421EvmDzdM7H523dBVQk4J0W_UwTT4U5syqP
55
55
  openedx_tagging/core/tagging/rules.py,sha256=Gzw2RCQxoAv2PpOwOWgpD17XoZfowlFnNgQqYn59q_g,6715
56
56
  openedx_tagging/core/tagging/urls.py,sha256=-0Nzmh0mlF9-GgEuocwBdSJn6n8EINnxR4m4pmPou44,159
57
57
  openedx_tagging/core/tagging/import_export/__init__.py,sha256=q5K4JalFQlJxAFUFyqhLY5zQtAskDnRM1H_aVuP_E3Q,83
58
- openedx_tagging/core/tagging/import_export/actions.py,sha256=1nsGoa7eSfMF4gB-GqNRlTkl22z3Lqo7y8ay1rnNy0E,13368
59
- openedx_tagging/core/tagging/import_export/api.py,sha256=Eio1KeVZB5lsRwZYLR-ECtJfIoPZSyV6ghuUAUSpWNE,6173
58
+ openedx_tagging/core/tagging/import_export/actions.py,sha256=n007-M59D0mXYcwi9CDldDDy5JHAaGCVv9dQbiY4pZ4,13275
59
+ openedx_tagging/core/tagging/import_export/api.py,sha256=n8xamMNsFoucyC_qynpjzkIS2EbOfFDWdhsG_SNT4V0,7120
60
60
  openedx_tagging/core/tagging/import_export/exceptions.py,sha256=GGBldoW0tjYBrSlqDDwKkl6N0FIg1Yt5xcl7efxfo20,3116
61
- openedx_tagging/core/tagging/import_export/import_plan.py,sha256=9JbZ8lMCLPpGqrw9sbcG1b1VvMpiaSuY1vMZCzXR4MA,6627
61
+ openedx_tagging/core/tagging/import_export/import_plan.py,sha256=ol9mLfqqR0t1q0Om7D-iC9zKw1EI9MX3yAEKL8q6ias,6824
62
62
  openedx_tagging/core/tagging/import_export/parsers.py,sha256=eXjMPfMfqcCUKSaXc5xfPEI5PFEK1tNJNGnKHz51tY8,9864
63
63
  openedx_tagging/core/tagging/import_export/tasks.py,sha256=ZNtCGZuWn7z5E5o6OskrKjeV3vzzVa_yHaa-KlCnaEs,924
64
64
  openedx_tagging/core/tagging/import_export/template.csv,sha256=HbmXyW94oyfqfVyiaPv1uBEyul9qb8oPmbk9UiMQYo4,1559
@@ -85,7 +85,7 @@ openedx_tagging/core/tagging/migrations/0017_alter_tagimporttask_status.py,sha25
85
85
  openedx_tagging/core/tagging/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
86
  openedx_tagging/core/tagging/models/__init__.py,sha256=yYdOnthuc7EUdfEULtZgqRwn5Y4bbYQmJCjVZqR5GTM,236
87
87
  openedx_tagging/core/tagging/models/base.py,sha256=1WAPxssL8thAg8LHh1GbwSo98H81-nVdTVQt1nC1ZdU,39335
88
- openedx_tagging/core/tagging/models/import_export.py,sha256=HoYYg4kcKFUro5_i7O6Ms7373zmrDQV4yK3skNWP5fU,4217
88
+ openedx_tagging/core/tagging/models/import_export.py,sha256=Aj0pleh0nh2LNS6zmdB1P4bpdgUMmvmobTkqBerORAI,4570
89
89
  openedx_tagging/core/tagging/models/system_defined.py,sha256=_6LfvUZGEltvQMtm2OXy6TOLh3C8GnVTqtZDSAZW6K4,9062
90
90
  openedx_tagging/core/tagging/models/utils.py,sha256=-A3Dj24twmTf65UB7G4WLvb_9qEvduEPIwahZ-FJDlg,1926
91
91
  openedx_tagging/core/tagging/rest_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -98,8 +98,8 @@ openedx_tagging/core/tagging/rest_api/v1/serializers.py,sha256=gbvEBLvsmfPc3swWz
98
98
  openedx_tagging/core/tagging/rest_api/v1/urls.py,sha256=dNUKCtUCx_YzrwlbEbpDfjGVQbb2QdJ1VuJCkladj6E,752
99
99
  openedx_tagging/core/tagging/rest_api/v1/views.py,sha256=ZRkSILdb8g5k_BcuuVVfdffEdY9vFQ_YtMa3JrN0Xz8,35581
100
100
  openedx_tagging/core/tagging/rest_api/v1/views_import.py,sha256=kbHUPe5A6WaaJ3J1lFIcYCt876ecLNQfd19m7YYub6c,1470
101
- openedx_learning-0.9.3.dist-info/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
102
- openedx_learning-0.9.3.dist-info/METADATA,sha256=qCr7maCmqbhW_lwaYhJRsu6BdicczVsjiRlxdcgJk1g,8860
103
- openedx_learning-0.9.3.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
104
- openedx_learning-0.9.3.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
105
- openedx_learning-0.9.3.dist-info/RECORD,,
101
+ openedx_learning-0.9.4.dist-info/LICENSE.txt,sha256=QTW2QN7q3XszgUAXm9Dzgtu5LXYKbR1SGnqMa7ufEuY,35139
102
+ openedx_learning-0.9.4.dist-info/METADATA,sha256=nmkH-b_5JrqbfKBYGFPv_flMHz_b7TJEnq2oOEXsWb4,8860
103
+ openedx_learning-0.9.4.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
104
+ openedx_learning-0.9.4.dist-info/top_level.txt,sha256=IYFbr5mgiEHd-LOtZmXj3q3a0bkGK1M9LY7GXgnfi4M,33
105
+ openedx_learning-0.9.4.dist-info/RECORD,,
@@ -244,16 +244,13 @@ class CreateTag(ImportAction):
244
244
  """
245
245
  Creates a Tag
246
246
  """
247
- parent = None
248
- if self.tag.parent_id:
249
- parent = self.taxonomy.tag_set.get(external_id=self.tag.parent_id)
250
- taxonomy_tag = Tag(
247
+ Tag.objects.create(
251
248
  taxonomy=self.taxonomy,
252
- parent=parent,
249
+ parent=self.taxonomy.tag_set.get(external_id=self.tag.parent_id)
250
+ if self.tag.parent_id is not None else None,
253
251
  value=self.tag.value,
254
252
  external_id=self.tag.id,
255
253
  )
256
- taxonomy_tag.save()
257
254
 
258
255
 
259
256
  class UpdateParentTag(ImportAction):
@@ -409,8 +406,7 @@ class DeleteTag(ImportAction):
409
406
  Delete a tag
410
407
  """
411
408
  try:
412
- taxonomy_tag = self._get_tag()
413
- taxonomy_tag.delete()
409
+ self._get_tag().delete()
414
410
  except Tag.DoesNotExist:
415
411
  pass # The tag may be already cascade deleted if the parent tag was deleted
416
412
 
@@ -44,6 +44,7 @@ TODO for next versions
44
44
  """
45
45
  from __future__ import annotations
46
46
 
47
+ import time
47
48
  from typing import BinaryIO
48
49
 
49
50
  from django.utils.translation import gettext as _
@@ -77,6 +78,7 @@ def import_tags(
77
78
 
78
79
  Set `plan_only` to True to only generate the actions and not execute them.
79
80
  """
81
+ global_start_time = time.time()
80
82
  _import_validations(taxonomy)
81
83
 
82
84
  # Checks that exists only one task import in progress at a time per taxonomy
@@ -92,7 +94,10 @@ def import_tags(
92
94
  task = TagImportTask.create(taxonomy)
93
95
 
94
96
  try:
97
+ # Start of parsing
98
+
95
99
  # Get the parser and parse the file
100
+ start_time = time.time()
96
101
  task.log_parser_start()
97
102
  parser = get_parser(parser_format)
98
103
  tags, errors = parser.parse_import(file)
@@ -102,23 +107,48 @@ def import_tags(
102
107
  task.handle_parser_errors(errors)
103
108
  return False, task, None
104
109
 
105
- task.log_parser_end()
110
+ end_time = time.time()
111
+ elapsed_time = end_time - start_time
112
+ elapsed_time = round(elapsed_time, 5)
113
+ task.log_parser_end(elapsed_time)
114
+
115
+ # End of parsing
116
+
117
+ # Start of generate actions
118
+
119
+ start_time = time.time()
106
120
 
107
- # Generate actions
108
121
  task.log_start_planning()
109
122
  tag_import_plan = TagImportPlan(taxonomy)
110
123
  tag_import_plan.generate_actions(tags, replace)
111
- task.log_plan(tag_import_plan)
124
+
125
+ end_time = time.time()
126
+ elapsed_time = end_time - start_time
127
+ elapsed_time = round(elapsed_time, 5)
128
+ task.log_plan(tag_import_plan, elapsed_time)
129
+
130
+ # End of generate actions
112
131
 
113
132
  if tag_import_plan.errors:
114
133
  task.handle_plan_errors()
115
134
  return False, task, tag_import_plan
116
135
 
117
136
  if not plan_only:
137
+ # Start of execute
138
+ start_time = time.time()
118
139
  task.log_start_execute()
119
140
  tag_import_plan.execute(task)
141
+ end_time = time.time()
142
+ elapsed_time = end_time - start_time
143
+ elapsed_time = round(elapsed_time, 5)
144
+ task.log_end_execute(elapsed_time)
145
+ # End of execute
146
+
147
+ global_end_time = time.time()
148
+ global_elapsed_time = global_end_time - global_start_time
149
+ global_elapsed_time = round(global_elapsed_time, 5)
120
150
 
121
- task.end_success()
151
+ task.end_success(global_elapsed_time)
122
152
 
123
153
  return True, task, tag_import_plan
124
154
  except Exception as exception:
@@ -207,8 +207,12 @@ class TagImportPlan:
207
207
  if self.errors:
208
208
  return
209
209
  for action in self.actions:
210
+ # Avoid to save each log because it is slow and costs a lot in memory
211
+ # It is necessary to save at the end.
210
212
  if task:
211
- task.add_log(f"#{action.index}: {str(action)} [Started]")
213
+ task.add_log(f"#{action.index}: {str(action)} [Started]", save=False)
212
214
  action.execute()
213
215
  if task:
214
- task.add_log("Success")
216
+ task.add_log("Success", save=False)
217
+ if task:
218
+ task.save()
@@ -90,11 +90,11 @@ class TagImportTask(models.Model):
90
90
  """
91
91
  self.add_log(_("Starting to load data from file"))
92
92
 
93
- def log_parser_end(self):
93
+ def log_parser_end(self, elapsed_time):
94
94
  """
95
95
  Logs the parser finished event.
96
96
  """
97
- self.add_log(_("Load data finished"))
97
+ self.add_log(_("Load data finished. Time elapsed: ") + str(elapsed_time) + _(" seconds"))
98
98
 
99
99
  def handle_parser_errors(self, errors):
100
100
  """
@@ -113,11 +113,11 @@ class TagImportTask(models.Model):
113
113
  self.status = TagImportTaskState.PLANNING.value
114
114
  self.save()
115
115
 
116
- def log_plan(self, plan):
116
+ def log_plan(self, plan, elapsed_time):
117
117
  """
118
118
  Logs the task plan.
119
119
  """
120
- self.add_log(_("Plan finished"))
120
+ self.add_log(_("Plan finished. Time elapsed: ") + str(elapsed_time) + _(" seconds"))
121
121
  plan_str = plan.plan()
122
122
  self.log += f"\n{plan_str}\n"
123
123
  self.save()
@@ -138,10 +138,13 @@ class TagImportTask(models.Model):
138
138
  self.status = TagImportTaskState.EXECUTING.value
139
139
  self.save()
140
140
 
141
- def end_success(self):
141
+ def log_end_execute(self, elapsed_time):
142
+ self.add_log(_("Execute actions finished. Time elapsed: ") + str(elapsed_time) + _(" seconds"))
143
+
144
+ def end_success(self, elapsed_time):
142
145
  """
143
146
  Completes task execution with a log message, and moves the task status to SUCCESS.
144
147
  """
145
- self.add_log(_("Execution finished"), save=False)
148
+ self.add_log(_("Execution finished. Total time elapsed: ") + str(elapsed_time) + _("seconds"), save=False)
146
149
  self.status = TagImportTaskState.SUCCESS.value
147
150
  self.save()