Skip to content
Open
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
1 change: 0 additions & 1 deletion .config/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ docutils==0.21.2
exceptiongroup==1.2.2 ; python_full_version < '3.11'
execnet==2.1.1
executing==2.2.0
filemagic==1.6
flaky==3.8.1
furo==2024.8.6
gssapi==1.9.0 ; sys_platform != 'win32'
Expand Down
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
("py:class", "jira.resources.AnyLike"), # Dummy subclass for type checking
("py:meth", "__recoverable"), # ResilientSession, not autogenerated
# From other packages
("py:mod", "filemagic"),
("py:mod", "ipython"),
("py:mod", "pip"),
("py:class", "_io.BufferedReader"),
Expand Down
1 change: 0 additions & 1 deletion docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,5 @@ Dependencies
- :py:mod:`requests-oauthlib` - Used to implement OAuth. The latest version as of this writing is 1.3.0.
- :py:mod:`requests-kerberos` - Used to implement Kerberos.
- :py:mod:`ipython` - The `IPython enhanced Python interpreter <https://ipython.org>`_ provides the fancy chrome used by :ref:`jirashell-label`.
- :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.

Installing through :py:mod:`pip` takes care of these dependencies for you.
65 changes: 20 additions & 45 deletions jira/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
import hashlib
import json
import logging as _logging
import mimetypes
import os
import re
import sys
import tempfile
import time
import urllib
import warnings
Expand Down Expand Up @@ -606,8 +604,6 @@ def __init__(
if len(context_path) > 0:
self._options["context_path"] = context_path

self._try_magic()

assert isinstance(self._options["headers"], dict) # for mypy benefit

# Create Session object and update with config options first
Expand Down Expand Up @@ -3336,9 +3332,7 @@ def create_temp_project_avatar(

The avatar created is temporary and must be confirmed before it can be used.

Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type
this mechanism relies on libmagic and will not work out of the box on Windows systems
(see `Their Documentation <https://filemagic.readthedocs.io/en/latest/guide.html>`_ for details on how to install support).
Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type.

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.)

Expand Down Expand Up @@ -4051,9 +4045,7 @@ def create_temp_user_avatar(

The avatar created is temporary and must be confirmed before it can be used.

Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type:
this mechanism relies on ``libmagic`` and will not work out of the box on Windows systems
(see `Their Documentation <https://filemagic.readthedocs.io/en/latest/guide.html>`_ for details on how to install support).
Avatar images are specified by a filename, size, and file object. By default, the client will attempt to autodetect the picture's content type.
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.)

Expand Down Expand Up @@ -4631,49 +4623,32 @@ def _find_for_resource(
raise JIRAError("Unable to find resource %s(%s)", resource_cls, str(ids))
return resource

def _try_magic(self):
try:
import weakref

import magic
except ImportError:
self._magic = None
else:
try:
_magic = magic.Magic(flags=magic.MAGIC_MIME_TYPE)

def cleanup(x):
_magic.close()

self._magic_weakref = weakref.ref(self, cleanup)
self._magic = _magic
except TypeError:
self._magic = None
except AttributeError:
self._magic = None

def _get_mime_type(self, buff: bytes) -> str | None:
"""Get the MIME type for a given stream of bytes.
"""Get the MIME type for a given stream of bytes of an avatar.

Args:
buff (bytes): Stream of bytes

Returns:
Optional[str]: the MIME type
"""
if self._magic is not None:
return self._magic.id_buffer(buff)
try:
with tempfile.TemporaryFile() as f:
f.write(buff)
return mimetypes.guess_type(f.name)[0]
return mimetypes.guess_type(f.name)[0]
except (OSError, TypeError):
self.log.warning(
"Couldn't detect content type of avatar image"
". Specify the 'contentType' parameter explicitly."
)
return None
# We assume the image is one of supported formats
# https://docs.atlassian.com/software/jira/docs/api/REST/9.14.0/#api/2/project-storeTemporaryAvatar
if buff[:3] == b"\xff\xd8\xff":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you investigate teh filetype package?

Copy link
Author

@kohtala kohtala Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It is mentioned in #1847 with a concern about it's maintenance. Also #1867 raises several concerns. On #1867 @ssbarnea commented on a plan to review and remove dependencies.

Jira supports a limited set of file types that are quite simple to tell apart. I expect any other MIME-types to be rejected by Jira. If Jira does not validate input, it could be a potential security issue on Jira.

Therefore I find that any dependency with wider support for file types does not add anything beyond this simple MIME-type discovery.

In my opinion, when use of a dependency is a larger and more complex problem than the root problem being solved, the solution does not need to be delegated to the dependency.

Do you know of any Jira instance that would accept any other MIME types to warrant a dependency that supports lots of MIME types?

return "image/jpeg"
if buff[:8] == b"\x89PNG\r\n\x1a\n":
return "image/png"
if buff[:6] in (b"GIF87a", b"GIF89a"):
return "image/gif"
if buff[:2] == b"BM":
return "image/bmp"
if buff[:2] == b"\0\0":
return "image/vnd.wap.wbmp"
self.log.warning(
"Couldn't detect content type of avatar image"
". Specify the 'contentType' parameter explicitly."
)
return None

def rename_user(self, old_user: str, new_user: str):
"""Rename a Jira user.
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ docs = [
"furo"
]
opt = [
"filemagic>=1.6",
"PyJWT",
"requests_jwt",
"requests_kerberos"
Expand Down
Loading