Plugin generated via plugin builder

This commit is contained in:
Marc Ducobu 2021-03-26 13:50:49 +01:00
commit ef06ad583b
28 changed files with 1950 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
resources.py
__pycache__

244
Makefile Normal file
View File

@ -0,0 +1,244 @@
#/***************************************************************************
# WebExporter
#
# This plugin exports your vector layers on a remote web server
# -------------------
# begin : 2021-03-26
# git sha : $Format:%H$
# copyright : (C) 2021 by Champs-Libres
# email : info@champs-libres.coop
# ***************************************************************************/
#
#/***************************************************************************
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License as published by *
# * the Free Software Foundation; either version 2 of the License, or *
# * (at your option) any later version. *
# * *
# ***************************************************************************/
#################################################
# Edit the following to match your sources lists
#################################################
#Add iso code for any locales you want to support here (space separated)
# default is no locales
# LOCALES = af
LOCALES =
# If locales are enabled, set the name of the lrelease binary on your system. If
# you have trouble compiling the translations, you may have to specify the full path to
# lrelease
#LRELEASE = lrelease
#LRELEASE = lrelease-qt4
# translation
SOURCES = \
__init__.py \
web_exporter.py web_exporter_dialog.py
PLUGINNAME = web_exporter
PY_FILES = \
__init__.py \
web_exporter.py web_exporter_dialog.py
UI_FILES = web_exporter_dialog_base.ui
EXTRAS = metadata.txt icon.png
EXTRA_DIRS =
COMPILED_RESOURCE_FILES = resources.py
PEP8EXCLUDE=pydev,resources.py,conf.py,third_party,ui
# QGISDIR points to the location where your plugin should be installed.
# This varies by platform, relative to your HOME directory:
# * Linux:
# .local/share/QGIS/QGIS3/profiles/default/python/plugins/
# * Mac OS X:
# Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins
# * Windows:
# AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins'
QGISDIR=/home/marcu/.local/share/QGIS/QGIS3/profiles/default/python/plugins/
#################################################
# Normally you would not need to edit below here
#################################################
HELP = help/build/html
PLUGIN_UPLOAD = $(c)/plugin_upload.py
RESOURCE_SRC=$(shell grep '^ *<file' resources.qrc | sed 's@</file>@@g;s/.*>//g' | tr '\n' ' ')
.PHONY: default
default:
@echo While you can use make to build and deploy your plugin, pb_tool
@echo is a much better solution.
@echo A Python script, pb_tool provides platform independent management of
@echo your plugins and runs anywhere.
@echo You can install pb_tool using: pip install pb_tool
@echo See https://g-sherman.github.io/plugin_build_tool/ for info.
compile: $(COMPILED_RESOURCE_FILES)
%.py : %.qrc $(RESOURCES_SRC)
pyrcc5 -o $*.py $<
%.qm : %.ts
$(LRELEASE) $<
test: compile transcompile
@echo
@echo "----------------------"
@echo "Regression Test Suite"
@echo "----------------------"
@# Preceding dash means that make will continue in case of errors
@-export PYTHONPATH=`pwd`:$(PYTHONPATH); \
export QGIS_DEBUG=0; \
export QGIS_LOG_FILE=/dev/null; \
nosetests -v --with-id --with-coverage --cover-package=. \
3>&1 1>&2 2>&3 3>&- || true
@echo "----------------------"
@echo "If you get a 'no module named qgis.core error, try sourcing"
@echo "the helper script we have provided first then run make test."
@echo "e.g. source run-env-linux.sh <path to qgis install>; make test"
@echo "----------------------"
deploy: compile doc transcompile
@echo
@echo "------------------------------------------"
@echo "Deploying plugin to your .qgis2 directory."
@echo "------------------------------------------"
# The deploy target only works on unix like operating system where
# the Python plugin directory is located at:
# $HOME/$(QGISDIR)/python/plugins
mkdir -p $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
cp -vf $(PY_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
cp -vf $(UI_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
cp -vf $(COMPILED_RESOURCE_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
cp -vf $(EXTRAS) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
cp -vfr i18n $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
cp -vfr $(HELP) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)/help
# Copy extra directories if any
(foreach EXTRA_DIR,(EXTRA_DIRS), cp -R (EXTRA_DIR) (HOME)/(QGISDIR)/python/plugins/(PLUGINNAME)/;)
# The dclean target removes compiled python files from plugin directory
# also deletes any .git entry
dclean:
@echo
@echo "-----------------------------------"
@echo "Removing any compiled python files."
@echo "-----------------------------------"
find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname "*.pyc" -delete
find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname ".git" -prune -exec rm -Rf {} \;
derase:
@echo
@echo "-------------------------"
@echo "Removing deployed plugin."
@echo "-------------------------"
rm -Rf $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)
zip: deploy dclean
@echo
@echo "---------------------------"
@echo "Creating plugin zip bundle."
@echo "---------------------------"
# The zip target deploys the plugin and creates a zip file with the deployed
# content. You can then upload the zip file on http://plugins.qgis.org
rm -f $(PLUGINNAME).zip
cd $(HOME)/$(QGISDIR)/python/plugins; zip -9r $(CURDIR)/$(PLUGINNAME).zip $(PLUGINNAME)
package: compile
# Create a zip package of the plugin named $(PLUGINNAME).zip.
# This requires use of git (your plugin development directory must be a
# git repository).
# To use, pass a valid commit or tag as follows:
# make package VERSION=Version_0.3.2
@echo
@echo "------------------------------------"
@echo "Exporting plugin to zip package. "
@echo "------------------------------------"
rm -f $(PLUGINNAME).zip
git archive --prefix=$(PLUGINNAME)/ -o $(PLUGINNAME).zip $(VERSION)
echo "Created package: $(PLUGINNAME).zip"
upload: zip
@echo
@echo "-------------------------------------"
@echo "Uploading plugin to QGIS Plugin repo."
@echo "-------------------------------------"
$(PLUGIN_UPLOAD) $(PLUGINNAME).zip
transup:
@echo
@echo "------------------------------------------------"
@echo "Updating translation files with any new strings."
@echo "------------------------------------------------"
@chmod +x scripts/update-strings.sh
@scripts/update-strings.sh $(LOCALES)
transcompile:
@echo
@echo "----------------------------------------"
@echo "Compiled translation files to .qm files."
@echo "----------------------------------------"
@chmod +x scripts/compile-strings.sh
@scripts/compile-strings.sh $(LRELEASE) $(LOCALES)
transclean:
@echo
@echo "------------------------------------"
@echo "Removing compiled translation files."
@echo "------------------------------------"
rm -f i18n/*.qm
clean:
@echo
@echo "------------------------------------"
@echo "Removing uic and rcc generated files"
@echo "------------------------------------"
rm $(COMPILED_UI_FILES) $(COMPILED_RESOURCE_FILES)
doc:
@echo
@echo "------------------------------------"
@echo "Building documentation using sphinx."
@echo "------------------------------------"
cd help; make html
pylint:
@echo
@echo "-----------------"
@echo "Pylint violations"
@echo "-----------------"
@pylint --reports=n --rcfile=pylintrc . || true
@echo
@echo "----------------------"
@echo "If you get a 'no module named qgis.core' error, try sourcing"
@echo "the helper script we have provided first then run make pylint."
@echo "e.g. source run-env-linux.sh <path to qgis install>; make pylint"
@echo "----------------------"
# Run pep8 style checking
#http://pypi.python.org/pypi/pep8
pep8:
@echo
@echo "-----------"
@echo "PEP8 issues"
@echo "-----------"
@pep8 --repeat --ignore=E203,E121,E122,E123,E124,E125,E126,E127,E128 --exclude $(PEP8EXCLUDE) . || true
@echo "-----------"
@echo "Ignored in PEP8 check:"
@echo $(PEP8EXCLUDE)

34
README.md Normal file
View File

@ -0,0 +1,34 @@
## How to install the plugin for development ?
1. Make a symbolic link in the qgis python repository (on linux
this reporitoy is ~/.local/share/QGIS/QGIS3/profiles/default/python/plugins ).
``
$ ln -s $(pwd) ~/.local/share/QGIS/QGIS3/profiles/default/python/plugins
``
2. Create the file `resources.py`
``
$ pyrcc5 resources.qrc -o resources.py
``
That's it ! You can restart QGIS and enable the plugin using the plugin manager.
What's Next:
* Run the tests (``make test``)
* Test the plugin by enabling it in the QGIS plugin manager
* Customize it by editing the implementation file: ``web_exporter.py``
* Create your own custom icon, replacing the default icon.png
* Modify your user interface by opening WebExporter_dialog_base.ui in Qt Designer
* You can use the Makefile to compile your Ui and resource files when
you make changes. This requires GNU make (gmake)

36
__init__.py Normal file
View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
"""
/***************************************************************************
WebExporter
A QGIS plugin
This plugin exports your vector layers on a remote web server
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2021-03-26
copyright : (C) 2021 by Champs-Libres
email : info@champs-libres.coop
git sha : $Format:%H$
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
This script initializes the plugin, making it known to QGIS.
"""
# noinspection PyPep8Naming
def classFactory(iface): # pylint: disable=invalid-name
"""Load WebExporter class from file WebExporter.
:param iface: A QGIS interface instance.
:type iface: QgsInterface
"""
#
from .web_exporter import WebExporter
return WebExporter(iface)

130
help/Makefile Normal file
View File

@ -0,0 +1,130 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/template_class.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/template_class.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/template_class"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/template_class"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

216
help/source/conf.py Normal file
View File

@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
#
# WebExporter documentation build configuration file, created by
# sphinx-quickstart on Sun Feb 12 17:11:03 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.todo', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'WebExporter'
copyright = u'2013, Champs-Libres'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_TemplateModuleNames = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'TemplateClassdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'WebExporter.tex', u'WebExporter Documentation',
u'Champs-Libres', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'TemplateClass', u'WebExporter Documentation',
[u'Champs-Libres'], 1)
]

20
help/source/index.rst Normal file
View File

@ -0,0 +1,20 @@
.. WebExporter documentation master file, created by
sphinx-quickstart on Sun Feb 12 17:11:03 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to WebExporter's documentation!
============================================
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

47
metadata.txt Normal file
View File

@ -0,0 +1,47 @@
# This file contains metadata for your plugin.
# This file should be included when you package your plugin.# Mandatory items:
[general]
name=Web Exporter
qgisMinimumVersion=3.0
description=This plugin exports your vector layers on a remote web server
version=0.1
author=Champs-Libres
email=info@champs-libres.coop
about=Provide a brief description of the plugin and its purpose.
tracker=http://bugs
repository=http://repo
# End of mandatory metadata
# Recommended items:
hasProcessingProvider=no
# Uncomment the following line and add your changelog:
# changelog=
# Tags are comma separated with spaces allowed
tags=python
homepage=http://homepage
category=Vector
icon=icon.png
# experimental flag
experimental=True
# deprecated flag (applies to the whole plugin, not just a single version)
deprecated=False
# Since QGIS 3.8, a comma separated list of plugins to be installed
# (or upgraded) can be specified.
# Check the documentation for more information.
# plugin_dependencies=
Category of the plugin: Raster, Vector, Database or Web
# category=
# If the plugin can run on QGIS Server.
server=False

281
pylintrc Normal file
View File

@ -0,0 +1,281 @@
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Profiled execution.
profile=no
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# see http://stackoverflow.com/questions/21487025/pylint-locally-defined-disables-still-give-warnings-how-to-suppress-them
disable=locally-disabled,C0103
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=yes
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Add a comment according to your evaluation note. This is used by the global
# evaluation report (RP0004).
comment=no
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
[BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input
# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression which should only match correct module level names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression which should only match correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct attribute names in class
# bodies
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=__.*__
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=SQLObject
# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
generated-members=REQUEST,acl_users,aq_parent
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the beginning of the name of dummy variables
# (i.e. not used).
dummy-variables-rgx=_$|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=80
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
# List of optional constructs for which whitespace checking is disabled
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
[CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

5
resources.qrc Normal file
View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/plugins/web_exporter" >
<file>icon.png</file>
</qresource>
</RCC>

2
test/__init__.py Normal file
View File

@ -0,0 +1,2 @@
# import qgis libs so that ve set the correct sip api version
import qgis # pylint: disable=W0611 # NOQA

205
test/qgis_interface.py Normal file
View File

@ -0,0 +1,205 @@
# coding=utf-8
"""QGIS plugin implementation.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.. note:: This source code was copied from the 'postgis viewer' application
with original authors:
Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk
Copyright (c) 2011 German Carrillo, geotux_tuxman@linuxmail.org
Copyright (c) 2014 Tim Sutton, tim@linfiniti.com
"""
__author__ = 'tim@linfiniti.com'
__revision__ = '$Format:%H$'
__date__ = '10/01/2011'
__copyright__ = (
'Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and '
'Copyright (c) 2011 German Carrillo, geotux_tuxman@linuxmail.org'
'Copyright (c) 2014 Tim Sutton, tim@linfiniti.com'
)
import logging
from qgis.PyQt.QtCore import QObject, pyqtSlot, pyqtSignal
from qgis.core import QgsMapLayerRegistry
from qgis.gui import QgsMapCanvasLayer
LOGGER = logging.getLogger('QGIS')
#noinspection PyMethodMayBeStatic,PyPep8Naming
class QgisInterface(QObject):
"""Class to expose QGIS objects and functions to plugins.
This class is here for enabling us to run unit tests only,
so most methods are simply stubs.
"""
currentLayerChanged = pyqtSignal(QgsMapCanvasLayer)
def __init__(self, canvas):
"""Constructor
:param canvas:
"""
QObject.__init__(self)
self.canvas = canvas
# Set up slots so we can mimic the behaviour of QGIS when layers
# are added.
LOGGER.debug('Initialising canvas...')
# noinspection PyArgumentList
QgsMapLayerRegistry.instance().layersAdded.connect(self.addLayers)
# noinspection PyArgumentList
QgsMapLayerRegistry.instance().layerWasAdded.connect(self.addLayer)
# noinspection PyArgumentList
QgsMapLayerRegistry.instance().removeAll.connect(self.removeAllLayers)
# For processing module
self.destCrs = None
@pyqtSlot('QStringList')
def addLayers(self, layers):
"""Handle layers being added to the registry so they show up in canvas.
:param layers: list<QgsMapLayer> list of map layers that were added
.. note:: The QgsInterface api does not include this method,
it is added here as a helper to facilitate testing.
"""
#LOGGER.debug('addLayers called on qgis_interface')
#LOGGER.debug('Number of layers being added: %s' % len(layers))
#LOGGER.debug('Layer Count Before: %s' % len(self.canvas.layers()))
current_layers = self.canvas.layers()
final_layers = []
for layer in current_layers:
final_layers.append(QgsMapCanvasLayer(layer))
for layer in layers:
final_layers.append(QgsMapCanvasLayer(layer))
self.canvas.setLayerSet(final_layers)
#LOGGER.debug('Layer Count After: %s' % len(self.canvas.layers()))
@pyqtSlot('QgsMapLayer')
def addLayer(self, layer):
"""Handle a layer being added to the registry so it shows up in canvas.
:param layer: list<QgsMapLayer> list of map layers that were added
.. note: The QgsInterface api does not include this method, it is added
here as a helper to facilitate testing.
.. note: The addLayer method was deprecated in QGIS 1.8 so you should
not need this method much.
"""
pass
@pyqtSlot()
def removeAllLayers(self):
"""Remove layers from the canvas before they get deleted."""
self.canvas.setLayerSet([])
def newProject(self):
"""Create new project."""
# noinspection PyArgumentList
QgsMapLayerRegistry.instance().removeAllMapLayers()
# ---------------- API Mock for QgsInterface follows -------------------
def zoomFull(self):
"""Zoom to the map full extent."""
pass
def zoomToPrevious(self):
"""Zoom to previous view extent."""
pass
def zoomToNext(self):
"""Zoom to next view extent."""
pass
def zoomToActiveLayer(self):
"""Zoom to extent of active layer."""
pass
def addVectorLayer(self, path, base_name, provider_key):
"""Add a vector layer.
:param path: Path to layer.
:type path: str
:param base_name: Base name for layer.
:type base_name: str
:param provider_key: Provider key e.g. 'ogr'
:type provider_key: str
"""
pass
def addRasterLayer(self, path, base_name):
"""Add a raster layer given a raster layer file name
:param path: Path to layer.
:type path: str
:param base_name: Base name for layer.
:type base_name: str
"""
pass
def activeLayer(self):
"""Get pointer to the active layer (layer selected in the legend)."""
# noinspection PyArgumentList
layers = QgsMapLayerRegistry.instance().mapLayers()
for item in layers:
return layers[item]
def addToolBarIcon(self, action):
"""Add an icon to the plugins toolbar.
:param action: Action to add to the toolbar.
:type action: QAction
"""
pass
def removeToolBarIcon(self, action):
"""Remove an action (icon) from the plugin toolbar.
:param action: Action to add to the toolbar.
:type action: QAction
"""
pass
def addToolBar(self, name):
"""Add toolbar with specified name.
:param name: Name for the toolbar.
:type name: str
"""
pass
def mapCanvas(self):
"""Return a pointer to the map canvas."""
return self.canvas
def mainWindow(self):
"""Return a pointer to the main window.
In case of QGIS it returns an instance of QgisApp.
"""
pass
def addDockWidget(self, area, dock_widget):
"""Add a dock widget to the main window.
:param area: Where in the ui the dock should be placed.
:type area:
:param dock_widget: A dock widget to add to the UI.
:type dock_widget: QDockWidget
"""
pass
def legendInterface(self):
"""Get the legend."""
return self.canvas

19
test/tenbytenraster.asc Normal file
View File

@ -0,0 +1,19 @@
NCOLS 10
NROWS 10
XLLCENTER 1535380.000000
YLLCENTER 5083260.000000
DX 10
DY 10
NODATA_VALUE -9999
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
CRS
NOTES

View File

@ -0,0 +1,13 @@
<PAMDataset>
<Metadata>
<MDI key="AREA_OR_POINT">Point</MDI>
</Metadata>
<PAMRasterBand band="1">
<Metadata>
<MDI key="STATISTICS_MAXIMUM">9</MDI>
<MDI key="STATISTICS_MEAN">4.5</MDI>
<MDI key="STATISTICS_MINIMUM">0</MDI>
<MDI key="STATISTICS_STDDEV">2.872281323269</MDI>
</Metadata>
</PAMRasterBand>
</PAMDataset>

View File

@ -0,0 +1 @@
title: Tenbytenraster

18
test/tenbytenraster.lic Normal file
View File

@ -0,0 +1,18 @@
<?xml version='1.0' encoding='iso-8859-1'?>
<ga_license_file>
<metadata>
<author>Tim Sutton, Linfiniti Consulting CC</author>
</metadata>
<datafile>
<filename>tenbytenraster.asc</filename>
<checksum>2700044251</checksum>
<publishable>Yes</publishable>
<accountable>Tim Sutton</accountable>
<source>Tim Sutton (QGIS Source Tree)</source>
<IP_owner>Tim Sutton</IP_owner>
<IP_info>This data is publicly available from QGIS Source Tree. The original
file was created and contributed to QGIS by Tim Sutton.</IP_info>
</datafile>
</ga_license_file>

1
test/tenbytenraster.prj Normal file
View File

@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]

26
test/tenbytenraster.qml Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis version="1.9.0-Master" minimumScale="-4.65661e-10" maximumScale="1e+08" hasScaleBasedVisibilityFlag="0">
<pipe>
<rasterrenderer opacity="1" alphaBand="0" classificationMax="9" classificationMinMaxOrigin="MinMaxFullExtentExact" band="1" classificationMin="0" type="singlebandpseudocolor">
<rasterTransparency/>
<rastershader>
<colorrampshader colorRampType="INTERPOLATED" clip="0">
<item alpha="255" value="0" label="0.000000" color="#d7191c"/>
<item alpha="255" value="1" label="1.000000" color="#e75b3a"/>
<item alpha="255" value="2" label="2.000000" color="#f89d59"/>
<item alpha="255" value="3" label="3.000000" color="#fdc980"/>
<item alpha="255" value="4" label="4.000000" color="#feedaa"/>
<item alpha="255" value="5" label="5.000000" color="#ecf7b9"/>
<item alpha="255" value="6" label="6.000000" color="#c7e8ad"/>
<item alpha="255" value="7" label="7.000000" color="#9cd3a6"/>
<item alpha="255" value="8" label="8.000000" color="#63abb0"/>
<item alpha="255" value="9" label="9.000000" color="#2b83ba"/>
</colorrampshader>
</rastershader>
</rasterrenderer>
<brightnesscontrast brightness="0" contrast="0"/>
<huesaturation colorizeGreen="128" colorizeOn="0" colorizeRed="255" colorizeBlue="128" grayscaleMode="0" saturation="0" colorizeStrength="100"/>
<rasterresampler maxOversampling="2"/>
</pipe>
<blendMode>0</blendMode>
</qgis>

64
test/test_init.py Normal file
View File

@ -0,0 +1,64 @@
# coding=utf-8
"""Tests QGIS plugin init."""
__author__ = 'Tim Sutton <tim@linfiniti.com>'
__revision__ = '$Format:%H$'
__date__ = '17/10/2010'
__license__ = "GPL"
__copyright__ = 'Copyright 2012, Australia Indonesia Facility for '
__copyright__ += 'Disaster Reduction'
import os
import unittest
import logging
import configparser
LOGGER = logging.getLogger('QGIS')
class TestInit(unittest.TestCase):
"""Test that the plugin init is usable for QGIS.
Based heavily on the validator class by Alessandro
Passoti available here:
http://github.com/qgis/qgis-django/blob/master/qgis-app/
plugins/validator.py
"""
def test_read_init(self):
"""Test that the plugin __init__ will validate on plugins.qgis.org."""
# You should update this list according to the latest in
# https://github.com/qgis/qgis-django/blob/master/qgis-app/
# plugins/validator.py
required_metadata = [
'name',
'description',
'version',
'qgisMinimumVersion',
'email',
'author']
file_path = os.path.abspath(os.path.join(
os.path.dirname(__file__), os.pardir,
'metadata.txt'))
LOGGER.info(file_path)
metadata = []
parser = configparser.ConfigParser()
parser.optionxform = str
parser.read(file_path)
message = 'Cannot find a section named "general" in %s' % file_path
assert parser.has_section('general'), message
metadata.extend(parser.items('general'))
for expectation in required_metadata:
message = ('Cannot find metadata "%s" in metadata source (%s).' % (
expectation, file_path))
self.assertIn(expectation, dict(metadata), message)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,60 @@
# coding=utf-8
"""Tests for QGIS functionality.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'tim@linfiniti.com'
__date__ = '20/01/2011'
__copyright__ = ('Copyright 2012, Australia Indonesia Facility for '
'Disaster Reduction')
import os
import unittest
from qgis.core import (
QgsProviderRegistry,
QgsCoordinateReferenceSystem,
QgsRasterLayer)
from .utilities import get_qgis_app
QGIS_APP = get_qgis_app()
class QGISTest(unittest.TestCase):
"""Test the QGIS Environment"""
def test_qgis_environment(self):
"""QGIS environment has the expected providers"""
r = QgsProviderRegistry.instance()
self.assertIn('gdal', r.providerList())
self.assertIn('ogr', r.providerList())
self.assertIn('postgres', r.providerList())
def test_projection(self):
"""Test that QGIS properly parses a wkt string.
"""
crs = QgsCoordinateReferenceSystem()
wkt = (
'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",'
'SPHEROID["WGS_1984",6378137.0,298.257223563]],'
'PRIMEM["Greenwich",0.0],UNIT["Degree",'
'0.0174532925199433]]')
crs.createFromWkt(wkt)
auth_id = crs.authid()
expected_auth_id = 'EPSG:4326'
self.assertEqual(auth_id, expected_auth_id)
# now test for a loaded layer
path = os.path.join(os.path.dirname(__file__), 'tenbytenraster.asc')
title = 'TestRaster'
layer = QgsRasterLayer(path, title)
auth_id = layer.crs().authid()
self.assertEqual(auth_id, expected_auth_id)
if __name__ == '__main__':
unittest.main()

44
test/test_resources.py Normal file
View File

@ -0,0 +1,44 @@
# coding=utf-8
"""Resources test.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'info@champs-libres.coop'
__date__ = '2021-03-26'
__copyright__ = 'Copyright 2021, Champs-Libres'
import unittest
from qgis.PyQt.QtGui import QIcon
class WebExporterDialogTest(unittest.TestCase):
"""Test rerources work."""
def setUp(self):
"""Runs before each test."""
pass
def tearDown(self):
"""Runs after each test."""
pass
def test_icon_png(self):
"""Test we can click OK."""
path = ':/plugins/WebExporter/icon.png'
icon = QIcon(path)
self.assertFalse(icon.isNull())
if __name__ == "__main__":
suite = unittest.makeSuite(WebExporterResourcesTest)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

55
test/test_translations.py Normal file
View File

@ -0,0 +1,55 @@
# coding=utf-8
"""Safe Translations Test.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
from .utilities import get_qgis_app
__author__ = 'ismailsunni@yahoo.co.id'
__date__ = '12/10/2011'
__copyright__ = ('Copyright 2012, Australia Indonesia Facility for '
'Disaster Reduction')
import unittest
import os
from qgis.PyQt.QtCore import QCoreApplication, QTranslator
QGIS_APP = get_qgis_app()
class SafeTranslationsTest(unittest.TestCase):
"""Test translations work."""
def setUp(self):
"""Runs before each test."""
if 'LANG' in iter(os.environ.keys()):
os.environ.__delitem__('LANG')
def tearDown(self):
"""Runs after each test."""
if 'LANG' in iter(os.environ.keys()):
os.environ.__delitem__('LANG')
def test_qgis_translations(self):
"""Test that translations work."""
parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir)
dir_path = os.path.abspath(parent_path)
file_path = os.path.join(
dir_path, 'i18n', 'af.qm')
translator = QTranslator()
translator.load(file_path)
QCoreApplication.installTranslator(translator)
expected_message = 'Goeie more'
real_message = QCoreApplication.translate("@default", 'Good morning')
self.assertEqual(real_message, expected_message)
if __name__ == "__main__":
suite = unittest.makeSuite(SafeTranslationsTest)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

View File

@ -0,0 +1,55 @@
# coding=utf-8
"""Dialog test.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'info@champs-libres.coop'
__date__ = '2021-03-26'
__copyright__ = 'Copyright 2021, Champs-Libres'
import unittest
from qgis.PyQt.QtGui import QDialogButtonBox, QDialog
from web_exporter_dialog import WebExporterDialog
from utilities import get_qgis_app
QGIS_APP = get_qgis_app()
class WebExporterDialogTest(unittest.TestCase):
"""Test dialog works."""
def setUp(self):
"""Runs before each test."""
self.dialog = WebExporterDialog(None)
def tearDown(self):
"""Runs after each test."""
self.dialog = None
def test_dialog_ok(self):
"""Test we can click OK."""
button = self.dialog.button_box.button(QDialogButtonBox.Ok)
button.click()
result = self.dialog.result()
self.assertEqual(result, QDialog.Accepted)
def test_dialog_cancel(self):
"""Test we can click cancel."""
button = self.dialog.button_box.button(QDialogButtonBox.Cancel)
button.click()
result = self.dialog.result()
self.assertEqual(result, QDialog.Rejected)
if __name__ == "__main__":
suite = unittest.makeSuite(WebExporterDialogTest)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

61
test/utilities.py Normal file
View File

@ -0,0 +1,61 @@
# coding=utf-8
"""Common functionality used by regression tests."""
import sys
import logging
LOGGER = logging.getLogger('QGIS')
QGIS_APP = None # Static variable used to hold hand to running QGIS app
CANVAS = None
PARENT = None
IFACE = None
def get_qgis_app():
""" Start one QGIS application to test against.
:returns: Handle to QGIS app, canvas, iface and parent. If there are any
errors the tuple members will be returned as None.
:rtype: (QgsApplication, CANVAS, IFACE, PARENT)
If QGIS is already running the handle to that app will be returned.
"""
try:
from qgis.PyQt import QtGui, QtCore
from qgis.core import QgsApplication
from qgis.gui import QgsMapCanvas
from .qgis_interface import QgisInterface
except ImportError:
return None, None, None, None
global QGIS_APP # pylint: disable=W0603
if QGIS_APP is None:
gui_flag = True # All test will run qgis in gui mode
#noinspection PyPep8Naming
QGIS_APP = QgsApplication(sys.argv, gui_flag)
# Make sure QGIS_PREFIX_PATH is set in your env if needed!
QGIS_APP.initQgis()
s = QGIS_APP.showSettings()
LOGGER.debug(s)
global PARENT # pylint: disable=W0603
if PARENT is None:
#noinspection PyPep8Naming
PARENT = QtGui.QWidget()
global CANVAS # pylint: disable=W0603
if CANVAS is None:
#noinspection PyPep8Naming
CANVAS = QgsMapCanvas(PARENT)
CANVAS.resize(QtCore.QSize(400, 400))
global IFACE # pylint: disable=W0603
if IFACE is None:
# QgisInterface is a stub implementation of the QGIS plugin interface
#noinspection PyPep8Naming
IFACE = QgisInterface(CANVAS)
return QGIS_APP, CANVAS, IFACE, PARENT

200
web_exporter.py Normal file
View File

@ -0,0 +1,200 @@
# -*- coding: utf-8 -*-
"""
/***************************************************************************
WebExporter
A QGIS plugin
This plugin exports your vector layers on a remote web server
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2021-03-26
git sha : $Format:%H$
copyright : (C) 2021 by Champs-Libres
email : info@champs-libres.coop
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction
# Initialize Qt resources from file resources.py
from .resources import *
# Import the code for the dialog
from .web_exporter_dialog import WebExporterDialog
import os.path
class WebExporter:
"""QGIS Plugin Implementation."""
def __init__(self, iface):
"""Constructor.
:param iface: An interface instance that will be passed to this class
which provides the hook by which you can manipulate the QGIS
application at run time.
:type iface: QgsInterface
"""
# Save reference to the QGIS interface
self.iface = iface
# initialize plugin directory
self.plugin_dir = os.path.dirname(__file__)
# initialize locale
locale = QSettings().value('locale/userLocale')[0:2]
locale_path = os.path.join(
self.plugin_dir,
'i18n',
'WebExporter_{}.qm'.format(locale))
if os.path.exists(locale_path):
self.translator = QTranslator()
self.translator.load(locale_path)
QCoreApplication.installTranslator(self.translator)
# Declare instance attributes
self.actions = []
self.menu = self.tr(u'&Web Exporter')
# Check if plugin was started the first time in current QGIS session
# Must be set in initGui() to survive plugin reloads
self.first_start = None
# noinspection PyMethodMayBeStatic
def tr(self, message):
"""Get the translation for a string using Qt translation API.
We implement this ourselves since we do not inherit QObject.
:param message: String for translation.
:type message: str, QString
:returns: Translated version of message.
:rtype: QString
"""
# noinspection PyTypeChecker,PyArgumentList,PyCallByClass
return QCoreApplication.translate('WebExporter', message)
def add_action(
self,
icon_path,
text,
callback,
enabled_flag=True,
add_to_menu=True,
add_to_toolbar=True,
status_tip=None,
whats_this=None,
parent=None):
"""Add a toolbar icon to the toolbar.
:param icon_path: Path to the icon for this action. Can be a resource
path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
:type icon_path: str
:param text: Text that should be shown in menu items for this action.
:type text: str
:param callback: Function to be called when the action is triggered.
:type callback: function
:param enabled_flag: A flag indicating if the action should be enabled
by default. Defaults to True.
:type enabled_flag: bool
:param add_to_menu: Flag indicating whether the action should also
be added to the menu. Defaults to True.
:type add_to_menu: bool
:param add_to_toolbar: Flag indicating whether the action should also
be added to the toolbar. Defaults to True.
:type add_to_toolbar: bool
:param status_tip: Optional text to show in a popup when mouse pointer
hovers over the action.
:type status_tip: str
:param parent: Parent widget for the new action. Defaults None.
:type parent: QWidget
:param whats_this: Optional text to show in the status bar when the
mouse pointer hovers over the action.
:returns: The action that was created. Note that the action is also
added to self.actions list.
:rtype: QAction
"""
icon = QIcon(icon_path)
action = QAction(icon, text, parent)
action.triggered.connect(callback)
action.setEnabled(enabled_flag)
if status_tip is not None:
action.setStatusTip(status_tip)
if whats_this is not None:
action.setWhatsThis(whats_this)
if add_to_toolbar:
# Adds plugin icon to Plugins toolbar
self.iface.addToolBarIcon(action)
if add_to_menu:
self.iface.addPluginToVectorMenu(
self.menu,
action)
self.actions.append(action)
return action
def initGui(self):
"""Create the menu entries and toolbar icons inside the QGIS GUI."""
icon_path = ':/plugins/web_exporter/icon.png'
self.add_action(
icon_path,
text=self.tr(u''),
callback=self.run,
parent=self.iface.mainWindow())
# will be set False in run()
self.first_start = True
def unload(self):
"""Removes the plugin menu item and icon from QGIS GUI."""
for action in self.actions:
self.iface.removePluginVectorMenu(
self.tr(u'&Web Exporter'),
action)
self.iface.removeToolBarIcon(action)
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
self.dlg = WebExporterDialog()
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
pass

44
web_exporter_dialog.py Normal file
View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
"""
/***************************************************************************
WebExporterDialog
A QGIS plugin
This plugin exports your vector layers on a remote web server
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2021-03-26
git sha : $Format:%H$
copyright : (C) 2021 by Champs-Libres
email : info@champs-libres.coop
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
import os
from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'web_exporter_dialog_base.ui'))
class WebExporterDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, parent=None):
"""Constructor."""
super(WebExporterDialog, self).__init__(parent)
# Set up the user interface from Designer through FORM_CLASS.
# After self.setupUi() you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)

View File

@ -0,0 +1,67 @@
<ui version="4.0" >
<class>WebExporterDialogBase</class>
<widget class="QDialog" name="WebExporterDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle" >
<string>Web Exporter</string>
</property>
<widget class="QDialogButtonBox" name="button_box" >
<property name="geometry" >
<rect>
<x>30</x>
<y>240</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>button_box</sender>
<signal>accepted()</signal>
<receiver>WebExporterDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="source_label" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destination_label" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>button_box</sender>
<signal>rejected()</signal>
<receiver>WebExporterDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="source_label" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destination_label" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>