Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to new python versions #17

Merged
merged 4 commits into from
Aug 15, 2024
Merged
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
3 changes: 1 addition & 2 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, 3.10, 3.11, 3.12]

python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand Down
28 changes: 14 additions & 14 deletions filestorage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@

def _read(rel_path):
here = os.path.abspath(os.path.dirname(__file__))
with codecs.open(os.path.join(here, rel_path), 'r') as fp:
with codecs.open(os.path.join(here, rel_path), "r") as fp:
return fp.read()


__version__ = _read('VERSION').strip()
__version__ = _read("VERSION").strip()

# Instantiate the store singleton
store = StorageContainer()


__all__ = [
'store',
'StorageContainer',
'StorageHandlerBase',
'AsyncStorageHandlerBase',
'FileItem',
'FilterBase',
'AsyncFilterBase',
'exceptions',
'handlers',
'filters',
'pyramid_config',
'config_utils',
"store",
"StorageContainer",
"StorageHandlerBase",
"AsyncStorageHandlerBase",
"FileItem",
"FilterBase",
"AsyncFilterBase",
"exceptions",
"handlers",
"filters",
"pyramid_config",
"config_utils",
]
76 changes: 38 additions & 38 deletions filestorage/config_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

def try_import(default_module: str, model: str):
"""Attempt to import the given name."""
module_name, _, cls_name = model.rpartition('.')
module_name, _, cls_name = model.rpartition(".")
module_name = module_name or default_module
try:
module = importlib.import_module(module_name)
cls = getattr(module, cls_name)
except (ImportError):
raise ValueError('module not installed')
except ImportError:
raise ValueError("module not installed")
except AttributeError:
raise ValueError('bad class name')
raise ValueError("bad class name")

return cls

Expand All @@ -32,14 +32,14 @@ def get_init_properties(cls, to_class=object) -> Set[str]:
Returns a set of all parameters found.
"""
result = set()
init = getattr(cls, '__init__', None)
init = getattr(cls, "__init__", None)

if init is not None:
for param in inspect.signature(init).parameters.values():
if param.kind == param.VAR_KEYWORD:
# Ignore any **kwargs
continue
if param.name == 'self':
if param.name == "self":
continue

result.add(param.name)
Expand All @@ -53,7 +53,7 @@ def get_init_properties(cls, to_class=object) -> Set[str]:
def setup_from_settings(
settings: Dict[str, str],
store: StorageContainer,
key_prefix: str = 'store',
key_prefix: str = "store",
) -> bool:
"""Setup the provided store with the settings dictionary.
Will only pay attention to keys that start with the key_prefix.
Expand All @@ -68,7 +68,7 @@ def setup_from_settings(

# If there's configuration to be had, setup the store with it.
if settings_dict:
setup_store(store, key_prefix, '', settings_dict)
setup_store(store, key_prefix, "", settings_dict)
return True
else:
# Otherwise, assume that the store isn't going to be used now
Expand All @@ -82,26 +82,26 @@ def setup_store(
"""Setup a specific store to the given name in the settings_dict.
key_prefix denotes where this name came from (for good error messages).
"""
name = name or ''
name = name or ""
try:
handler_class_name = settings_dict['handler'][None]
handler_class_name = settings_dict["handler"][None]
except KeyError:
raise FilestorageConfigError(
f'Pyramid settings has no key for {key_prefix}{name}.handler'
f"Pyramid settings has no key for {key_prefix}{name}.handler"
)
if handler_class_name.lower() == 'none':
if handler_class_name.lower() == "none":
handler = None
else:
handler = get_handler(key_prefix + name, settings_dict['handler'])
handler = get_handler(key_prefix + name, settings_dict["handler"])

settings_dict.pop('handler')
settings_dict.pop("handler")

store.handler = handler

# Setup any sub-store configuration
for key, sub_config in settings_dict.items():
if key.startswith('[') and key.endswith(']'):
sub_store = key.lstrip('[').rstrip(']').strip('"').strip("'")
if key.startswith("[") and key.endswith("]"):
sub_store = key.lstrip("[").rstrip("]").strip('"').strip("'")
setup_store(
store=store[sub_store],
key_prefix=key_prefix + key,
Expand All @@ -110,53 +110,53 @@ def setup_store(
)
else:
raise FilestorageConfigError(
f'Pyramid settings unknown key {key_prefix}.{key}'
f"Pyramid settings unknown key {key_prefix}.{key}"
)


def get_handler(key_prefix: str, settings_dict: Dict) -> StorageHandlerBase:
name = f'{key_prefix}.handler'
name = f"{key_prefix}.handler"
handler_name = settings_dict.pop(None)
try:
handler_cls = try_import('filestorage.handlers', handler_name)
handler_cls = try_import("filestorage.handlers", handler_name)
except ValueError:
raise FilestorageConfigError(f'Pyramid settings bad value for {name}')
raise FilestorageConfigError(f"Pyramid settings bad value for {name}")

valid_args = get_init_properties(handler_cls, StorageHandlerBase)

kwargs = {}
for key, value in settings_dict.items():
if key not in valid_args:
maybe = difflib.get_close_matches(key, valid_args, 1)
maybe_txt = ''
maybe_txt = ""
if maybe:
maybe_txt = f' Did you mean "{name}.{maybe[0]}"?'
raise FilestorageConfigError(
f'Pyramid invalid setting "{name}.{key}". {maybe_txt}'
)
if key == 'filters':
kwargs['filters'] = get_all_filters(name, value)
if key == "filters":
kwargs["filters"] = get_all_filters(name, value)
else:
kwargs[key] = decode_kwarg(value)

try:
return handler_cls(**kwargs)
except Exception as err:
raise FilestorageConfigError(
f'Pyramid settings bad args for {name}: {err}'
f"Pyramid settings bad args for {name}: {err}"
)


def get_all_filters(key_prefix: str, settings_dict: Dict) -> List[FilterBase]:
"""Get all the filters from within the settings_dict"""
filters: List[Tuple[int, FilterBase]] = []
for filter_ref, filter_dict in settings_dict.items():
filter_prefix = f'{key_prefix}.filters{filter_ref}'
filter_prefix = f"{key_prefix}.filters{filter_ref}"
try:
filter_id = int(filter_ref.lstrip('[').rstrip(']'))
filter_id = int(filter_ref.lstrip("[").rstrip("]"))
except Exception as err:
raise FilestorageConfigError(
f'Pyramid settings bad key {key_prefix}{filter_ref}: {err}'
f"Pyramid settings bad key {key_prefix}{filter_ref}: {err}"
)
filters.append((filter_id, get_filter(filter_prefix, filter_dict)))

Expand All @@ -168,18 +168,18 @@ def get_filter(key_prefix: str, settings_dict: Dict) -> FilterBase:
"""Get a single filter from within the settings_dict"""
filter_name = settings_dict.pop(None)
try:
filter_cls = try_import('filestorage.filters', filter_name)
filter_cls = try_import("filestorage.filters", filter_name)
except ValueError:
raise FilestorageConfigError(
f'Pyramid settings bad value for {key_prefix}'
f"Pyramid settings bad value for {key_prefix}"
)

kwargs = {key: decode_kwarg(value) for key, value in settings_dict.items()}
try:
return filter_cls(**kwargs)
except Exception as err:
raise FilestorageConfigError(
f'Pyramid settings bad args for {key_prefix}: {err}'
f"Pyramid settings bad args for {key_prefix}: {err}"
)


Expand All @@ -198,20 +198,20 @@ def decode_kwarg(value) -> Any:
try:
value = value.pop(None)
except KeyError:
raise ValueError(f'decode_kwarg got an invalid dict: {value!r}')
raise ValueError(f"decode_kwarg got an invalid dict: {value!r}")
return decode_kwarg(value)

if not isinstance(value, str):
raise ValueError(f'decode_kwarg expected a str, got: {value!r}')
if (value.startswith('[') and value.endswith(']')) or (
value.startswith('{') and value.endswith('}')
raise ValueError(f"decode_kwarg expected a str, got: {value!r}")
if (value.startswith("[") and value.endswith("]")) or (
value.startswith("{") and value.endswith("}")
):
# handle lists, sets and dicts
try:
return eval(value, {}, {})
except Exception as err:
raise FilestorageConfigError(
f'Pyramid settings bad value {value}: {err}'
f"Pyramid settings bad value {value}: {err}"
)

if value.isdigit():
Expand Down Expand Up @@ -258,7 +258,7 @@ def get_keys_from(prefix: str, settings: Dict) -> Dict:
"""Get nested dicts from a dictionary of . separated keys"""
result: Dict = {}
for key, value in settings.items():
if key.startswith(f'{prefix}.') or key.startswith(f'{prefix}['):
if key.startswith(f"{prefix}.") or key.startswith(f"{prefix}["):
set_nested_value(key, value, result)

return result.get(prefix, {})
Expand All @@ -269,8 +269,8 @@ def set_nested_value(key: str, value: str, result: Dict) -> Dict:
sub = result
# Add a . to each [ to make the parsing delimiter consistent:
# 'foo[0][1]' to 'foo.[0].[1]'
key = key.replace('[', '.[')
for part in key.split('.'):
key = key.replace("[", ".[")
for part in key.split("."):
sub = sub.setdefault(part, {})
sub[None] = value.strip()
return result
26 changes: 13 additions & 13 deletions filestorage/file_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class SyncReader:
def __init__(self, item: 'FileItem'):
def __init__(self, item: "FileItem"):
self.data = item.data
self.filename = item.filename
if self.data is not None:
Expand All @@ -20,14 +20,14 @@ def seek(self, offset: int, whence: int = 0) -> int:

def read(self, size: int = -1) -> bytes:
if self.data is None:
return b''
return b""
return self._reader(size)

closed = False


class AsyncReader:
def __init__(self, item: 'FileItem'):
def __init__(self, item: "FileItem"):
self.data = item.data
self.filename = item.filename
if self.data is not None:
Expand All @@ -41,7 +41,7 @@ async def seek(self, offset: int, whence: int = 0) -> int:

async def read(self, size: int = -1) -> bytes:
if self.data is None:
return b''
return b""
return await self._reader(size)

closed = False
Expand All @@ -53,21 +53,21 @@ class FileItem(NamedTuple):
data: Optional[BinaryIO] = None
media_type: Optional[str] = None # Formerly known as MIME-type

def copy(self, **kwargs) -> 'FileItem':
filename = kwargs.get('filename', self.filename)
path = kwargs.get('path', self.path)
data = kwargs.get('data', self.data)
media_type = kwargs.get('media_type', self.media_type)
def copy(self, **kwargs) -> "FileItem":
filename = kwargs.get("filename", self.filename)
path = kwargs.get("path", self.path)
data = kwargs.get("data", self.data)
media_type = kwargs.get("media_type", self.media_type)

return FileItem(
filename=filename, path=path, data=data, media_type=media_type
)

def __repr__(self) -> str:
has_data = 'no data' if self.data is None else 'with data'
has_data = "no data" if self.data is None else "with data"
return (
f'<FileItem filename:{self.filename!r} '
f'path:{self.path!r} {has_data}>'
f"<FileItem filename:{self.filename!r} "
f"path:{self.path!r} {has_data}>"
)

@property
Expand All @@ -77,7 +77,7 @@ def has_data(self) -> bool:
@property
def url_path(self) -> str:
"""A relative URL path string for this path/filename"""
return '/'.join(self.path + (self.filename,))
return "/".join(self.path + (self.filename,))

@property
def fs_path(self) -> str:
Expand Down
4 changes: 2 additions & 2 deletions filestorage/filter_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ async def async_call(self, item: FileItem) -> FileItem:
"""Apply the filter asynchronously"""
if not self.async_ok:
raise FilestorageConfigError(
f'The {self.__class__.__name__} filter cannot be used '
'asynchronously'
f"The {self.__class__.__name__} filter cannot be used "
"asynchronously"
)

if iscoroutinefunction(self._apply):
Expand Down
2 changes: 1 addition & 1 deletion filestorage/filters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .randomize_filename import RandomizeFilename
from .valid_extensions import ValidateExtension

__all__ = ['RandomizeFilename', 'ValidateExtension']
__all__ = ["RandomizeFilename", "ValidateExtension"]
Loading
Loading