Skip to content

Commit b5cce60

Browse files
committed
fix: Recognize avatar content type without libmagic
The magic package for libmagic support has many different implementations that conflict with each other. For the avatar only JPEG, GIF and PNG are supported in Jira Could REST API and also BMP and WBMP for Data Center, so we can decide which it is ourselves.
1 parent 6dbc5cf commit b5cce60

File tree

5 files changed

+20
-49
lines changed

5 files changed

+20
-49
lines changed

.config/constraints.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ docutils==0.21.2
1717
exceptiongroup==1.2.2 ; python_full_version < '3.11'
1818
execnet==2.1.1
1919
executing==2.2.0
20-
filemagic==1.6
2120
flaky==3.8.1
2221
furo==2024.8.6
2322
gssapi==1.9.0 ; sys_platform != 'win32'

docs/conf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
("py:class", "jira.resources.AnyLike"), # Dummy subclass for type checking
5757
("py:meth", "__recoverable"), # ResilientSession, not autogenerated
5858
# From other packages
59-
("py:mod", "filemagic"),
6059
("py:mod", "ipython"),
6160
("py:mod", "pip"),
6261
("py:class", "_io.BufferedReader"),

docs/installation.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,5 @@ Dependencies
3838
- :py:mod:`requests-oauthlib` - Used to implement OAuth. The latest version as of this writing is 1.3.0.
3939
- :py:mod:`requests-kerberos` - Used to implement Kerberos.
4040
- :py:mod:`ipython` - The `IPython enhanced Python interpreter <https://ipython.org>`_ provides the fancy chrome used by :ref:`jirashell-label`.
41-
- :py:mod:`filemagic` - This library handles content-type autodetection for things like image uploads. This will only work on a system that provides libmagic; Mac and Unix will almost always have it preinstalled, but Windows users will have to use Cygwin or compile it natively. If your system doesn't have libmagic, you'll have to manually specify the ``contentType`` parameter on methods that take an image object, such as project and user avatar creation.
4241

4342
Installing through :py:mod:`pip` takes care of these dependencies for you.

jira/client.py

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414
import hashlib
1515
import json
1616
import logging as _logging
17-
import mimetypes
1817
import os
1918
import re
2019
import sys
21-
import tempfile
2220
import time
2321
import urllib
2422
import warnings
@@ -606,8 +604,6 @@ def __init__(
606604
if len(context_path) > 0:
607605
self._options["context_path"] = context_path
608606

609-
self._try_magic()
610-
611607
assert isinstance(self._options["headers"], dict) # for mypy benefit
612608

613609
# Create Session object and update with config options first
@@ -3336,9 +3332,7 @@ def create_temp_project_avatar(
33363332
33373333
The avatar created is temporary and must be confirmed before it can be used.
33383334
3339-
Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type
3340-
this mechanism relies on libmagic and will not work out of the box on Windows systems
3341-
(see `Their Documentation <https://filemagic.readthedocs.io/en/latest/guide.html>`_ for details on how to install support).
3335+
Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type.
33423336
33433337
The ``contentType`` argument can be used to explicitly set the value (note that Jira will reject any type other than the well-known ones for images, e.g. ``image/jpg``, ``image/png``, etc.)
33443338
@@ -4051,9 +4045,7 @@ def create_temp_user_avatar(
40514045
40524046
The avatar created is temporary and must be confirmed before it can be used.
40534047
4054-
Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type:
4055-
this mechanism relies on ``libmagic`` and will not work out of the box on Windows systems
4056-
(see `Their Documentation <https://filemagic.readthedocs.io/en/latest/guide.html>`_ for details on how to install support).
4048+
Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type.
40574049
The ``contentType`` argument can be used to explicitly set the value
40584050
(note that Jira will reject any type other than the well-known ones for images, e.g. ``image/jpg``, ``image/png``, etc.)
40594051
@@ -4631,49 +4623,32 @@ def _find_for_resource(
46314623
raise JIRAError("Unable to find resource %s(%s)", resource_cls, str(ids))
46324624
return resource
46334625

4634-
def _try_magic(self):
4635-
try:
4636-
import weakref
4637-
4638-
import magic
4639-
except ImportError:
4640-
self._magic = None
4641-
else:
4642-
try:
4643-
_magic = magic.Magic(flags=magic.MAGIC_MIME_TYPE)
4644-
4645-
def cleanup(x):
4646-
_magic.close()
4647-
4648-
self._magic_weakref = weakref.ref(self, cleanup)
4649-
self._magic = _magic
4650-
except TypeError:
4651-
self._magic = None
4652-
except AttributeError:
4653-
self._magic = None
4654-
46554626
def _get_mime_type(self, buff: bytes) -> str | None:
4656-
"""Get the MIME type for a given stream of bytes.
4627+
"""Get the MIME type for a given stream of bytes of an avatar.
46574628
46584629
Args:
46594630
buff (bytes): Stream of bytes
46604631
46614632
Returns:
46624633
Optional[str]: the MIME type
46634634
"""
4664-
if self._magic is not None:
4665-
return self._magic.id_buffer(buff)
4666-
try:
4667-
with tempfile.TemporaryFile() as f:
4668-
f.write(buff)
4669-
return mimetypes.guess_type(f.name)[0]
4670-
return mimetypes.guess_type(f.name)[0]
4671-
except (OSError, TypeError):
4672-
self.log.warning(
4673-
"Couldn't detect content type of avatar image"
4674-
". Specify the 'contentType' parameter explicitly."
4675-
)
4676-
return None
4635+
# We assume the image is one of supported formats
4636+
# https://docs.atlassian.com/software/jira/docs/api/REST/9.14.0/#api/2/project-storeTemporaryAvatar
4637+
if buff[:3] == b"\xff\xd8\xff":
4638+
return "image/jpeg"
4639+
if buff[:8] == b"\x89PNG\r\n\x1a\n":
4640+
return "image/png"
4641+
if buff[:6] in (b"GIF87a", b"GIF89a"):
4642+
return "image/gif"
4643+
if buff[:2] == b"BM":
4644+
return "image/bmp"
4645+
if buff[:2] == b"\0\0":
4646+
return "image/vnd.wap.wbmp"
4647+
self.log.warning(
4648+
"Couldn't detect content type of avatar image"
4649+
". Specify the 'contentType' parameter explicitly."
4650+
)
4651+
return None
46774652

46784653
def rename_user(self, old_user: str, new_user: str):
46794654
"""Rename a Jira user.

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ docs = [
4848
"furo"
4949
]
5050
opt = [
51-
"filemagic>=1.6",
5251
"PyJWT",
5352
"requests_jwt",
5453
"requests_kerberos"

0 commit comments

Comments
 (0)