Skip to content

Commit

Permalink
fixes for case-insensitive file systems
Browse files Browse the repository at this point in the history
  • Loading branch information
berquist committed Jun 10, 2024
1 parent 3d4031f commit 7afe2ef
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 19 deletions.
14 changes: 12 additions & 2 deletions exdir/core/exdir_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,24 @@ def __init__(self, directory, mode=None, allow_remove=False,
else:
self.io_mode = OpenMode.READ_WRITE

parent_path = pathlib.PurePosixPath("")
super().__init__(
root_directory=directory,
parent_path=pathlib.PurePosixPath(""),
parent_path=parent_path,
object_name="",
file=self
)

already_exists = directory.exists()
# If we have name validation, we need to check for uniqueness. The
# directory may exist but with a different case, in which case we
# don't want to say that it already exists so that it matches the
# correct checks for the requested mode.
if name_validation != validation.none:
already_exists = validation.path_already_exists_case_sensitive(
str(directory.parent), directory.name
)
else:
already_exists = directory.exists()
if already_exists:
if not exob.is_nonraw_object_directory(directory):
raise RuntimeError(
Expand Down
39 changes: 22 additions & 17 deletions exdir/core/validation.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from enum import Enum
import os
import os.path
import sys
from pathlib import Path, WindowsPath
from tempfile import NamedTemporaryFile
from unicodedata import category
from . import constants as exob

Expand Down Expand Up @@ -36,13 +36,14 @@ def _contains_control_character(s):

def _assert_unique(parent_path, name):
try:
name_str = str(name)
name = str(name)
except UnicodeEncodeError:
name = name.encode('utf8')

if (parent_path / name).exists():
if path_already_exists_case_insensitive(str(parent_path), name.lower()):
raise RuntimeError(
"'{}' already exists in '{}'".format(name, parent_path)
"A directory with name (case independent) '{}' already exists "
" and cannot be made according to the naming rule 'thorough'.".format(name)
)


Expand Down Expand Up @@ -108,6 +109,7 @@ def strict(parent_path, name):
_assert_unique(parent_path, name)
_assert_valid_characters(name)


def thorough(parent_path, name):
_assert_nonempty(parent_path, name)
_assert_nonreserved(name)
Expand All @@ -117,21 +119,24 @@ def thorough(parent_path, name):
name_str = name.encode('utf8')
name_lower = name_str.lower()
_assert_valid_characters(name_lower)
_assert_unique(parent_path, name)

if isinstance(Path(parent_path), WindowsPath):
# use _assert_unique if we're already on Windows, because it is much faster
# than the test below
_assert_unique(parent_path, name)
return

def none(parent_path, name):
pass


def path_already_exists_case_insensitive(parent_path, name_lower):
# os.listdir is much faster here than os.walk or parent_path.iterdir
for item in os.listdir(str(parent_path)):
for item in os.listdir(parent_path):
if name_lower == item.lower():
raise RuntimeError(
"A directory with name (case independent) '{}' already exists "
" and cannot be made according to the naming rule 'thorough'.".format(name)
)
return True
return False


def none(parent_path, name):
pass
def path_already_exists_case_sensitive(parent_path, name):
# os.listdir is much faster here than os.walk or parent_path.iterdir
for item in os.listdir(parent_path):
if name == item:
return True
return False

0 comments on commit 7afe2ef

Please sign in to comment.