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 '