Coverage for tests/test_file.py: 25%

99 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-15 02:25 -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. 

11 

12import os 

13import pathlib 

14import sys 

15import unittest 

16import unittest.mock 

17import urllib.parse 

18 

19from lsst.resources import ResourcePath, ResourcePathExpression 

20from lsst.resources.tests import GenericReadWriteTestCase, GenericTestCase 

21 

22TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

23 

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 

27 

28 

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) 

39 

40 for example in ({1, 2, 3}, 42, self): 

41 self.assertNotIsInstance(example, ResourcePathExpression) 

42 

43 

44class FileTestCase(GenericTestCase, unittest.TestCase): 

45 scheme = "file" 

46 netloc = "localhost" 

47 

48 def test_env_var(self): 

49 """Test that environment variables are expanded.""" 

50 

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

55 

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) 

60 

61 def test_ospath(self): 

62 """File URIs have ospath property.""" 

63 

64 file = ResourcePath(self._make_uri("a/test.txt")) 

65 self.assertEqual(file.ospath, "/a/test.txt") 

66 self.assertEqual(file.ospath, file.path) 

67 

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) 

75 

76 def test_path_lib(self): 

77 """File URIs can be created from pathlib""" 

78 file = ResourcePath(self._make_uri("a/test.txt")) 

79 

80 path_file = pathlib.Path(file.ospath) 

81 from_path = ResourcePath(path_file) 

82 self.assertEqual(from_path.ospath, file.ospath) 

83 

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

88 

89 

90class FileReadWriteTestCase(GenericReadWriteTestCase, unittest.TestCase): 

91 scheme = "file" 

92 netloc = "localhost" 

93 testdir = TESTDIR 

94 transfer_modes = ("move", "copy", "link", "hardlink", "symlink", "relsymlink") 

95 

96 def test_transfer_identical(self): 

97 """Test overwrite of identical files. 

98 

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) 

110 

111 # Write a test file. 

112 src_file = dir1.join("test.txt") 

113 content = "0123456" 

114 src_file.write(content.encode()) 

115 

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) 

120 

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) 

125 

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) 

136 

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

145 

146 def test_transfers_from_local(self): 

147 """Extra tests for local transfers.""" 

148 

149 target = self.tmpdir.join("a/target.txt") 

150 with ResourcePath.temporary_uri() as tmp: 

151 tmp.write(b"") 

152 self.assertTrue(tmp.isTemporary) 

153 

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

161 

162 # Force the target directory to be created. 

163 target.transfer_from(tmp, "move") 

164 self.assertFalse(tmp.exists()) 

165 

166 # Temporary file now gone so transfer should not work. 

167 with self.assertRaises(FileNotFoundError): 

168 target.transfer_from(tmp, "move", overwrite=True) 

169 

170 

171if __name__ == "__main__": 

172 unittest.main()