def _acquire_entry_lock(entry, user): """ Acquire the lock. The caller must make sure that there is no lock yet on the entry before calling this function. :param entry: The entry for which to acquire the lock. :type entry: :class:`.Entry` :param user: The user who is acquiring the lock. :type user: The value of :attr:`settings.AUTH_USER_MODEL` determines the class. :returns: The lock if the lock was acquired, or ``None`` if not. :rtype: :class:`.EntryLock` """ if not transaction.is_managed(): raise Exception("_acquire_entry_lock requires transactions to be " "managed") lock = EntryLock() lock.entry = entry now = util.utcnow() lock.owner = user lock.datetime = now lock.save() _report(lock, "acquired") return lock
def update(self, user, session_key, chunk, lemma, ctype, subtype, note=""): if self.id is None and ctype != ChangeRecord.CREATE: raise ValueError("The Entry has no id but the ctype is not CREATE") self.lemma = lemma # save() first. So that if we have an integrity error, there is no # stale ChangeRecord to remove. self.save() cr = ChangeRecord( entry=self, lemma=lemma, user=user, datetime=util.utcnow(), session=session_key, ctype=ctype, csubtype=subtype, c_hash=chunk, note=note) cr.save() # We can't set latest before we've saved cr. self.latest = cr self.save()
def _refresh_entry_lock(lock): """ Refresh the entry lock. :param lock: The lock to update. :type lock: :class:`.EntryLock` """ lock.datetime = util.utcnow() lock.save() _report(lock, "refreshed")
def undelete(self, user): dr = DeletionChange(entry=self, user=user, ctype=DeletionChange.UNDELETE, datetime=util.utcnow()) dr.save() was_deleted = self.deleted self.deleted = False self.save() if was_deleted: self._send(signals.entry_available)
def mark_deleted(self, user): dr = DeletionChange(entry=self, user=user, ctype=DeletionChange.DELETE, datetime=util.utcnow()) dr.save() was_deleted = self.deleted self.deleted = True self.save() if not was_deleted: self._send(signals.entry_unavailable)
def create_valid_article(): data = get_valid_document_data() now = util.utcnow() client = Client() add_raw_url = reverse("full-admin:lexicography_entry_rawnew") assert client.login(username='******', password='******') response = client.post(add_raw_url, {"data": data}) assert response.status_code == 302,\ "response was " + str(response.status_code) return Entry.objects.get(latest__datetime__gte=now)
def mark_deleted(self, user): dr = DeletionChange( entry=self, user=user, ctype=DeletionChange.DELETE, datetime=util.utcnow() ) dr.save() was_deleted = self.deleted self.deleted = True self.save() if not was_deleted: self._send(signals.entry_unavailable)
def update_entry(request, entry, chunk, xmltree, ctype, subtype): cr = ChangeRecord() cr.entry = entry entry.copy_to(cr) entry.headword = xmltree.extract_headword() entry.user = request.user entry.datetime = util.utcnow() entry.session = request.session.session_key entry.ctype = ctype entry.csubtype = subtype entry.c_hash = chunk cr.save() entry.save()
def undelete(self, user): dr = DeletionChange( entry=self, user=user, ctype=DeletionChange.UNDELETE, datetime=util.utcnow() ) dr.save() was_deleted = self.deleted self.deleted = False self.save() if was_deleted: self._send(signals.entry_available)
def _refresh_entry_lock(lock): """ Refresh the entry lock. This function requires manual transaction to be enabled. :param lock: The lock to update. :type lock: :class:`.EntryLock` """ if not transaction.is_managed(): raise Exception("refresh_entry_lock requires transactions to be " "managed") lock.datetime = util.utcnow() lock.save() _report(lock, "refreshed")
def test_now_works(self): """ ``now`` evaluates to something useful and does not change once evaluated. """ cleaner = Cleaner() then = cleaner.now time.sleep(1) # We can perform date arithmetics with it. self.assertTrue(then - utcnow() < datetime.timedelta(minutes=1)) # It does not change. self.assertEqual(then, cleaner.now)
def unpublish(self, user): if self.published: if not self.can_publish(user): raise PermissionDenied self.published = False self.save() pc = PublicationChange(changerecord=self, ctype=PublicationChange.UNPUBLISH, user=user, datetime=util.utcnow()) pc.save() # pylint: disable=protected-access self.entry._update_latest_published() return True return False
def test_fetch_items(self): """ Tests that the task populates the Item table and that FETCH_KEY and FETCH_KEY are set appropriately. """ self.assertIsNone(cache.get(tasks.FETCH_KEY)) self.assertIsNone(cache.get(tasks.FETCH_DATE_KEY)) items = Item.objects.all() self.assertEqual(items.count(), 0) tasks.fetch_items.delay().get() self.assertIsNone(cache.get(tasks.FETCH_KEY)) last_fetch = cache.get(tasks.FETCH_DATE_KEY) self.assertTrue(utcnow() - last_fetch < datetime.timedelta(seconds=5)) items = Item.objects.all() self.assertEqual(items.count(), 47)
def test_unpublish_creates_publication_change(self): """ Unpublishing a change record creates a new PublicationChange. """ entry = self.valid latest = entry.latest self.assertTrue(latest.publish(self.foo)) old_count = PublicationChange.objects.filter( changerecord=latest).count() self.assertTrue(latest.unpublish(self.foo)) self.assertEqual( PublicationChange.objects.filter(changerecord=latest).count(), old_count + 1) latest_pc = PublicationChange.objects.latest('datetime') self.assertEqual(latest_pc.changerecord, latest) self.assertEqual(latest_pc.ctype, PublicationChange.UNPUBLISH) self.assertEqual(latest_pc.user, self.foo) # The timedelta is arbitrary. self.assertTrue(util.utcnow() - latest_pc.datetime <= datetime.timedelta(seconds=5))
def _acquire_entry_lock(entry, user): """ Acquire the lock. The caller must make sure that there is no lock yet on the entry before calling this function. :param entry: The entry for which to acquire the lock. :type entry: :class:`.Entry` :param user: The user who is acquiring the lock. :type user: The value of :attr:`settings.AUTH_USER_MODEL` determines the class. :returns: The lock if the lock was acquired, or ``None`` if not. :rtype: :class:`.EntryLock` """ lock = EntryLock() lock.entry = entry now = util.utcnow() lock.owner = user lock.datetime = now lock.save() _report(lock, "acquired") return lock
def test_edit(self): """ Tests that a user with editing rights can edit an entry obtained by searching. """ response, old_entry = self.open_abcd('foo') nr_changes = ChangeRecord.objects.filter(entry=old_entry).count() messages, data = self.save(response, 'foo') self.assertEqual(len(messages), 1) self.assertIn("save_successful", messages) self.assertEqual(ChangeRecord.objects.filter(entry=old_entry).count(), nr_changes + 1, "there is one and only one additional record change") # Check that we recorded the right thing. entry = Entry.objects.get(pk=old_entry.pk) self.assertEqual(entry.user, self.foo) # The delay used here is arbitrary self.assertTrue(util.utcnow() - entry.datetime <= datetime.timedelta(minutes=1)) self.assertEqual(entry.session, self.app.session.session_key) self.assertEqual(entry.ctype, entry.UPDATE) self.assertEqual(entry.csubtype, entry.MANUAL) # Check the chunk self.assertEqual(entry.c_hash.data, data) self.assertTrue(entry.c_hash.is_normal) # Check that the lastest ChangeRecord corresponds to the old_entry change = ChangeRecord.objects.filter(entry=old_entry) \ .order_by('-datetime')[0] # pylint: disable=W0212 for i in ChangeInfo._meta.get_all_field_names(): self.assertEqual(getattr(old_entry, i), getattr(change, i))
def try_updating_entry(request, entry, chunk, xmltree, ctype, subtype): if not transaction.is_managed(): raise Exception("try_updating_entry requires transactions to be " "managed") chunk.save() if entry.id is None: entry.headword = xmltree.extract_headword() entry.user = request.user entry.datetime = util.utcnow() entry.session = request.session.session_key entry.ctype = Entry.CREATE entry.csubtype = subtype entry.c_hash = chunk entry.save() if try_acquiring_lock(entry, request.user) is None: raise Exception("unable to acquire the lock of an entry " "that was just created but not committed!") else: if try_acquiring_lock(entry, request.user) is None: return False update_entry(request, entry, chunk, xmltree, ctype, subtype) return True
def test_publish_creates_publication_change(self): """ Publishing a change record creates a new PublicationChange. """ entry = self.valid latest = entry.latest old_count = PublicationChange.objects.filter( changerecord=latest).count() self.assertFalse(latest.published, "The change record we are about to use must not be " "published yet.") self.assertTrue(latest.publish(self.foo)) self.assertEqual( PublicationChange.objects.filter(changerecord=latest).count(), old_count + 1) latest_pc = PublicationChange.objects.latest('datetime') self.assertEqual(latest_pc.changerecord, latest) self.assertEqual(latest_pc.ctype, PublicationChange.PUBLISH) self.assertEqual(latest_pc.user, self.foo) # The timedelta is arbitrary. self.assertTrue(util.utcnow() - latest_pc.datetime <= datetime.timedelta(seconds=5))
def test_publish_creates_publication_change(self): """ Publishing a change record creates a new PublicationChange. """ entry = self.valid latest = entry.latest old_count = PublicationChange.objects.filter( changerecord=latest).count() self.assertFalse( latest.published, "The change record we are about to use must not be " "published yet.") self.assertTrue(latest.publish(self.foo)) self.assertEqual( PublicationChange.objects.filter(changerecord=latest).count(), old_count + 1) latest_pc = PublicationChange.objects.latest('datetime') self.assertEqual(latest_pc.changerecord, latest) self.assertEqual(latest_pc.ctype, PublicationChange.PUBLISH) self.assertEqual(latest_pc.user, self.foo) # The timedelta is arbitrary. self.assertTrue(util.utcnow() - latest_pc.datetime <= datetime.timedelta(seconds=5))
def fetch_the_items(task, test=None): """ Fetch the bibliographical items from the Zotero database. """ if test is None: test = {} # There's another task running. if task.request.id is not None and \ not acquire_mutex(cache, FETCH_KEY, task.request.id, logger): return # Simulate a task that mysteriously stops working after it has # claimed the key. if test.get("vanish"): return # Simulate a task that fails due to an exception. if test.get("fail"): raise Exception("failing") logger.info("fetching all bibliographical items") search_results = btw_zotero.get_all() for result in search_results: key = result["data"]["key"] try: item = Item.objects.get(item_key=key) item.refresh(result) except Item.DoesNotExist: item = Item(item_key=key, uid=btw_zotero.full_uid) item.refresh(result) # We're done cache.set(FETCH_DATE_KEY, utcnow()) cache.delete(FETCH_KEY)
def update(self, user, session_key, chunk, lemma, ctype, subtype, note=""): if self.id is None and ctype != ChangeRecord.CREATE: raise ValueError("The Entry has no id but the ctype is not CREATE") self.lemma = lemma # save() first. So that if we have an integrity error, there is no # stale ChangeRecord to remove. self.save() cr = ChangeRecord(entry=self, lemma=lemma, user=user, datetime=util.utcnow(), session=session_key, ctype=ctype, csubtype=subtype, c_hash=chunk, note=note) cr.save() # We can't set latest before we've saved cr. self.latest = cr self.save()
def make_records(self): to_clean = [] to_keep = [] # # entry1: Generic cases... # entry1 = Entry() # Old and unpublished... entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.CREATE, ChangeRecord.MANUAL) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() # ... but not right type. to_keep.append(entry1.latest) # Old, unpublished, not of a proscribed type: will be cleaned entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.RECOVERY) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() to_clean.append(entry1.latest) # Old, unpublished, not of a proscribed type: will be cleaned entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() to_clean.append(entry1.latest) entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() self.assertTrue(entry1.latest.publish(self.foo)) # Published, won't be cleaned to_keep.append(entry1.latest) entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.MANUAL) # Too recent. to_keep.append(entry1.latest) entry1 = None # Make sure we cannot access it again. # # entry3: We keep the latest record. entry3 = Entry() entry3.update( self.foo, "q", self.chunk, "foo3", ChangeRecord.CREATE, ChangeRecord.MANUAL) # Keep, not right type, and too young. to_keep.append(entry3.latest) entry3.update( self.foo, "q", self.chunk, "foo3", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry3.latest.datetime = utcnow() - datetime.timedelta(days=2) entry3.latest.save() # Clean: meets all requirements and is not latest. to_clean.append(entry3.latest) entry3.update( self.foo, "q", self.chunk, "foo3", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry3.latest.datetime = utcnow() - datetime.timedelta(days=2) entry3.latest.save() # Keep the latest. to_keep.append(entry3.latest) entry3 = None # # entry4: Already partially hidden. # entry4 = Entry() entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.CREATE, ChangeRecord.MANUAL) to_keep.append(entry4.latest) entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry4.latest.datetime = utcnow() - datetime.timedelta(days=2) entry4.latest.hidden = True entry4.latest.save() # This is neither to_keep nor to_clean. entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry4.latest.datetime = utcnow() - datetime.timedelta(days=2) entry4.latest.save() to_clean.append(entry4.latest) entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry4.latest.datetime = utcnow() - datetime.timedelta(days=2) entry4.latest.save() to_keep.append(entry4.latest) return to_clean, to_keep
def expired(self): """ True if the invitation has expired. False if not. """ return util.utcnow() - self.creation_date >= \ Invitation.objects.expiration_delay
def make_success_obj(self, cleaner): e = self.entry e.latest.datetime = utcnow() - datetime.timedelta(days=2) return e.latest
def create_document(self, what): add_raw_url = reverse("full-admin:lexicography_entry_rawnew") from lexicography.tests.util import get_valid_document_data data = get_valid_document_data() publish = True if what == "valid article": xmltree = XMLTree(data) elif what in ("valid article, with one author", "valid article, with two authors", "valid article, with three authors", "valid article, with four authors"): total_authors = { "valid article, with one author": 1, "valid article, with two authors": 2, "valid article, with three authors": 3, "valid article, with four authors": 4 }[what] publish = True xmltree = XMLTree(data) authors = xmltree.tree.xpath("//btw:credit", namespaces=default_namespace_mapping) assert len(authors) == 2 if total_authors == 1: authors[1].getparent().remove(authors[1]) elif total_authors == 2: pass else: btw_credits = authors[0].getparent() for number in range(len(authors) + 1, total_authors + 1): btw_credits.append( lxml.etree.XML(""" <btw:credit xmlns="{0}" xmlns:btw="{1}"> <resp>Resp</resp> <persName><forename>Forename {2}</forename><surname>Surname {2}</surname>\ <genName>GenName {2}</genName></persName> </btw:credit>""".format(tei_namespace, btw_namespace, number))) xmltree.alter_lemma(what) data = xmltree.serialize() elif what in ("valid article, with one editor", "valid article, with two editors", "valid article, with three editors", "valid article, with four editors"): total_editors = { "valid article, with one editor": 1, "valid article, with two editors": 2, "valid article, with three editors": 3, "valid article, with four editors": 4 }[what] publish = True xmltree = XMLTree(data) editors = xmltree.tree.xpath("//tei:editor", namespaces=default_namespace_mapping) assert len(editors) == 1 if total_editors == 1: pass else: btw_credits = editors[0].getparent() for number in range(len(editors) + 1, total_editors + 1): btw_credits.append( lxml.etree.XML(""" <editor xmlns="{0}"> <persName><forename>Forename {1}</forename><surname>Surname {1}</surname>\ <genName>GenName {1}</genName></persName> </editor>""".format(tei_namespace, number))) xmltree.alter_lemma(what) data = xmltree.serialize() elif what in ("valid article, with bad semantic fields", "valid article, with good semantic fields"): publish = False xmltree = XMLTree(data) sfs = xmltree.tree.xpath("//btw:sf", namespaces=default_namespace_mapping) ix = 0 cases = invalid_sf_cases if what.endswith("bad semantic fields") \ else valid_sf_cases for case in cases: sfs[ix].text = case ix += 1 xmltree.alter_lemma(what) data = xmltree.serialize() else: print("Unknown document: ", what) from lexicography.models import Entry try: entry = Entry.objects.get(lemma=xmltree.extract_lemma()) except Entry.DoesNotExist: entry = None if entry is None: User = get_user_model() foo = User.objects.get(username='******') now = util.utcnow() client = Client() assert client.login(username='******', password='******') response = client.post(add_raw_url, {"data": data}) assert response.status_code == 302 entry = Entry.objects.get(latest__datetime__gte=now) if publish: assert entry.latest.publish(foo) with open(self.__control_write, 'w') as out: out.write(entry.lemma + "\n")
def expirable(self): """ :returns: ``True`` if the lock is expirable, ``False`` if not. :rtype: :class:`bool` """ return util.utcnow() - self.datetime > LEXICOGRAPHY_LOCK_EXPIRY
def make_records(self): to_clean = [] to_keep = [] # # entry1: Generic cases... # entry1 = Entry() # Old and unpublished... entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.CREATE, ChangeRecord.MANUAL) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() # ... but not right type. to_keep.append(entry1.latest) # Old, unpublished, not of a proscribed type: will be cleaned entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.MANUAL) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() to_clean.append(entry1.latest) # Old, unpublished, not of a proscribed type: will be cleaned entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() to_clean.append(entry1.latest) entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.AUTOMATIC) entry1.latest.datetime = utcnow() - datetime.timedelta(days=2) entry1.latest.save() self.assertTrue(entry1.latest.publish(self.foo)) # Published to_keep.append(entry1.latest) entry1.update( self.foo, "q", self.chunk, "foo", ChangeRecord.UPDATE, ChangeRecord.MANUAL) # Too recent. to_keep.append(entry1.latest) entry1 = None # Make sure we cannot access it again. # # entry2: Make sure that we favor keeping CREATE records. # entry2 = Entry() # Old and unpublished... entry2.update( self.foo, "q", self.chunk, "foo2", ChangeRecord.CREATE, ChangeRecord.MANUAL) entry2.latest.datetime = utcnow() - datetime.timedelta(days=2) entry2.latest.save() # ... but not right type. to_keep.append(entry2.latest) entry2.update( self.foo, "q", self.chunk, "foo2", ChangeRecord.UPDATE, ChangeRecord.MANUAL) entry2.latest.datetime = utcnow() - datetime.timedelta(days=2) entry2.latest.save() # The CREATE record is favored. to_clean.append(entry2.latest) entry2 = None # # entry3: everything is eligible for collpasing. We elect the # newest record to keep. See the comments in the code of the # class. This should be an unusual case, but we test it here. # entry3 = Entry() entry3.update( self.foo, "q", self.chunk, "foo3", ChangeRecord.CREATE, ChangeRecord.MANUAL) # We cannot call .update above with a type of UPDATE. The # system is *designed* to prevent doing so. (It prevents # creating a new record with ctype UPDATE! So we munge it. entry3.latest.ctype = ChangeRecord.UPDATE entry3.latest.datetime = utcnow() - datetime.timedelta(days=2) entry3.latest.save() # We clean the oldest record. to_clean.append(entry3.latest) entry3.update( self.foo, "q", self.chunk, "foo3", ChangeRecord.UPDATE, ChangeRecord.MANUAL) entry3.latest.datetime = utcnow() - datetime.timedelta(days=2) entry3.latest.save() # Keep the newest. to_keep.append(entry3.latest) entry3 = None # # entry4: Already partially hidden. # entry4 = Entry() entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.CREATE, ChangeRecord.MANUAL) to_keep.append(entry4.latest) entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.UPDATE, ChangeRecord.MANUAL) entry4.latest.datetime = utcnow() - datetime.timedelta(days=2) entry4.latest.hidden = True entry4.latest.save() # This is neither to_keep nor to_clean. entry4.update( self.foo, "q", self.chunk, "foo4", ChangeRecord.UPDATE, ChangeRecord.MANUAL) entry4.latest.datetime = utcnow() - datetime.timedelta(days=2) entry4.latest.save() to_clean.append(entry4.latest) return to_clean, to_keep
def create_document(self, what): add_raw_url = reverse("full-admin:lexicography_entry_rawnew") from lexicography.tests.util import get_valid_document_data data = get_valid_document_data() publish = True if what == "valid article": xmltree = XMLTree(data) elif what in ("valid article, with one author", "valid article, with two authors", "valid article, with three authors", "valid article, with four authors"): total_authors = { "valid article, with one author": 1, "valid article, with two authors": 2, "valid article, with three authors": 3, "valid article, with four authors": 4 }[what] publish = True xmltree = XMLTree(data) authors = xmltree.tree.xpath("//btw:credit", namespaces=default_namespace_mapping) assert len(authors) == 2 if total_authors == 1: authors[1].getparent().remove(authors[1]) elif total_authors == 2: pass else: btw_credits = authors[0].getparent() for number in xrange(len(authors) + 1, total_authors + 1): btw_credits.append(lxml.etree.XML(""" <btw:credit xmlns="{0}" xmlns:btw="{1}"> <resp>Resp</resp> <persName><forename>Forename {2}</forename><surname>Surname {2}</surname>\ <genName>GenName {2}</genName></persName> </btw:credit>""".format(tei_namespace, btw_namespace, number))) xmltree.alter_lemma(what) data = xmltree.serialize() elif what in ("valid article, with one editor", "valid article, with two editors", "valid article, with three editors", "valid article, with four editors"): total_editors = { "valid article, with one editor": 1, "valid article, with two editors": 2, "valid article, with three editors": 3, "valid article, with four editors": 4 }[what] publish = True xmltree = XMLTree(data) editors = xmltree.tree.xpath("//tei:editor", namespaces=default_namespace_mapping) assert len(editors) == 1 if total_editors == 1: pass else: btw_credits = editors[0].getparent() for number in xrange(len(editors) + 1, total_editors + 1): btw_credits.append(lxml.etree.XML(""" <editor xmlns="{0}"> <persName><forename>Forename {1}</forename><surname>Surname {1}</surname>\ <genName>GenName {1}</genName></persName> </editor>""".format(tei_namespace, number))) xmltree.alter_lemma(what) data = xmltree.serialize() elif what in ("valid article, with bad semantic fields", "valid article, with good semantic fields"): publish = False xmltree = XMLTree(data) sfs = xmltree.tree.xpath("//btw:sf", namespaces=default_namespace_mapping) ix = 0 cases = invalid_sf_cases if what.endswith("bad semantic fields") \ else valid_sf_cases for case in cases: sfs[ix].text = case ix += 1 xmltree.alter_lemma(what) data = xmltree.serialize() else: print "Unknown document: ", what from lexicography.models import Entry try: entry = Entry.objects.get(lemma=xmltree.extract_lemma()) except Entry.DoesNotExist: entry = None if entry is None: User = get_user_model() foo = User.objects.get(username='******') now = util.utcnow() client = Client() assert client.login(username='******', password='******') response = client.post(add_raw_url, {"data": data}) assert response.status_code == 302 entry = Entry.objects.get(latest__datetime__gte=now) if publish: assert entry.latest.publish(foo) with open(self.__control_write, 'w') as out: out.write(entry.lemma.encode('utf-8') + "\n")
def is_expirable(self): """ :returns: ``True`` if the lock is expirable, ``False`` if not. :rtype: :class:`bool` """ return util.utcnow() - self.datetime > LEXICOGRAPHY_LOCK_EXPIRY