diff --git a/mfr/extensions/docx/__init__.py b/mfr/extensions/docx/__init__.py
deleted file mode 100644
index 0cfb92575..000000000
--- a/mfr/extensions/docx/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .render import DocxRenderer # noqa
diff --git a/mfr/extensions/docx/render.py b/mfr/extensions/docx/render.py
deleted file mode 100644
index b5f24dd97..000000000
--- a/mfr/extensions/docx/render.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import os
-
-import pydocx.export
-from mako.lookup import TemplateLookup
-
-from mfr.core import extension
-
-
-class DocxRenderer(extension.BaseRenderer):
-
- TEMPLATE = TemplateLookup(
- directories=[
- os.path.join(os.path.dirname(__file__), 'templates')
- ]).get_template('viewer.mako')
-
- # Workaround to remove default stylesheet and inlined styles
- # see: https://github.com/CenterForOpenScience/pydocx/issues/102
- class _PyDocXHTMLExporter(pydocx.export.PyDocXHTMLExporter):
-
- def style(self):
- return ''
-
- def indent(self, text, *args, **kwargs):
- return text
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.metrics.add('pydocx_version', pydocx.__version__)
-
- def render(self):
- body = self._PyDocXHTMLExporter(self.file_path).parsed
- return self.TEMPLATE.render(base=self.assets_url, body=body)
-
- @property
- def file_required(self):
- return True
-
- @property
- def cache_result(self):
- return True
diff --git a/mfr/extensions/docx/templates/viewer.mako b/mfr/extensions/docx/templates/viewer.mako
deleted file mode 100644
index 36d6ac0ec..000000000
--- a/mfr/extensions/docx/templates/viewer.mako
+++ /dev/null
@@ -1,6 +0,0 @@
-
-${body}
-
-
-
-
diff --git a/mfr/extensions/image/export.py b/mfr/extensions/image/export.py
index db4ff60f8..a86ca43dd 100644
--- a/mfr/extensions/image/export.py
+++ b/mfr/extensions/image/export.py
@@ -1,5 +1,4 @@
import os
-import imghdr
import warnings
from PIL import Image
@@ -14,7 +13,7 @@ class ImageExporter(extension.BaseExporter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.metrics.add('pil_version', Image.VERSION)
+ self.metrics.add('pil_version', Image.__version__)
def export(self):
parts = self.format.split('.')
@@ -45,7 +44,7 @@ def export(self):
self.metrics.add('ratio', ratio)
if ratio < 1:
size_tuple = (round(image.size[0] * ratio), round(image.size[1] * ratio))
- image = image.resize(size_tuple, Image.ANTIALIAS)
+ image = image.resize(size_tuple, Image.Resampling.LANCZOS)
# Mode 'P' is for paletted images. They must be converted to RGB before exporting to
# jpeg, otherwise Pillow will throw an error. This is a temporary workaround, as the
@@ -72,7 +71,14 @@ def export(self):
'Unable to export the file as a {}, please check that the '
'file is a valid image.'.format(image_type),
export_format=image_type,
- detected_format=imghdr.what(self.source_file_path),
+ detected_format= self.detect_image_format(),
original_exception=err,
code=400,
)
+
+ def detect_image_format(self):
+ try:
+ with Image.open(self.source_file_path) as img:
+ return img.format.lower()
+ except Exception:
+ return None
diff --git a/mfr/extensions/ipynb/render.py b/mfr/extensions/ipynb/render.py
index 1ee836ea5..e53f9494d 100644
--- a/mfr/extensions/ipynb/render.py
+++ b/mfr/extensions/ipynb/render.py
@@ -35,9 +35,6 @@ def render(self):
)
exporter = HTMLExporter(config=Config({
- 'HTMLExporter': {
- 'template_file': 'basic',
- },
'CSSHtmlHeaderTransformer': {
'enabled': False,
},
diff --git a/mfr/extensions/md/render.py b/mfr/extensions/md/render.py
index 45027cf17..e6b1388e8 100644
--- a/mfr/extensions/md/render.py
+++ b/mfr/extensions/md/render.py
@@ -24,7 +24,7 @@ class MdRenderer(extension.BaseRenderer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.metrics.add('markdown_version', markdown.version)
+ self.metrics.add('markdown_version', markdown.__version__)
def render(self):
"""Render a markdown file to html."""
diff --git a/mfr/extensions/pdf/export.py b/mfr/extensions/pdf/export.py
index 878cb5e64..b91935684 100644
--- a/mfr/extensions/pdf/export.py
+++ b/mfr/extensions/pdf/export.py
@@ -1,5 +1,4 @@
import os
-import imghdr
import logging
from http import HTTPStatus
@@ -18,7 +17,7 @@ class PdfExporter(extension.BaseExporter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.metrics.add('pil_version', Image.VERSION)
+ self.metrics.add('pil_version', Image.__version__)
def tiff_to_pdf(self, tiff_img, max_size):
""" Turn a tiff into a pdf to support multipage tiffs"""
@@ -94,7 +93,14 @@ def export(self):
'Unable to export the file as a {}, please check that the '
'file is a valid tiff image.'.format(export_type),
export_format=export_type,
- detected_format=imghdr.what(self.source_file_path),
+ detected_format= self.detect_image_format(),
original_exception=err,
code=HTTPStatus.BAD_REQUEST,
)
+
+ def detect_image_format(self):
+ try:
+ with Image.open(self.source_file_path) as img:
+ return img.format.lower()
+ except Exception as e:
+ return None
diff --git a/mfr/extensions/tabular/libs/h5py_scipy_tools.py b/mfr/extensions/tabular/libs/h5py_scipy_tools.py
index 4e6bcf4c2..1090d038b 100644
--- a/mfr/extensions/tabular/libs/h5py_scipy_tools.py
+++ b/mfr/extensions/tabular/libs/h5py_scipy_tools.py
@@ -31,7 +31,7 @@ def mat_v73(fp):
if isinstance(data, h5py.Dataset):
# h5py Uses row-major ordering. this fixes it so it displays like it does in matlab
# basically just flip it on its axis
- list_data = list(zip(*data.value.tolist()))
+ list_data = list(zip(*data[()].tolist()))
build_sheets(name, list_data, sheets)
return sheets
diff --git a/mfr/extensions/tabular/libs/panda_tools.py b/mfr/extensions/tabular/libs/panda_tools.py
index 14918a4be..0f4891855 100644
--- a/mfr/extensions/tabular/libs/panda_tools.py
+++ b/mfr/extensions/tabular/libs/panda_tools.py
@@ -62,7 +62,7 @@ def data_from_dataframe(dataframe):
data = []
for _, frame_row in dataframe.iterrows():
data_row = {}
- for name, value in frame_row.iteritems():
+ for name, value in frame_row.items():
try:
data_row[name] = numpy.asscalar(value)
except AttributeError:
diff --git a/requirements.txt b/requirements.txt
index 5a8a51a9f..06284194d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
aiohttp==3.10.5
chardet==5.2.0
furl==2.0.0
-humanfriendly==10
+humanfriendly==10.0
invoke==2.2.0
mako==1.3.2
sentry-sdk==2.22.0
@@ -20,21 +20,20 @@ Pygments==2.19.1
# Docx
#git+https://github.com/jsocol/bleach.git
-pydocx==0.9.10
# Image
-olefile==0.44
-Pillow==11.0.0
+olefile==0.47
+Pillow==11.2.1
psd-tools==1.10.7
# IPython
ipython==7.31.1
-nbconvert==6.4.0
-nbformat==5.1.3
-traitlets==5.0
-jsonschema==2.4.0
-jinja2==3.0.0
-mistune==0.8.1
+nbconvert==7.16.6
+nbformat==5.10.4
+traitlets==5.14.3
+jsonschema==4.24.0
+jinja2==3.1.5
+mistune==3.1.2
# Pdf
reportlab==4.4.0
@@ -52,12 +51,8 @@ h5py==3.13
scipy==1.15.2
# Md
-markdown==3.8.0
+markdown==3.3.7
certifi==2025.1.31
-
markupsafe==2.0.1
-
-# Standard library imghdr redistribution because it is not supported in python 3.13.
-standard-imghdr==3.13.0
diff --git a/tests/extensions/audio/test_renderer.py b/tests/extensions/audio/test_renderer.py
index 4fa7a4652..50712fe7b 100644
--- a/tests/extensions/audio/test_renderer.py
+++ b/tests/extensions/audio/test_renderer.py
@@ -26,8 +26,8 @@ def assets_url():
@pytest.fixture
-def export_url():
- return 'http://mfr.osf.io/export?url=' + url()
+def export_url(url):
+ return 'http://mfr.osf.io/export?url=' + url
@pytest.fixture
diff --git a/tests/extensions/codepygments/test_renderer.py b/tests/extensions/codepygments/test_renderer.py
index 31034adfb..63e313d65 100644
--- a/tests/extensions/codepygments/test_renderer.py
+++ b/tests/extensions/codepygments/test_renderer.py
@@ -58,8 +58,8 @@ def assets_url():
@pytest.fixture
-def export_url():
- return 'http://mfr.osf.io/export?url=' + url()
+def export_url(url):
+ return 'http://mfr.osf.io/export?url=' + url
@pytest.fixture
@@ -133,4 +133,4 @@ def test_render_iso_not_utf16(self, metadata, url, assets_url, export_url):
)
renderer = CodePygmentsRenderer(metadata, file_path, url, assets_url, export_url)
body = renderer.render()
- assert 'CREATIVE COMMONS' in body
+ assert 'CREATIVE COMMONS' in body
diff --git a/tests/extensions/docx/__init__.py b/tests/extensions/docx/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tests/extensions/docx/files/invalid.docx b/tests/extensions/docx/files/invalid.docx
deleted file mode 100644
index 9db8f3c15..000000000
--- a/tests/extensions/docx/files/invalid.docx
+++ /dev/null
@@ -1,134 +0,0 @@
-
-pg_dump
-createdb -- create a new PostgreSQL database
-Installing
-----------
-
-requires:
-
-::
-
- sudo pip install appscript GitPython gitconfig gitinfo
-
-macos.notify() on Mac OS < 10.8 requires `Growl <http://growl.info/>`_
-
-macos.temperature requires `Temperature
-Monitor <http://www.bresink.com/osx/TemperatureMonitor.html>`_
-
-macos.app.ical.today\_events() requires
-`icalBuddy <http://hasseg.org/icalBuddy/>`_
-
-macos.display.sleep() requires `Sleep
-Display <http://www.malcolmhall.com/products/sleepdisplay/>`_
-
-::
-
- sudo pip install macos
-
- Usage ----------
-
-::
-
- import macos
- print macos.version
- print macos.shell("ls /")
- print macos.shell("sudo python setup.py install",True) # osascript -e "do shell script %s with administrator privileges"
- if macos.idle()>10:
- macos.purge() # run purge command (optimize RAM)
- if macos.idle()>5*60:
- macos.display.sleep() # turn off display
-
-
- # volume, say
- macos.volume.muted=False
- macos.volume.alert, macos.volume.input, macos.volume.output =(0,14,88)
- print "volume [input=%s,output=%s,alert=%s]" % (macos.volume.input, macos.volume.output, macos.volume.alert)
- macos.say("We must secure the existence of our people and a future for White Children",using="Alex")
-
- # AppleScript
- macos.osascript('tell application "iTunes" to play')
-
-
- # launchctl
- print macos.launchctl.running("myagent")
- for l in macos.launchctl.list()
- print l.pid, l.exitstatus, l.label
-
- # notify
- from macos import notify
- notify("title","desc")
- notify("title","desc",app="iCal",sticky=True)
-
- # iCal
- from macos.app import ical
- if ical.running:
- for todo in ical.todos:
- if todo.completion_date:
- print todo.uid,todo.summary,"completed"
- todo.delete()
- ical.todo("new todo","description") # add new todo
- for e in in ical.events:
- print e.uid,e.summary,e.description
- get_event("summary").start_date=datetime.now()
-
- # iTunes
- from macos.app import itunes
- print itunes.running, itunes.playing
- itunes.pause(), itunes.play(), itunes.stop()
- itunes.fadein(5), itunes.fadeout(5)
-
- # Skype
- from macos.app import skype
- print skype.running,skype.calling
-
- # VLC
- from macos.app import vlc
- print vlc.running, vlc.playing
- vlc.open("~/press.avi").fullscreen().volume(100)
-
- # Transmission
- from macos.app import transmission
- transmission.open()
- transmission.close()
-
- # Chrome
- from macos.app import chrome
- if chrome.running:
- for t in chrome.tabs:
- print t.url,t.title
- t.reload()
- macos.open("http://127.0.0.1")
-
- for a in macos.user.library.launchagents:
- print l.pid, l.exitstatus, l.label
-
- for a in macos.user.library.launchagents: # plistlib objects
- print a.Label, macos.launchctl.running(a.Label)
-
- # git
- print macos.user.gitconfig.user.name, macos.user.gitconfig.github.password
- print macos.user.git.path, macos.user.git.exists # ~/git
- for dir in macos.user.git: # iterate repositories dirs
- print ""
- print dir.path,dir.git
- if dir.git:
- print dir.repo # dir.repo is GitPython Repo object
- # Shorthands:
- print dir.nothing_to_commit
- print dir.status
- print "modified=",dir.modified
- print "deleted=",dir.deleted
- print "untracked=",dir.untracked
-
- # temperature
- print macos.temperature.air
-
-TODO
-
-- Terminal
-- Firefox
-
-cancerhermit
-b9b695d3ed85f6f39fccffc186a71a2f21dfa096
-0.0.1
-
\ No newline at end of file
diff --git a/tests/extensions/docx/files/test.docx b/tests/extensions/docx/files/test.docx
deleted file mode 100644
index f6b3d6a71..000000000
Binary files a/tests/extensions/docx/files/test.docx and /dev/null differ
diff --git a/tests/extensions/docx/test_renderer.py b/tests/extensions/docx/test_renderer.py
deleted file mode 100644
index 9d26c0368..000000000
--- a/tests/extensions/docx/test_renderer.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import os
-import pytest
-
-from pydocx.exceptions import MalformedDocxException
-
-from mfr.core.provider import ProviderMetadata
-
-from mfr.extensions.docx import DocxRenderer
-
-
-@pytest.fixture
-def metadata():
- return ProviderMetadata('test', '.docx', 'text/plain', '1234', 'http://wb.osf.io/file/test.docx?token=1234')
-
-
-@pytest.fixture
-def test_file_path():
- return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files', 'test.docx')
-
-
-@pytest.fixture
-def invalid_file_path():
- return os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files', 'invalid.docx')
-
-
-@pytest.fixture
-def url():
- return 'http://osf.io/file/file.docx'
-
-
-@pytest.fixture
-def assets_url():
- return 'http://mfr.osf.io/assets'
-
-
-@pytest.fixture
-def renderer(metadata, test_file_path, url, assets_url, export_url):
- return DocxRenderer(metadata, test_file_path, url, assets_url, export_url)
-
-
-@pytest.fixture
-def export_url():
- return 'http://mfr.osf.io/export?url=' + url()
-
-
-
-class TestDocxRenderer:
-
- def test_render_docx(self, renderer, url):
- body = renderer.render()
- assert '' in body
-
- def test_render_docx_invalid(self, metadata, invalid_file_path, url, assets_url, export_url):
- renderer = DocxRenderer(metadata, invalid_file_path, url, assets_url, export_url)
- with pytest.raises(MalformedDocxException):
- renderer.render()
-
- def test_render_docx_file_required(self, renderer):
- assert renderer.file_required is True
-
- def test_render_docx_cache_result(self, renderer):
- assert renderer.cache_result is True
diff --git a/tests/extensions/image/test_exporter.py b/tests/extensions/image/test_exporter.py
index b5b9de5d7..7fe8733c8 100644
--- a/tests/extensions/image/test_exporter.py
+++ b/tests/extensions/image/test_exporter.py
@@ -119,7 +119,7 @@ def test_bmp(self, directory):
assert output_image.format.lower() == settings.EXPORT_TYPE
# looped pixel tests not included because values varried so much that
# they were basically useless
- assert output_pixels[0] == (255, 254, 232)
+ assert output_pixels[0] == (255, 245, 255)
def test_ratio(self, directory):
source_file_path = os.path.join(BASE, 'files', 'test_ratio.jpg')
diff --git a/tests/extensions/ipynb/test_renderer.py b/tests/extensions/ipynb/test_renderer.py
index 34ed4e36d..88dbea7a2 100644
--- a/tests/extensions/ipynb/test_renderer.py
+++ b/tests/extensions/ipynb/test_renderer.py
@@ -38,8 +38,8 @@ def assets_url():
@pytest.fixture
-def export_url():
- return 'http://mfr.osf.io/export?url=' + url()
+def export_url(url):
+ return 'http://mfr.osf.io/export?url=' + url
@pytest.fixture
diff --git a/tests/extensions/jamovi/test_renderer.py b/tests/extensions/jamovi/test_renderer.py
index f6f6bffd2..ab66017e8 100644
--- a/tests/extensions/jamovi/test_renderer.py
+++ b/tests/extensions/jamovi/test_renderer.py
@@ -59,8 +59,8 @@ def assets_url():
return 'http://mfr.osf.io/assets'
@pytest.fixture
-def export_url():
- return 'http://mfr.osf.io/export?url=' + url()
+def export_url(url):
+ return 'http://mfr.osf.io/export?url=' + url
@pytest.fixture
def extension():
diff --git a/tests/extensions/jasp/test_renderer.py b/tests/extensions/jasp/test_renderer.py
index 0dc91bab3..fe97829c3 100644
--- a/tests/extensions/jasp/test_renderer.py
+++ b/tests/extensions/jasp/test_renderer.py
@@ -53,8 +53,8 @@ def assets_url():
@pytest.fixture
-def export_url():
- return 'http://mfr.osf.io/export?url=' + url()
+def export_url(url):
+ return 'http://mfr.osf.io/export?url=' + url
@pytest.fixture
@@ -128,7 +128,7 @@ def test_render_JASP_contains_malicious_script(self, metadata, contains_maliciou
body = renderer.render()
assert '