Example #1
0
  def test_ancestry(self):
    k1 = Key('/A/B/C')
    k2 = Key('/A/B/C/D')

    self.assertEqual(k1._string, '/A/B/C')
    self.assertEqual(k2._string, '/A/B/C/D')
    self.assertTrue(k1.isAncestorOf(k2))
    self.assertTrue(k2.isDescendantOf(k1))
    self.assertTrue(Key('/A').isAncestorOf(k2))
    self.assertTrue(Key('/A').isAncestorOf(k1))
    self.assertFalse(Key('/A').isDescendantOf(k2))
    self.assertFalse(Key('/A').isDescendantOf(k1))
    self.assertTrue(k2.isDescendantOf(Key('/A')))
    self.assertTrue(k1.isDescendantOf(Key('/A')))
    self.assertFalse(k2.isAncestorOf(Key('/A')))
    self.assertFalse(k1.isAncestorOf(Key('/A')))
    self.assertFalse(k2.isAncestorOf(k2))
    self.assertFalse(k1.isAncestorOf(k1))
    self.assertEqual(k1.child('D'), k2)
    self.assertEqual(k1, k2.parent)
    self.assertEqual(k1.path, k2.parent.path)
Example #2
0
    async def _put_new_indirect(
        self,
        prefix: datastore.Key  # type: ignore[override]
    ) -> datastore.abc.BinaryDatastore._PUT_NEW_INDIRECT_RT:
        """Stores data in a new subkey below *prefix*
		
		Arguments
		---------
		prefix
			Key below which to create a new binary data slot to store data at
		
		Raises
		------
		RuntimeError
			The given *prefix* names a value, not a subtree OR contains a
			value item as part of the key path
		"""
        # Validate that the key is well-formed
        #
        # Usage of assert here will cause this call to be optimized away in `-O` mode.
        assert self.verify_key_valid(prefix)

        path_dir = trio.Path(self.object_path(prefix, suffix=False))
        path_prefix_t = ".tmp-new-"
        path_prefix_f = ".new-"

        # Ensure containing directory exists
        try:
            await path_dir.mkdir(parents=True, exist_ok=True)
        except FileExistsError as exc:
            # Should hopefully only happen if `object_extension` is `""`
            raise RuntimeError(
                f"Adding a new file below \"{path_dir}\" requires that path "
                f"to not be a value") from exc

        # Create target file
        target_file = await make_named_tempfile(mode="wb",
                                                dir=path_dir,
                                                prefix=path_prefix_f,
                                                suffix=self.object_extension,
                                                delete=False)

        # Write to extra temporary file if stats tracking to account for collisions, else write
        # directly to target file
        if self._stats is not None:
            try:
                file = await make_named_tempfile(mode="wb",
                                                 dir=path_dir,
                                                 prefix=path_prefix_t,
                                                 delete=False)
            finally:
                # This file will not be directly written to
                await target_file.aclose()
        else:
            file = target_file

        # Return a pretty uninspired callback function that reads data from the stream
        # and writes it to the target file
        async def callback(value: datastore.abc.ReceiveStream) -> None:
            try:
                await self._receive_and_write(file, value)
            except BaseException:
                try:
                    await file.aclose()
                finally:
                    with trio.CancelScope(shield=True):
                        await file.unlink()
                raise
            else:
                await file.aclose()

                if self._stats is not None:
                    async with self._stats_lock:  # type: ignore[union-attr]
                        await self._put_replace(file.name, target_file.name)

        return prefix.child(
            pathlib.Path(
                target_file.name).name[:-len(self.object_extension)]), callback