diff --git a/cookiecutter.json b/cookiecutter.json index 8b875da..8875aa6 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -10,5 +10,6 @@ "create_config_page": "n", "use_ciocheck": "y", "support_python_2": "n", - "spyder3_compatibility": "y" + "spyder3_compatibility": "n", + "graphical_plugin": "y" } diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 0580b4f..47d361f 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -5,15 +5,27 @@ from __future__ import print_function import os +import shutil from subprocess import call # Get the root project directory PROJECT_DIRECTORY = os.path.realpath(os.path.curdir) -def remove_file(file_name): - if os.path.exists(file_name): - os.remove(file_name) +def remove(filepath): + """Remove files or directory given a path.""" + if os.path.isfile(filepath): + os.remove(filepath) + elif os.path.isdir(filepath): + shutil.rmtree(filepath) + + +create_widget = '{{cookiecutter.graphical_plugin}}' == 'y' + +if not create_widget: + # Remove the widgets folder if the plugin is not graphical + remove(os.path.join(PROJECT_DIRECTORY, + '{{cookiecutter.project_name}}', 'widgets')) def init_git(): diff --git a/requirements/tests.txt b/requirements/tests.txt index 21bcc78..5624bea 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -1,3 +1,2 @@ # Testing -pytest pytest-cookies \ No newline at end of file diff --git a/tests/test_cookiecutter_generation.py b/tests/test_cookiecutter_generation.py index 6d82dee..00aa00c 100644 --- a/tests/test_cookiecutter_generation.py +++ b/tests/test_cookiecutter_generation.py @@ -17,6 +17,21 @@ def context(): } +@pytest.fixture +def non_graphical(): + return { + 'author': 'Spyder Project Contributors', + 'email': 'admin@spyder-ide.org', + 'github_username': 'spyder-ide', + 'plugin_name': 'Demo-nongraphic', + 'repo_name': 'spyder-demo-nongraphic', + 'project_name': 'spyder_demo_nongraphic', + 'description': 'Plugin for Spyder IDE.', + 'version': '0.1.0', + 'graphical_plugin': 'n' + } + + def test_default_configuration(cookies, context): result = cookies.bake(extra_context=context) assert result.exit_code == 0 @@ -44,3 +59,33 @@ def test_default_configuration(cookies, context): for path in project_files: assert path in found_project_files + + +def test_non_graphical_configuration(cookies, non_graphical): + """Test generation of non-graphical plugin.""" + result = cookies.bake(extra_context=non_graphical) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == non_graphical['repo_name'] + assert result.project.isdir() + + # Test creation of project files + + toplevel_files = ['MANIFEST.in', 'README.rst', 'setup.py', + 'requirements.txt', '.gitattributes'] + + found_toplevel_files = [f.basename for f in result.project.listdir()] + + for path in toplevel_files: + assert path in found_toplevel_files + + # Test creation of plugin files + + project_files = ['assets', 'demo-nongraphicplugin.py', '_version.py', + '__init__.py', 'tests'] + + project_dir = result.project.join(non_graphical['project_name']) + found_project_files = [f.basename for f in project_dir.listdir()] + + for path in project_files: + assert path in found_project_files diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/tests/test_plugin.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/tests/test_plugin.py index 64c6a8b..ec435c0 100644 --- a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/tests/test_plugin.py +++ b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/tests/test_plugin.py @@ -16,6 +16,7 @@ from {{ cookiecutter.project_name }}.{{ module_name }} import {{ plugin_name }} +{%- if cookiecutter.graphical_plugin == 'y' %} @pytest.fixture def setup_{{ object_name }}(qtbot): """Set up the {{ plugin_name }} plugin.""" @@ -31,7 +32,21 @@ def test_basic_initialization(qtbot): # Assert that plugin object exist assert {{ object_name }} is not None +{% else %} +@pytest.fixture +def setup_{{ object_name }}(): + """Set up the {{ plugin_name }} plugin.""" + {{ object_name }} = {{ plugin_name }}(None) + return {{ object_name }} + +def test_basic_initialization(): + """Test {{ plugin_name }} initialization.""" + {{ object_name }} = setup_{{ object_name }}() + + # Assert that plugin object exist + assert {{ object_name }} is not None +{% endif %} if __name__ == "__main__": pytest.main() diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/widgets/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}gui.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/widgets/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}gui.py index 273bbbb..d7f8090 100644 --- a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/widgets/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}gui.py +++ b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/widgets/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}gui.py @@ -6,9 +6,10 @@ # (see LICENSE.txt for details) # ----------------------------------------------------------------------------- """{{ cookiecutter.plugin_name }} Widget.""" - +# Third party imports from qtpy.QtWidgets import QWidget + class {{ cookiecutter.plugin_name.replace(' ', '') }}Widget(QWidget): """{{ cookiecutter.plugin_name }} widget.""" def __init__(self, parent): diff --git a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}plugin.py b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}plugin.py index 8583fe1..55ddf36 100644 --- a/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}plugin.py +++ b/{{ cookiecutter.repo_name }}/{{ cookiecutter.project_name }}/{{ cookiecutter.plugin_name.lower().replace(' ', '') }}plugin.py @@ -10,56 +10,74 @@ {%- set widget_name = cookiecutter.plugin_name.replace(' ', '') + 'Widget' -%} {%- set config_page = cookiecutter.plugin_name.replace(' ', '') + 'ConfigPage' %} +{%- if cookiecutter.graphical_plugin != 'n' %} from qtpy.QtWidgets import QVBoxLayout - -{% if cookiecutter.spyder3_compatibility == 'y' -%} +{%- endif %} +{% if cookiecutter.spyder3_compatibility == 'y' %} try: from spyder.api.plugins import SpyderPluginWidget except ImportError: from spyder.plugins import SpyderPluginWidget # Spyder3 {%- if cookiecutter.create_config_page == 'y' %} try: - from spyder.api.preferences import + from spyder.api.preferences import PluginConfigPage except ImportError: from spyder.plugins.configdialog import PluginConfigPage # Spyder3 {%- endif %} -{% else -%} +{% else %} + {%- if cookiecutter.graphical_plugin == 'y' %} from spyder.api.plugins import SpyderPluginWidget + {%- else %} +from spyder.api.plugins import SpyderPlugin + {%- endif %} {%- if cookiecutter.create_config_page == 'y' %} from spyder.api.preferences import PluginConfigPage - {%- endif %} -{%- endif -%} - + {% endif %} +{%- endif %} +{%- if cookiecutter.graphical_plugin != 'n' %} from .widgets.{{ cookiecutter.plugin_name.lower().replace(' ', '') }}gui import {{ widget_name }} -{% if cookiecutter.create_config_page == 'y' %} +{%- endif %} +{% if cookiecutter.create_config_page == 'y' %} class {{ config_page }}(PluginConfigPage): """{{ cookiecutter.plugin_name }} plugin preferences.""" pass {% endif %} - +{%- if cookiecutter.graphical_plugin == 'n' %} +class {{ cookiecutter.plugin_name.replace(' ', '') }}Plugin(SpyderPlugin): + """{{ cookiecutter.plugin_name }} plugin.""" + CONF_SECTION = '{{ cookiecutter.plugin_name.lower() }}' + {% if cookiecutter.create_config_page == 'y' %} + CONFIGWIDGET_CLASS = {{ config_page }} + {% else %} + CONFIGWIDGET_CLASS = None + {% endif %} + def __init__(self, parent=None): + QObject.__init__(self, parent) + SpyderPlugin.__init__(self, parent) +{%- else %} class {{ cookiecutter.plugin_name.replace(' ', '') }}Plugin(SpyderPluginWidget): """{{ cookiecutter.plugin_name }} plugin.""" CONF_SECTION = '{{ cookiecutter.plugin_name }}' -{% if cookiecutter.create_config_page == 'y' %} + {% if cookiecutter.create_config_page == 'y' %} CONFIGWIDGET_CLASS = {{ config_page }} -{% else %} + {% else %} CONFIGWIDGET_CLASS = None -{% endif %} - + {% endif %} def __init__(self, parent=None): + QObject.__init__(self, parent) SpyderPluginWidget.__init__(self, parent) - self.main = parent # Spyder3 - # Create widget and add to dockwindow - self.widget = {{ widget_name }}(self.main) + {% if cookiecutter.spyder3_compatibility == 'y' %} + # Initialize plugin + self.initialize_plugin() + {% endif %} + + # Graphical view layout = QVBoxLayout() layout.addWidget(self.widget) self.setLayout(layout) - # Initialize plugin - self.initialize_plugin() - # --- SpyderPluginWidget API ---------------------------------------------- def get_plugin_title(self): """Return widget title.""" @@ -69,6 +87,17 @@ def get_focus_widget(self): """Return the widget to give focus to.""" return self.widget + def on_first_registration(self): + """Action to be performed on first plugin registration.""" + # Define where the plugin is going to be tabified next to + # As default, it will be tabbed next to the ipython console + {% if cookiecutter.spyder3_compatibility == 'y' %} + self.main.tabify_plugins(self.main.help, self) + {% else %} + self.tabify(self.main.help) + {% endif %} + + {% if cookiecutter.spyder3_compatibility == 'y' %} def refresh_plugin(self): """Refresh {{ widget_name }} widget.""" pass @@ -81,10 +110,9 @@ def register_plugin(self): """Register plugin in Spyder's main window.""" self.main.add_dockwidget(self) - 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 + {% endif %} +{%- endif -%}