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)
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