morango 0.7.0__py2.py3-none-any.whl → 0.7.1__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.

Potentially problematic release.


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

morango/__init__.py CHANGED
@@ -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"
@@ -1,5 +1,6 @@
1
1
  import datetime
2
2
  import logging
3
+ import uuid
3
4
 
4
5
  from django.core.management.base import BaseCommand
5
6
  from django.db import transaction
@@ -29,6 +30,36 @@ class Command(BaseCommand):
29
30
  default=6,
30
31
  help="Number of hours of inactivity after which a session should be considered stale",
31
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
+ )
32
63
 
33
64
  def handle(self, *args, **options):
34
65
 
@@ -37,10 +68,17 @@ class Command(BaseCommand):
37
68
 
38
69
  sync_sessions = SyncSession.objects.filter(active=True)
39
70
 
40
- # if ids arg was passed, filter down sessions to only those IDs if included by expiration filter
71
+ # if ids arg was passed, filter down sessions to only those IDs
72
+ # if included by expiration filter
41
73
  if options["ids"]:
42
74
  sync_sessions = sync_sessions.filter(id__in=options["ids"])
43
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
+
44
82
  # retrieve all sessions still marked as active but with no activity since the cutoff
45
83
  transfer_sessions = TransferSession.objects.filter(
46
84
  sync_session_id__in=sync_sessions.values("id"),
@@ -48,11 +86,19 @@ class Command(BaseCommand):
48
86
  last_activity_timestamp__lt=cutoff,
49
87
  )
50
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
+
51
98
  transfer_count = transfer_sessions.count()
52
99
 
53
100
  # 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]
101
+ for i, transfer_session in enumerate(transfer_sessions):
56
102
  logger.info(
57
103
  "TransferSession {} of {}: deleting {} Buffers and {} RMC Buffers...".format(
58
104
  i + 1,
@@ -68,17 +114,21 @@ class Command(BaseCommand):
68
114
  transfer_session.active = False
69
115
  transfer_session.save()
70
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
+ )
71
124
  sync_count = sync_sessions.count()
72
125
 
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
- )
126
+ for i, sync_session in enumerate(sync_sessions):
127
+ logger.info(
128
+ "Closing SyncSession {} of {}".format(
129
+ i + 1,
130
+ sync_count,
82
131
  )
83
- sync_session.active = False
84
- sync_session.save()
132
+ )
133
+ sync_session.active = False
134
+ sync_session.save()
morango/models/core.py CHANGED
@@ -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:
morango/sync/session.py CHANGED
@@ -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
  ):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: morango
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Pure Python sqlite-based Django DB replication engine.
5
5
  Home-page: https://github.com/learningequality/morango
6
6
  Author: Learning Equality
@@ -20,12 +20,14 @@ Classifier: Programming Language :: Python :: 3.9
20
20
  Classifier: Programming Language :: Python :: 3.10
21
21
  Classifier: Programming Language :: Python :: 3.11
22
22
  Description-Content-Type: text/markdown
23
- Requires-Dist: django (<2,>=1.10)
24
- Requires-Dist: django-mptt (<0.10.0)
25
- Requires-Dist: rsa (<3.5,>=3.4.2)
26
- Requires-Dist: djangorestframework (==3.9.1)
27
- Requires-Dist: django-ipware (<1.2,>=1.1.6)
28
- Requires-Dist: future (==0.16.0)
23
+ License-File: LICENSE
24
+ License-File: AUTHORS.md
25
+ Requires-Dist: django <2,>=1.10
26
+ Requires-Dist: django-mptt <0.10.0
27
+ Requires-Dist: rsa <3.5,>=3.4.2
28
+ Requires-Dist: djangorestframework ==3.9.1
29
+ Requires-Dist: django-ipware <1.2,>=1.1.6
30
+ Requires-Dist: future ==0.16.0
29
31
  Requires-Dist: requests
30
32
  Requires-Dist: ifcfg
31
33
 
@@ -1,4 +1,4 @@
1
- morango/__init__.py,sha256=Ou8LIEKHUoQQBn7VeoYWZvCz8vDRklNUI0mc_9p8pKU,190
1
+ morango/__init__.py,sha256=4JEWqdXPhqGXLmHDKnCM3ASxeQQ1jNJYFbtMSpnikdQ,190
2
2
  morango/apps.py,sha256=qJ0Tu2YmprNC-7iYlOb1OTG-JxRAweHLnbyb5kHlU9U,546
3
3
  morango/errors.py,sha256=okjt7FqSHIf3x9SmnmoW6aqNJ_g7Ye3Fx7tuQSNUYEI,1223
4
4
  morango/proquint.py,sha256=oHlbNPi7bkqylUhRbq9GbpdtywxU0AXKslJrowcsrqg,3735
@@ -20,7 +20,7 @@ morango/constants/transfer_stages.py,sha256=nmM-ywKPFcwOICPkHN_1e4xFOWTxwnvb99hr
20
20
  morango/constants/transfer_statuses.py,sha256=__Reiqxal53Obq-Hch-Ty-HJwlEUZLFSBdRF9ytim0I,510
21
21
  morango/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  morango/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- morango/management/commands/cleanupsyncs.py,sha256=cOgm5p9hO_xyPUSOmNw5r76WyGej2n7h9SN7bTmuAiE,3044
23
+ morango/management/commands/cleanupsyncs.py,sha256=Huaz8etLNbmW8X-Vy4x1QY801JYln0iyaeUTJF2L3kE,4833
24
24
  morango/migrations/0001_initial.py,sha256=ZUmqmw6DneAFBfsfhapyC3cIDneV9zqC7Lws61UN2VA,11933
25
25
  morango/migrations/0002_auto_20170511_0400.py,sha256=6gTEf4g56Y6ZvL0UHGK0AQvURPaWuAmpRVKONdP1GH4,2304
26
26
  morango/migrations/0003_auto_20170519_0543.py,sha256=ltBTLl130cjwtRao0zw_FXkEWMrGMTRj1mpgpJmaWP0,682
@@ -47,7 +47,7 @@ morango/migrations/0023_add_instance_id_fields.py,sha256=lgTETXKFcXM1CnNwXb6kqJ3
47
47
  morango/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  morango/models/__init__.py,sha256=6sTAlg7gpmX9xRmjw4GPLdjh6_FzZJEN-WEtRBsgGA8,1983
49
49
  morango/models/certificates.py,sha256=Kc4aDNJZMp4JQMqdpZDx6zp-qqG_OhAa5n4f-Q605r8,15331
50
- morango/models/core.py,sha256=z4JDnyys5p_VJqEco2_7Ut7F4xZ1T_yUdZcJpEtKdjs,38771
50
+ morango/models/core.py,sha256=64iEy1DTm_gEyJs4L9BQ8m7FTXkVMyawglIuziqrKmc,38940
51
51
  morango/models/fsic_utils.py,sha256=B9RM-uPZFvEXWbsPeeit5qA21gKGpA0NkKCLFIdNI_0,7130
52
52
  morango/models/manager.py,sha256=fzzX7k8qV5W5dMBb0ASOBNRJRpvQZbEG1hgyuMtzt4g,163
53
53
  morango/models/morango_mptt.py,sha256=K_ZF0lRv3EX6n5K5iCSCjDx4qVnMIG_gq9dAyIIQLIU,1024
@@ -61,17 +61,17 @@ morango/sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  morango/sync/context.py,sha256=_gqfE-RfTIn0UMKFeI2snIJEGCbmR_NRl-Ts5u35B7Q,17815
62
62
  morango/sync/controller.py,sha256=rcibQcq579hneUef2p41Ze4OCysLI7rVz6FCFIfYiVA,11575
63
63
  morango/sync/operations.py,sha256=jDIHPF8IdqoUOer3aaoq9VHcL0-BVeS7-wlMxMHA1-w,69494
64
- morango/sync/session.py,sha256=SDM120mzRItszCpVmWBGNWbJX9S-f8kUj0NB9MFmPDI,3293
65
- morango/sync/syncsession.py,sha256=KxKGayO_fy0TMPf_NOa0XfltMLWd2Eymt9aLTeXC7HI,25198
64
+ morango/sync/session.py,sha256=9CTLhpEPM8q1M_b2HHxouZbzm7vBJoImoqPWqdodgII,3853
65
+ morango/sync/syncsession.py,sha256=82u95pFN68-Fk9fm63q8dueZ4lZyuDsvhtEe3fZFrMI,25479
66
66
  morango/sync/utils.py,sha256=BrG8CYVmaAhRNa_HYuPCYSnncskSsW_ig0Cf7xsY2mo,8792
67
67
  morango/sync/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
68
  morango/sync/backends/base.py,sha256=zQP5hOB2Qw0qv0G00LXFHl2GQ3b0bheyujdNVl5rT-8,10867
69
69
  morango/sync/backends/postgres.py,sha256=N0IeXN67AkdQKlD20b8LQZ1ocdarapL8pqu8FQAc6lM,19850
70
70
  morango/sync/backends/sqlite.py,sha256=vg7kWFIF346-NjVwexYfjYbrrOyzzvcCmk5uUkqhabw,12850
71
71
  morango/sync/backends/utils.py,sha256=KaTfj8dKrhRhl6wua2m_jKifmLZ2Kzsd8wPi1NWEtHM,5198
72
- morango-0.7.0.dist-info/AUTHORS.md,sha256=9Ussd3Fq3RPjHyQT_3AyGss5jiVbn858WQuIBOi1ajI,276
73
- morango-0.7.0.dist-info/LICENSE,sha256=RkI6MjmrrTKa3aoPAVyk9QdeLZclcrKds6FH3phRSRU,1074
74
- morango-0.7.0.dist-info/METADATA,sha256=aTyd64Bu8qBI2D_ofrJgNCkZbS0RcatdPaMmItqSpHw,2520
75
- morango-0.7.0.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
76
- morango-0.7.0.dist-info/top_level.txt,sha256=pzREWN0EeEq3yHDRast9XI081Ow_rtcm7WV0ZQTlIPY,8
77
- morango-0.7.0.dist-info/RECORD,,
72
+ morango-0.7.1.dist-info/AUTHORS.md,sha256=9Ussd3Fq3RPjHyQT_3AyGss5jiVbn858WQuIBOi1ajI,276
73
+ morango-0.7.1.dist-info/LICENSE,sha256=RkI6MjmrrTKa3aoPAVyk9QdeLZclcrKds6FH3phRSRU,1074
74
+ morango-0.7.1.dist-info/METADATA,sha256=GdViBtA_HnZnDsaz7tPeGjNegrsO4C6FBS1XHwAZ4sg,2555
75
+ morango-0.7.1.dist-info/WHEEL,sha256=-G_t0oGuE7UD0DrSpVZnq1hHMBV9DD2XkS5v7XpmTnk,110
76
+ morango-0.7.1.dist-info/top_level.txt,sha256=pzREWN0EeEq3yHDRast9XI081Ow_rtcm7WV0ZQTlIPY,8
77
+ morango-0.7.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any