Skip to content

Commit 2389e29

Browse files
Merge pull request #66 from insightindustry/issue-63-mimetype-validator
Closes #63 by adding a MIME type validator and checker.
2 parents 259dbb3 + a9f05a4 commit 2389e29

11 files changed

+1508
-4
lines changed

README.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ Validators
215215
-
216216
-
217217
- ``writeable``
218-
-
218+
- ``mimetype``
219219
* -
220220
-
221221
-
@@ -275,7 +275,7 @@ Checkers
275275
-
276276
-
277277
- ``is_writeable``
278-
-
278+
- ``is_mimetype``
279279
* - ``is_iterable``
280280
-
281281
-

docs/_checker_list.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
-
5252
-
5353
- :func:`is_executable <validator_collection.checkers.is_executable>`
54-
-
54+
- :func:`is_mimetype <validator_collection.checkers.is_mimetype>`
5555
* - :func:`is_not_empty <validator_collection.checkers.is_not_empty>`
5656
-
5757
-

docs/_validator_list.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
-
4747
-
4848
- :func:`writeable <validator_collection.validators.writeable>`
49-
-
49+
- :func:`mimetype <validator_collection.validators.mimetype>`
5050
* -
5151
-
5252
-

docs/checkers.rst

+5
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,8 @@ is_mac_address
235235
-------------------
236236

237237
.. autofunction:: is_mac_address
238+
239+
is_mimetype
240+
-------------------
241+
242+
.. autofunction:: is_mimetype

docs/errors.rst

+5
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,8 @@ InvalidMACAddressError (from :class:`ValueError <python:ValueError>`)
369369
-----------------------------------------------------------------------
370370

371371
.. autoclass:: InvalidMACAddressError
372+
373+
InvalidMimeTypeError (from :class:`ValueError <python:ValueError>`)
374+
-----------------------------------------------------------------------
375+
376+
.. autoclass:: InvalidMimeTypeError

docs/validators.rst

+5
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,8 @@ mac_address
222222
--------------
223223

224224
.. autofunction:: mac_address
225+
226+
mimetype
227+
--------------
228+
229+
.. autofunction:: mimetype

tests/test_checkers.py

+703
Large diffs are not rendered by default.

tests/test_validators.py

+709
Large diffs are not rendered by default.

validator_collection/checkers.py

+22
Original file line numberDiff line numberDiff line change
@@ -1595,3 +1595,25 @@ def is_mac_address(value, **kwargs):
15951595
return False
15961596

15971597
return True
1598+
1599+
1600+
@disable_checker_on_env
1601+
def is_mimetype(value, **kwargs):
1602+
"""Indicate whether ``value`` is a valid MIME type.
1603+
1604+
:param value: The value to evaluate.
1605+
1606+
:returns: ``True`` if ``value`` is valid, ``False`` if it is not.
1607+
:rtype: :class:`bool <python:bool>`
1608+
1609+
:raises SyntaxError: if ``kwargs`` contains duplicate keyword parameters or duplicates
1610+
keyword parameters passed to the underlying validator
1611+
"""
1612+
try:
1613+
value = validators.mimetype(value, **kwargs)
1614+
except SyntaxError as error:
1615+
raise error
1616+
except Exception:
1617+
return False
1618+
1619+
return True

validator_collection/errors.py

+8
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ class InvalidMACAddressError(ValueError):
148148
"""
149149
pass
150150

151+
class InvalidMimeTypeError(ValueError):
152+
"""Exception raised when a value is not a valid MIME type.
153+
154+
**INHERITS FROM:** :class:`ValueError <python:ValueError>`
155+
156+
"""
157+
pass
158+
151159

152160
class CannotCoerceError(TypeError):
153161
"""Exception raised when a value cannot be coerced to an expected type.

validator_collection/validators.py

+47
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@
134134
TIMEDELTA_REGEX = re.compile(r'((?P<days>\d+) days?, )?(?P<hours>\d+):'
135135
r'(?P<minutes>\d+):(?P<seconds>\d+(\.\d+)?)')
136136

137+
MIME_TYPE_REGEX = re.compile(r"^multipart|[-\w.]+/[-\w.\+]+$")
138+
137139
# pylint: disable=W0613
138140

139141
## CORE
@@ -2805,3 +2807,48 @@ def mac_address(value,
28052807
'address' % value)
28062808

28072809
return value
2810+
2811+
2812+
@disable_on_env
2813+
def mimetype(value,
2814+
allow_empty = False,
2815+
**kwargs):
2816+
"""Validate that ``value`` is a valid MIME-type.
2817+
2818+
:param value: The value to validate.
2819+
:type value: :class:`str <python:str>`
2820+
2821+
:param allow_empty: If ``True``, returns :obj:`None <python:None>` if
2822+
``value`` is empty. If ``False``, raises a
2823+
:class:`EmptyValueError <validator_collection.errors.EmptyValueError>`
2824+
if ``value`` is empty. Defaults to ``False``.
2825+
:type allow_empty: :class:`bool <python:bool>`
2826+
2827+
:returns: ``value`` / :obj:`None <python:None>`
2828+
:rtype: :class:`str <python:str>` / :obj:`None <python:None>`
2829+
2830+
:raises EmptyValueError: if ``value`` is empty and ``allow_empty`` is ``False``
2831+
:raises CannotCoerceError: if ``value`` is not a valid string
2832+
:raises InvalidMimetypeError: if ``value`` is neither a valid MIME type nor empty
2833+
with ``allow_empty`` set to ``True``
2834+
2835+
"""
2836+
if not value and not allow_empty:
2837+
raise errors.EmptyValueError('value (%s) was empty' % value)
2838+
elif not value:
2839+
return None
2840+
2841+
if not isinstance(value, basestring):
2842+
raise errors.CannotCoerceError('value must be a valid string, '
2843+
'was %s' % type(value))
2844+
2845+
value = value.lower().strip()
2846+
2847+
is_valid = MIME_TYPE_REGEX.fullmatch(value)
2848+
2849+
if not is_valid:
2850+
raise errors.InvalidMimeTypeError(
2851+
'value (%s) is not a valid MIME Type' % value
2852+
)
2853+
2854+
return value

0 commit comments

Comments
 (0)