Coverage for tests/test_file.py: 25%
99 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-18 02:06 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-18 02:06 -0700
1# This file is part of lsst-resources.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
12import os
13import pathlib
14import sys
15import unittest
16import unittest.mock
17import urllib.parse
19from lsst.resources import ResourcePath, ResourcePathExpression
20from lsst.resources.tests import GenericReadWriteTestCase, GenericTestCase
22TESTDIR = os.path.abspath(os.path.dirname(__file__))
24_OLD_PYTHON = False
25if sys.version_info < (3, 10, 0): 25 ↛ 26line 25 didn't jump to line 26, because the condition on line 25 was never true
26 _OLD_PYTHON = True
29class SimpleTestCase(unittest.TestCase):
30 @unittest.skipIf(_OLD_PYTHON, "isinstance() with unions is not supported.")
31 def test_instance(self):
32 for example in (
33 "xxx",
34 ResourcePath("xxx"),
35 pathlib.Path("xxx"),
36 urllib.parse.urlparse("file:///xxx"),
37 ):
38 self.assertIsInstance(example, ResourcePathExpression)
40 for example in ({1, 2, 3}, 42, self):
41 self.assertNotIsInstance(example, ResourcePathExpression)
44class FileTestCase(GenericTestCase, unittest.TestCase):
45 scheme = "file"
46 netloc = "localhost"
48 def test_env_var(self):
49 """Test that environment variables are expanded."""
51 with unittest.mock.patch.dict(os.environ, {"MY_TEST_DIR": "/a/b/c"}):
52 uri = ResourcePath("${MY_TEST_DIR}/d.txt")
53 self.assertEqual(uri.path, "/a/b/c/d.txt")
54 self.assertEqual(uri.scheme, "file")
56 # This will not expand
57 uri = ResourcePath("${MY_TEST_DIR}/d.txt", forceAbsolute=False)
58 self.assertEqual(uri.path, "${MY_TEST_DIR}/d.txt")
59 self.assertFalse(uri.scheme)
61 def test_ospath(self):
62 """File URIs have ospath property."""
64 file = ResourcePath(self._make_uri("a/test.txt"))
65 self.assertEqual(file.ospath, "/a/test.txt")
66 self.assertEqual(file.ospath, file.path)
68 # A Schemeless URI can take unquoted files but will be quoted
69 # when it becomes a file URI.
70 something = "/a#/???.txt"
71 file = ResourcePath(something, forceAbsolute=True)
72 self.assertEqual(file.scheme, "file")
73 self.assertEqual(file.ospath, something, "From URI: {file}")
74 self.assertNotIn("???", file.path)
76 def test_path_lib(self):
77 """File URIs can be created from pathlib"""
78 file = ResourcePath(self._make_uri("a/test.txt"))
80 path_file = pathlib.Path(file.ospath)
81 from_path = ResourcePath(path_file)
82 self.assertEqual(from_path.ospath, file.ospath)
84 def test_schemeless_root(self):
85 root = ResourcePath(self._make_uri("/root"))
86 via_root = ResourcePath("b.txt", root=root)
87 self.assertEqual(via_root.ospath, "/root/b.txt")
90class FileReadWriteTestCase(GenericReadWriteTestCase, unittest.TestCase):
91 scheme = "file"
92 netloc = "localhost"
93 testdir = TESTDIR
94 transfer_modes = ("move", "copy", "link", "hardlink", "symlink", "relsymlink")
96 def test_transfer_identical(self):
97 """Test overwrite of identical files.
99 Only relevant for local files.
100 """
101 dir1 = self.tmpdir.join("dir1", forceDirectory=True)
102 dir1.mkdir()
103 self.assertTrue(dir1.exists())
104 dir2 = self.tmpdir.join("dir2", forceDirectory=True)
105 # A symlink can't include a trailing slash.
106 dir2_ospath = dir2.ospath
107 if dir2_ospath.endswith("/"):
108 dir2_ospath = dir2_ospath[:-1]
109 os.symlink(dir1.ospath, dir2_ospath)
111 # Write a test file.
112 src_file = dir1.join("test.txt")
113 content = "0123456"
114 src_file.write(content.encode())
116 # Construct URI to destination that should be identical.
117 dest_file = dir2.join("test.txt")
118 self.assertTrue(dest_file.exists())
119 self.assertNotEqual(src_file, dest_file)
121 # Transfer it over itself.
122 dest_file.transfer_from(src_file, transfer="symlink", overwrite=True)
123 new_content = dest_file.read().decode()
124 self.assertEqual(content, new_content)
126 def test_local_temporary(self):
127 """Create temporary local file if no prefix specified."""
128 with ResourcePath.temporary_uri(suffix=".json") as tmp:
129 self.assertEqual(tmp.getExtension(), ".json", f"uri: {tmp}")
130 self.assertTrue(tmp.isabs(), f"uri: {tmp}")
131 self.assertFalse(tmp.exists(), f"uri: {tmp}")
132 tmp.write(b"abcd")
133 self.assertTrue(tmp.exists(), f"uri: {tmp}")
134 self.assertTrue(tmp.isTemporary)
135 self.assertTrue(tmp.isLocal)
137 # If we now ask for a local form of this temporary file
138 # it should still be temporary and it should not be deleted
139 # on exit.
140 with tmp.as_local() as loc:
141 self.assertEqual(tmp, loc)
142 self.assertTrue(loc.isTemporary)
143 self.assertTrue(tmp.exists())
144 self.assertFalse(tmp.exists(), f"uri: {tmp}")
146 def test_transfers_from_local(self):
147 """Extra tests for local transfers."""
149 target = self.tmpdir.join("a/target.txt")
150 with ResourcePath.temporary_uri() as tmp:
151 tmp.write(b"")
152 self.assertTrue(tmp.isTemporary)
154 # Symlink transfers for temporary resources should
155 # trigger a debug message.
156 for transfer in ("symlink", "relsymlink"):
157 with self.assertLogs("lsst.resources", level="DEBUG") as cm:
158 target.transfer_from(tmp, transfer)
159 target.remove()
160 self.assertIn("Using a symlink for a temporary", "".join(cm.output))
162 # Force the target directory to be created.
163 target.transfer_from(tmp, "move")
164 self.assertFalse(tmp.exists())
166 # Temporary file now gone so transfer should not work.
167 with self.assertRaises(FileNotFoundError):
168 target.transfer_from(tmp, "move", overwrite=True)
171if __name__ == "__main__":
172 unittest.main()