Skip to content

Commit 92fd2c3

Browse files
authored
Merge pull request #43 from Deric-W/Issue#42
fix Issue #42
2 parents 89bbe16 + bd252f7 commit 92fd2c3

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

pyhp/backends/caches/timestamped/files.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from __future__ import annotations
1717
import os
18+
import sys
1819
import base64
1920
import pickle
2021
from typing import TypeVar, Any, Mapping, Iterator
@@ -33,12 +34,16 @@
3334

3435

3536
__all__ = (
37+
"FILE_EXTENSION",
3638
"FileCacheSource",
3739
"FileCache"
3840
)
3941

4042
S = TypeVar("S", bound=TimestampedCodeSource)
4143

44+
# use cache tag in extension to prevent errors with different python versions
45+
FILE_EXTENSION = f".{sys.implementation.cache_tag}.pickle"
46+
4247

4348
class FileCacheSource(CacheSource[S]):
4449
"""
@@ -139,9 +144,10 @@ def __eq__(self, other: object) -> bool:
139144

140145
def __getitem__(self, name: str) -> FileCacheSource[S]:
141146
"""get FileCacheSource with path as returned by .path()"""
147+
path = self.path(name) # dont leak sources if self.path fails
142148
return FileCacheSource(
143149
self.source_container[name],
144-
self.path(name),
150+
path,
145151
self.ttl
146152
)
147153

@@ -194,20 +200,20 @@ def clear(self) -> None:
194200
pass
195201

196202
def path(self, name: str) -> str:
197-
"""return directory_name/<base32 encoded name>.pickle"""
203+
"""return directory_name/<base32 encoded name>FILE_EXTENSION"""
198204
return os.path.join(
199205
self.directory_name,
200-
base64.b32encode(name.encode("utf8")).decode("utf8") + ".pickle"
206+
base64.b32encode(name.encode("utf8")).decode("utf8") + FILE_EXTENSION
201207
) # use base32 because of case-insensitive file systems and forbidden characters
202208

203209
def reconstruct_name(self, path: str) -> str:
204210
"""reconstruct the name from a file cache path"""
205-
name, _, _ = os.path.basename(path).rpartition(".")
211+
name, _, _ = os.path.basename(path).partition(".")
206212
return base64.b32decode(name.encode("utf8"), casefold=True).decode("utf8")
207213

208214
def paths(self) -> Iterator[str]:
209215
"""return a iterator yielding all paths currently in use (including outdated ones)"""
210216
with os.scandir(self.directory_name) as directory:
211217
for entry in directory:
212-
if entry.name.endswith(".pickle") and entry.is_file():
218+
if entry.name.endswith(FILE_EXTENSION) and entry.is_file():
213219
yield entry.path

tests/backends/caches/timestamped/test_files.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
from pyhp.backends.caches import NotCachedException
1515
from pyhp.backends.caches.timestamped.files import (
1616
FileCacheSource,
17-
FileCache
17+
FileCache,
18+
FILE_EXTENSION
1819
)
1920
from pyhp.compiler.parsers import RegexParser
2021
from pyhp.compiler.generic import GenericCodeBuilder
@@ -250,3 +251,48 @@ def test_path(self) -> None:
250251
self.assertNotEqual(cache.path("test"), cache.path("test2"))
251252
self.assertNotIn("|", cache.path("|"))
252253
self.assertEqual(cache.reconstruct_name(cache.path("test2")), "test2")
254+
255+
def test_paths(self) -> None:
256+
"""test FileCache.paths"""
257+
with tempfile.TemporaryDirectory() as directory, \
258+
FileCache(Directory("tests/embedding", compiler), directory) as cache:
259+
tmp_path = os.path.join(directory, "test.txt")
260+
dir_path = os.path.join(directory, "test" + FILE_EXTENSION)
261+
with cache["syntax.pyhp"] as source:
262+
source.fetch()
263+
with cache["shebang.pyhp"] as source:
264+
source.fetch()
265+
try:
266+
open(tmp_path, "xb").close()
267+
try:
268+
os.mkdir(dir_path)
269+
try:
270+
paths = list(cache.paths())
271+
self.assertEqual(len(paths), 2)
272+
self.assertEqual( # order not important, use sets
273+
set(paths),
274+
{
275+
cache.path("syntax.pyhp"),
276+
cache.path("shebang.pyhp")
277+
}
278+
)
279+
finally:
280+
os.rmdir(dir_path)
281+
finally:
282+
os.unlink(tmp_path)
283+
finally:
284+
cache.clear()
285+
286+
def test_reconstruct_name(self) -> None:
287+
"""test FileCache.reconstruct_name"""
288+
names = [
289+
"test",
290+
"test/42/9",
291+
"äöü|<",
292+
"\n\n\n"
293+
]
294+
with FileCache(Directory("tests/embedding", compiler), "tmp") as cache:
295+
for name in names:
296+
path = cache.path(name)
297+
self.assertEqual(cache.reconstruct_name(path.lower()), name)
298+
self.assertEqual(cache.reconstruct_name(path.upper()), name)

0 commit comments

Comments
 (0)