Skip to content

Commit abf4ef4

Browse files
committed
- Add additional Ruff rules
- Improve StoreFile implementation - Update dependencies
1 parent f1d480f commit abf4ef4

17 files changed

+210
-167
lines changed

.pre-commit-config.yaml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,18 @@ repos:
1212
- id: end-of-file-fixer
1313
- id: trailing-whitespace
1414
- repo: https://github.com/asottile/pyupgrade
15-
rev: v3.3.1
15+
rev: v3.9.0
1616
hooks:
1717
- id: pyupgrade
1818
args:
19-
- --py3-plus
20-
- --keep-runtime-typing
19+
- --py37-plus
2120
- repo: https://github.com/charliermarsh/ruff-pre-commit
22-
rev: v0.0.254
21+
rev: v0.0.277
2322
hooks:
2423
- id: ruff
2524
args:
2625
- --fix
2726
- repo: https://github.com/psf/black
28-
rev: 23.1.0
27+
rev: 23.7.0
2928
hooks:
3029
- id: black

pyproject.toml

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ Changelog = "https://jowilf.github.io/sqlalchemy-file/changelog/"
4444
[project.optional-dependencies]
4545
test = [
4646
"pytest >=7.2.0, <7.3.0",
47-
"mypy ==1.1.1",
48-
"ruff ==0.0.253",
49-
"black ==23.1.0",
47+
"mypy ==1.4.1",
48+
"ruff ==0.0.277",
49+
"black ==23.7.0",
5050
"coverage >=7.0.0, <7.3.0",
5151
"fasteners ==0.18",
5252
"PyMySQL[rsa] >=1.0.2, <1.1.0",
@@ -73,7 +73,7 @@ features = [
7373
]
7474
[tool.hatch.envs.default.scripts]
7575
format = [
76-
"ruff sqlalchemy_file tests docs_src --fix",
76+
"ruff sqlalchemy_file tests --fix",
7777
"black ."
7878
]
7979

@@ -135,18 +135,37 @@ source = ["sqlalchemy_file", "tests"]
135135

136136
[tool.ruff]
137137
select = [
138+
"B", # flake8-bugbear
139+
"C4", # flake8-comprehensions
140+
"C90", # mccabe
141+
"D", # pydocstyle
138142
"E", # pycodestyle errors
139-
"W", # pycodestyle warnings
143+
"ERA", # eradicate
140144
"F", # pyflakes
141145
"I", # isort
142-
"C", # flake8-comprehensions
143-
"B", # flake8-bugbear
146+
"N", # pep8-naming
147+
"PIE", # flake8-pie,
148+
"PLC", # pylint - convention
149+
"PLE", # pylint - error
150+
"PLW", # pylint - warning
151+
"Q", # flake8-quotes
152+
"RET", # flake8-return,
153+
"RUF", # Ruff-specific rules
154+
"SIM", # flake8-simplify
155+
"UP", # pyupgrade
156+
"W", # pycodestyle warnings
144157
]
145-
ignore = ["E501", "B904", "B008"]
158+
ignore = ["E501", "B904", "B008", "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107", "D205"]
159+
160+
[tool.ruff.pydocstyle]
161+
convention = "google"
146162

147163
[tool.ruff.isort]
148164
known-third-party = ["sqlalchemy_file"]
149165

166+
[tool.ruff.per-file-ignores]
167+
"__init__.py" = ["F401"]
168+
150169
[tool.mypy]
151170
strict = true
152171
warn_unused_ignores = false

sqlalchemy_file/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
__version__ = "0.4.0"
22

3-
from .file import File as File
4-
from .types import FileField as FileField
5-
from .types import ImageField as ImageField
3+
from .file import File
4+
from .types import FileField, ImageField

sqlalchemy_file/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44

55
class BaseFile(typing.Dict[str, Any]):
6-
"""
7-
Base class for file object. It keeps information on a content related to a specific storage.
6+
"""Base class for file object.
7+
8+
It keeps information on a content related to a specific storage.
89
It is a specialized dictionary that provides also attribute style access,
910
the dictionary parent permits easy encoding/decoding to JSON.
1011

sqlalchemy_file/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ class ValidationError(Exception):
22
"""Base class for ValidationError
33
Parameters:
44
key: Current Column key
5-
msg: Validation error message
5+
msg: Validation error message.
66
"""
77

88
def __init__(self, key: str, msg: str): # pragma: no cover
9-
super().__init__("{}: {}".format(key, msg))
9+
super().__init__(f"{key}: {msg}")
1010
self.key = key
1111
self.msg = msg
1212

sqlalchemy_file/file.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717

1818

1919
class File(BaseFile):
20-
"""
21-
Takes a file as content and uploads it to the appropriate storage
20+
"""Takes a file as content and uploads it to the appropriate storage
2221
according to the attached Column and file information into the
2322
database as JSON.
2423
2524
Default attributes provided for all ``File`` include:
2625
2726
Attributes:
28-
27+
----------
2928
filename (str): This is the name of the uploaded file
3029
file_id: This is the generated UUID for the uploaded file
3130
upload_storage: Name of the storage used to save the uploaded file
@@ -69,7 +68,7 @@ def __init__(
6968
self._thaw()
7069

7170
def apply_validators(self, validators: List[Validator], key: str = "") -> None:
72-
"""Apply validators to current file"""
71+
"""Apply validators to current file."""
7372
for validator in validators:
7473
validator.process(self, key)
7574

@@ -78,13 +77,13 @@ def apply_processors(
7877
processors: List[Processor],
7978
upload_storage: Optional[str] = None,
8079
) -> None:
81-
"""Apply processors to current file"""
80+
"""Apply processors to current file."""
8281
for processor in processors:
8382
processor.process(self, upload_storage)
8483
self._freeze()
8584

8685
def save_to_storage(self, upload_storage: Optional[str] = None) -> None:
87-
"""Save current file into provided `upload_storage`"""
86+
"""Save current file into provided `upload_storage`."""
8887
extra = self.get("extra", {})
8988
extra.update({"content_type": self.content_type})
9089

@@ -93,6 +92,7 @@ def save_to_storage(self, upload_storage: Optional[str] = None) -> None:
9392
warnings.warn(
9493
'metadata attribute is deprecated. Use extra={"meta_data": ...} instead',
9594
DeprecationWarning,
95+
stacklevel=1,
9696
)
9797
extra.update({"meta_data": metadata})
9898

@@ -111,7 +111,7 @@ def save_to_storage(self, upload_storage: Optional[str] = None) -> None:
111111
self["file_id"] = stored_file.name
112112
self["upload_storage"] = upload_storage
113113
self["uploaded_at"] = datetime.utcnow().isoformat()
114-
self["path"] = "{}/{}".format(upload_storage, stored_file.name)
114+
self["path"] = f"{upload_storage}/{stored_file.name}"
115115
self["url"] = stored_file.get_cdn_url()
116116
self["saved"] = True
117117

@@ -125,7 +125,7 @@ def store_content(
125125
headers: Optional[Dict[str, str]] = None,
126126
) -> StoredFile:
127127
"""Store content into provided `upload_storage`
128-
with additional `metadata`. Can be use by processors
128+
with additional `metadata`. Can be used by processors
129129
to store additional files.
130130
"""
131131
name = name or str(uuid.uuid4())
@@ -137,7 +137,7 @@ def store_content(
137137
extra=extra,
138138
headers=headers,
139139
)
140-
self["files"].append("{}/{}".format(upload_storage, name))
140+
self["files"].append(f"{upload_storage}/{name}")
141141
return stored_file
142142

143143
def encode(self) -> Dict[str, Any]:

sqlalchemy_file/helpers.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,24 @@ def get_metadata_file_obj(metadata: Dict[str, Any]) -> "SpooledTemporaryFile[byt
1818

1919

2020
def get_content_from_file_obj(fileobj: Any) -> Any:
21-
"""Provides a real file object from file content
21+
"""Provides a real file object from file content.
22+
2223
Converts ``str`` and ``bytes`` to an actual file.
2324
"""
2425
if isinstance(fileobj, (str, bytes)):
2526
f = SpooledTemporaryFile(INMEMORY_FILESIZE)
2627
f.write(fileobj.encode() if isinstance(fileobj, str) else fileobj)
2728
f.seek(0)
2829
return f
29-
elif getattr(fileobj, "file", None) is not None:
30+
if getattr(fileobj, "file", None) is not None:
3031
return fileobj.file
3132
return fileobj
3233

3334

3435
def get_filename_from_fileob(fileobj: Any) -> Any:
3536
if getattr(fileobj, "filename", None) is not None:
3637
return fileobj.filename
37-
elif getattr(fileobj, "name", None) is not None:
38+
if getattr(fileobj, "name", None) is not None:
3839
return os.path.basename(fileobj.name)
3940
return "unnamed"
4041

@@ -66,11 +67,12 @@ def convert_size(size: Union[str, int]) -> int:
6667
# convert size to number of bytes ex: 1k -> 1000; 1Ki->1024
6768
if isinstance(size, int):
6869
return size
69-
elif isinstance(size, str):
70+
if isinstance(size, str):
7071
pattern = re.compile(r"^(\d+)\s*(k|([KM]i?))$")
7172
m = re.fullmatch(pattern, size)
7273
if m is None:
7374
raise ValueError("Invalid size %s" % size)
7475
value, si, _ = m.groups()
7576
si_map = {"k": 1000, "K": 1000, "M": 1000**2, "Ki": 1024, "Mi": 1024**2}
7677
return int(value) * si_map[si]
78+
return None

sqlalchemy_file/mutable_list.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88

99
class MutableList(Mutable, typing.List[T]):
10-
"""
11-
A list type that implements :class:`Mutable`.
10+
"""A list type that implements :class:`Mutable`.
1211
1312
The :class:`MutableList` object implements a list that will
1413
emit change events to the underlying mapping when the contents of
@@ -32,8 +31,7 @@ def coerce(cls, key: Any, value: Any) -> Any:
3231
return MutableList(value)
3332
# this call will raise ValueError
3433
return Mutable.coerce(key, value) # pragma: no cover
35-
else:
36-
return value # pragma: no cover
34+
return value # pragma: no cover
3735

3836
@no_type_check
3937
def __reduce_ex__(self, proto): # pragma: no cover
@@ -50,20 +48,14 @@ def __setstate__(self, state: Any) -> None: # pragma: no cover
5048

5149
def __setitem__(self, index: Any, value: Any) -> None:
5250
"""Detect list set events and emit change events."""
53-
if isinstance(index, slice):
54-
old_value = self[index]
55-
else:
56-
old_value = [self[index]]
51+
old_value = self[index] if isinstance(index, slice) else [self[index]]
5752
list.__setitem__(self, index, value)
5853
self.changed()
5954
self._removed.extend(old_value)
6055

6156
def __delitem__(self, index: Any) -> None:
6257
"""Detect list del events and emit change events."""
63-
if isinstance(index, slice):
64-
old_value = self[index]
65-
else:
66-
old_value = [self[index]]
58+
old_value = self[index] if isinstance(index, slice) else [self[index]]
6759
list.__delitem__(self, index)
6860
self.changed()
6961
self._removed.extend(old_value)

sqlalchemy_file/processors.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010

1111

1212
class Processor:
13-
"""
14-
Interface that must be implemented by file processors.
13+
"""Interface that must be implemented by file processors.
1514
Can be used to add additional data to the stored file or change it.
1615
When file processors are run the file has already been stored.
1716
@@ -21,21 +20,18 @@ class Processor:
2120
def process(
2221
self, file: "File", upload_storage: Optional[str] = None
2322
) -> None: # pragma: no cover
24-
"""
25-
Should be overridden in inherited class
23+
"""Should be overridden in inherited class
2624
Parameters:
2725
file: [File][sqlalchemy_file.file.File] object,
2826
Use file.original_content to access uploaded file
2927
upload_storage: pass this to
3028
[file.store_content()][sqlalchemy_file.file.File.store_content]
31-
to attach additional files to the original file
29+
to attach additional files to the original file.
3230
"""
33-
pass
3431

3532

3633
class ThumbnailGenerator(Processor):
37-
"""
38-
Generate thumbnail from original content.
34+
"""Generate thumbnail from original content.
3935
4036
The default thumbnail format and size are `PNG@128x128`, those can be changed
4137
by giving custom `thumbnail_size` and `thumbnail_format`
@@ -135,7 +131,7 @@ def process(self, file: "File", upload_storage: Optional[str] = None) -> None:
135131
"width": width,
136132
"height": height,
137133
"upload_storage": upload_storage,
138-
"path": "{}/{}".format(upload_storage, stored_file.name),
134+
"path": f"{upload_storage}/{stored_file.name}",
139135
"url": stored_file.get_cdn_url(),
140136
}
141137
}

0 commit comments

Comments
 (0)