morango 0.7.0__tar.gz → 0.7.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.

Potentially problematic release.


This version of morango might be problematic. Click here for more details.

Files changed (93) hide show
  1. {morango-0.7.0 → morango-0.7.1}/CHANGELOG.md +19 -0
  2. morango-0.7.1/PKG-INFO +58 -0
  3. {morango-0.7.0 → morango-0.7.1}/morango/__init__.py +1 -1
  4. morango-0.7.1/morango/management/commands/cleanupsyncs.py +134 -0
  5. {morango-0.7.0 → morango-0.7.1}/morango/models/core.py +8 -7
  6. {morango-0.7.0 → morango-0.7.1}/morango/sync/session.py +11 -0
  7. {morango-0.7.0 → morango-0.7.1}/morango/sync/syncsession.py +7 -2
  8. morango-0.7.1/morango.egg-info/PKG-INFO +58 -0
  9. {morango-0.7.0 → morango-0.7.1}/requirements/docs.txt +0 -2
  10. {morango-0.7.0 → morango-0.7.1}/setup.cfg +1 -0
  11. morango-0.7.0/PKG-INFO +0 -54
  12. morango-0.7.0/morango/management/commands/cleanupsyncs.py +0 -84
  13. morango-0.7.0/morango.egg-info/PKG-INFO +0 -54
  14. {morango-0.7.0 → morango-0.7.1}/AUTHORS.md +0 -0
  15. {morango-0.7.0 → morango-0.7.1}/LICENSE +0 -0
  16. {morango-0.7.0 → morango-0.7.1}/MANIFEST.in +0 -0
  17. {morango-0.7.0 → morango-0.7.1}/README.md +0 -0
  18. {morango-0.7.0 → morango-0.7.1}/morango/api/__init__.py +0 -0
  19. {morango-0.7.0 → morango-0.7.1}/morango/api/fields.py +0 -0
  20. {morango-0.7.0 → morango-0.7.1}/morango/api/parsers.py +0 -0
  21. {morango-0.7.0 → morango-0.7.1}/morango/api/permissions.py +0 -0
  22. {morango-0.7.0 → morango-0.7.1}/morango/api/serializers.py +0 -0
  23. {morango-0.7.0 → morango-0.7.1}/morango/api/urls.py +0 -0
  24. {morango-0.7.0 → morango-0.7.1}/morango/api/viewsets.py +0 -0
  25. {morango-0.7.0 → morango-0.7.1}/morango/apps.py +0 -0
  26. {morango-0.7.0 → morango-0.7.1}/morango/constants/__init__.py +0 -0
  27. {morango-0.7.0 → morango-0.7.1}/morango/constants/api_urls.py +0 -0
  28. {morango-0.7.0 → morango-0.7.1}/morango/constants/capabilities.py +0 -0
  29. {morango-0.7.0 → morango-0.7.1}/morango/constants/settings.py +0 -0
  30. {morango-0.7.0 → morango-0.7.1}/morango/constants/transfer_stages.py +0 -0
  31. {morango-0.7.0 → morango-0.7.1}/morango/constants/transfer_statuses.py +0 -0
  32. {morango-0.7.0 → morango-0.7.1}/morango/errors.py +0 -0
  33. {morango-0.7.0 → morango-0.7.1}/morango/management/__init__.py +0 -0
  34. {morango-0.7.0 → morango-0.7.1}/morango/management/commands/__init__.py +0 -0
  35. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0001_initial.py +0 -0
  36. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0002_auto_20170511_0400.py +0 -0
  37. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0003_auto_20170519_0543.py +0 -0
  38. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0004_auto_20170520_2112.py +0 -0
  39. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0005_auto_20170629_2139.py +0 -0
  40. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0006_instanceidmodel_system_id.py +0 -0
  41. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0007_auto_20171018_1615.py +0 -0
  42. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0008_auto_20171114_2217.py +0 -0
  43. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0009_auto_20171205_0252.py +0 -0
  44. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0010_auto_20171206_1615.py +0 -0
  45. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0011_sharedkey.py +0 -0
  46. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0012_auto_20180927_1658.py +0 -0
  47. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0013_auto_20190627_1513.py +0 -0
  48. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0014_syncsession_extra_fields.py +0 -0
  49. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0015_auto_20200508_2104.py +0 -0
  50. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0016_store_deserialization_error.py +0 -0
  51. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0017_store_last_transfer_session_id.py +0 -0
  52. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0018_auto_20210714_2216.py +0 -0
  53. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0019_auto_20220113_1807.py +0 -0
  54. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0020_postgres_fix_nullable.py +0 -0
  55. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0021_store_partition_index_create.py +0 -0
  56. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0022_rename_instance_fields.py +0 -0
  57. {morango-0.7.0 → morango-0.7.1}/morango/migrations/0023_add_instance_id_fields.py +0 -0
  58. {morango-0.7.0 → morango-0.7.1}/morango/migrations/__init__.py +0 -0
  59. {morango-0.7.0 → morango-0.7.1}/morango/models/__init__.py +0 -0
  60. {morango-0.7.0 → morango-0.7.1}/morango/models/certificates.py +0 -0
  61. {morango-0.7.0 → morango-0.7.1}/morango/models/fields/__init__.py +0 -0
  62. {morango-0.7.0 → morango-0.7.1}/morango/models/fields/crypto.py +0 -0
  63. {morango-0.7.0 → morango-0.7.1}/morango/models/fields/uuids.py +0 -0
  64. {morango-0.7.0 → morango-0.7.1}/morango/models/fsic_utils.py +0 -0
  65. {morango-0.7.0 → morango-0.7.1}/morango/models/manager.py +0 -0
  66. {morango-0.7.0 → morango-0.7.1}/morango/models/morango_mptt.py +0 -0
  67. {morango-0.7.0 → morango-0.7.1}/morango/models/query.py +0 -0
  68. {morango-0.7.0 → morango-0.7.1}/morango/models/signals.py +0 -0
  69. {morango-0.7.0 → morango-0.7.1}/morango/models/utils.py +0 -0
  70. {morango-0.7.0 → morango-0.7.1}/morango/proquint.py +0 -0
  71. {morango-0.7.0 → morango-0.7.1}/morango/registry.py +0 -0
  72. {morango-0.7.0 → morango-0.7.1}/morango/sync/__init__.py +0 -0
  73. {morango-0.7.0 → morango-0.7.1}/morango/sync/backends/__init__.py +0 -0
  74. {morango-0.7.0 → morango-0.7.1}/morango/sync/backends/base.py +0 -0
  75. {morango-0.7.0 → morango-0.7.1}/morango/sync/backends/postgres.py +0 -0
  76. {morango-0.7.0 → morango-0.7.1}/morango/sync/backends/sqlite.py +0 -0
  77. {morango-0.7.0 → morango-0.7.1}/morango/sync/backends/utils.py +0 -0
  78. {morango-0.7.0 → morango-0.7.1}/morango/sync/context.py +0 -0
  79. {morango-0.7.0 → morango-0.7.1}/morango/sync/controller.py +0 -0
  80. {morango-0.7.0 → morango-0.7.1}/morango/sync/operations.py +0 -0
  81. {morango-0.7.0 → morango-0.7.1}/morango/sync/utils.py +0 -0
  82. {morango-0.7.0 → morango-0.7.1}/morango/urls.py +0 -0
  83. {morango-0.7.0 → morango-0.7.1}/morango/utils.py +0 -0
  84. {morango-0.7.0 → morango-0.7.1}/morango.egg-info/SOURCES.txt +0 -0
  85. {morango-0.7.0 → morango-0.7.1}/morango.egg-info/dependency_links.txt +0 -0
  86. {morango-0.7.0 → morango-0.7.1}/morango.egg-info/not-zip-safe +0 -0
  87. {morango-0.7.0 → morango-0.7.1}/morango.egg-info/requires.txt +0 -0
  88. {morango-0.7.0 → morango-0.7.1}/morango.egg-info/top_level.txt +0 -0
  89. {morango-0.7.0 → morango-0.7.1}/requirements/accelerated.txt +0 -0
  90. {morango-0.7.0 → morango-0.7.1}/requirements/dev.txt +0 -0
  91. {morango-0.7.0 → morango-0.7.1}/requirements/postgres.txt +0 -0
  92. {morango-0.7.0 → morango-0.7.1}/requirements/test.txt +0 -0
  93. {morango-0.7.0 → morango-0.7.1}/setup.py +0 -0
@@ -2,6 +2,25 @@
2
2
 
3
3
  List of the most important changes for each release.
4
4
 
5
+ ## 0.7.1
6
+ - Supersedes 0.7.0
7
+ - Drops support for Python 3.4 and 3.5
8
+ - Upgrades cryptography library to 3.3.2, the latest version that supports Python 2.7
9
+
10
+ ## 0.6.19
11
+ - The `cleanupsyncs` management command now only cleans up sync sessions if also inactive for `expiration` amount of time
12
+ - Fixes issue accessing index on queryset in `cleanupsyncs` management command
13
+
14
+ ## 0.6.18
15
+ - Prevent creation of Deleted and HardDeleted models during deserialization to allow propagation of syncable objects that are recreated after a previous deletion without causing a merge conflict.
16
+
17
+ ## 0.6.17
18
+ - Added `client-instance-id`, `server-instance-id`, `sync-filter`, `push` and `pull` arguments to `cleanupsyncs` management command
19
+ - Added option for resuming a sync to ignore the `SyncSession`'s existing `process_id`
20
+ - Added custom user agent to sync HTTP requests
21
+ - Fixed documentation build issues
22
+ - Makefile no longer defines shell with explicit path
23
+
5
24
  ## 0.6.16
6
25
  - Added dedicated `client_instance_id` and `server_instance_id` fields to `SyncSession`
7
26
  - Renamed `client_instance` and `server_instance` fields on `SyncSession` to `client_instance_json` and `server_instance_json` respectively
morango-0.7.1/PKG-INFO ADDED
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.1
2
+ Name: morango
3
+ Version: 0.7.1
4
+ Summary: Pure Python sqlite-based Django DB replication engine.
5
+ Home-page: https://github.com/learningequality/morango
6
+ Author: Learning Equality
7
+ Author-email: dev@learningequality.org
8
+ License: MIT
9
+ Keywords: database,syncing,morango
10
+ Platform: UNKNOWN
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Programming Language :: Python :: 2.7
16
+ Classifier: Programming Language :: Python :: 3.6
17
+ Classifier: Programming Language :: Python :: 3.7
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ License-File: AUTHORS.md
25
+
26
+ # Morango
27
+
28
+ [![build](https://github.com/learningequality/morango/actions/workflows/tox.yml/badge.svg?branch=master)](https://github.com/learningequality/morango/actions)
29
+ [![image](http://codecov.io/github/learningequality/morango/coverage.svg?branch=master)](http://codecov.io/github/learningequality/morango?branch=master)
30
+ [![image](https://readthedocs.org/projects/morango/badge/?version=latest)](http://morango.readthedocs.org/en/latest/)
31
+
32
+ Morango is a pure-Python database replication engine for Django that supports peer-to-peer syncing of data. It is structured as a Django app that can be included in projects to make specific application models syncable.
33
+
34
+ Developed in support of the [Kolibri](https://github.com/learningequality/kolibri) product ecosystem, Morango includes some important features including:
35
+
36
+ - A certificate-based authentication system to protect privacy and integrity of data
37
+ - A change-tracking system to support calculation of differences between databases across low-bandwidth connections
38
+ - A set of constructs to support data partitioning
39
+
40
+ ## Developer documentation
41
+
42
+ See [morango.readthedocs.io](https://morango.readthedocs.io)
43
+
44
+ To build and edit the docs, run:
45
+
46
+ ```bash
47
+ # install requirements
48
+ pip install -r requirements/docs.txt
49
+ pip install -e .
50
+
51
+ # build docs
52
+ make docs
53
+
54
+ # auto-build and refresh docs on edit
55
+ make docs-autobuild
56
+ ```
57
+
58
+
@@ -3,4 +3,4 @@ from __future__ import print_function
3
3
  from __future__ import unicode_literals
4
4
 
5
5
  default_app_config = "morango.apps.MorangoConfig"
6
- __version__ = "0.7.0"
6
+ __version__ = "0.7.1"
@@ -0,0 +1,134 @@
1
+ import datetime
2
+ import logging
3
+ import uuid
4
+
5
+ from django.core.management.base import BaseCommand
6
+ from django.db import transaction
7
+ from django.utils import timezone
8
+
9
+ from morango.models import SyncSession
10
+ from morango.models import TransferSession
11
+
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class Command(BaseCommand):
17
+ help = "Closes and cleans up the data for any incomplete sync sessions older than a certain number of hours."
18
+
19
+ def add_arguments(self, parser):
20
+ parser.add_argument(
21
+ "--ids",
22
+ type=lambda ids: ids.split(","),
23
+ default=None,
24
+ help="Comma separated list of SyncSession IDs to filter against"
25
+ )
26
+ parser.add_argument(
27
+ "--expiration",
28
+ action="store",
29
+ type=int,
30
+ default=6,
31
+ help="Number of hours of inactivity after which a session should be considered stale",
32
+ )
33
+ parser.add_argument(
34
+ "--client-instance-id",
35
+ type=uuid.UUID,
36
+ default=None,
37
+ help="Filters the SyncSession models to those with matching 'client_instance_id'",
38
+ )
39
+ parser.add_argument(
40
+ "--server-instance-id",
41
+ type=uuid.UUID,
42
+ default=None,
43
+ help="Filters the SyncSession models to those with matching 'server_instance_id'",
44
+ )
45
+ parser.add_argument(
46
+ "--sync-filter",
47
+ type=str,
48
+ default=None,
49
+ help="Filters the TransferSession models to those with 'filters' starting with 'sync_filter'",
50
+ )
51
+ parser.add_argument(
52
+ "--push",
53
+ type=bool,
54
+ default=None,
55
+ help="Filters the TransferSession models to those with 'push' set to True",
56
+ )
57
+ parser.add_argument(
58
+ "--pull",
59
+ type=bool,
60
+ default=None,
61
+ help="Filters the TransferSession models to those with 'push' set to False",
62
+ )
63
+
64
+ def handle(self, *args, **options):
65
+
66
+ # establish the cutoff time and date for stale sessions
67
+ cutoff = timezone.now() - datetime.timedelta(hours=options["expiration"])
68
+
69
+ sync_sessions = SyncSession.objects.filter(active=True)
70
+
71
+ # if ids arg was passed, filter down sessions to only those IDs
72
+ # if included by expiration filter
73
+ if options["ids"]:
74
+ sync_sessions = sync_sessions.filter(id__in=options["ids"])
75
+
76
+ if options["client_instance_id"]:
77
+ sync_sessions = sync_sessions.filter(client_instance_id=options["client_instance_id"])
78
+
79
+ if options["server_instance_id"]:
80
+ sync_sessions = sync_sessions.filter(server_instance_id=options["server_instance_id"])
81
+
82
+ # retrieve all sessions still marked as active but with no activity since the cutoff
83
+ transfer_sessions = TransferSession.objects.filter(
84
+ sync_session_id__in=sync_sessions.values("id"),
85
+ active=True,
86
+ last_activity_timestamp__lt=cutoff,
87
+ )
88
+
89
+ if options["sync_filter"]:
90
+ transfer_sessions = transfer_sessions.filter(filter__startswith=options["sync_filter"])
91
+
92
+ if options["push"] and not options["pull"]:
93
+ transfer_sessions = transfer_sessions.filter(push=True)
94
+
95
+ if options["pull"] and not options["push"]:
96
+ transfer_sessions = transfer_sessions.filter(push=False)
97
+
98
+ transfer_count = transfer_sessions.count()
99
+
100
+ # loop over the stale sessions one by one to close them out
101
+ for i, transfer_session in enumerate(transfer_sessions):
102
+ logger.info(
103
+ "TransferSession {} of {}: deleting {} Buffers and {} RMC Buffers...".format(
104
+ i + 1,
105
+ transfer_count,
106
+ transfer_session.buffer_set.all().count(),
107
+ transfer_session.recordmaxcounterbuffer_set.all().count(),
108
+ )
109
+ )
110
+
111
+ # delete buffer data and mark as inactive
112
+ with transaction.atomic():
113
+ transfer_session.delete_buffers()
114
+ transfer_session.active = False
115
+ transfer_session.save()
116
+
117
+ # in order to close a sync session, it must have no active transfer sessions
118
+ # and must have no activity since the cutoff
119
+ sync_sessions = sync_sessions.filter(
120
+ last_activity_timestamp__lt=cutoff,
121
+ ).exclude(
122
+ transfersession__active=True,
123
+ )
124
+ sync_count = sync_sessions.count()
125
+
126
+ for i, sync_session in enumerate(sync_sessions):
127
+ logger.info(
128
+ "Closing SyncSession {} of {}".format(
129
+ i + 1,
130
+ sync_count,
131
+ )
132
+ )
133
+ sync_session.active = False
134
+ sync_session.save()
@@ -17,6 +17,7 @@ from django.db.models import F
17
17
  from django.db.models import Func
18
18
  from django.db.models import Max
19
19
  from django.db.models import Q
20
+ from django.db.models import signals
20
21
  from django.db.models import TextField
21
22
  from django.db.models import Value
22
23
  from django.db.models.deletion import Collector
@@ -468,13 +469,13 @@ class Store(AbstractStore):
468
469
  klass_model = syncable_models.get_model(self.profile, self.model_name)
469
470
  # if store model marked as deleted, attempt to delete in app layer
470
471
  if self.deleted:
471
- # if hard deleted, propagate to related models
472
- if self.hard_deleted:
473
- try:
474
- klass_model.objects.get(id=self.id).delete(hard_delete=True)
475
- except klass_model.DoesNotExist:
476
- pass
477
- else:
472
+ # Don't differentiate between deletion and hard deletion here,
473
+ # as we don't want to add additional tracking for models in either case,
474
+ # just to actually delete them.
475
+ # Import here to avoid circular import, as the utils module
476
+ # imports core models.
477
+ from morango.sync.utils import mute_signals
478
+ with mute_signals(signals.post_delete):
478
479
  klass_model.objects.filter(id=self.id).delete()
479
480
  return None, deferred_fks
480
481
  else:
@@ -1,11 +1,13 @@
1
1
  import logging
2
2
 
3
3
  from requests import exceptions
4
+ from morango import __version__
4
5
  from requests.sessions import Session
5
6
  from requests.utils import super_len
6
7
  from requests.packages.urllib3.util.url import parse_url
7
8
 
8
9
  from morango.utils import serialize_capabilities_to_client_request
10
+ from morango.utils import SETTINGS
9
11
 
10
12
 
11
13
  logger = logging.getLogger(__name__)
@@ -35,6 +37,15 @@ class SessionWrapper(Session):
35
37
  bytes_sent = 0
36
38
  bytes_received = 0
37
39
 
40
+ def __init__(self):
41
+ super(SessionWrapper, self).__init__()
42
+ user_agent_header = "morango/{}".format(__version__)
43
+ if SETTINGS.CUSTOM_INSTANCE_INFO is not None:
44
+ instances = list(SETTINGS.CUSTOM_INSTANCE_INFO)
45
+ if instances:
46
+ user_agent_header += " " + "{}/{}".format(instances[0], SETTINGS.CUSTOM_INSTANCE_INFO.get(instances[0]))
47
+ self.headers["User-Agent"] = "{} {}".format(user_agent_header, self.headers["User-Agent"])
48
+
38
49
  def request(self, method, url, **kwargs):
39
50
  response = None
40
51
  try:
@@ -260,12 +260,16 @@ class NetworkSyncConnection(Connection):
260
260
  sync_session = SyncSession.objects.create(**data)
261
261
  return SyncSessionClient(self, sync_session)
262
262
 
263
- def resume_sync_session(self, sync_session_id, chunk_size=None):
263
+ def resume_sync_session(self, sync_session_id, chunk_size=None, ignore_existing_process=False):
264
264
  """
265
265
  Resumes an existing sync session given an ID
266
266
 
267
267
  :param sync_session_id: The UUID of the `SyncSession` to resume
268
268
  :param chunk_size: An optional parameter specifying the size for each transferred chunk
269
+ :type chunk_size: int
270
+ :param ignore_existing_process:An optional parameter specifying whether to ignore an
271
+ existing active process ID
272
+ :type ignore_existing_process: bool
269
273
  :return: A SyncSessionClient instance
270
274
  :rtype: SyncSessionClient
271
275
  """
@@ -281,7 +285,8 @@ class NetworkSyncConnection(Connection):
281
285
 
282
286
  # check that process of existing session isn't still running
283
287
  if (
284
- sync_session.process_id
288
+ not ignore_existing_process
289
+ and sync_session.process_id
285
290
  and sync_session.process_id != os.getpid()
286
291
  and pid_exists(sync_session.process_id)
287
292
  ):
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.1
2
+ Name: morango
3
+ Version: 0.7.1
4
+ Summary: Pure Python sqlite-based Django DB replication engine.
5
+ Home-page: https://github.com/learningequality/morango
6
+ Author: Learning Equality
7
+ Author-email: dev@learningequality.org
8
+ License: MIT
9
+ Keywords: database,syncing,morango
10
+ Platform: UNKNOWN
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Programming Language :: Python :: 2.7
16
+ Classifier: Programming Language :: Python :: 3.6
17
+ Classifier: Programming Language :: Python :: 3.7
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ License-File: AUTHORS.md
25
+
26
+ # Morango
27
+
28
+ [![build](https://github.com/learningequality/morango/actions/workflows/tox.yml/badge.svg?branch=master)](https://github.com/learningequality/morango/actions)
29
+ [![image](http://codecov.io/github/learningequality/morango/coverage.svg?branch=master)](http://codecov.io/github/learningequality/morango?branch=master)
30
+ [![image](https://readthedocs.org/projects/morango/badge/?version=latest)](http://morango.readthedocs.org/en/latest/)
31
+
32
+ Morango is a pure-Python database replication engine for Django that supports peer-to-peer syncing of data. It is structured as a Django app that can be included in projects to make specific application models syncable.
33
+
34
+ Developed in support of the [Kolibri](https://github.com/learningequality/kolibri) product ecosystem, Morango includes some important features including:
35
+
36
+ - A certificate-based authentication system to protect privacy and integrity of data
37
+ - A change-tracking system to support calculation of differences between databases across low-bandwidth connections
38
+ - A set of constructs to support data partitioning
39
+
40
+ ## Developer documentation
41
+
42
+ See [morango.readthedocs.io](https://morango.readthedocs.io)
43
+
44
+ To build and edit the docs, run:
45
+
46
+ ```bash
47
+ # install requirements
48
+ pip install -r requirements/docs.txt
49
+ pip install -e .
50
+
51
+ # build docs
52
+ make docs
53
+
54
+ # auto-build and refresh docs on edit
55
+ make docs-autobuild
56
+ ```
57
+
58
+
@@ -15,5 +15,3 @@ djangorestframework==3.9.1
15
15
  django-mptt==0.9.1
16
16
  rsa==3.4.2
17
17
  ifcfg==0.21
18
-
19
- -r ./accelerated.txt
@@ -36,6 +36,7 @@ exclude_lines =
36
36
  raise NotImplementedError
37
37
  raise AssertionError
38
38
  raise NotImplementedError
39
+
39
40
  if __name__ == .__main__.:
40
41
 
41
42
  [egg_info]
morango-0.7.0/PKG-INFO DELETED
@@ -1,54 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: morango
3
- Version: 0.7.0
4
- Summary: Pure Python sqlite-based Django DB replication engine.
5
- Home-page: https://github.com/learningequality/morango
6
- Author: Learning Equality
7
- Author-email: dev@learningequality.org
8
- License: MIT
9
- Description: # Morango
10
-
11
- [![build](https://github.com/learningequality/morango/actions/workflows/tox.yml/badge.svg?branch=master)](https://github.com/learningequality/morango/actions)
12
- [![image](http://codecov.io/github/learningequality/morango/coverage.svg?branch=master)](http://codecov.io/github/learningequality/morango?branch=master)
13
- [![image](https://readthedocs.org/projects/morango/badge/?version=latest)](http://morango.readthedocs.org/en/latest/)
14
-
15
- Morango is a pure-Python database replication engine for Django that supports peer-to-peer syncing of data. It is structured as a Django app that can be included in projects to make specific application models syncable.
16
-
17
- Developed in support of the [Kolibri](https://github.com/learningequality/kolibri) product ecosystem, Morango includes some important features including:
18
-
19
- - A certificate-based authentication system to protect privacy and integrity of data
20
- - A change-tracking system to support calculation of differences between databases across low-bandwidth connections
21
- - A set of constructs to support data partitioning
22
-
23
- ## Developer documentation
24
-
25
- See [morango.readthedocs.io](https://morango.readthedocs.io)
26
-
27
- To build and edit the docs, run:
28
-
29
- ```bash
30
- # install requirements
31
- pip install -r requirements/docs.txt
32
- pip install -e .
33
-
34
- # build docs
35
- make docs
36
-
37
- # auto-build and refresh docs on edit
38
- make docs-autobuild
39
- ```
40
-
41
- Keywords: database,syncing,morango
42
- Platform: UNKNOWN
43
- Classifier: Intended Audience :: Developers
44
- Classifier: License :: OSI Approved :: MIT License
45
- Classifier: Natural Language :: English
46
- Classifier: Development Status :: 4 - Beta
47
- Classifier: Programming Language :: Python :: 2.7
48
- Classifier: Programming Language :: Python :: 3.6
49
- Classifier: Programming Language :: Python :: 3.7
50
- Classifier: Programming Language :: Python :: 3.8
51
- Classifier: Programming Language :: Python :: 3.9
52
- Classifier: Programming Language :: Python :: 3.10
53
- Classifier: Programming Language :: Python :: 3.11
54
- Description-Content-Type: text/markdown
@@ -1,84 +0,0 @@
1
- import datetime
2
- import logging
3
-
4
- from django.core.management.base import BaseCommand
5
- from django.db import transaction
6
- from django.utils import timezone
7
-
8
- from morango.models import SyncSession
9
- from morango.models import TransferSession
10
-
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
-
15
- class Command(BaseCommand):
16
- help = "Closes and cleans up the data for any incomplete sync sessions older than a certain number of hours."
17
-
18
- def add_arguments(self, parser):
19
- parser.add_argument(
20
- "--ids",
21
- type=lambda ids: ids.split(","),
22
- default=None,
23
- help="Comma separated list of SyncSession IDs to filter against"
24
- )
25
- parser.add_argument(
26
- "--expiration",
27
- action="store",
28
- type=int,
29
- default=6,
30
- help="Number of hours of inactivity after which a session should be considered stale",
31
- )
32
-
33
- def handle(self, *args, **options):
34
-
35
- # establish the cutoff time and date for stale sessions
36
- cutoff = timezone.now() - datetime.timedelta(hours=options["expiration"])
37
-
38
- sync_sessions = SyncSession.objects.filter(active=True)
39
-
40
- # if ids arg was passed, filter down sessions to only those IDs if included by expiration filter
41
- if options["ids"]:
42
- sync_sessions = sync_sessions.filter(id__in=options["ids"])
43
-
44
- # retrieve all sessions still marked as active but with no activity since the cutoff
45
- transfer_sessions = TransferSession.objects.filter(
46
- sync_session_id__in=sync_sessions.values("id"),
47
- active=True,
48
- last_activity_timestamp__lt=cutoff,
49
- )
50
-
51
- transfer_count = transfer_sessions.count()
52
-
53
- # loop over the stale sessions one by one to close them out
54
- for i in range(transfer_count):
55
- transfer_session = transfer_sessions[0]
56
- logger.info(
57
- "TransferSession {} of {}: deleting {} Buffers and {} RMC Buffers...".format(
58
- i + 1,
59
- transfer_count,
60
- transfer_session.buffer_set.all().count(),
61
- transfer_session.recordmaxcounterbuffer_set.all().count(),
62
- )
63
- )
64
-
65
- # delete buffer data and mark as inactive
66
- with transaction.atomic():
67
- transfer_session.delete_buffers()
68
- transfer_session.active = False
69
- transfer_session.save()
70
-
71
- sync_count = sync_sessions.count()
72
-
73
- # finally loop over sync sessions and close out if there are no other active transfer sessions
74
- for i in range(sync_count):
75
- sync_session = sync_sessions[0]
76
- if not sync_session.transfersession_set.filter(active=True).exists():
77
- logger.info(
78
- "Closing SyncSession {} of {}".format(
79
- i + 1,
80
- sync_count,
81
- )
82
- )
83
- sync_session.active = False
84
- sync_session.save()
@@ -1,54 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: morango
3
- Version: 0.7.0
4
- Summary: Pure Python sqlite-based Django DB replication engine.
5
- Home-page: https://github.com/learningequality/morango
6
- Author: Learning Equality
7
- Author-email: dev@learningequality.org
8
- License: MIT
9
- Description: # Morango
10
-
11
- [![build](https://github.com/learningequality/morango/actions/workflows/tox.yml/badge.svg?branch=master)](https://github.com/learningequality/morango/actions)
12
- [![image](http://codecov.io/github/learningequality/morango/coverage.svg?branch=master)](http://codecov.io/github/learningequality/morango?branch=master)
13
- [![image](https://readthedocs.org/projects/morango/badge/?version=latest)](http://morango.readthedocs.org/en/latest/)
14
-
15
- Morango is a pure-Python database replication engine for Django that supports peer-to-peer syncing of data. It is structured as a Django app that can be included in projects to make specific application models syncable.
16
-
17
- Developed in support of the [Kolibri](https://github.com/learningequality/kolibri) product ecosystem, Morango includes some important features including:
18
-
19
- - A certificate-based authentication system to protect privacy and integrity of data
20
- - A change-tracking system to support calculation of differences between databases across low-bandwidth connections
21
- - A set of constructs to support data partitioning
22
-
23
- ## Developer documentation
24
-
25
- See [morango.readthedocs.io](https://morango.readthedocs.io)
26
-
27
- To build and edit the docs, run:
28
-
29
- ```bash
30
- # install requirements
31
- pip install -r requirements/docs.txt
32
- pip install -e .
33
-
34
- # build docs
35
- make docs
36
-
37
- # auto-build and refresh docs on edit
38
- make docs-autobuild
39
- ```
40
-
41
- Keywords: database,syncing,morango
42
- Platform: UNKNOWN
43
- Classifier: Intended Audience :: Developers
44
- Classifier: License :: OSI Approved :: MIT License
45
- Classifier: Natural Language :: English
46
- Classifier: Development Status :: 4 - Beta
47
- Classifier: Programming Language :: Python :: 2.7
48
- Classifier: Programming Language :: Python :: 3.6
49
- Classifier: Programming Language :: Python :: 3.7
50
- Classifier: Programming Language :: Python :: 3.8
51
- Classifier: Programming Language :: Python :: 3.9
52
- Classifier: Programming Language :: Python :: 3.10
53
- Classifier: Programming Language :: Python :: 3.11
54
- Description-Content-Type: text/markdown
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes