Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion mypy/metastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,12 @@ def __init__(
if cache_dir_prefix.startswith(os.devnull):
return

os.makedirs(cache_dir_prefix, exist_ok=True)
try:
os.makedirs(cache_dir_prefix, exist_ok=True)
except OSError:
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a bit too broad, but catching all sort of possible FS read-only states can be difficult, and also this is consistent with what FilesystemMetadataStore was doing..

# Prevent failing on read-only filesystem and such.
return

if num_shards <= 1:
self.dbs.append(
connect_db(os_path_join(cache_dir_prefix, "cache.db"), set_journal_mode)
Expand Down
40 changes: 40 additions & 0 deletions mypy/test/testmetastore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from __future__ import annotations

import os
import sys
import tempfile
import unittest

from mypy.metastore import SqliteMetadataStore


@unittest.skipIf(
sys.platform == "win32",
"POSIX chmod semantics: os.chmod(dir, 0o555) does not prevent writes on Windows",
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't sure what's better -- excluding test altogether, or checking the same thing after store = SqliteMetadataStore(cache_dir) and returning early/skipping in the test body.

I figured excluding it altogether is less confusing.

)
class TestSqliteMetadataStore(unittest.TestCase):
def test_init_degrades_to_noop_when_cache_dir_not_creatable(self) -> None:
with tempfile.TemporaryDirectory() as parent:
os.chmod(parent, 0o555)

cache_dir = os.path.join(parent, "mypy_cache")

# Must not raise.
store = SqliteMetadataStore(cache_dir)

# Degraded to no-op state, matching the os.devnull short-circuit
# and FilesystemMetadataStore's behavior on read-only filesystems.
self.assertEqual(store.dbs, [])
self.assertFalse(store.write("foo.meta.json", b"{}"))
with self.assertRaises(FileNotFoundError):
store.read("foo.meta.json")
with self.assertRaises(FileNotFoundError):
store.getmtime("foo.meta.json")
self.assertEqual(list(store.list_all()), [])
# commit/close must be safe on an empty store
store.commit()
store.close()


if __name__ == "__main__":
unittest.main()
Loading