spyder-reports-0.1.1/0000755000175000017500000000000013145142762016152 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/PKG-INFO0000644000175000017500000000552013145142762017251 0ustar rlaverderlaverde00000000000000Metadata-Version: 1.1 Name: spyder-reports Version: 0.1.1 Summary: Spyder-IDE plugin for Markdown reports using Pweave. Home-page: https://github.com/spyder-ide/spyder-ide Author: Spyder Project Contributors Author-email: admin@spyder-ide.org License: MIT Description: Spyder reports plugin ===================== Spyder plugin to render Markdown reports using `Pweave `_ as a backend. Build status ------------ |circleci status| |coverage| Project information ------------------- |license| |pypi version| |gitter| .. |circleci status| image:: https://img.shields.io/circleci/project/github/spyder-ide/spyder-reports/master.svg :target: https://circleci.com/gh/spyder-ide/spyder-reports/tree/master :alt: Circle-CI build status .. |license| image:: https://img.shields.io/pypi/l/spyder-reports.svg :target: LICENSE.txt :alt: License .. |pypi version| image:: https://img.shields.io/pypi/v/spyder-reports.svg :target: https://pypi.python.org/pypi/spyder-reports :alt: Latest PyPI version .. |gitter| image:: https://badges.gitter.im/spyder-ide/spyder-reports.svg :target: https://gitter.im/spyder-ide/spyder-reports :alt: Join the chat at https://gitter.im/spyder-ide/spyder-reports .. |coverage| image:: https://coveralls.io/repos/github/spyder-ide/spyder-reports/badge.svg :target: https://coveralls.io/github/spyder-ide/spyder-reports?branch=master :alt: Code Coverage Installation ------------ Using conda ``conda install spyder-reports -c spyder-ide`` Using pip ``pip install spyder-reports`` Dependencies ------------ This project depends on: * `Spyder `_ >= 3.2 * `Pweave `_ * `Pandoc `_ Overview -------- .. image:: https://github.com/spyder-ide/spyder-reports/blob/master/doc/reports_screenshot.png :alt: Reports Screenshot Keywords: Spyder,Plugin Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: MacOS Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 spyder-reports-0.1.1/LICENSE.txt0000644000175000017500000000207513075157105020000 0ustar rlaverderlaverde00000000000000MIT License Copyright (c) 2017, Spyder Project Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. spyder-reports-0.1.1/setup.py0000644000175000017500000000421713145140600017655 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Setup script for spyder_reports.""" # Standard library imports import ast import os # Third party imports from setuptools import find_packages, setup HERE = os.path.abspath(os.path.dirname(__file__)) def get_version(module='spyder_reports'): """Get version.""" with open(os.path.join(HERE, module, '_version.py'), 'r') as f: data = f.read() lines = data.split('\n') for line in lines: if line.startswith('VERSION_INFO'): version_tuple = ast.literal_eval(line.split('=')[-1].strip()) version = '.'.join(map(str, version_tuple)) break return version def get_description(): """Get long description.""" with open(os.path.join(HERE, 'README.rst'), 'r') as f: data = f.read() return data REQUIREMENTS = ['spyder>=3.2.0', 'pweave', 'matplotlib'] setup( name='spyder-reports', version=get_version(), keywords=['Spyder', 'Plugin'], url='https://github.com/spyder-ide/spyder-ide', license='MIT', author='Spyder Project Contributors', author_email='admin@spyder-ide.org', description='Spyder-IDE plugin for Markdown reports using Pweave.', long_description=get_description(), packages=find_packages(exclude=['contrib', 'docs', 'tests*']), install_requires=REQUIREMENTS, include_package_data=True, package_data={'spyder_reports.utils': ['*.md']}, classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Operating System :: MacOS', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6' ]) spyder-reports-0.1.1/MANIFEST.in0000644000175000017500000000021213144152242017674 0ustar rlaverderlaverde00000000000000include CHANGELOG.md include CONTRIBUTORS.md include LICENSE.txt include README.rst recursive-include spyder_reports/utils/templates *.md spyder-reports-0.1.1/CONTRIBUTORS.md0000644000175000017500000000003413075157105020425 0ustar rlaverderlaverde00000000000000Spyder Project Contributors spyder-reports-0.1.1/CHANGELOG.md0000644000175000017500000001155013145141755017766 0ustar rlaverderlaverde00000000000000## Version 0.1.1 (2017-08-16) ### Issues Closed * [Issue 55](https://github.com/spyder-ide/spyder-reports/issues/55) - Add Python 2 Support * [Issue 54](https://github.com/spyder-ide/spyder-reports/issues/54) - Add build and dist to .gitignore * [Issue 53](https://github.com/spyder-ide/spyder-reports/issues/53) - Change readme image url for complete url In this release 3 issues were closed. ### Pull Requests Merged * [PR 57](https://github.com/spyder-ide/spyder-reports/pull/57) - PR: Misc fixes * [PR 56](https://github.com/spyder-ide/spyder-reports/pull/56) - PR: Add Python 2 support In this release 2 pull requests were merged ## Version 0.1 (2017-08-15) ### New features Initial release ### Bugs fixed **Issues** * [Issue 51](https://github.com/spyder-ide/spyder-reports/issues/51) - Release 0.1 * [Issue 46](https://github.com/spyder-ide/spyder-reports/issues/46) - Some fixes before 0.1 release * [Issue 43](https://github.com/spyder-ide/spyder-reports/issues/43) - Save reports * [Issue 40](https://github.com/spyder-ide/spyder-reports/issues/40) - Show some progress while report is rendering * [Issue 39](https://github.com/spyder-ide/spyder-reports/issues/39) - Disambiguate report tabs * [Issue 38](https://github.com/spyder-ide/spyder-reports/issues/38) - Render reports in Spyder's temp directory * [Issue 36](https://github.com/spyder-ide/spyder-reports/issues/36) - Render welcome.md in Spyder's temp directory * [Issue 34](https://github.com/spyder-ide/spyder-reports/issues/34) - Error at startup when opening welcome.html * [Issue 32](https://github.com/spyder-ide/spyder-reports/issues/32) - Error when trying to display error message box * [Issue 27](https://github.com/spyder-ide/spyder-reports/issues/27) - Error when rendering reports on Windows * [Issue 26](https://github.com/spyder-ide/spyder-reports/issues/26) - Use check_compatibility to deactivate this plugin in Python 2 * [Issue 23](https://github.com/spyder-ide/spyder-reports/issues/23) - Add some content to the Welcome page * [Issue 22](https://github.com/spyder-ide/spyder-reports/issues/22) - Add support for Pweave 0.30 * [Issue 14](https://github.com/spyder-ide/spyder-reports/issues/14) - Add usage and screenshot to Readme * [Issue 13](https://github.com/spyder-ide/spyder-reports/issues/13) - Add basic tests and activate CI * [Issue 12](https://github.com/spyder-ide/spyder-reports/issues/12) - Save file before rendering report * [Issue 11](https://github.com/spyder-ide/spyder-reports/issues/11) - Add framed web view and share with terminal and help viewer * [Issue 9](https://github.com/spyder-ide/spyder-reports/issues/9) - Create diferent tabs for each report * [Issue 4](https://github.com/spyder-ide/spyder-reports/issues/4) - Use as basic structure, pylint plugin In this release 19 issues were closed **Pull requests** * [PR 52](https://github.com/spyder-ide/spyder-reports/pull/52) - PR: Add Release instructions * [PR 47](https://github.com/spyder-ide/spyder-reports/pull/47) - PR: Several release fixes * [PR 45](https://github.com/spyder-ide/spyder-reports/pull/45) - PR: Save reports to disk * [PR 44](https://github.com/spyder-ide/spyder-reports/pull/44) - PR: Show render progress and errors * [PR 42](https://github.com/spyder-ide/spyder-reports/pull/42) - PR: Render reports in a temp dir * [PR 41](https://github.com/spyder-ide/spyder-reports/pull/41) - PR: Disambiguate tabs * [PR 37](https://github.com/spyder-ide/spyder-reports/pull/37) - PR: Use Spyder's temp directory to render our welcome file * [PR 35](https://github.com/spyder-ide/spyder-reports/pull/35) - PR: Remove unnecessary reloading of welcome file output * [PR 33](https://github.com/spyder-ide/spyder-reports/pull/33) - PR: Fix error with error messagebox * [PR 31](https://github.com/spyder-ide/spyder-reports/pull/31) - PR: Add pandoc as a dependency in our tests * [PR 30](https://github.com/spyder-ide/spyder-reports/pull/30) - PR: Install Spyder with pip on first CircleCI node * [PR 29](https://github.com/spyder-ide/spyder-reports/pull/29) - PR: Render report in a thread. * [PR 24](https://github.com/spyder-ide/spyder-reports/pull/24) - PR: Add some content to welcome and improve CI * [PR 21](https://github.com/spyder-ide/spyder-reports/pull/21) - PR: Add screenshot to Readme * [PR 20](https://github.com/spyder-ide/spyder-reports/pull/20) - PR: Improve Readme * [PR 19](https://github.com/spyder-ide/spyder-reports/pull/19) - PR: Use a tabs per each file * [PR 17](https://github.com/spyder-ide/spyder-reports/pull/17) - PR: Activate ciocheck in CI * [PR 15](https://github.com/spyder-ide/spyder-reports/pull/15) - PR: Activate continuous integration * [PR 8](https://github.com/spyder-ide/spyder-reports/pull/8) - PR: Pweave support * [PR 7](https://github.com/spyder-ide/spyder-reports/pull/7) - PR: Create empty widget * [PR 5](https://github.com/spyder-ide/spyder-reports/pull/5) - PR: Basic template In this release 21 pull requests were merged spyder-reports-0.1.1/README.rst0000644000175000017500000000315413145140600017631 0ustar rlaverderlaverde00000000000000Spyder reports plugin ===================== Spyder plugin to render Markdown reports using `Pweave `_ as a backend. Build status ------------ |circleci status| |coverage| Project information ------------------- |license| |pypi version| |gitter| .. |circleci status| image:: https://img.shields.io/circleci/project/github/spyder-ide/spyder-reports/master.svg :target: https://circleci.com/gh/spyder-ide/spyder-reports/tree/master :alt: Circle-CI build status .. |license| image:: https://img.shields.io/pypi/l/spyder-reports.svg :target: LICENSE.txt :alt: License .. |pypi version| image:: https://img.shields.io/pypi/v/spyder-reports.svg :target: https://pypi.python.org/pypi/spyder-reports :alt: Latest PyPI version .. |gitter| image:: https://badges.gitter.im/spyder-ide/spyder-reports.svg :target: https://gitter.im/spyder-ide/spyder-reports :alt: Join the chat at https://gitter.im/spyder-ide/spyder-reports .. |coverage| image:: https://coveralls.io/repos/github/spyder-ide/spyder-reports/badge.svg :target: https://coveralls.io/github/spyder-ide/spyder-reports?branch=master :alt: Code Coverage Installation ------------ Using conda ``conda install spyder-reports -c spyder-ide`` Using pip ``pip install spyder-reports`` Dependencies ------------ This project depends on: * `Spyder `_ >= 3.2 * `Pweave `_ * `Pandoc `_ Overview -------- .. image:: https://github.com/spyder-ide/spyder-reports/blob/master/doc/reports_screenshot.png :alt: Reports Screenshot spyder-reports-0.1.1/spyder_reports/0000755000175000017500000000000013145142762021236 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports/widgets/0000755000175000017500000000000013145142762022704 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports/widgets/tests/0000755000175000017500000000000013145142762024046 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports/widgets/tests/__init__.py0000644000175000017500000000050113144602716026152 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Tests.""" spyder-reports-0.1.1/spyder_reports/widgets/tests/test_report_widget.py0000644000175000017500000001333013144152242030326 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # # Copyright © Spyder Project Contributors # Licensed under the terms of the MIT License # """Tests for the reportsgui.""" # Third party imports import pytest import os.path as osp from qtpy.QtCore import Qt from qtpy.QtWebEngineWidgets import WEBENGINE # Spyder-IDE and Local imports from spyder_reports.widgets.reportsgui import ReportsWidget from spyder.utils.qthelpers import create_action from spyder_reports.utils import WELCOME_PATH def same_html(widget, html): """Check if certain html content is exactly the same in a web widget.""" if WEBENGINE: def callback(data): global HTML HTML = data widget.toHtml(callback) try: return html == HTML except NameError: return False else: return html == widget.mainFrame().toHtml() @pytest.fixture def setup_reports(qtbot): """Set up reports.""" widget = ReportsWidget(None) qtbot.addWidget(widget) return widget @pytest.fixture def setup_reports_actions(qtbot): """Set up reports, with some actions.""" action = create_action(None, "Some action", triggered=lambda self: None) widget = ReportsWidget(None, [action]) qtbot.addWidget(widget) return widget, action @pytest.fixture def setup_reports_close_tab(qtbot): """Set up reports widget, witha handy function to close tabs.""" reports = setup_reports(qtbot) def close_tab(index): """Find the close button and click it.""" for i in [0, 1]: # LeftSide, RightSide close_button = reports.tabs.tabBar().tabButton(index, i) if close_button: break qtbot.mouseClick(close_button, Qt.LeftButton) return reports, close_tab def test_reports(qtbot): """Run Reports Widget.""" reports = setup_reports(qtbot) assert reports def test_overwrite_welcome(qtbot): """ Test that the first rendering doesn't create a new tab. It should overwrite 'Welcome' tab instead. """ reports = setup_reports(qtbot) reports.set_html('some html', WELCOME_PATH) renderview = reports.renderviews[WELCOME_PATH] reports.set_html('some html', 'file name') assert reports.tabs.count() == 1 assert len(reports.renderviews) == 1 assert reports.renderviews['file name'] == renderview def test_open_several_tabs(qtbot): """Test behaviour when opening several tabs.""" reports = setup_reports(qtbot) reports.set_html('some html', 'file1') reports.set_html('some html', 'file2') assert reports.tabs.currentIndex() == 1 assert reports.tabs.count() == 2 # when re-rendering 'file1' should change to tab 0 reports.set_html('some html', 'file1') assert reports.tabs.currentIndex() == 0 # It shouldn't open a new tab because the file was already rendered assert reports.tabs.count() == 2 def test_close_tabs(qtbot): """ Test closing tabs. When a tab is closed also the reference to the renderview should be removed. """ reports, close_tab = setup_reports_close_tab(qtbot) fname1 = osp.join('dir', 'file1') fname2 = osp.join('dir', 'file2') reports.set_html('some html', fname1) reports.set_html('some html', fname2) assert reports.tabs.count() == 2 # close 'file2' close_tab(1) assert reports.tabs.count() == 1 assert reports.renderviews.get(fname2) is None # close 'file1' close_tab(0) assert reports.tabs.count() == 0 assert reports.renderviews.get(fname1) is None def test_move_tabs(qtbot): """Test that move_tab moves filenames list.""" reports, close_tab = setup_reports_close_tab(qtbot) reports.set_html('some html', 'file1') reports.set_html('some html', 'file2') assert reports.filenames == ['file1', 'file2'] # Move tab reports.move_tab(1, 0) assert reports.filenames == ['file2', 'file1'] # Test closing a tab close_tab(1) # closes file1 assert reports.tabs.count() == 1 assert reports.renderviews.get('file1') is None def test_set_html(qtbot): """Test set html.""" reports = setup_reports(qtbot) html = "some html" reports.set_html(html, 'file1') renderviews = reports.renderviews.get('file1') qtbot.waitUntil(lambda: same_html(renderviews.page(), html), timeout=5000) assert same_html(renderviews.page(), html) def test_set_html_from_file(qtbot, tmpdir_factory): """Test seting a html from a file.""" reports = setup_reports(qtbot) # Create html file html = "some html" html_file = tmpdir_factory.mktemp('data').join('test_report.html') html_file.write(html) reports.set_html_from_file(str(html_file)) renderviews = reports.renderviews.get(str(html_file)) qtbot.waitUntil(lambda: same_html(renderviews.page(), html), timeout=5000) assert same_html(renderviews.page(), html) def test_menu_actions(qtbot): """Test adding tooltip menu to teh widget.""" reports, action = setup_reports_actions(qtbot) assert action in reports.tabs.cornerWidget().menu().actions() def test_get_focus_report(setup_reports_close_tab): """Test get current report.""" reports, close_tab = setup_reports_close_tab fname1 = osp.join('dir', 'file1') fname2 = osp.join('dir', 'file2') reports.set_html('some html', fname1) reports.set_html('some html', fname2) assert reports.tabs.count() == 2 assert reports.get_focus_report() == fname2 # close 'file2' close_tab(1) assert reports.get_focus_report() == fname1 # close 'file1' close_tab(0) assert reports.get_focus_report() is None if __name__ == "__main__": pytest.main() spyder-reports-0.1.1/spyder_reports/widgets/reportsgui.py0000644000175000017500000001545513144152242025464 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Reports Widget.""" # Standard library imports import codecs # Third party imports from qtpy.QtCore import QUrl, Slot from qtpy.QtWidgets import (QVBoxLayout, QHBoxLayout, QLabel, QWidget, QMenu, QToolButton) # Spyder-IDE and Local imports from spyder.widgets.browser import FrameWebView from spyder.utils.sourcecode import disambiguate_fname from spyder.widgets.waitingspinner import QWaitingSpinner from spyder.widgets.tabs import BaseTabs from spyder.utils import icon_manager as ima from spyder.utils.qthelpers import (add_actions, create_toolbutton) from ..utils import WELCOME_PATH class RenderView(FrameWebView): """Web widget that shows rendered report.""" def __init__(self, parent): """Initialiaze the WebView.""" FrameWebView.__init__(self, parent) class ReportsWidget(QWidget): """Reports widget.""" def __init__(self, parent, menu_actions=None): """Initialiaze ReportsWidget.""" QWidget.__init__(self, parent) self.renderviews = {} self.filenames = [] self.menu_actions = menu_actions self.setWindowTitle("Reports") self.tabs = BaseTabs(self, actions=self.menu_actions, menu_use_tooltips=False) self.tabs.setMovable(True) self.tabs.setTabsClosable(True) self.tabs.tabCloseRequested.connect(self.close_tab) self.tabs.tabBar().tabMoved.connect(self.move_tab) # Progress bar self.progress_bar = QWidget(self) self.status_text = QLabel(self.progress_bar) self.spinner = QWaitingSpinner(self.progress_bar, centerOnParent=False) self.spinner.setNumberOfLines(12) self.spinner.setInnerRadius(2) progress_layout = QHBoxLayout() progress_layout.addWidget(self.spinner) progress_layout.addWidget(self.status_text) self.progress_bar.setLayout(progress_layout) self.progress_bar.hide() # Menu as corner widget if self.menu_actions: options_button = create_toolbutton(self, text='Options', icon=ima.icon('tooloptions')) options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) add_actions(menu, self.menu_actions) options_button.setMenu(menu) self.tabs.setCornerWidget(options_button) layout = QVBoxLayout() layout.addWidget(self.tabs) layout.addWidget(self.progress_bar) self.setLayout(layout) def set_html(self, html_text, fname, base_url=None): """Set html text.""" name = self.disambiguate_fname(fname) renderview = self.renderviews.get(fname) if WELCOME_PATH in self.renderviews and renderview is None: # Overwrite the welcome tab renderview = self.renderviews.pop(WELCOME_PATH) self.renderviews[fname] = renderview self.tabs.setTabText(0, name) self.filenames[0] = fname if renderview is None: # create a new renderview renderview = RenderView(self) self.renderviews[fname] = renderview self.tabs.addTab(renderview, name) self.filenames.append(fname) if base_url is not None: renderview.setHtml(html_text, base_url) else: renderview.setHtml(html_text) self.tabs.setCurrentWidget(renderview) self.tabs.currentChanged.emit(self.tabs.currentIndex()) def set_html_from_file(self, output_fname, input_fname=None): """Set html text from a file.""" if input_fname is None: input_fname = output_fname html = "" with codecs.open(output_fname, encoding="utf-8") as file: html = file.read() base_url = QUrl() self.set_html(html, input_fname, base_url) @Slot(str) def render_started(self, fname): """Show progress bar and starts spinner. Args: fname (str): Name of the file being rendered """ self.spinner.start() name = self.disambiguate_fname(fname) text = "Rendering: {}".format(name) self.status_text.setText(text) self.progress_bar.show() self.set_html('', fname) @Slot(str) def update_progress(self, text): """Update progress bar status text. Args: text (str): text to be displayed. """ if len(text) > 50: text = "{}...".format(text[:47]) self.status_text.setText(text) @Slot(bool, object, object) def render_finished(self, ok, fname, error): """Handle render finish signal. If error, displays it, otherwise hide progress bar. Args: ok (bool): True f the rener was succesful fname (str): Name of the file being rendered error (str): Error string to display """ self.spinner.stop() if error is not None: self.status_text.setText(error) self.close_tab(self.filenames.index(fname)) else: self.progress_bar.hide() def close_tab(self, index): """Close tab, and remove its widget form renderviews.""" fname = self.filenames.pop(index) self.renderviews.pop(fname) self.tabs.removeTab(index) def move_tab(self, start, end): """Move self.filenames list to be synchronized when tabs are moved.""" if start < 0 or end < 0: return steps = abs(end - start) direction = (end - start) // steps # +1 for right, -1 for left fnames = self.filenames for i in range(start, end, direction): fnames[i], fnames[i + direction] = fnames[i + direction], fnames[i] def disambiguate_fname(self, fname): """Generate a file name without ambiguation.""" files_path_list = [filename for filename in self.filenames if filename] return disambiguate_fname(files_path_list, fname) def get_focus_report(self): """Return current report.""" try: return self.filenames[self.tabs.currentIndex()] except IndexError: return None def test(): # pragma: no cover """Run Find in Files widget test.""" from spyder.utils.qthelpers import qapplication import sys app = qapplication() widget = ReportsWidget(None) widget.resize(640, 480) widget.show() sys.exit(app.exec_()) if __name__ == '__main__': test() spyder-reports-0.1.1/spyder_reports/widgets/__init__.py0000644000175000017500000000052213075157105025013 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Spyder Reports Widgets.""" spyder-reports-0.1.1/spyder_reports/tests/0000755000175000017500000000000013145142762022400 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports/tests/__init__.py0000644000175000017500000000051513075157105024511 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Tests for Reports.""" spyder-reports-0.1.1/spyder_reports/tests/test_plugin.py0000644000175000017500000002374213145140600025304 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # # Copyright © Spyder Project Contributors # Licensed under the terms of the MIT License # """Tests for the plugin.""" # Third party imports import pytest import os import os.path as osp # Spyder-IDE and Local imports from spyder.utils.programs import TEMPDIR from spyder_reports.reportsplugin import ReportsPlugin from spyder_reports.utils import WELCOME_PATH @pytest.fixture def setup_reports(qtbot, monkeypatch): """Set up the Reports plugin.""" monkeypatch.setattr( 'spyder_reports.reportsplugin.ReportsPlugin.initialize_plugin', lambda self: None) reports = ReportsPlugin(None) qtbot.addWidget(reports) reports.show() class MainMock(): run_menu_actions = [] # patch reports object with mock MainWindow reports.main = MainMock() # setup plugin actions (render, save, save as) reports.get_plugin_actions() return reports @pytest.fixture(scope='session', params=['mdw', 'md']) def report_file(request, tmpdir_factory): """ Fixture for create a temporary report file. Returns: str: Path of temporary report file. """ report_file = tmpdir_factory.mktemp('data').join( "'test_report.{}".format(request.param)) report_file.write('# This is a Markdown report') return str(report_file) def test_basic_initialization(qtbot, setup_reports): """Test Reports plugin initialization.""" reports = setup_reports # Assert that reports exist assert reports is not None def test_register_plugin(qtbot, setup_reports): """Test register plugin, It should render welcome page.""" reports = setup_reports def add_dockwidget(*args): pass reports.main.add_dockwidget = add_dockwidget with qtbot.waitSignal(reports.sig_render_finished, timeout=10000) as sig: reports.register_plugin() ok, filename, error = sig.args assert ok assert error is None assert 'welcome' in filename # Assert that reports exist assert reports is not None def test_basic_render(qtbot, report_file, setup_reports): """Test rendering of an basic .mdw report returning a .html file.""" reports = setup_reports output_file = reports._render_report(report_file) # Assert that output_file is an html file assert output_file.split('.')[-1] == 'html' def test_check_compability(qtbot, setup_reports, monkeypatch): """Test state and message returned by check_compatibility.""" monkeypatch.setattr('spyder_reports.reportsplugin.PYQT4', True) reports = setup_reports valid, message = reports.check_compatibility() assert not valid assert 'qt4' in message.lower() def test_get_plugin_actions(qtbot, setup_reports): """Test get plugin actions method.""" reports = setup_reports menu_actions = reports.get_plugin_actions() assert len(menu_actions) == 3 assert "Render report to HTML" in menu_actions[0].text() assert "Save Report" in menu_actions[1].text() assert "Save Report as" in menu_actions[2].text() assert "Render report to HTML" in reports.main.run_menu_actions[0].text() def test_run_reports_render(qtbot, setup_reports, report_file): """Test rendering a report when calling it from menu entry.""" reports = setup_reports class EditorStackMock(): def save(self): return True class EditorMock(): def get_current_editorstack(self): return EditorStackMock() def get_current_filename(self): return report_file class MainMock(): editor = EditorMock() def switch_to_plugin(): pass # patch reports object with mock MainWindow reports.main = MainMock() reports.switch_to_plugin = switch_to_plugin with qtbot.waitSignal(reports.sig_render_finished, timeout=5000) as sig: reports.run_reports_render() ok, filename, error = sig.args assert ok assert error is None assert osp.exists(filename) renderview = reports.report_widget.renderviews.get(report_file) assert renderview is not None def test_render_report_thread(qtbot, setup_reports, report_file): """Test rendering report in a worker thread.""" reports = setup_reports with qtbot.waitSignal(reports.sig_render_finished, timeout=5000) as sig: with qtbot.waitSignal(reports.sig_render_started): reports.render_report_thread(report_file) # Assert that progress bar was shown assert reports.report_widget.progress_bar.isVisible() assert 'Rendering' in reports.report_widget.status_text.text() ok, filename, error = sig.args assert ok assert error is None assert osp.exists(filename) # Assert that progress bar was hidden assert not reports.report_widget.progress_bar.isVisible() renderview = reports.report_widget.renderviews.get(report_file) assert renderview is not None def test_render_report_thread_error(qtbot, setup_reports): """Test rendering report in a worker thread.""" reports = setup_reports with qtbot.waitSignal(reports.sig_render_finished, timeout=5000) as sig: reports.render_report_thread('file_that_doesnt_exist.mdw') ok, filename, error = sig.args assert not ok assert "[Errno 2]" in error assert filename == 'file_that_doesnt_exist.mdw' def tab_closed(): assert reports.report_widget.tabs.count() == 0 qtbot.waitUntil(tab_closed) for renderview in reports.report_widget.renderviews: assert 'file_that_doesnt_exist' not in renderview # Assert that progress bar shows the error assert reports.report_widget.progress_bar.isVisible() assert error in reports.report_widget.status_text.text() def test_render_report_thread_not_supported(qtbot, setup_reports, tmpdir_factory): """Test rendering report in a worker thread.""" reports = setup_reports python_file = tmpdir_factory.mktemp('data').join("'test_report.py") python_file.write('# This is a python file') python_file = str(python_file) with qtbot.waitSignal(reports.sig_render_finished, timeout=5000) as sig: reports.render_report_thread(python_file) ok, filename, error = sig.args assert not ok assert "Format not supported (.py)" in error assert filename == python_file def tab_closed(): assert reports.report_widget.tabs.count() == 0 qtbot.waitUntil(tab_closed) for renderview in reports.report_widget.renderviews: assert python_file not in renderview # Assert that progress bar shows the error assert reports.report_widget.progress_bar.isVisible() assert error in reports.report_widget.status_text.text() def test_render_tmp_dir(qtbot, setup_reports, report_file): """Test that rendered files are created in spyder's tempdir.""" reports = setup_reports output_file = reports._render_report(report_file) # Test that outfile is in spyder tmp dir assert osp.samefile(osp.commonprefix([output_file, TEMPDIR]), TEMPDIR) def test_render_same_file(qtbot, setup_reports, report_file): """Test that re-rendered files are created in the same tempdir.""" reports = setup_reports output_file1 = reports._render_report(report_file) output_file2 = reports._render_report(report_file) assert osp.exists(output_file2) # Assert that file has been re-rendered in the same path assert osp.samefile(output_file1, output_file2) def test_save_report(qtbot, tmpdir_factory, setup_reports, report_file, monkeypatch): """Test saving a report. Test copying from tempdir to an user selected location. """ reports = setup_reports with qtbot.waitSignal(reports.sig_render_finished, timeout=5000) as sig: reports.render_report_thread(report_file) ok, filename, error = sig.args assert ok assert error is None assert osp.exists(filename) folder, _ = osp.split(filename) save_folder = str(tmpdir_factory.mktemp('data2')) monkeypatch.setattr('spyder_reports.reportsplugin.getexistingdirectory', lambda *args, **kwargs: save_folder) reports.save_report() assert set(os.listdir(folder)) == set(os.listdir(save_folder)) def raise_exception(): raise(Exception()) # Saving again shouldn't call getexistingdirectory monkeypatch.setattr('spyder_reports.reportsplugin.getexistingdirectory', raise_exception) reports.save_report() # Saving a new location (Save Report as...) save_folder2 = str(tmpdir_factory.mktemp('data3')) monkeypatch.setattr('spyder_reports.reportsplugin.getexistingdirectory', lambda *args, **kwargs: save_folder2) reports.save_report(new_path=True) assert set(os.listdir(folder)) == set(os.listdir(save_folder2)) # Test cancelling dialog, shouldn't call copy_tree monkeypatch.setattr('spyder_reports.reportsplugin.getexistingdirectory', lambda *args, **kwargs: '') monkeypatch.setattr('spyder_reports.reportsplugin.copy_tree', raise_exception) reports.save_report(new_path=True) def test_save_no_report(setup_reports): """Test save report when no report is open. Should do nothing, but shouldn't raise an error. """ reports = setup_reports reports.report_widget.get_focus_report = lambda: None reports.save_report() def test_activate_deactivate_actions(qtbot, setup_reports, report_file): """Test that actions should be deactivated if welcome page is open.""" reports = setup_reports with qtbot.waitSignal(reports.sig_render_finished, timeout=5000): reports.render_report_thread(WELCOME_PATH) assert not reports.save_action.isEnabled() assert not reports.save_as_action.isEnabled() with qtbot.waitSignal(reports.sig_render_finished, timeout=5000): reports.render_report_thread(report_file) qtbot.waitUntil(reports.save_action.isEnabled) qtbot.waitUntil(reports.save_as_action.isEnabled) if __name__ == "__main__": pytest.main() spyder-reports-0.1.1/spyder_reports/__init__.py0000644000175000017500000000106513132434060023340 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Spyder Reports Plugin.""" from ._version import __version__ # noqa: F401 from .reportsplugin import ReportsPlugin # The following statements are required to register this 3rd party plugin: PLUGIN_CLASS = ReportsPlugin # pylint: disable=invalid-name spyder-reports-0.1.1/spyder_reports/utils/0000755000175000017500000000000013145142762022376 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports/utils/__init__.py0000644000175000017500000000066113144152242024503 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Spyder Reports Utils.""" import os.path as osp WELCOME_PATH = osp.join(osp.dirname(__file__), 'templates', 'welcome.md') spyder-reports-0.1.1/spyder_reports/utils/templates/0000755000175000017500000000000013145142762024374 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports/utils/templates/welcome.md0000644000175000017500000000074013144152242026343 0ustar rlaverderlaverde00000000000000# Welcome to the Reports plugin ## Usage In this panel you can see the rendered output of report files, i.e: Markdown files or files with the `mdw` extension, that contain code, text, mathematical equations and graphics. It uses the the [Pweave](http://mpastell.com/pweave/) project to generate the reports. Please use the _Run > Render report to HTML_ menu entry to render a report. Reports are rendered in a temporary location, if you want to save them use the tooltip menu.spyder-reports-0.1.1/spyder_reports/_version.py0000644000175000017500000000064713145142027023435 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*-# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Version File.""" VERSION_INFO = (0, 1, 1) __version__ = '.'.join(map(str, VERSION_INFO)) spyder-reports-0.1.1/spyder_reports/reportsplugin.py0000644000175000017500000003012413144627532024527 0ustar rlaverderlaverde00000000000000# -*- coding: utf-8 -*- # ----------------------------------------------------------------------------- # Copyright (c) Spyder Project Contributors # # Licensed under the terms of the MIT License # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """Reports Plugin.""" # Standard library imports import os import os.path as osp import uuid import shutil from distutils.dir_util import copy_tree from io import StringIO from collections import defaultdict try: from contextlib import redirect_stdout except ImportError: # pragma: no cover def redirect_stdout(stdout): """Fallback function for python2 compatibility.""" return stdout # Third party imports from pweave import Pweb, __version__ as pweave_version from qtpy import PYQT4, PYSIDE from qtpy.compat import getsavefilename, getexistingdirectory from qtpy.QtCore import Qt, Signal from qtpy.QtWidgets import QVBoxLayout, QMessageBox # Spyder-IDE and Local imports from spyder.py3compat import to_text_string from spyder.utils.programs import TEMPDIR from spyder.utils.qthelpers import create_action from spyder.utils.workers import WorkerManager from spyder.utils import icon_manager as ima from .widgets.reportsgui import ReportsWidget from .utils import WELCOME_PATH try: from spyder.api.plugins import SpyderPluginWidget except ImportError: from spyder.plugins import SpyderPluginWidget # Spyder 3 compatibility REPORTS_TEMPDIR = osp.join(TEMPDIR, 'reports') class CaptureStdOutput(StringIO): """Captures IO stream and emit a signal.""" def __init__(self, sig_write): """Initialize object. Args: sig_write (Signal): signal to emit """ super(CaptureStdOutput, self).__init__() self.sig_write = sig_write def write(self, text): """Emit a signal instead of writing. (Overloaded method).""" self.sig_write.emit(text.strip()) return len(text) class Report(): """Report file. Save information about a rendered report render_tmpdir (str): Temporary dir path where the render has been saved save_path (str) Path where the plugin was last saved. TODO: Some ReportPlugin logic, as save_report, render_report could be moved to this class. """ render_tmpdir = None save_path = None class ReportsPlugin(SpyderPluginWidget): """Reports plugin.""" CONF_SECTION = 'reports' CONFIGWIDGET_CLASS = None sig_render_started = Signal(str) # input filename # Success, output filename(str), error(str) # When an error happened returns input filename instead sig_render_finished = Signal(bool, object, object) sig_render_progress = Signal(str) def __init__(self, parent=None): """ Initialize main widget. Create a basic layout and add ReportWidget. """ SpyderPluginWidget.__init__(self, parent) self.main = parent # Spyder 3 compatibility self.render_action = None self.save_action = None self.save_as_action = None # Initialize plugin self.initialize_plugin() # Create widget and add to dockwindow self.report_widget = ReportsWidget(self.main, [self.save_action, self.save_as_action]) layout = QVBoxLayout() layout.addWidget(self.report_widget) self.setLayout(layout) self.sig_render_started.connect(self.report_widget.render_started) self.sig_render_progress.connect(self.report_widget.update_progress) self.sig_render_finished.connect(self.report_widget.render_finished) self.report_widget.tabs.currentChanged.connect( self.update_actions_status) # This worker runs in a thread to avoid blocking when rendering # a report self._worker_manager = WorkerManager() # Dict to save reports information: self._reports = defaultdict(Report) # --- SpyderPluginWidget API ---------------------------------------------- def get_plugin_title(self): """Return widget title.""" return "Reports" def refresh_plugin(self): """Refresh Reports widget.""" pass def get_plugin_actions(self): """Return a list of actions related to plugin.""" self.render_action = create_action(self, "Render report to HTML", icon=self.get_plugin_icon(), triggered=self.run_reports_render) self.save_action = create_action(self, "Save Report...", icon=ima.icon('filesave'), triggered=self.save_report) self.save_as_action = create_action( self, "Save Report as...", icon=ima.icon('filesaveas'), triggered=lambda: self.save_report(new_path=True)) self.main.run_menu_actions += [self.render_action] return [self.render_action, self.save_action, self.save_as_action] def register_plugin(self): """Register plugin in Spyder's main window.""" self.main.add_dockwidget(self) # Render welcome.md in a temp location self.render_report_thread(WELCOME_PATH) self.save_action.setEnabled(False) self.save_as_action.setEnabled(False) def on_first_registration(self): """Action to be performed on first plugin registration.""" self.main.tabify_plugins(self.main.help, self) def apply_plugin_settings(self, options): """Apply configuration file's plugin settings.""" pass def check_compatibility(self): """ Check plugin requirements. - PyQt version is greater or equal to 5. """ messages = [] valid = True if PYQT4 or PYSIDE: messages.append('Spyder-reports does not work with Qt4') valid = False return valid, ", ".join(messages) # ------------------------------------------------------------------------- def update_actions_status(self): """Disable/enable actions, avoiding the welcome page to be saved.""" report = self.report_widget.get_focus_report() enabled = report is not None and report != WELCOME_PATH self.save_action.setEnabled(enabled) self.save_as_action.setEnabled(enabled) def check_create_tmp_dir(self, folder): """Create temp dir if it does not exists.""" if not os.path.exists(folder): os.makedirs(folder) def show_error_message(self, message): """Show error message.""" messageBox = QMessageBox(self) messageBox.setWindowModality(Qt.NonModal) messageBox.setAttribute(Qt.WA_DeleteOnClose) messageBox.setWindowTitle('Render Report Error') messageBox.setText(message) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.show() def save_report(self, new_path=False): """Save report. If the report was already saved, save it in the same path. If the output are several files copy temporary dir to user selected directory. If the output is just one file copy it, to the user selected path. Args: new_path: force saving in a new path """ report_filename = self.report_widget.get_focus_report() if report_filename is None: return report = self._reports[report_filename] output_filename = report.render_dir input_dir, _ = osp.split(report_filename) tmpdir, output_fname = osp.split(output_filename) output = None if new_path else report.save_path # TODO This should be improved because Pweave creates a # figures dir even when there isn't figures causing this # to evaluate always to True if len([name for name in os.listdir(tmpdir)]) > 1: # if there is more than one file save a dir if output is None: output = getexistingdirectory(parent=self, caption='Save Report', basedir=input_dir) if not osp.isdir(output): return report.save_path = output # Using distutils instead of shutil.copytree # because shutil.copytree fails if the dir already exists copy_tree(tmpdir, output) else: if output is None: basedir = osp.join(input_dir, output_fname) output, _ = getsavefilename(parent=self, caption='Save Report', basedir=basedir) if not osp.isfile(output): return report.save_path = output shutil.copy(output_filename, output) def run_reports_render(self): """Call report rendering and displays its output.""" editorstack = self.main.editor.get_current_editorstack() if editorstack.save(): fname = osp.abspath(self.main.editor.get_current_filename()) self.render_report_thread(fname) self.switch_to_plugin() def render_report_thread(self, file_name): """Render report in a thread and update the widget when finished.""" def worker_output(worker, output_file, error): """Receive the worker output, and update the widget.""" if error is None and output_file: self.report_widget.set_html_from_file(output_file, file_name) self.sig_render_finished.emit(True, output_file, None) else: self.show_error_message(to_text_string(error)) self.sig_render_finished.emit(False, file_name, to_text_string(error)) # Before starting a new worker process make sure to end previous # incarnations self._worker_manager.terminate_all() worker = self._worker_manager.create_python_worker( self._render_report, file_name, ) worker.sig_finished.connect(worker_output) self.sig_render_started.emit(file_name) worker.start() def _render_report(self, file, output=None): """ Parse report document using pweave. Args: file: Path of the file to be parsed. Return: Output file path """ if output is None: report = self._reports.get(file) if report is not None: output = report.render_dir if output is None: name = osp.splitext(osp.basename(file))[0] id_ = to_text_string(uuid.uuid4()) output = osp.join(REPORTS_TEMPDIR, id_, '{}.html'.format(name)) self._reports[file].render_dir = output folder = osp.split(output)[0] self.check_create_tmp_dir(folder) doc = Pweb(file, output=output) # TODO Add more formats support if doc.file_ext == '.mdw': _format = 'md2html' elif doc.file_ext == '.md': _format = 'pandoc2html' else: raise Exception("Format not supported ({})".format(doc.file_ext)) f = CaptureStdOutput(self.sig_render_progress) if pweave_version.startswith('0.3'): with redirect_stdout(f): self.sig_render_progress.emit("Readign") doc.read() self.sig_render_progress.emit("Running") doc.run() self.sig_render_progress.emit("Formating") doc.format(doctype=_format) self.sig_render_progress.emit("Writing") doc.write() return doc.sink else: with redirect_stdout(f): doc.setformat(_format) doc.detect_reader() doc.parse() doc.run() doc.format() doc.write() return doc.sink spyder-reports-0.1.1/spyder_reports.egg-info/0000755000175000017500000000000013145142762022730 5ustar rlaverderlaverde00000000000000spyder-reports-0.1.1/spyder_reports.egg-info/PKG-INFO0000644000175000017500000000552013145142762024027 0ustar rlaverderlaverde00000000000000Metadata-Version: 1.1 Name: spyder-reports Version: 0.1.1 Summary: Spyder-IDE plugin for Markdown reports using Pweave. Home-page: https://github.com/spyder-ide/spyder-ide Author: Spyder Project Contributors Author-email: admin@spyder-ide.org License: MIT Description: Spyder reports plugin ===================== Spyder plugin to render Markdown reports using `Pweave `_ as a backend. Build status ------------ |circleci status| |coverage| Project information ------------------- |license| |pypi version| |gitter| .. |circleci status| image:: https://img.shields.io/circleci/project/github/spyder-ide/spyder-reports/master.svg :target: https://circleci.com/gh/spyder-ide/spyder-reports/tree/master :alt: Circle-CI build status .. |license| image:: https://img.shields.io/pypi/l/spyder-reports.svg :target: LICENSE.txt :alt: License .. |pypi version| image:: https://img.shields.io/pypi/v/spyder-reports.svg :target: https://pypi.python.org/pypi/spyder-reports :alt: Latest PyPI version .. |gitter| image:: https://badges.gitter.im/spyder-ide/spyder-reports.svg :target: https://gitter.im/spyder-ide/spyder-reports :alt: Join the chat at https://gitter.im/spyder-ide/spyder-reports .. |coverage| image:: https://coveralls.io/repos/github/spyder-ide/spyder-reports/badge.svg :target: https://coveralls.io/github/spyder-ide/spyder-reports?branch=master :alt: Code Coverage Installation ------------ Using conda ``conda install spyder-reports -c spyder-ide`` Using pip ``pip install spyder-reports`` Dependencies ------------ This project depends on: * `Spyder `_ >= 3.2 * `Pweave `_ * `Pandoc `_ Overview -------- .. image:: https://github.com/spyder-ide/spyder-reports/blob/master/doc/reports_screenshot.png :alt: Reports Screenshot Keywords: Spyder,Plugin Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: MacOS Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 spyder-reports-0.1.1/spyder_reports.egg-info/requires.txt0000644000175000017500000000004013145142762025322 0ustar rlaverderlaverde00000000000000spyder>=3.2.0 pweave matplotlib spyder-reports-0.1.1/spyder_reports.egg-info/dependency_links.txt0000644000175000017500000000000113145142762026776 0ustar rlaverderlaverde00000000000000 spyder-reports-0.1.1/spyder_reports.egg-info/SOURCES.txt0000644000175000017500000000123113145142762024611 0ustar rlaverderlaverde00000000000000CHANGELOG.md CONTRIBUTORS.md LICENSE.txt MANIFEST.in README.rst setup.cfg setup.py spyder_reports/__init__.py spyder_reports/_version.py spyder_reports/reportsplugin.py spyder_reports.egg-info/PKG-INFO spyder_reports.egg-info/SOURCES.txt spyder_reports.egg-info/dependency_links.txt spyder_reports.egg-info/requires.txt spyder_reports.egg-info/top_level.txt spyder_reports/tests/__init__.py spyder_reports/tests/test_plugin.py spyder_reports/utils/__init__.py spyder_reports/utils/templates/welcome.md spyder_reports/widgets/__init__.py spyder_reports/widgets/reportsgui.py spyder_reports/widgets/tests/__init__.py spyder_reports/widgets/tests/test_report_widget.pyspyder-reports-0.1.1/spyder_reports.egg-info/top_level.txt0000644000175000017500000000001713145142762025460 0ustar rlaverderlaverde00000000000000spyder_reports spyder-reports-0.1.1/setup.cfg0000644000175000017500000000027113145142762017773 0ustar rlaverderlaverde00000000000000[bdist_wheel] universal = 1 [tool:pytest] addopts = -x -v -rw --durations=10 --cov=spyder_reports --cov-report=term-missing [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0