From 0d9da52dc5c05524be8c5adf84dd0c3f76a9a2d3 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Mon, 20 May 2019 22:57:09 +0200
Subject: readme
---
README | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
create mode 100644 README
diff --git a/README b/README
new file mode 100644
index 0000000..9bdc8fa
--- /dev/null
+++ b/README
@@ -0,0 +1,63 @@
+Installation instructions
+-------------------------
+
+First, initialize the configure script.
+
+$ ./bootstrap
+
+Then, choose the installation prefix
+
+$ ./configure --prefix=
+
+Last, install
+
+$ make install
+
+Optionally, to run tests:
+
+$ make check
+
+Configuration options.
+----------------------
+
+The following configuration excerpt shows all the options
+accepted by the donations shop.
+
+$ cat ~/.config/taler.conf
+
+[frontends]
+
+# Merchant backend to use.
+backend = http://backend.test.taler.net/
+
+# This value will fill: "Authorization: ApiKey "
+backend_apikey = sandbox
+
+[donations]
+
+# The following three options configure the way the blog
+# will serve UWSGI requests via unix domain sockets.
+uwsgi_serve = unix
+uwsgi_unixpath = /path/to/blog.uwsgi
+uwsgi_unixpath_mode = 660
+
+# The following option picks the merchant instance that
+# will be represented by the running blog.
+instance = default
+
+Running instructions
+--------------------
+
+The following command launches the blog to serve HTTP requests
+on the port .
+
+$ taler-merchant-donations serve-http -p
+
+The following command launches the blog to serve UWSGI requests
+via a unix domain socket.
+
+$ taler-merchant-donations serve-uwsgi
+
+Finally, get a help message with the following command
+
+$ taler-merchant-donations --help
--
cgit v1.2.3
From 27e5a47358437bc6e1894be0ddc9689761a39bcd Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Tue, 21 May 2019 00:19:23 +0200
Subject: readme
---
README | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/README b/README
index 9bdc8fa..586a9e7 100644
--- a/README
+++ b/README
@@ -35,26 +35,26 @@ backend_apikey = sandbox
[donations]
-# The following three options configure the way the blog
-# will serve UWSGI requests via unix domain sockets.
+# The following three options configure the way the donations
+# shop will serve UWSGI requests via unix domain sockets.
uwsgi_serve = unix
-uwsgi_unixpath = /path/to/blog.uwsgi
+uwsgi_unixpath = /path/to/donations.uwsgi
uwsgi_unixpath_mode = 660
# The following option picks the merchant instance that
-# will be represented by the running blog.
+# will be represented by the running donations shop.
instance = default
Running instructions
--------------------
-The following command launches the blog to serve HTTP requests
-on the port .
+The following command launches the donations shop
+to serve HTTP requests on the port .
$ taler-merchant-donations serve-http -p
-The following command launches the blog to serve UWSGI requests
-via a unix domain socket.
+The following command launches the donations shop
+to serve UWSGI requests via a unix domain socket.
$ taler-merchant-donations serve-uwsgi
--
cgit v1.2.3
From 62b549f47e86634b8ee822268770ee553e8455a3 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Fri, 24 May 2019 17:23:58 +0200
Subject: provide default config
---
Makefile.in | 1 +
donations.conf | 20 +++++++++++++++-----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 5cb170b..c19386a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -25,6 +25,7 @@ $(script_templates): %: Makefile %.in
.PHONY: install-data
install-data: $(templates)
@$(INSTALL_DATA) -Dt $(prefix)/share/taler/ frontend-donations.wsgi
+ @$(INSTALL_DATA) -Dt $(prefix)/share/taler/config.d/ donations.conf
# @test -n "$$(ls -A talerbank/app/static/web-common/)" || \
# (echo "please check out git submodules"; exit 1)
diff --git a/donations.conf b/donations.conf
index e0492dc..7404b3c 100644
--- a/donations.conf
+++ b/donations.conf
@@ -2,11 +2,21 @@
currency = TESTKUDOS
[frontends]
-BACKEND = http://backend.test.taler.net/
+
+# Merchant backend to use.
+backend = http://backend.test.taler.net/
+
+# This value will fill: "Authorization: ApiKey "
+backend_apikey = sandbox
[donations]
-UWSGI_UNIXPATH_MODE = 660
+
+# The following three options configure the way the donations
+# shop will serve UWSGI requests via unix domain sockets.
+uwsgi_serve = unix
+uwsgi_unixpath = /path/to/donations.uwsgi
+uwsgi_unixpath_mode = 660
+
+# The following option picks the merchant instance that
+# will be represented by the running donations shop.
instance = default
-UWSGI_SERVE = unix
-UWSGI_UNIXPATH = $HOME/sockets/donations.uwsgi
-UWSGI_UNIXMODE = 666
--
cgit v1.2.3
From f7829956ff2ee4b517f010a3f23bc62012e881e7 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Mon, 27 May 2019 18:03:08 +0200
Subject: use latest config logic
---
talerdonations/talerconfig.py | 392 ++++++++++++++++++++++++++++++++----------
1 file changed, 304 insertions(+), 88 deletions(-)
diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py
index a7ca065..2d2c78e 100644
--- a/talerdonations/talerconfig.py
+++ b/talerdonations/talerconfig.py
@@ -1,22 +1,21 @@
-# This file is part of TALER
-# (C) 2016 INRIA
+##
+# This file is part of TALER
+# (C) 2016 INRIA
#
-# TALER is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Affero General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
+# TALER is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
#
-# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public License along with
-# TALER; see the file COPYING. If not, see
+# You should have received a copy of the GNU General Public License along with
+# TALER; see the file COPYING. If not, see
#
-# @author Florian Dold
-
-"""
-Parse GNUnet-style configurations in pure Python
-"""
+# @author Florian Dold
+# @author Marcello Stanisci
+# @brief Parse GNUnet-style configurations in pure Python
import logging
import collections
@@ -24,34 +23,48 @@ import os
import weakref
import sys
import re
+from typing import Callable, Any
LOGGER = logging.getLogger(__name__)
__all__ = ["TalerConfig"]
TALER_DATADIR = None
+
try:
- # not clear if this is a good idea ...
from talerpaths import TALER_DATADIR as t
TALER_DATADIR = t
except ImportError:
pass
+##
+# Exception class for a any configuration error.
class ConfigurationError(Exception):
pass
+##
+# Exception class for malformed strings having with parameter
+# expansion.
class ExpansionSyntaxError(Exception):
pass
-
-def expand(var, getter):
- """
- Do shell-style parameter expansion.
- Supported syntax:
- - ${X}
- - ${X:-Y}
- - $X
- """
+##
+# Do shell-style parameter expansion.
+# Supported syntax:
+# - ${X}
+# - ${X:-Y}
+# - $X
+#
+# @param var entire config value that might contain a parameter
+# to expand.
+# @param getter function that is in charge of returning _some_
+# value to be used in place of the parameter to expand.
+# Typically, the replacement is searched first under the
+# PATHS section of the current configuration, or (if not
+# found) in the environment.
+#
+# @return the expanded config value.
+def expand(var: str, getter: Callable[[str], str]) -> str:
pos = 0
result = ""
while pos != -1:
@@ -88,38 +101,25 @@ def expand(var, getter):
result = result + replace
pos = end
-
return result + var[pos:]
-
-class OptionDict(collections.defaultdict):
- def __init__(self, config, section_name):
- self.config = weakref.ref(config)
- self.section_name = section_name
- super().__init__()
- def __missing__(self, key):
- entry = Entry(self.config(), self.section_name, key)
- self[key] = entry
- return entry
- def __getitem__(self, chunk):
- return super().__getitem__(chunk.lower())
- def __setitem__(self, chunk, value):
- super().__setitem__(chunk.lower(), value)
-
-
-class SectionDict(collections.defaultdict):
- def __missing__(self, key):
- value = OptionDict(self, key)
- self[key] = value
- return value
- def __getitem__(self, chunk):
- return super().__getitem__(chunk.lower())
- def __setitem__(self, chunk, value):
- super().__setitem__(chunk.lower(), value)
-
-
+##
+# A configuration entry.
class Entry:
- def __init__(self, config, section, option, **kwargs):
+
+ ##
+ # Init constructor.
+ #
+ # @param self the object itself.
+ # @param config reference to a configuration object - FIXME
+ # define "configuration object".
+ # @param section name of the config section where this entry
+ # got defined.
+ # @param option name of the config option associated with this
+ # entry.
+ # @param kwargs keyword arguments that hold the value / filename
+ # / line number of this current option.
+ def __init__(self, config, section: str, option: str, **kwargs) -> None:
self.value = kwargs.get("value")
self.filename = kwargs.get("filename")
self.lineno = kwargs.get("lineno")
@@ -127,14 +127,36 @@ class Entry:
self.option = option
self.config = weakref.ref(config)
- def __repr__(self):
+ ##
+ # XML representation of this entry.
+ #
+ # @param self the object itself.
+ # @return XML string holding all the relevant information
+ # for this entry.
+ def __repr__(self) -> str:
return "" \
% (self.section, self.option, repr(self.value),)
- def __str__(self):
+ ##
+ # Return the value for this entry, as is.
+ #
+ # @param self the object itself.
+ # @return the config value.
+ def __str__(self) -> Any:
return self.value
- def value_string(self, default=None, required=False, warn=False):
+ ##
+ # Return entry value, accepting defaults.
+ #
+ # @param self the object itself
+ # @param default default value to return if none was found.
+ # @param required indicate whether the value was required or not.
+ # If the value was required, but was not found, an exception
+ # is found.
+ # @param warn if True, outputs a warning message if the value was
+ # not found -- regardless of it being required or not.
+ # @return the value, or the given @a default, if not found.
+ def value_string(self, default=None, required=False, warn=False) -> str:
if required and self.value is None:
raise ConfigurationError("Missing required option '%s' in section '%s'" \
% (self.option.upper(), self.section.upper()))
@@ -149,7 +171,16 @@ class Entry:
return default
return self.value
- def value_int(self, default=None, required=False, warn=False):
+ ##
+ # Return entry value as a _int_. Raise exception if the
+ # value is not convertible to a integer.
+ #
+ # @param self the object itself
+ # @param default currently ignored.
+ # @param required currently ignored.
+ # @param warn currently ignored.
+ # @return the value, or the given @a default, if not found.
+ def value_int(self, default=None, required=False, warn=False) -> int:
value = self.value_string(default, warn, required)
if value is None:
return None
@@ -158,8 +189,13 @@ class Entry:
except ValueError:
raise ConfigurationError("Expected number for option '%s' in section '%s'" \
% (self.option.upper(), self.section.upper()))
-
- def _getsubst(self, key):
+ ##
+ # Fetch value to substitute to expansion variables.
+ #
+ # @param self the object itself.
+ # @param key the value's name to lookup.
+ # @return the value, if found, None otherwise.
+ def _getsubst(self, key: str) -> Any:
value = self.config()["paths"][key].value
if value is not None:
return value
@@ -168,31 +204,136 @@ class Entry:
return value
return None
- def value_filename(self, default=None, required=False, warn=False):
+ ##
+ # Fetch the config value that should be a filename,
+ # taking care of invoking the variable-expansion logic first.
+ #
+ # @param self the object itself.
+ # @param default currently ignored.
+ # @param required currently ignored.
+ # @param warn currently ignored.
+ # @return the (expanded) filename.
+ def value_filename(self, default=None, required=False, warn=False) -> str:
value = self.value_string(default, required, warn)
if value is None:
return None
return expand(value, self._getsubst)
- def location(self):
+ ##
+ # Give the filename and line number of this config entry.
+ #
+ # @param self this object.
+ # @return :, or "" if one
+ # is not known.
+ def location(self) -> str:
if self.filename is None or self.lineno is None:
return ""
return "%s:%s" % (self.filename, self.lineno)
+##
+# Represent a section by inheriting from 'defaultdict'.
+class OptionDict(collections.defaultdict):
+
+ ##
+ # Init constructor.
+ #
+ # @param self the object itself
+ # @param config the "config" object -- typically a @a TalerConfig instance.
+ # @param section_name the section name to assign to this object.
+ def __init__(self, config, section_name: str) -> None:
+ self.config = weakref.ref(config)
+ self.section_name = section_name
+ super().__init__()
+
+ ##
+ # Logic to run when a non-existent key is dereferenced.
+ # Just create and return a empty config @a Entry. Note
+ # that the freshly created entry will nonetheless put
+ # under the accessed key (that *does* become existent
+ # afterwards).
+ #
+ # @param self the object itself.
+ # @param key the key attempted to be accessed.
+ # @return the no-value entry.
+ def __missing__(self, key: str) -> Entry:
+ entry = Entry(self.config(), self.section_name, key)
+ self[key] = entry
+ return entry
+
+ ##
+ # Attempt to fetch one value from the object.
+ #
+ # @param self the object itself.
+ # @param chunk the key (?) that is tried to access.
+ # @return the object, if it exists, or a freshly created
+ # (empty) one, if it doesn't exist.
+ def __getitem__(self, chunk: str) -> Entry:
+ return super().__getitem__(chunk.lower())
+
+ ##
+ # Set one value into the object.
+ #
+ # @param self the object itself.
+ # @param chunk key under which the value is going to be set.
+ # @param value value to set the @a chunk to.
+ def __setitem__(self, chunk: str, value: Entry) -> None:
+ super().__setitem__(chunk.lower(), value)
+
+##
+# Collection of all the (@a OptionDict) sections.
+class SectionDict(collections.defaultdict):
+ ##
+ # Automatically invoked when a missing section is
+ # dereferenced. It creates the missing - empty - section.
+ #
+ # @param self the object itself.
+ # @param key the dereferenced section name.
+ # @return the freshly created section.
+ def __missing__(self, key):
+ value = OptionDict(self, key)
+ self[key] = value
+ return value
+
+ ##
+ # Attempt to retrieve a section.
+ #
+ # @param self the object itself.
+ # @param chunk the section name.
+ def __getitem__(self, chunk: str) -> OptionDict:
+ return super().__getitem__(chunk.lower())
+
+ ##
+ # Set a section.
+ #
+ # @param self the object itself.
+ # @param chunk the section name to set.
+ # @param value the value to set under that @a chunk.
+ def __setitem__(self, chunk: str, value: OptionDict) -> None:
+ super().__setitem__(chunk.lower(), value)
+
+##
+# One loaded taler configuration, including base configuration
+# files and included files.
class TalerConfig:
- """
- One loaded taler configuration, including base configuration
- files and included files.
- """
- def __init__(self):
- """
- Initialize an empty configuration
- """
- self.sections = SectionDict()
-
- # defaults != config file: the first is the 'base'
- # whereas the second overrides things from the first.
+
+ ##
+ # Init constructor..
+ #
+ # @param self the object itself.
+ def __init__(self) -> None:
+ self.sections = SectionDict() # just plain dict
+
+ ##
+ # Load a configuration file, instantiating a config object.
+ #
+ # @param filename the filename where to load the configuration
+ # from. If None, it defaults "taler.conf".
+ # @param load_defaults if True, then defaults values are loaded
+ # (from canonical directories like "/share/config.d/taler/")
+ # before the actual configuration file. This latter then
+ # can override some/all the defaults.
+ # @return the config object.
@staticmethod
def from_file(filename=None, load_defaults=True):
cfg = TalerConfig()
@@ -204,22 +345,57 @@ class TalerConfig:
filename = os.path.expanduser("~/.config/taler.conf")
if load_defaults:
cfg.load_defaults()
- cfg.load_file(filename)
+ cfg.load_file(os.path.expanduser(filename))
return cfg
- def value_string(self, section, option, **kwargs):
+ ##
+ # Get a string value from the config.
+ #
+ # @param self the config object itself.
+ # @param section the section to fetch the value from.
+ # @param option the value's option name.
+ # @param kwargs dict argument with instructions about
+ # the value retrieval logic.
+ # @return the wanted string (or a default / exception if
+ # a error occurs).
+ def value_string(self, section, option, **kwargs) -> str:
return self.sections[section][option].value_string(
kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
- def value_filename(self, section, option, **kwargs):
+ ##
+ # Get a value from the config that should be a filename.
+ # The variable expansion for the path's components is internally managed.
+ #
+ # @param self the config object itself.
+ # @param section the section to fetch the value from.
+ # @param option the value's option name.
+ # @param kwargs dict argument with instructions about
+ # the value retrieval logic.
+ # @return the wanted filename (or a default / exception if
+ # a error occurs).
+ def value_filename(self, section, option, **kwargs) -> str:
return self.sections[section][option].value_filename(
kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
- def value_int(self, section, option, **kwargs):
+ ##
+ # Get a integer value from the config.
+ #
+ # @param self the config object itself.
+ # @param section the section to fetch the value from.
+ # @param option the value's option name.
+ # @param kwargs dict argument with instructions about
+ # the value retrieval logic.
+ # @return the wanted integer (or a default / exception if
+ # a error occurs).
+ def value_int(self, section, option, **kwargs) -> int:
return self.sections[section][option].value_int(
kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
- def load_defaults(self):
+ ##
+ # Load default values from canonical locations.
+ #
+ # @param self the object itself.
+ def load_defaults(self) -> None:
base_dir = os.environ.get("TALER_BASE_CONFIG")
if base_dir:
self.load_dir(base_dir)
@@ -236,16 +412,25 @@ class TalerConfig:
return
LOGGER.warning("no base directory found")
+ ##
+ # Load configuration from environment variable
+ # TALER_CONFIG_FILE or from default location if the
+ # variable is not set.
+ #
+ # @param args currently unused.
+ # @param kwargs kwargs for subroutine @a from_file.
+ # @return freshly instantiated config object.
@staticmethod
def from_env(*args, **kwargs):
- """
- Load configuration from environment variable TALER_CONFIG_FILE
- or from default location if the variable is not set.
- """
filename = os.environ.get("TALER_CONFIG_FILE")
return TalerConfig.from_file(filename, *args, **kwargs)
- def load_dir(self, dirname):
+ ##
+ # Load config values from _each_ file found in a directory.
+ #
+ # @param self the object itself.
+ # @param dirname the directory to crawl in the look for config files.
+ def load_dir(self, dirname) -> None:
try:
files = os.listdir(dirname)
except FileNotFoundError:
@@ -256,7 +441,11 @@ class TalerConfig:
continue
self.load_file(os.path.join(dirname, file))
- def load_file(self, filename):
+ ##
+ # Load config values from a file.
+ #
+ # @param filename config file to take the values from.
+ def load_file(self, filename) -> None:
sections = self.sections
try:
with open(filename, "r") as file:
@@ -271,6 +460,16 @@ class TalerConfig:
if line.startswith("#"):
# comment
continue
+ if line.startswith("@INLINE@"):
+ pair = line.split()
+ if 2 != len(pair):
+ LOGGER.error("invalid inlined config filename given ('%s')" % line)
+ continue
+ if pair[1].startswith("/"):
+ self.load_file(pair[1])
+ else:
+ self.load_file(os.path.join(os.path.dirname(filename), pair[1]))
+ continue
if line.startswith("["):
if not line.endswith("]"):
LOGGER.error("invalid section header in line %s: %s",
@@ -299,8 +498,16 @@ class TalerConfig:
LOGGER.error("Configuration file (%s) not found", filename)
sys.exit(3)
-
- def dump(self):
+ ##
+ # Dump the textual representation of a config object.
+ #
+ # Format:
+ #
+ # [section]
+ # option = value # FIXME (what is location?)
+ #
+ # @param self the object itself, that will be dumped.
+ def dump(self) -> None:
for kv_section in self.sections.items():
print("[%s]" % (kv_section[1].section_name,))
for kv_option in kv_section[1].items():
@@ -309,7 +516,16 @@ class TalerConfig:
kv_option[1].value,
kv_option[1].location()))
- def __getitem__(self, chunk):
+
+ ##
+ # Return a whole section from this object.
+ #
+ # @param self the object itself.
+ # @param chunk name of the section to return.
+ # @return the section - note that if the section is
+ # not found, a empty one will created on the fly,
+ # then set under 'chunk', and returned.
+ def __getitem__(self, chunk: str) -> OptionDict:
if isinstance(chunk, str):
return self.sections[chunk]
raise TypeError("index must be string")
--
cgit v1.2.3
From 7becf0b04e22fcfd4457203fd5d3fbda1ddf10f3 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Mon, 27 May 2019 18:04:03 +0200
Subject: fix order
---
taler-merchant-donations.in | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/taler-merchant-donations.in b/taler-merchant-donations.in
index 5e3243d..691f7d4 100644
--- a/taler-merchant-donations.in
+++ b/taler-merchant-donations.in
@@ -35,12 +35,8 @@ site.addsitedir("%s/lib/python%d.%d/site-packages" % (
sys.version_info.major,
sys.version_info.minor))
-## @cond
-TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE"))
-
# No perfect match to our logging format, but good enough ...
UWSGI_LOGFMT = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)"
-## @endcond
##
@@ -118,4 +114,5 @@ if getattr(ARGS, 'func', None) is None:
if ARGS.config is not None:
os.environ["TALER_CONFIG_FILE"] = ARGS.config
+TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE"))
ARGS.func(ARGS)
--
cgit v1.2.3
From 5cdf3b0799b848b0b9f547b49b7b57f6c27df372 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Mon, 27 May 2019 18:08:22 +0200
Subject: ux
---
talerdonations/talerconfig.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py
index 2d2c78e..9598be5 100644
--- a/talerdonations/talerconfig.py
+++ b/talerdonations/talerconfig.py
@@ -32,6 +32,7 @@ __all__ = ["TalerConfig"]
TALER_DATADIR = None
try:
+ # not clear if this is a good idea ...
from talerpaths import TALER_DATADIR as t
TALER_DATADIR = t
except ImportError:
@@ -343,6 +344,7 @@ class TalerConfig:
filename = os.path.join(xdg, "taler.conf")
else:
filename = os.path.expanduser("~/.config/taler.conf")
+ logging.info("Loading default config: (%s)" % filename)
if load_defaults:
cfg.load_defaults()
cfg.load_file(os.path.expanduser(filename))
--
cgit v1.2.3
From dd835689654c18353b02f9f5809c7746de222ab9 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Mon, 27 May 2019 18:17:12 +0200
Subject: talerconfig
---
talerdonations/talerconfig.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py
index 9598be5..4a44c97 100644
--- a/talerdonations/talerconfig.py
+++ b/talerdonations/talerconfig.py
@@ -344,7 +344,7 @@ class TalerConfig:
filename = os.path.join(xdg, "taler.conf")
else:
filename = os.path.expanduser("~/.config/taler.conf")
- logging.info("Loading default config: (%s)" % filename)
+ print("Loading default config: (%s)" % filename)
if load_defaults:
cfg.load_defaults()
cfg.load_file(os.path.expanduser(filename))
@@ -497,7 +497,8 @@ class TalerConfig:
value=value, filename=filename, lineno=lineno)
sections[current_section][key] = entry
except FileNotFoundError:
- LOGGER.error("Configuration file (%s) not found", filename)
+ # not logging here, as this interests the final user mostly.
+ print("Configuration file (%s) not found" % filename)
sys.exit(3)
##
--
cgit v1.2.3
From f09cb421c2eeec58b2f768e09b97b39b8616ec02 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Mon, 10 Jun 2019 20:23:56 +0200
Subject: dependencies
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 5cddc40..3e89959 100755
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@ setup(name='talerdonations',
author_email='stanisci.m@gmail.com',
license='GPL',
packages=find_packages(),
- install_requires=["Flask>=0.10"],
+ install_requires=["Flask>=0.10", "requests", "uwsgi"],
tests_require=["mock", "nose"],
test_suite="nose.collector",
package_data={
--
cgit v1.2.3
From f80d6a250c99210c366410bb313a6c11f6fc58b1 Mon Sep 17 00:00:00 2001
From: Marcello Stanisci
Date: Tue, 25 Jun 2019 10:47:21 +0200
Subject: 5667: move jsmin dep to setup.py.
---
configure.ac | 10 ----------
setup.py | 5 ++++-
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/configure.ac b/configure.ac
index c7440be..e2ecfbe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,16 +48,6 @@ AC_SUBST(DEBIAN_PIP3_SYSTEM)
AC_CHECK_PROG([tsc],[tsc],[yes],[no])
AM_CONDITIONAL([HAVE_TSC], [test "x$tsc" = xyes])
-#
-# Check for minifier
-#
-AC_MSG_CHECKING([Checking for jsmin])
-python3 -m jsmin &> /dev/null
-if test $? -ne 0;
- then
- AC_MSG_ERROR([Please install Python3 module 'jsmin'])
-fi
-
#
# Report
#
diff --git a/setup.py b/setup.py
index 3e89959..a917c11 100755
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,10 @@ setup(name='talerdonations',
author_email='stanisci.m@gmail.com',
license='GPL',
packages=find_packages(),
- install_requires=["Flask>=0.10", "requests", "uwsgi"],
+ install_requires=["Flask>=0.10",
+ "requests",
+ "uwsgi",
+ "jsmin"],
tests_require=["mock", "nose"],
test_suite="nose.collector",
package_data={
--
cgit v1.2.3
From ea2a0c9dbe52c4a4922ee1e9a22b97b9024822a8 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:01:01 +0200
Subject: simplify build system
---
Doxyfile | 331 -----------------------
Makefile.in | 56 ----
bootstrap | 12 -
configure.ac | 66 -----
contrib/Doxyfile | 331 +++++++++++++++++++++++
frontend-donations.wsgi.in | 21 --
m4/ax_compare_version.m4 | 177 ------------
m4/python.m4 | 646 --------------------------------------------
setup.py | 8 +-
taler-merchant-donations.in | 118 --------
10 files changed, 335 insertions(+), 1431 deletions(-)
delete mode 100644 Doxyfile
delete mode 100644 Makefile.in
delete mode 100755 bootstrap
delete mode 100644 configure.ac
create mode 100644 contrib/Doxyfile
delete mode 100644 frontend-donations.wsgi.in
delete mode 100644 m4/ax_compare_version.m4
delete mode 100644 m4/python.m4
delete mode 100644 taler-merchant-donations.in
diff --git a/Doxyfile b/Doxyfile
deleted file mode 100644
index 530157e..0000000
--- a/Doxyfile
+++ /dev/null
@@ -1,331 +0,0 @@
-# Doxyfile 1.8.13
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-DOXYFILE_ENCODING = UTF-8
-PROJECT_NAME = "taler-donations"
-PROJECT_NUMBER =
-PROJECT_BRIEF =
-PROJECT_LOGO =
-OUTPUT_DIRECTORY = doxygen-doc/
-CREATE_SUBDIRS = NO
-ALLOW_UNICODE_NAMES = NO
-OUTPUT_LANGUAGE = English
-BRIEF_MEMBER_DESC = YES
-REPEAT_BRIEF = YES
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-ALWAYS_DETAILED_SEC = NO
-INLINE_INHERITED_MEMB = NO
-FULL_PATH_NAMES = YES
-STRIP_FROM_PATH =
-STRIP_FROM_INC_PATH =
-SHORT_NAMES = NO
-JAVADOC_AUTOBRIEF = NO
-QT_AUTOBRIEF = NO
-MULTILINE_CPP_IS_BRIEF = NO
-INHERIT_DOCS = YES
-SEPARATE_MEMBER_PAGES = NO
-TAB_SIZE = 4
-ALIASES =
-TCL_SUBST =
-OPTIMIZE_OUTPUT_FOR_C = NO
-OPTIMIZE_OUTPUT_JAVA = NO
-OPTIMIZE_FOR_FORTRAN = NO
-OPTIMIZE_OUTPUT_VHDL = NO
-EXTENSION_MAPPING = in=Python
-MARKDOWN_SUPPORT = YES
-TOC_INCLUDE_HEADINGS = 0
-AUTOLINK_SUPPORT = YES
-BUILTIN_STL_SUPPORT = NO
-CPP_CLI_SUPPORT = NO
-SIP_SUPPORT = NO
-IDL_PROPERTY_SUPPORT = YES
-DISTRIBUTE_GROUP_DOC = NO
-GROUP_NESTED_COMPOUNDS = NO
-SUBGROUPING = YES
-INLINE_GROUPED_CLASSES = NO
-INLINE_SIMPLE_STRUCTS = NO
-TYPEDEF_HIDES_STRUCT = NO
-LOOKUP_CACHE_SIZE = 0
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-EXTRACT_ALL = YES
-EXTRACT_PRIVATE = NO
-EXTRACT_PACKAGE = NO
-EXTRACT_STATIC = NO
-EXTRACT_LOCAL_CLASSES = YES
-EXTRACT_LOCAL_METHODS = NO
-EXTRACT_ANON_NSPACES = NO
-HIDE_UNDOC_MEMBERS = NO
-HIDE_UNDOC_CLASSES = NO
-HIDE_FRIEND_COMPOUNDS = NO
-HIDE_IN_BODY_DOCS = NO
-INTERNAL_DOCS = NO
-CASE_SENSE_NAMES = YES
-HIDE_SCOPE_NAMES = NO
-HIDE_COMPOUND_REFERENCE= NO
-SHOW_INCLUDE_FILES = YES
-SHOW_GROUPED_MEMB_INC = NO
-FORCE_LOCAL_INCLUDES = NO
-INLINE_INFO = YES
-SORT_MEMBER_DOCS = YES
-SORT_BRIEF_DOCS = NO
-SORT_MEMBERS_CTORS_1ST = NO
-SORT_GROUP_NAMES = NO
-SORT_BY_SCOPE_NAME = NO
-STRICT_PROTO_MATCHING = NO
-GENERATE_TODOLIST = YES
-GENERATE_TESTLIST = YES
-GENERATE_BUGLIST = YES
-GENERATE_DEPRECATEDLIST= YES
-ENABLED_SECTIONS =
-MAX_INITIALIZER_LINES = 30
-SHOW_USED_FILES = YES
-SHOW_FILES = YES
-SHOW_NAMESPACES = NO
-FILE_VERSION_FILTER =
-LAYOUT_FILE =
-CITE_BIB_FILES =
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-QUIET = NO
-WARNINGS = YES
-WARN_IF_UNDOCUMENTED = YES
-WARN_IF_DOC_ERROR = YES
-WARN_NO_PARAMDOC = NO
-WARN_AS_ERROR = NO
-WARN_FORMAT = "$file:$line: $text"
-WARN_LOGFILE =
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-INPUT =
-INPUT_ENCODING = UTF-8
-FILE_PATTERNS = *.py *.in
-RECURSIVE = YES
-EXCLUDE = Makefile.in
-EXCLUDE_SYMLINKS = NO
-EXCLUDE_PATTERNS =
-EXCLUDE_SYMBOLS =
-EXAMPLE_PATH =
-EXAMPLE_PATTERNS = *
-EXAMPLE_RECURSIVE = NO
-IMAGE_PATH =
-INPUT_FILTER =
-FILTER_PATTERNS =
-FILTER_SOURCE_FILES = NO
-FILTER_SOURCE_PATTERNS =
-USE_MDFILE_AS_MAINPAGE =
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-SOURCE_BROWSER = NO
-INLINE_SOURCES = NO
-STRIP_CODE_COMMENTS = YES
-REFERENCED_BY_RELATION = NO
-REFERENCES_RELATION = NO
-REFERENCES_LINK_SOURCE = YES
-SOURCE_TOOLTIPS = YES
-USE_HTAGS = NO
-VERBATIM_HEADERS = YES
-CLANG_ASSISTED_PARSING = NO
-CLANG_OPTIONS =
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-ALPHABETICAL_INDEX = YES
-COLS_IN_ALPHA_INDEX = 5
-IGNORE_PREFIX =
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-GENERATE_HTML = YES
-HTML_OUTPUT = html
-HTML_FILE_EXTENSION = .html
-HTML_HEADER =
-HTML_FOOTER =
-HTML_STYLESHEET =
-HTML_EXTRA_STYLESHEET =
-HTML_EXTRA_FILES =
-HTML_COLORSTYLE_HUE = 220
-HTML_COLORSTYLE_SAT = 100
-HTML_COLORSTYLE_GAMMA = 80
-HTML_TIMESTAMP = NO
-HTML_DYNAMIC_SECTIONS = NO
-HTML_INDEX_NUM_ENTRIES = 100
-GENERATE_DOCSET = NO
-DOCSET_FEEDNAME = "Doxygen generated docs"
-DOCSET_BUNDLE_ID = org.doxygen.Project
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-DOCSET_PUBLISHER_NAME = Publisher
-GENERATE_HTMLHELP = NO
-CHM_FILE =
-HHC_LOCATION =
-GENERATE_CHI = NO
-CHM_INDEX_ENCODING =
-BINARY_TOC = NO
-TOC_EXPAND = NO
-GENERATE_QHP = NO
-QCH_FILE =
-QHP_NAMESPACE = org.doxygen.Project
-QHP_VIRTUAL_FOLDER = doc
-QHP_CUST_FILTER_NAME =
-QHP_CUST_FILTER_ATTRS =
-QHP_SECT_FILTER_ATTRS =
-QHG_LOCATION =
-GENERATE_ECLIPSEHELP = NO
-ECLIPSE_DOC_ID = org.doxygen.Project
-DISABLE_INDEX = NO
-GENERATE_TREEVIEW = NO
-ENUM_VALUES_PER_LINE = 4
-TREEVIEW_WIDTH = 250
-EXT_LINKS_IN_WINDOW = NO
-FORMULA_FONTSIZE = 10
-FORMULA_TRANSPARENT = YES
-USE_MATHJAX = NO
-MATHJAX_FORMAT = HTML-CSS
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-MATHJAX_EXTENSIONS =
-MATHJAX_CODEFILE =
-SEARCHENGINE = YES
-SERVER_BASED_SEARCH = NO
-EXTERNAL_SEARCH = NO
-SEARCHENGINE_URL =
-SEARCHDATA_FILE = searchdata.xml
-EXTERNAL_SEARCH_ID =
-EXTRA_SEARCH_MAPPINGS =
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-GENERATE_LATEX = NO
-LATEX_OUTPUT = latex
-LATEX_CMD_NAME = latex
-MAKEINDEX_CMD_NAME = makeindex
-COMPACT_LATEX = NO
-PAPER_TYPE = a4
-EXTRA_PACKAGES =
-LATEX_HEADER =
-LATEX_FOOTER =
-LATEX_EXTRA_STYLESHEET =
-LATEX_EXTRA_FILES =
-PDF_HYPERLINKS = YES
-USE_PDFLATEX = YES
-LATEX_BATCHMODE = NO
-LATEX_HIDE_INDICES = NO
-LATEX_SOURCE_CODE = NO
-LATEX_BIB_STYLE = plain
-LATEX_TIMESTAMP = NO
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-GENERATE_RTF = NO
-RTF_OUTPUT = rtf
-COMPACT_RTF = NO
-RTF_HYPERLINKS = NO
-RTF_STYLESHEET_FILE =
-RTF_EXTENSIONS_FILE =
-RTF_SOURCE_CODE = NO
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-GENERATE_MAN = NO
-MAN_OUTPUT = man
-MAN_EXTENSION = .3
-MAN_SUBDIR =
-MAN_LINKS = NO
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-GENERATE_XML = NO
-XML_OUTPUT = xml
-XML_PROGRAMLISTING = YES
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-GENERATE_DOCBOOK = NO
-DOCBOOK_OUTPUT = docbook
-DOCBOOK_PROGRAMLISTING = NO
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-GENERATE_AUTOGEN_DEF = NO
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-GENERATE_PERLMOD = NO
-PERLMOD_LATEX = NO
-PERLMOD_PRETTY = YES
-PERLMOD_MAKEVAR_PREFIX =
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-ENABLE_PREPROCESSING = YES
-MACRO_EXPANSION = NO
-EXPAND_ONLY_PREDEF = NO
-SEARCH_INCLUDES = YES
-INCLUDE_PATH =
-INCLUDE_FILE_PATTERNS =
-PREDEFINED =
-EXPAND_AS_DEFINED =
-SKIP_FUNCTION_MACROS = YES
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-TAGFILES =
-GENERATE_TAGFILE =
-ALLEXTERNALS = NO
-EXTERNAL_GROUPS = YES
-EXTERNAL_PAGES = YES
-PERL_PATH = /usr/bin/perl
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-CLASS_DIAGRAMS = NO
-MSCGEN_PATH =
-DIA_PATH =
-HIDE_UNDOC_RELATIONS = YES
-HAVE_DOT = YES
-DOT_NUM_THREADS = 0
-DOT_FONTNAME = Helvetica
-DOT_FONTSIZE = 10
-DOT_FONTPATH =
-CLASS_GRAPH = YES
-COLLABORATION_GRAPH = YES
-GROUP_GRAPHS = YES
-UML_LOOK = NO
-UML_LIMIT_NUM_FIELDS = 10
-TEMPLATE_RELATIONS = NO
-INCLUDE_GRAPH = YES
-INCLUDED_BY_GRAPH = YES
-CALL_GRAPH = NO
-CALLER_GRAPH = NO
-GRAPHICAL_HIERARCHY = YES
-DIRECTORY_GRAPH = YES
-DOT_IMAGE_FORMAT = png
-INTERACTIVE_SVG = NO
-DOT_PATH =
-DOTFILE_DIRS =
-MSCFILE_DIRS =
-DIAFILE_DIRS =
-PLANTUML_JAR_PATH =
-PLANTUML_CFG_FILE =
-PLANTUML_INCLUDE_PATH =
-DOT_GRAPH_MAX_NODES = 50
-MAX_DOT_GRAPH_DEPTH = 0
-DOT_TRANSPARENT = NO
-DOT_MULTI_TARGETS = NO
-GENERATE_LEGEND = YES
-DOT_CLEANUP = YES
diff --git a/Makefile.in b/Makefile.in
deleted file mode 100644
index c19386a..0000000
--- a/Makefile.in
+++ /dev/null
@@ -1,56 +0,0 @@
-INSTALL = install
-INSTALL_PROGRAM = $(INSTALL)
-INSTALL_DATA = $(INSTALL) -m 644
-prefix = @prefix@
-srcdir = @srcdir@
-
-script_templates = taler-merchant-donations frontend-donations.wsgi
-templates = Makefile $(script_templates)
-
-edit = sed -e 's|@prefix[@]|$(prefix)|g'
-
-.PHONY: all
-all: $(templates)
- cd talerdonations/donations/static/web-common && make && cd -
-
-Makefile: Makefile.in
- ./config.status $@
-
-$(script_templates): %: Makefile %.in
- rm -f $@ $@.tmp
- $(edit) '$(srcdir)/$@.in' >$@.tmp
- mv $@.tmp $@
-
-
-.PHONY: install-data
-install-data: $(templates)
- @$(INSTALL_DATA) -Dt $(prefix)/share/taler/ frontend-donations.wsgi
- @$(INSTALL_DATA) -Dt $(prefix)/share/taler/config.d/ donations.conf
-
-# @test -n "$$(ls -A talerbank/app/static/web-common/)" || \
-# (echo "please check out git submodules"; exit 1)
-
-
-
-# link package under prefix to source tree
-.PHONY: devinstall
-devinstall: $(templates) install-data
- @pip3 install -e . --install-option="--prefix=@prefix@"
-
-
-# install into prefix
-.PHONY: install
-install: $(templates) install-data
- @pip3 install . @DEBIAN_PIP3_SYSTEM@ --install-option="--prefix=@prefix@"
- @# force update when sources changed
- @pip3 install . @DEBIAN_PIP3_SYSTEM@ --install-option="--prefix=@prefix@" --upgrade --no-deps
- cd talerdonations/donations/static/web-common && make install && cd -
-
-# run testcases
-.PHONY: check
-check:
- @export TALER_CONFIG_FILE=@abs_srcdir@/talerdonations/tests.conf; \
- python3 setup.py test
-
-pylint:
- @pylint talerdonations/
diff --git a/bootstrap b/bootstrap
deleted file mode 100755
index 373e5f5..0000000
--- a/bootstrap
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-if ! git --version >/dev/null; then
- echo "git not installed"
- exit 1
-fi
-
-echo "$0: Updating submodules"
-echo | git submodule update --init
-
-echo "$0: Running autoreconf"
-autoreconf -if
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index e2ecfbe..0000000
--- a/configure.ac
+++ /dev/null
@@ -1,66 +0,0 @@
-AC_INIT([talerdonations], [0.1.0], [taler-bug@gnunet.org])
-
-AC_CONFIG_MACRO_DIR([m4])
-AM_INIT_AUTOMAKE
-AC_PROG_AWK
-AC_PROG_SED
-
-#
-# Check for Python
-#
-
-PC_INIT([3.4])
-pyheaders=0
-PC_PYTHON_CHECK_HEADERS([pyheaders=1])
-PC_PYTHON_CHECK_VERSION()
-
-#
-# Check for pip3
-#
-
-AC_MSG_CHECKING([pip3])
-pip3 --version >/dev/null
-if test $? -ne 0;
- then
- AC_MSG_ERROR([Please install pip3>=6.0])
-fi
-
-VERSION=$(pip3 --version | $AWK '{ print $2 }')
-
-AC_MSG_RESULT([$VERSION])
-
-AX_COMPARE_VERSION([$VERSION],[lt],[6.0], [AC_MSG_ERROR([Please install pip3>=6.0])])
-
-# On Debian systems, we may need to pass "--system" to pip3 to get
-# to the desired installation target directory
-pip3 install --help | grep '\-\-system' >> /dev/null
-if test $? -ne 0;
-then
- DEBIAN_PIP3_SYSTEM=""
-else
- DEBIAN_PIP3_SYSTEM="--system"
-fi
-AC_SUBST(DEBIAN_PIP3_SYSTEM)
-
-#
-# Check for tsc
-#
-AC_CHECK_PROG([tsc],[tsc],[yes],[no])
-AM_CONDITIONAL([HAVE_TSC], [test "x$tsc" = xyes])
-
-#
-# Report
-#
-if test x$pyheaders != x1; then
- AC_MSG_WARN([Python headers not installed, might be required to build uwsgi])
-fi
-
-
-#
-# Finish
-#
-
-AC_CONFIG_FILES([Makefile
- talerdonations/donations/static/web-common/Makefile])
-
-AC_OUTPUT
diff --git a/contrib/Doxyfile b/contrib/Doxyfile
new file mode 100644
index 0000000..530157e
--- /dev/null
+++ b/contrib/Doxyfile
@@ -0,0 +1,331 @@
+# Doxyfile 1.8.13
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "taler-donations"
+PROJECT_NUMBER =
+PROJECT_BRIEF =
+PROJECT_LOGO =
+OUTPUT_DIRECTORY = doxygen-doc/
+CREATE_SUBDIRS = NO
+ALLOW_UNICODE_NAMES = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 4
+ALIASES =
+TCL_SUBST =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING = in=Python
+MARKDOWN_SUPPORT = YES
+TOC_INCLUDE_HEADINGS = 0
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+GROUP_NESTED_COMPOUNDS = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = NO
+TYPEDEF_HIDES_STRUCT = NO
+LOOKUP_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+HIDE_COMPOUND_REFERENCE= NO
+SHOW_INCLUDE_FILES = YES
+SHOW_GROUPED_MEMB_INC = NO
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_FILES = YES
+SHOW_NAMESPACES = NO
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+CITE_BIB_FILES =
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_AS_ERROR = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT =
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.py *.in
+RECURSIVE = YES
+EXCLUDE = Makefile.in
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+SOURCE_TOOLTIPS = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+CLANG_ASSISTED_PARSING = NO
+CLANG_OPTIONS =
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = NO
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 4
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = YES
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4
+EXTRA_PACKAGES =
+LATEX_HEADER =
+LATEX_FOOTER =
+LATEX_EXTRA_STYLESHEET =
+LATEX_EXTRA_FILES =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+LATEX_SOURCE_CODE = NO
+LATEX_BIB_STYLE = plain
+LATEX_TIMESTAMP = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+RTF_SOURCE_CODE = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_SUBDIR =
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+DOCBOOK_PROGRAMLISTING = NO
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+EXTERNAL_PAGES = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+MSCGEN_PATH =
+DIA_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DIAFILE_DIRS =
+PLANTUML_JAR_PATH =
+PLANTUML_CFG_FILE =
+PLANTUML_INCLUDE_PATH =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
diff --git a/frontend-donations.wsgi.in b/frontend-donations.wsgi.in
deleted file mode 100644
index 8007866..0000000
--- a/frontend-donations.wsgi.in
+++ /dev/null
@@ -1,21 +0,0 @@
-import sys
-
-if sys.version_info.major < 3:
- print("The taler bank needs to run with Python>=3.4")
- sys.exit(1)
-
-import site
-import os
-import logging
-
-logging.basicConfig(level=logging.INFO)
-
-os.environ.setdefault("TALER_PREFIX", "@prefix@")
-site.addsitedir("%s/lib/python%d.%d/site-packages" % (
- "@prefix@",
- sys.version_info.major,
- sys.version_info.minor))
-
-import talerdonations.donations
-
-application = talerdonations.donations.app
diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4
deleted file mode 100644
index 74dc0fd..0000000
--- a/m4/ax_compare_version.m4
+++ /dev/null
@@ -1,177 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_compare_version.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
-#
-# DESCRIPTION
-#
-# This macro compares two version strings. Due to the various number of
-# minor-version numbers that can exist, and the fact that string
-# comparisons are not compatible with numeric comparisons, this is not
-# necessarily trivial to do in a autoconf script. This macro makes doing
-# these comparisons easy.
-#
-# The six basic comparisons are available, as well as checking equality
-# limited to a certain number of minor-version levels.
-#
-# The operator OP determines what type of comparison to do, and can be one
-# of:
-#
-# eq - equal (test A == B)
-# ne - not equal (test A != B)
-# le - less than or equal (test A <= B)
-# ge - greater than or equal (test A >= B)
-# lt - less than (test A < B)
-# gt - greater than (test A > B)
-#
-# Additionally, the eq and ne operator can have a number after it to limit
-# the test to that number of minor versions.
-#
-# eq0 - equal up to the length of the shorter version
-# ne0 - not equal up to the length of the shorter version
-# eqN - equal up to N sub-version levels
-# neN - not equal up to N sub-version levels
-#
-# When the condition is true, shell commands ACTION-IF-TRUE are run,
-# otherwise shell commands ACTION-IF-FALSE are run. The environment
-# variable 'ax_compare_version' is always set to either 'true' or 'false'
-# as well.
-#
-# Examples:
-#
-# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
-# AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
-#
-# would both be true.
-#
-# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
-# AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
-#
-# would both be false.
-#
-# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
-#
-# would be true because it is only comparing two minor versions.
-#
-# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
-#
-# would be true because it is only comparing the lesser number of minor
-# versions of the two values.
-#
-# Note: The characters that separate the version numbers do not matter. An
-# empty string is the same as version 0. OP is evaluated by autoconf, not
-# configure, so must be a string, not a variable.
-#
-# The author would like to acknowledge Guido Draheim whose advice about
-# the m4_case and m4_ifvaln functions make this macro only include the
-# portions necessary to perform the specific comparison specified by the
-# OP argument in the final configure script.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Tim Toolan
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 11
-
-dnl #########################################################################
-AC_DEFUN([AX_COMPARE_VERSION], [
- AC_REQUIRE([AC_PROG_AWK])
-
- # Used to indicate true or false condition
- ax_compare_version=false
-
- # Convert the two version strings to be compared into a format that
- # allows a simple string comparison. The end result is that a version
- # string of the form 1.12.5-r617 will be converted to the form
- # 0001001200050617. In other words, each number is zero padded to four
- # digits, and non digits are removed.
- AS_VAR_PUSHDEF([A],[ax_compare_version_A])
- A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
- -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/[[^0-9]]//g'`
-
- AS_VAR_PUSHDEF([B],[ax_compare_version_B])
- B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
- -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/[[^0-9]]//g'`
-
- dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
- dnl # then the first line is used to determine if the condition is true.
- dnl # The sed right after the echo is to remove any indented white space.
- m4_case(m4_tolower($2),
- [lt],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
- ],
- [gt],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
- ],
- [le],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
- ],
- [ge],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
- ],[
- dnl Split the operator from the subversion count if present.
- m4_bmatch(m4_substr($2,2),
- [0],[
- # A count of zero means use the length of the shorter version.
- # Determine the number of characters in A and B.
- ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
- ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
-
- # Set A to no more than B's length and B to no more than A's length.
- A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
- B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
- ],
- [[0-9]+],[
- # A count greater than zero means use only that many subversions
- A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
- B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
- ],
- [.+],[
- AC_WARNING(
- [illegal OP numeric parameter: $2])
- ],[])
-
- # Pad zeros at end of numbers to make same length.
- ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
- B="$B`echo $A | sed 's/./0/g'`"
- A="$ax_compare_version_tmp_A"
-
- # Check for equality or inequality as necessary.
- m4_case(m4_tolower(m4_substr($2,0,2)),
- [eq],[
- test "x$A" = "x$B" && ax_compare_version=true
- ],
- [ne],[
- test "x$A" != "x$B" && ax_compare_version=true
- ],[
- AC_WARNING([illegal OP parameter: $2])
- ])
- ])
-
- AS_VAR_POPDEF([A])dnl
- AS_VAR_POPDEF([B])dnl
-
- dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
- if test "$ax_compare_version" = "true" ; then
- m4_ifvaln([$4],[$4],[:])dnl
- m4_ifvaln([$5],[else $5])dnl
- fi
-]) dnl AX_COMPARE_VERSION
diff --git a/m4/python.m4 b/m4/python.m4
deleted file mode 100644
index 98a68b8..0000000
--- a/m4/python.m4
+++ /dev/null
@@ -1,646 +0,0 @@
-# Copyright 2012, 2013, 2014 Brandon Invergo
-#
-# This file is part of pyconfigure. 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 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# Under Section 7 of GPL version 3, you are granted additional
-# permissions described in the Autoconf Configure Script Exception,
-# version 3.0, as published by the Free Software Foundation.
-#
-# You should have received a copy of the GNU General Public License
-# and a copy of the Autoconf Configure Script Exception along with
-# this program; see the files COPYINGv3 and COPYING.EXCEPTION
-# respectively. If not, see .
-
-
-# Many of these macros were adapted from ones written by Andrew Dalke
-# and James Henstridge and are included with the Automake utility
-# under the following copyright terms:
-#
-# Copyright (C) 1999-2012 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# Table of Contents:
-#
-# 1. Language selection
-# and routines to produce programs in a given language.
-#
-# 2. Producing programs in a given language.
-#
-# 3. Looking for a compiler
-# And possibly the associated preprocessor.
-#
-# 4. Looking for specific libs & functionality
-
-
-## ----------------------- ##
-## 1. Language selection. ##
-## ----------------------- ##
-
-
-# AC_LANG(Python)
-# ---------------
-AC_LANG_DEFINE([Python], [py], [PY], [PYTHON], [],
-[ac_ext=py
-ac_compile='chmod +x conftest.$ac_ext >&AS_MESSAGE_LOG_FD'
-ac_link='chmod +x conftest.$ac_ext && cp conftest.$ac_ext conftest >&AS_MESSAGE_LOG_FD'
-])
-
-
-# AC_LANG_PYTHON
-# --------------
-AU_DEFUN([AC_LANG_PYTHON], [AC_LANG(Python)])
-
-
-## ----------------------- ##
-## 2. Producing programs. ##
-## ----------------------- ##
-
-
-# AC_LANG_PROGRAM(Python)([PROLOGUE], [BODY])
-# -------------------------------------------
-m4_define([AC_LANG_PROGRAM(Python)], [dnl
-@%:@!$PYTHON
-$1
-m4_if([$2], [], [], [dnl
-if __name__ == '__main__':
-$2])])
-
-
-# _AC_LANG_IO_PROGRAM(Python)
-# ---------------------------
-# Produce source that performs I/O.
-m4_define([_AC_LANG_IO_PROGRAM(Python)],
-[AC_LANG_PROGRAM([dnl
-import sys
-try:
- h = open('conftest.out')
-except:
- sys.exit(1)
-else:
- close(h)
- sys.exit(0)
-], [])])
-
-
-# _AC_LANG_CALL(Python)([PROLOGUE], [FUNCTION])
-# ---------------------
-# Produce source that calls FUNCTION
-m4_define([_AC_LANG_CALL(Python)],
-[AC_LANG_PROGRAM([$1], [$2])])
-
-
-## -------------------------------------------- ##
-## 3. Looking for Compilers and Interpreters. ##
-## -------------------------------------------- ##
-
-
-AC_DEFUN([AC_LANG_COMPILER(Python)],
-[AC_REQUIRE([PC_PROG_PYTHON])])
-
-
-# PC_INIT([MIN-VERSION], [MAX-VERSION])
-# -----------------------------
-# Initialize pyconfigure, finding a Python interpreter with a given
-# minimum and/or maximum version.
-AC_DEFUN([PC_INIT],
-[PC_PROG_PYTHON([], [$1], [$2])
-dnl If we found something, do a sanity check that the interpreter really
-dnl has the version its name would suggest.
-m4_ifval([PYTHON],
- [PC_PYTHON_VERIFY_VERSION([>=], [pc_min_ver], [],
- [AC_MSG_FAILURE([No compatible Python interpreter found. If you're sure that you have one, try setting the PYTHON environment variable to the location of the interpreter.])])])
-m4_ifval([PYTHON],
- [PC_PYTHON_VERIFY_VERSION([<=], [pc_max_ver], [],
- [AC_MSG_FAILURE([No compatible Python interpreter found. If you're sure that you have one, try setting the PYTHON environment variable to the location of the interpreter.])])])
-])# PC_INIT
-
-# PC_PROG_PYTHON([PROG-TO-CHECK-FOR], [MIN-VERSION], [MAX-VERSION])
-# ---------------------------------
-# Find a Python interpreter. Python versions prior to 2.0 are not
-# supported. (2.0 was released on October 16, 2000).
-AC_DEFUN_ONCE([PC_PROG_PYTHON],
-[AC_ARG_VAR([PYTHON], [the Python interpreter])
-dnl The default minimum version is 2.0
-m4_define_default([pc_min_ver], m4_ifval([$2], [$2], [2.0]))
-dnl The default maximum version is 3.3
-m4_define_default([pc_max_ver], m4_ifval([$3], [$3], [4.0]))
-dnl Build up a list of possible interpreter names.
-m4_define_default([_PC_PYTHON_INTERPRETER_LIST],
- [dnl If we want some Python 3 versions (max version >= 3.0),
-dnl also search for "python3"
- m4_if(m4_version_compare(pc_max_ver, [2.9]), [1], [python3], []) \
-dnl If we want some Python 2 versions (min version <= 2.7),
-dnl also search for "python2".
- m4_if(m4_version_compare(pc_min_ver, [2.8]), [-1], [python2], []) \
-dnl Construct a comma-separated list of interpreter names (python2.6,
-dnl python2.7, etc). We only care about the first 3 characters of the
-dnl version strings (major-dot-minor; not
-dnl major-dot-minor-dot-bugfix[-dot-whatever])
- m4_foreach([pc_ver],
- m4_esyscmd_s(seq -s[[", "]] -f["[[%.1f]]"] m4_substr(pc_max_ver, [0], [3]) -0.1 m4_substr(pc_min_ver, [0], [3])),
-dnl Remove python2.8 and python2.9 since they will never exist
- [m4_bmatch(pc_ver, [2.[89]], [], [python]pc_ver)]) \
- [python]])
-dnl Do the actual search at last.
-m4_ifval([$1],
- [AC_PATH_PROGS(PYTHON, [$1 _PC_PYTHON_INTERPRETER_LIST])],
- [AC_PATH_PROGS(PYTHON, [_PC_PYTHON_INTERPRETER_LIST])])
-])# PC_PROG_PYTHON
-
-
-# PC_PYTHON_PROG_PYTHON_CONFIG(PROG-TO-CHECK-FOR)
-# ----------------------------------------------
-# Find the python-config program
-AC_DEFUN([PC_PYTHON_PROG_PYTHON_CONFIG],
-[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
-AC_ARG_VAR([PYTHON_CONFIG], [the Python-config program])
-dnl python-config's binary name is normally based on the Python interpreter's
-dnl binary name (i.e. python2.7 -> python2.7-config)
-m4_define([_PYTHON_BASENAME], [`basename $PYTHON`])
-m4_ifval([$1],
- [AC_PATH_PROGS(PYTHON_CONFIG, [$1 _PYTHON_BASENAME-config])],
- [AC_PATH_PROG(PYTHON_CONFIG, _PYTHON_BASENAME-config)])
-]) # PC_PYTHON_PROG_PYTHON_CONFIG
-
-
-# PC_PYTHON_VERIFY_VERSION([RELATION], [VERSION], [ACTION-IF-TRUE], [ACTION-IF-FALSE])
-# ---------------------------------------------------------------------------
-# Run ACTION-IF-TRUE if the Python interpreter PROG has version [RELATION] VERSION.
-# i.e if RELATION is "<", check if PROG has a version number less than VERSION.
-# Run ACTION-IF-FALSE otherwise.
-# Specify RELATION as any mathematical comparison "<", ">", "<=", ">=", "==" or "!="
-# This test uses sys.hexversion instead of the string equivalent (first
-# word of sys.version), in order to cope with versions such as 2.2c1.
-# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
-AC_DEFUN([PC_PYTHON_VERIFY_VERSION],
-[m4_define([pc_python_safe_ver], m4_bpatsubsts($2, [\.], [_]))
-AC_CACHE_CHECK([if Python $1 '$2'],
- [[pc_cv_python_req_version_]pc_python_safe_ver],
- [AC_LANG_PUSH(Python)[]dnl
- AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([dnl
-import sys
-], [dnl
- # split strings by '.' and convert to numeric. Append some zeros
- # because we need at least 4 digits for the hex conversion.
- # map returns an iterator in Python 3.0 and a list in 2.x
- reqver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
- reqverhex = 0
- # xrange is not present in Python 3.0 and range returns an iterator
- for i in list(range(4)):
- reqverhex = (reqverhex << 8) + reqver[[i]]
- # the final 8 bits are "0xf0" for final versions, which are all
- # we'll test against, since it's doubtful that a released software
- # will depend on an alpha- or beta-state Python.
- reqverhex += 0xf0
- if sys.hexversion $1 reqverhex:
- sys.exit()
- else:
- sys.exit(1)
-])],
- [[pc_cv_python_req_version_]pc_python_safe_ver=yes],
- [[pc_cv_python_req_version_]pc_python_safe_ver=no])
- AC_LANG_POP(Python)[]dnl
- ])
-AS_IF([test "$[pc_cv_python_req_version_]pc_python_safe_ver" = "no"], [$4], [$3])
-])# PC_PYTHON_VERIFY_VERSION
-
-
-# PC_PYTHON_CHECK_VERSION
-# -----------------------
-# Query Python for its version number. Getting [:3] seems to be
-# the best way to do this; it's what "site.py" does in the standard
-# library.
-AC_DEFUN([PC_PYTHON_CHECK_VERSION],
-[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
-AC_CACHE_CHECK([for $1 version],
- [pc_cv_python_version],
- [AC_LANG_PUSH(Python)[]dnl
- AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
-import sys
-], [dnl
- sys.stdout.write(sys.version[[:3]])
-])],
- [pc_cv_python_version=`./conftest`],
- [AC_MSG_FAILURE([failed to run Python program])])
- AC_LANG_POP(Python)[]dnl
- ])
-AC_SUBST([PYTHON_VERSION], [$pc_cv_python_version])
-])# PC_PYTHON_CHECK_VERSION
-
-
-# PC_PYTHON_CHECK_PREFIX
-# ----------------------
-# Use the value of $prefix for the corresponding value of
-# PYTHON_PREFIX. This is made a distinct variable so it can be
-# overridden if need be. However, general consensus is that you
-# shouldn't need this ability.
-AC_DEFUN([PC_PYTHON_CHECK_PREFIX],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to get it with python-config otherwise do it from within Python
-AC_CACHE_CHECK([for Python prefix], [pc_cv_python_prefix],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_prefix=`$PYTHON_CONFIG --prefix 2>&AS_MESSAGE_LOG_FD`
-else
- AC_LANG_PUSH(Python)[]dnl
- AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
-import sys
-], [dnl
- sys.stdout.write(sys.prefix)
-])], [pc_cv_python_prefix=`./conftest`;
- if test $? != 0; then
- AC_MSG_FAILURE([could not determine Python prefix])
- fi],
- [AC_MSG_FAILURE([failed to run Python program])])
- AC_LANG_POP(Python)[]dnl
-fi])
-AC_SUBST([PYTHON_PREFIX], [$pc_cv_python_prefix])])
-
-
-# PC_PYTHON_CHECK_EXEC_PREFIX
-# --------------------------
-# Like above, but for $exec_prefix
-AC_DEFUN([PC_PYTHON_CHECK_EXEC_PREFIX],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to get it with python-config otherwise do it from within Python
-AC_CACHE_CHECK([for Python exec-prefix], [pc_cv_python_exec_prefix],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_exec_prefix=`$PYTHON_CONFIG --exec-prefix 2>&AS_MESSAGE_LOG_FD`
-else
- AC_LANG_PUSH(Python)[]dnl
- AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
-import sys
-], [dnl
- sys.stdout.write(sys.exec_prefix)
-])],
- [pc_cv_python_exec_prefix=`./conftest`;
- if test $? != 0; then
- AC_MSG_FAILURE([could not determine Python exec_prefix])
- fi],
- [AC_MSG_FAILURE([failed to run Python program])])
- AC_LANG_POP(Python)[]dnl
-fi
-])
-AC_SUBST([PYTHON_EXEC_PREFIX], [$pc_cv_python_exec_prefix])])
-
-
-# PC_PYTHON_CHECK_INCLUDES
-# ------------------------
-# Find the Python header file include flags (ie
-# '-I/usr/include/python')
-AC_DEFUN([PC_PYTHON_CHECK_INCLUDES],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to find the headers location with python-config otherwise guess
-AC_CACHE_CHECK([for Python includes], [pc_cv_python_includes],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_includes=`$PYTHON_CONFIG --includes 2>&AS_MESSAGE_LOG_FD`
-else
- pc_cv_python_includes="[-I$includedir/$_PYTHON_BASENAME]m4_ifdef(PYTHON_ABI_FLAGS,
- PYTHON_ABI_FLAGS,)"
-fi
-])
-AC_SUBST([PYTHON_INCLUDES], [$pc_cv_python_includes])])
-
-
-# PC_PYTHON_CHECK_HEADERS([ACTION-IF-PRESENT], [ACTION-IF-ABSENT])
-# -----------------------
-# Check for the presence and usability of Python.h
-AC_DEFUN([PC_PYTHON_CHECK_HEADERS],
-[AC_REQUIRE([PC_PYTHON_CHECK_INCLUDES])[]dnl
-pc_cflags_store=$CPPFLAGS
-CPPFLAGS="$CFLAGS $PYTHON_INCLUDES"
-AC_CHECK_HEADER([Python.h], [$1], [$2])
-CPPFLAGS=$pc_cflags_store
-])
-
-
-# PC_PYTHON_CHECK_LIBS
-# --------------------
-# Find the Python lib flags (ie '-lpython')
-AC_DEFUN([PC_PYTHON_CHECK_LIBS],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to find the lib flags with python-config otherwise guess
-AC_CACHE_CHECK([for Python libs], [pc_cv_python_libs],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_libs=`$PYTHON_CONFIG --libs 2>&AS_MESSAGE_LOG_FD`
-else
- pc_cv_python_libs="[-l$_PYTHON_BASENAME]m4_ifdef(PYTHON_ABI_FLAGS, PYTHON_ABI_FLAGS,)"
-fi
-])
-AC_SUBST([PYTHON_LIBS], [$pc_cv_python_libs])])
-
-
-# PC_PYTHON_TEST_LIBS(LIBRARY-FUNCTION, [ACTION-IF-PRESENT], [ACTION-IF-ABSENT])
-# -------------------
-# Verify that the Python libs can be loaded
-AC_DEFUN([PC_PYTHON_TEST_LIBS],
-[AC_REQUIRE([PC_PYTHON_CHECK_LIBS])[]dnl
-pc_libflags_store=$LIBS
-for lflag in $PYTHON_LIBS; do
- case $lflag in
- -lpython*@:}@
- LIBS="$LIBS $lflag"
- pc_libpython=`echo $lflag | sed -e 's/^-l//'`
- ;;
- *@:}@;;
- esac
-done
-AC_CHECK_LIB([$pc_libpython], [$1], [$2], [$3])])
-
-
-# PC_PYTHON_CHECK_CFLAGS
-# ----------------------
-# Find the Python CFLAGS
-AC_DEFUN([PC_PYTHON_CHECK_CFLAGS],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to find the CFLAGS with python-config otherwise give up
-AC_CACHE_CHECK([for Python CFLAGS], [pc_cv_python_cflags],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_cflags=`$PYTHON_CONFIG --cflags 2>&AS_MESSAGE_LOG_FD`
-else
- pc_cv_python_cflags=
-fi
-])
-AC_SUBST([PYTHON_CFLAGS], [$pc_cv_python_cflags])])
-
-
-# PC_PYTHON_CHECK_LDFLAGS
-# -----------------------
-# Find the Python LDFLAGS
-AC_DEFUN([PC_PYTHON_CHECK_LDFLAGS],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to find the LDFLAGS with python-config otherwise give up
-AC_CACHE_CHECK([for Python LDFLAGS], [pc_cv_python_ldflags],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_ldflags=`$PYTHON_CONFIG --ldflags 2>&AS_MESSAGE_LOG_FD`
-else
- pc_cv_python_ldflags=
-fi
-])
-AC_SUBST([PYTHON_LDFLAGS], [$pc_cv_python_ldflags])])
-
-
-# PC_PYTHON_CHECK_EXTENSION_SUFFIX
-# --------------------------------
-# Find the Python extension suffix (i.e. '.cpython-32.so')
-AC_DEFUN([PC_PYTHON_CHECK_EXTENSION_SUFFIX],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to find the suffix with python-config otherwise give up
-AC_CACHE_CHECK([for Python extension suffix], [pc_cv_python_extension_suffix],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_extension_suffix=`$PYTHON_CONFIG --extension-suffix 2>&AS_MESSAGE_LOG_FD`
-else
- pc_cv_python_extension_suffix=
-fi
-])
-AC_SUBST([PYTHON_EXTENSION_SUFFIX], [$pc_cv_python_extension_suffix])])
-
-
-# PC_PYTHON_CHECK_ABI_FLAGS
-# -------------------------
-# Find the Python ABI flags
-AC_DEFUN([PC_PYTHON_CHECK_ABI_FLAGS],
-[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
-dnl Try to find the ABI flags with python-config otherwise give up
-AC_CACHE_CHECK([for Python ABI flags], [pc_cv_python_abi_flags],
-[if test -x "$PYTHON_CONFIG"; then
- pc_cv_python_abi_flags=`$PYTHON_CONFIG --abiflags 2>&AS_MESSAGE_LOG_FD`
-else
- pc_cv_python_abi_flags=
-fi
-])
-AC_SUBST([PYTHON_ABI_FLAGS], [$pc_cv_python_abi_flags])])
-
-
-# PC_PYTHON_CHECK_PLATFORM
-# ------------------------
-# At times (like when building shared libraries) you may want
-# to know which OS platform Python thinks this is.
-AC_DEFUN([PC_PYTHON_CHECK_PLATFORM],
-[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
-dnl Get the platform from within Python (sys.platform)
-AC_CACHE_CHECK([for Python platform], [pc_cv_python_platform],
- [AC_LANG_PUSH(Python)[]dnl
- AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
-import sys
-], [dnl
- sys.stdout.write(sys.platform)
-])], [pc_cv_python_platform=`./conftest`;
- if test $? != 0; then
- AC_MSG_FAILURE([could not determine Python platform])
- fi],
- [AC_MSG_FAILURE([failed to run Python program])])
- AC_LANG_POP(Python)[]dnl
- ])
-AC_SUBST([PYTHON_PLATFORM], [$pc_cv_python_platform])
-])
-
-
-# PC_PYTHON_CHECK_SITE_DIR
-# ---------------------
-# The directory to which new libraries are installed (i.e. the
-# "site-packages" directory.
-AC_DEFUN([PC_PYTHON_CHECK_SITE_DIR],
-[AC_REQUIRE([PC_PROG_PYTHON])AC_REQUIRE([PC_PYTHON_CHECK_PREFIX])[]dnl
-AC_CACHE_CHECK([for Python site-packages directory],
- [pc_cv_python_site_dir],
- [AC_LANG_PUSH(Python)[]dnl
- if test "x$prefix" = xNONE
- then
- pc_py_prefix=$ac_default_prefix
- else
- pc_py_prefix=$prefix
- fi
- AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
-import sys
-from platform import python_implementation
-# sysconfig in CPython 2.7 doesn't work in virtualenv
-#
-try:
- import sysconfig
-except:
- can_use_sysconfig = False
-else:
- can_use_sysconfig = True
-if can_use_sysconfig:
- if python_implementation() == "CPython" and sys.version[[:3]] == '2.7':
- can_use_sysconfig = False
-if not can_use_sysconfig:
- from distutils import sysconfig
- sitedir = sysconfig.get_python_lib(False, False, prefix='$pc_py_prefix')
-else:
- sitedir = sysconfig.get_path('purelib', vars={'base':'$pc_py_prefix'})
-], [dnl
- sys.stdout.write(sitedir)
-])], [pc_cv_python_site_dir=`./conftest`],
- [AC_MSG_FAILURE([failed to run Python program])])
- AC_LANG_POP(Python)[]dnl
- case $pc_cv_python_site_dir in
- $pc_py_prefix*)
- pc__strip_prefix=`echo "$pc_py_prefix" | sed 's|.|.|g'`
- pc_cv_python_site_dir=`echo "$pc_cv_python_site_dir" | sed "s,^$pc__strip_prefix/,,"`
- ;;
- *)
- case $pc_py_prefix in
- /usr|/System*) ;;
- *)
- pc_cv_python_site_dir=lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
- esac
- ])
-AC_SUBST([pythondir], [\${prefix}/$pc_cv_python_site_dir])])# PC_PYTHON_CHECK_SITE_DIR
-
-# PC_PYTHON_SITE_PACKAGE_DIR
-# --------------------------
-# $PACKAGE directory under PYTHON_SITE_DIR
-AC_DEFUN([PC_PYTHON_SITE_PACKAGE_DIR],
-[AC_REQUIRE([PC_PYTHON_CHECK_SITE_DIR])[]dnl
-AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE_NAME])])
-
-
-# PC_PYTHON_CHECK_EXEC_DIR
-# ------------------------
-# directory for installing python extension modules (shared libraries)
-AC_DEFUN([PC_PYTHON_CHECK_EXEC_DIR],
-[AC_REQUIRE([PC_PROG_PYTHON])AC_REQUIRE([PC_PYTHON_CHECK_EXEC_PREFIX])[]dnl
- AC_CACHE_CHECK([for Python extension module directory],
- [pc_cv_python_exec_dir],
- [AC_LANG_PUSH(Python)[]dnl
- if test "x$pc_cv_python_exec_prefix" = xNONE
- then
- pc_py_exec_prefix=$pc_cv_python_prefix
- else
- pc_py_exec_prefix=$pc_cv_python_exec_prefix
- fi
- AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
-import sys
-from platform import python_implementation
-# sysconfig in CPython 2.7 doesn't work in virtualenv
-#
-try:
- import sysconfig
-except:
- can_use_sysconfig = False
-else:
- can_use_sysconfig = True
-if can_use_sysconfig:
- if python_implementation() == "CPython" and sys.version[[:3]] == '2.7':
- can_use_sysconfig = False
-if not can_use_sysconfig:
- from distutils import sysconfig
- sitedir = sysconfig.get_python_lib(False, False, prefix='$pc_py__exec_prefix')
-else:
- sitedir = sysconfig.get_path('purelib', vars={'platbase':'$pc_py_exec_prefix'})
-], [dnl
- sys.stdout.write(sitedir)
-])], [pc_cv_python_exec_dir=`./conftest`],
- [AC_MSG_FAILURE([failed to run Python program])])
- AC_LANG_POP(Python)[]dnl
- case $pc_cv_python_exec_dir in
- $pc_py_exec_prefix*)
- pc__strip_prefix=`echo "$pc_py_exec_prefix" | sed 's|.|.|g'`
- pc_cv_python_exec_dir=`echo "$pc_cv_python_exec_dir" | sed "s,^$pc__strip_prefix/,,"`
- ;;
- *)
- case $pc_py_exec_prefix in
- /usr|/System*) ;;
- *)
- pc_cv_python_exec_dir=lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
- esac
- ])
-AC_SUBST([pyexecdir], [\${exec_prefix}/$pc_cv_python_pyexecdir])]) #PY_PYTHON_CHECK_EXEC_LIB_DIR
-
-
-# PC_PYTHON_EXEC_PACKAGE_DIR
-# --------------------------
-# $PACKAGE directory under PYTHON_SITE_DIR
-AC_DEFUN([PC_PYTHON_EXEC_PACKAGE_DIR],
-[AC_REQUIRE([PC_PYTHON_CHECK_EXEC_DIR])[]dnl
-AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE_NAME])])
-
-
-## -------------------------------------------- ##
-## 4. Looking for specific libs & functionality ##
-## -------------------------------------------- ##
-
-
-# PC_PYTHON_CHECK_MODULE(LIBRARY, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-# ----------------------------------------------------------------------
-# Macro for checking if a Python library is installed
-AC_DEFUN([PC_PYTHON_CHECK_MODULE],
-[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
-m4_define([pc_python_safe_mod], m4_bpatsubsts($1, [\.], [_]))
-AC_CACHE_CHECK([for Python '$1' library],
- [[pc_cv_python_module_]pc_python_safe_mod],
- [AC_LANG_PUSH(Python)[]dnl
- AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([dnl
-import sys
-try:
- import $1
-except:
- sys.exit(1)
-else:
- sys.exit(0)
-], [])],
- [[pc_cv_python_module_]pc_python_safe_mod="yes"],
- [[pc_cv_python_module_]pc_python_safe_mod="no"])
- AC_LANG_POP(Python)[]dnl
- ])
-AS_IF([test "$[pc_cv_python_module_]pc_python_safe_mod" = "no"], [$3], [$2])
-])# PC_PYTHON_CHECK_MODULE
-
-
-# PC_PYTHON_CHECK_FUNC([LIBRARY], FUNCTION, ARGS, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-# ---------------------------------------------------------------------------------------
-# Check to see if a given function call, optionally from a module, can
-# be successfully called
-AC_DEFUN([PC_PYTHON_CHECK_FUNC],
-[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
-m4_define([pc_python_safe_mod], m4_bpatsubsts($1, [\.], [_]))
-AC_CACHE_CHECK([for Python m4_ifnblank($1, '$1.$2()', '$2()') function],
- [[pc_cv_python_func_]pc_python_safe_mod[_$2]],
- [AC_LANG_PUSH(Python)[]dnl
- AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([dnl
-import sys
-m4_ifnblank([$1], [dnl
-try:
- import $1
-except:
- sys.exit(1)
-], [])],
-[
-m4_ifnblank([$1], [
- try:
- $1.$2($3)], [
- try:
- $2($3)])
- except:
- sys.exit(1)
- else:
- sys.exit(0)
-])],
- [[pc_cv_python_func_]pc_python_safe_mod[_$2]="yes"],
- [[pc_cv_python_func_]pc_python_safe_mod[_$2]="no"])
- AC_LANG_POP(Python)[]dnl
- ])
-AS_IF([test "$[pc_cv_python_func_]pc_python_safe_mod[_$2]" = "no"], [$5], [$4])
-])# PC_PYTHON_CHECK_FUNC
diff --git a/setup.py b/setup.py
index a917c11..71526a9 100755
--- a/setup.py
+++ b/setup.py
@@ -1,11 +1,11 @@
from setuptools import setup, find_packages
setup(name='talerdonations',
- version='0.0',
+ version='0.6.0pre1',
description='Example donations site for GNU Taler',
url='git://taler.net/donations',
- author='Marcello Stanisci',
- author_email='stanisci.m@gmail.com',
+ author=['Marcello Stanisci', 'Florian Dold'],
+ author_email=['stanisci.m@gmail.com', 'dold@taler.net'],
license='GPL',
packages=find_packages(),
install_requires=["Flask>=0.10",
@@ -24,5 +24,5 @@ setup(name='talerdonations',
"donations/static/web-common/*.html",
]
},
- scripts=['taler-merchant-donations'],
+ scripts=['./bin/taler-merchant-donations'],
zip_safe=False)
diff --git a/taler-merchant-donations.in b/taler-merchant-donations.in
deleted file mode 100644
index 691f7d4..0000000
--- a/taler-merchant-donations.in
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python3
-
-##
-# This file is part of TALER
-# (C) 2017 INRIA
-#
-# TALER is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Affero General Public
-# License as published by the Free Software Foundation; either
-# version 3, or (at your option) any later version.
-#
-# TALER is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty
-# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public
-# License along with TALER; see the file COPYING. If not,
-# see
-#
-# @author Florian Dold
-# @file Standalone script to run the donations site.
-
-import argparse
-import sys
-import os
-import site
-import logging
-from talerdonations.talerconfig import TalerConfig
-
-
-os.environ.setdefault("TALER_PREFIX", "@prefix@")
-site.addsitedir("%s/lib/python%d.%d/site-packages" % (
- "@prefix@",
- sys.version_info.major,
- sys.version_info.minor))
-
-# No perfect match to our logging format, but good enough ...
-UWSGI_LOGFMT = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)"
-
-
-##
-# This function interprets the 'serve-http' subcommand.
-# The effect it to launch the donations HTTP service.
-#
-# @param args command line options.
-def handle_serve_http(args):
- port = args.port
- if port is None:
- port = TC["donations"]["http_port"].value_int(required=True)
- spec = ":%d" % (port,)
- os.execlp("uwsgi", "uwsgi",
- "--master",
- "--die-on-term",
- "--log-format", UWSGI_LOGFMT,
- "--http", spec,
- "--wsgi-file", "@prefix@/share/taler/frontend-donations.wsgi")
-
-
-##
-# This function interprets the 'serve-uwsgi' subcommand.
-# The effect is to launch the donations UWSGI service. This
-# type of service is usually used when the HTTP donations interface
-# is accessed via a reverse proxy (like Nginx, for example).
-#
-# @param command line options.
-def handle_serve_uwsgi(args):
- del args # pacify PEP checkers
- serve_uwsgi = TC["donations"]["uwsgi_serve"].value_string(required=True).lower()
- params = ["uwsgi", "uwsgi",
- "--master",
- "--die-on-term",
- "--log-format", UWSGI_LOGFMT,
- "--wsgi-file", "@prefix@/share/taler/frontend-donations.wsgi"]
- if serve_uwsgi == "tcp":
- port = TC["donations"]["uwsgi_port"].value_int(required=True)
- spec = ":%d" % (port,)
- params.extend(["--socket", spec])
- elif serve_uwsgi == "unix":
- spec = TC["donations"]["uwsgi_unixpath"].value_filename(required=True)
- mode = TC["donations"]["uwsgi_unixpath_mode"].value_filename(required=True)
- params.extend(["--socket", spec])
- params.extend(["--chmod-socket="+mode])
- os.makedirs(os.path.dirname(spec), exist_ok=True)
- logging.info("launching uwsgi with argv %s", params[1:])
- os.execlp(*params)
-
-
-## @cond
-PARSER = argparse.ArgumentParser()
-PARSER.set_defaults(func=None)
-PARSER.add_argument('--config', '-c',
- help="configuration file to use",
- metavar="CONFIG", type=str,
- dest="config", default=None)
-SUB = PARSER.add_subparsers()
-
-P = SUB.add_parser('serve-http', help="Serve over HTTP")
-P.add_argument("--port", "-p", dest="port",
- type=int, default=None, metavar="PORT")
-P.set_defaults(func=handle_serve_http)
-
-P = SUB.add_parser('serve-uwsgi', help="Serve over UWSGI")
-P.set_defaults(func=handle_serve_uwsgi)
-
-ARGS = PARSER.parse_args()
-## @endcond
-
-
-if getattr(ARGS, 'func', None) is None:
- PARSER.print_help()
- sys.exit(1)
-
-if ARGS.config is not None:
- os.environ["TALER_CONFIG_FILE"] = ARGS.config
-
-TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE"))
-ARGS.func(ARGS)
--
cgit v1.2.3
From 455755737e6dcb7f938f7e6f9672bfc3e38f0a73 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:01:43 +0200
Subject: yapf style file
---
.style.yapf | 5 ++
talerdonations/donations/donations.py | 76 ++++++++++++++++------------
talerdonations/talerconfig.py | 95 ++++++++++++++++++++++++-----------
talerdonations/tests.py | 1 +
4 files changed, 116 insertions(+), 61 deletions(-)
create mode 100644 .style.yapf
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 0000000..3b39780
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,5 @@
+[style]
+based_on_style = pep8
+coalesce_brackets=True
+column_limit=80
+dedent_closing_brackets=True
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index f0f97c5..5655734 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -53,6 +53,7 @@ app.config.from_object(__name__)
def utility_processor():
def env(name, default=None):
return os.environ.get(name, default)
+
return dict(env=env)
@@ -76,7 +77,9 @@ def err_abort(abort_status_code, **params):
def backend_get(endpoint, params):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.get(urljoin(BACKEND_URL, endpoint), params=params, headers=headers)
+ resp = requests.get(urljoin(BACKEND_URL, endpoint),
+ params=params,
+ headers=headers)
except requests.ConnectionError:
err_abort(500, message="Could not establish connection to backend")
try:
@@ -84,8 +87,10 @@ def backend_get(endpoint, params):
except ValueError:
err_abort(500, message="Could not parse response from backend")
if resp.status_code != 200:
- err_abort(500, message="Backend returned error status",
- json=response_json, status_code=resp.status_code)
+ err_abort(500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code)
return response_json
@@ -100,21 +105,25 @@ def backend_get(endpoint, params):
def backend_post(endpoint, json):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json, headers=headers)
+ resp = requests.post(urljoin(BACKEND_URL, endpoint),
+ json=json,
+ headers=headers)
except requests.ConnectionError:
err_abort(500, message="Could not establish connection to backend")
try:
response_json = resp.json()
except ValueError:
- err_abort(500, message="Could not parse response from backend",
+ err_abort(500,
+ message="Could not parse response from backend",
status_code=resp.status_code)
if resp.status_code != 200:
- err_abort(500, message="Backend returned error status",
- json=response_json, status_code=resp.status_code)
+ err_abort(500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code)
return response_json
-
##
# Inspect GET arguments in the look for a parameter.
#
@@ -126,6 +135,7 @@ def expect_parameter(name):
return err_abort(400, message="parameter '{}' required".format(name))
return val
+
##
# "Fallback" exception handler to capture all the unmanaged errors.
#
@@ -138,13 +148,16 @@ def internal_error(e):
message="Internal error",
stack=traceback.format_exc())
+
##
# Serve the main index page.
#
# @return response object of the index page.
@app.route("/")
def index():
- return flask.render_template("templates/index.html", merchant_currency=CURRENCY)
+ return flask.render_template("templates/index.html",
+ merchant_currency=CURRENCY)
+
##
# Serve the "/javascript" page.
@@ -155,7 +168,6 @@ def javascript_licensing():
return flask.render_template("templates/javascript.html")
-
##
# Serve the "/checkout" page. This page lets the
# user pick the payment method they want to use,
@@ -167,12 +179,11 @@ def checkout():
amount = expect_parameter("donation_amount")
donation_receiver = expect_parameter("donation_receiver")
donation_donor = expect_parameter("donation_donor")
- return flask.render_template(
- "templates/checkout.html",
- donation_amount=amount,
- donation_receiver=donation_receiver,
- donation_donor=donation_donor,
- merchant_currency=CURRENCY)
+ return flask.render_template("templates/checkout.html",
+ donation_amount=amount,
+ donation_receiver=donation_receiver,
+ donation_donor=donation_donor,
+ merchant_currency=CURRENCY)
##
@@ -182,8 +193,7 @@ def checkout():
# @return response object about the mentioned impossibility.
@app.route("/provider-not-supported")
def provider_not_supported():
- return flask.render_template( "templates/provider-not-supported.html")
-
+ return flask.render_template("templates/provider-not-supported.html")
##
@@ -201,18 +211,24 @@ def donate():
payment_system = expect_parameter("payment_system")
if payment_system != "taler":
return flask.redirect(flask.url_for("provider_not_supported"))
- fulfillment_url = flask.url_for("fulfillment", receiver=donation_receiver, _external=True)
+ fulfillment_url = flask.url_for("fulfillment",
+ receiver=donation_receiver,
+ _external=True)
order = dict(
amount=donation_amount,
- extra=dict(donor=donation_donor, receiver=donation_receiver, amount=donation_amount),
+ extra=dict(donor=donation_donor,
+ receiver=donation_receiver,
+ amount=donation_amount),
fulfillment_url=fulfillment_url,
instance=donation_receiver,
summary="Donation to {}".format(donation_receiver),
)
order_resp = backend_post("order", dict(order=order))
order_id = order_resp["order_id"]
- return flask.redirect(flask.url_for("fulfillment", receiver=donation_receiver, order_id=order_id))
-
+ return flask.redirect(
+ flask.url_for("fulfillment",
+ receiver=donation_receiver,
+ order_id=order_id))
##
@@ -226,8 +242,7 @@ def donate():
@app.route("/donation/")
def fulfillment(receiver):
order_id = expect_parameter("order_id")
- pay_params = dict(instance=receiver,
- order_id=order_id)
+ pay_params = dict(instance=receiver, order_id=order_id)
pay_status = backend_get("check-payment", pay_params)
if pay_status.get("payment_redirect_url"):
@@ -235,13 +250,12 @@ def fulfillment(receiver):
if pay_status.get("paid"):
extra = pay_status["contract_terms"]["extra"]
- return flask.render_template(
- "templates/fulfillment.html",
- donation_receiver=extra["receiver"],
- donation_amount=extra["amount"],
- donation_donor=extra["donor"],
- order_id=order_id,
- currency=CURRENCY)
+ return flask.render_template("templates/fulfillment.html",
+ donation_receiver=extra["receiver"],
+ donation_amount=extra["amount"],
+ donation_donor=extra["donor"],
+ order_id=order_id,
+ currency=CURRENCY)
# no pay_redirect but article not paid, this should never happen!
err_abort(500, message="Internal error, invariant failed", json=pay_status)
diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py
index 4a44c97..7959ec2 100644
--- a/talerdonations/talerconfig.py
+++ b/talerdonations/talerconfig.py
@@ -38,17 +38,20 @@ try:
except ImportError:
pass
+
##
# Exception class for a any configuration error.
class ConfigurationError(Exception):
pass
+
##
# Exception class for malformed strings having with parameter
# expansion.
class ExpansionSyntaxError(Exception):
pass
+
##
# Do shell-style parameter expansion.
# Supported syntax:
@@ -80,7 +83,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
end += 1
if balance != 0:
raise ExpansionSyntaxError("unbalanced parentheses")
- piece = var[start+2:end-1]
+ piece = var[start + 2:end - 1]
if piece.find(":-") > 0:
varname, alt = piece.split(":-", 1)
replace = getter(varname)
@@ -93,9 +96,9 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
replace = var[start:end]
else:
end = start + 2
- while end < len(var) and var[start+1:end+1].isalnum():
+ while end < len(var) and var[start + 1:end + 1].isalnum():
end += 1
- varname = var[start+1:end]
+ varname = var[start + 1:end]
replace = getter(varname)
if replace is None:
replace = var[start:end]
@@ -104,6 +107,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
return result + var[pos:]
+
##
# A configuration entry.
class Entry:
@@ -164,11 +168,14 @@ class Entry:
if self.value is None:
if warn:
if default is not None:
- LOGGER.warning("Configuration is missing option '%s' in section '%s',\
- falling back to '%s'", self.option, self.section, default)
+ LOGGER.warning(
+ "Configuration is missing option '%s' in section '%s',\
+ falling back to '%s'", self.option,
+ self.section, default)
else:
- LOGGER.warning("Configuration ** is missing option '%s' in section '%s'",
- self.option.upper(), self.section.upper())
+ LOGGER.warning(
+ "Configuration ** is missing option '%s' in section '%s'",
+ self.option.upper(), self.section.upper())
return default
return self.value
@@ -190,6 +197,7 @@ class Entry:
except ValueError:
raise ConfigurationError("Expected number for option '%s' in section '%s'" \
% (self.option.upper(), self.section.upper()))
+
##
# Fetch value to substitute to expansion variables.
#
@@ -231,6 +239,7 @@ class Entry:
return ""
return "%s:%s" % (self.filename, self.lineno)
+
##
# Represent a section by inheriting from 'defaultdict'.
class OptionDict(collections.defaultdict):
@@ -280,6 +289,7 @@ class OptionDict(collections.defaultdict):
def __setitem__(self, chunk: str, value: Entry) -> None:
super().__setitem__(chunk.lower(), value)
+
##
# Collection of all the (@a OptionDict) sections.
class SectionDict(collections.defaultdict):
@@ -313,6 +323,7 @@ class SectionDict(collections.defaultdict):
def __setitem__(self, chunk: str, value: OptionDict) -> None:
super().__setitem__(chunk.lower(), value)
+
##
# One loaded taler configuration, including base configuration
# files and included files.
@@ -323,7 +334,7 @@ class TalerConfig:
#
# @param self the object itself.
def __init__(self) -> None:
- self.sections = SectionDict() # just plain dict
+ self.sections = SectionDict() # just plain dict
##
# Load a configuration file, instantiating a config object.
@@ -465,36 +476,49 @@ class TalerConfig:
if line.startswith("@INLINE@"):
pair = line.split()
if 2 != len(pair):
- LOGGER.error("invalid inlined config filename given ('%s')" % line)
- continue
+ LOGGER.error(
+ "invalid inlined config filename given ('%s')"
+ % line)
+ continue
if pair[1].startswith("/"):
self.load_file(pair[1])
else:
- self.load_file(os.path.join(os.path.dirname(filename), pair[1]))
+ self.load_file(
+ os.path.join(os.path.dirname(filename),
+ pair[1]))
continue
if line.startswith("["):
if not line.endswith("]"):
- LOGGER.error("invalid section header in line %s: %s",
- lineno, repr(line))
+ LOGGER.error(
+ "invalid section header in line %s: %s",
+ lineno, repr(line))
section_name = line.strip("[]").strip().strip('"')
current_section = section_name
continue
if current_section is None:
- LOGGER.error("option outside of section in line %s: %s", lineno, repr(line))
+ LOGGER.error(
+ "option outside of section in line %s: %s", lineno,
+ repr(line))
continue
pair = line.split("=", 1)
if len(pair) != 2:
- LOGGER.error("invalid option in line %s: %s", lineno, repr(line))
+ LOGGER.error("invalid option in line %s: %s", lineno,
+ repr(line))
key = pair[0].strip()
value = pair[1].strip()
if value.startswith('"'):
value = value[1:]
if not value.endswith('"'):
- LOGGER.error("mismatched quotes in line %s: %s", lineno, repr(line))
+ LOGGER.error("mismatched quotes in line %s: %s",
+ lineno, repr(line))
else:
value = value[:-1]
- entry = Entry(self.sections, current_section, key,
- value=value, filename=filename, lineno=lineno)
+ entry = Entry(self.sections,
+ current_section,
+ key,
+ value=value,
+ filename=filename,
+ lineno=lineno)
sections[current_section][key] = entry
except FileNotFoundError:
# not logging here, as this interests the final user mostly.
@@ -503,23 +527,22 @@ class TalerConfig:
##
# Dump the textual representation of a config object.
- #
+ #
# Format:
- #
+ #
# [section]
# option = value # FIXME (what is location?)
#
# @param self the object itself, that will be dumped.
def dump(self) -> None:
for kv_section in self.sections.items():
- print("[%s]" % (kv_section[1].section_name,))
+ print("[%s]" % (kv_section[1].section_name, ))
for kv_option in kv_section[1].items():
print("%s = %s # %s" % \
(kv_option[1].option,
kv_option[1].value,
kv_option[1].location()))
-
##
# Return a whole section from this object.
#
@@ -538,14 +561,26 @@ if __name__ == "__main__":
import argparse
PARSER = argparse.ArgumentParser()
- PARSER.add_argument("--section", "-s", dest="section",
- default=None, metavar="SECTION")
- PARSER.add_argument("--option", "-o", dest="option",
- default=None, metavar="OPTION")
- PARSER.add_argument("--config", "-c", dest="config",
- default=None, metavar="FILE")
- PARSER.add_argument("--filename", "-f", dest="expand_filename",
- default=False, action='store_true')
+ PARSER.add_argument("--section",
+ "-s",
+ dest="section",
+ default=None,
+ metavar="SECTION")
+ PARSER.add_argument("--option",
+ "-o",
+ dest="option",
+ default=None,
+ metavar="OPTION")
+ PARSER.add_argument("--config",
+ "-c",
+ dest="config",
+ default=None,
+ metavar="FILE")
+ PARSER.add_argument("--filename",
+ "-f",
+ dest="expand_filename",
+ default=False,
+ action='store_true')
ARGS = PARSER.parse_args()
TC = TalerConfig.from_file(ARGS.config)
diff --git a/talerdonations/tests.py b/talerdonations/tests.py
index c9918c2..2e95b60 100644
--- a/talerdonations/tests.py
+++ b/talerdonations/tests.py
@@ -27,6 +27,7 @@ from talerdonations.talerconfig import TalerConfig
TC = TalerConfig.from_env()
CURRENCY = TC["taler"]["currency"].value_string(required=True)
+
##
# Main class that gathers all the tests.
class DonationsTestCase(unittest.TestCase):
--
cgit v1.2.3
From 9c282aa69a4d25f186e591a075b0f2830b5ec45a Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:02:31 +0200
Subject: make pretty
---
setup.py | 51 +++++++++--------
talerdonations/donations/donations.py | 100 ++++++++++++++++++++--------------
talerdonations/talerconfig.py | 95 ++++++++++++++++++--------------
3 files changed, 136 insertions(+), 110 deletions(-)
diff --git a/setup.py b/setup.py
index 71526a9..906567c 100755
--- a/setup.py
+++ b/setup.py
@@ -1,28 +1,27 @@
from setuptools import setup, find_packages
-setup(name='talerdonations',
- version='0.6.0pre1',
- description='Example donations site for GNU Taler',
- url='git://taler.net/donations',
- author=['Marcello Stanisci', 'Florian Dold'],
- author_email=['stanisci.m@gmail.com', 'dold@taler.net'],
- license='GPL',
- packages=find_packages(),
- install_requires=["Flask>=0.10",
- "requests",
- "uwsgi",
- "jsmin"],
- tests_require=["mock", "nose"],
- test_suite="nose.collector",
- package_data={
- '':[
- "donations/templates/*.html",
- "donations/static/*.svg",
- "donations/static/*.css",
- "donations/static/web-common/*.png",
- "donations/static/web-common/*.css",
- "donations/static/web-common/*.html",
- ]
- },
- scripts=['./bin/taler-merchant-donations'],
- zip_safe=False)
+setup(
+ name='talerdonations',
+ version='0.6.0pre1',
+ description='Example donations site for GNU Taler',
+ url='git://taler.net/donations',
+ author=['Marcello Stanisci', 'Florian Dold'],
+ author_email=['stanisci.m@gmail.com', 'dold@taler.net'],
+ license='GPL',
+ packages=find_packages(),
+ install_requires=["Flask>=0.10", "requests", "uwsgi", "jsmin"],
+ tests_require=["mock", "nose"],
+ test_suite="nose.collector",
+ package_data={
+ '': [
+ "donations/templates/*.html",
+ "donations/static/*.svg",
+ "donations/static/*.css",
+ "donations/static/web-common/*.png",
+ "donations/static/web-common/*.css",
+ "donations/static/web-common/*.html",
+ ]
+ },
+ scripts=['./bin/taler-merchant-donations'],
+ zip_safe=False
+)
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index 5655734..220fbb7 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -77,9 +77,9 @@ def err_abort(abort_status_code, **params):
def backend_get(endpoint, params):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.get(urljoin(BACKEND_URL, endpoint),
- params=params,
- headers=headers)
+ resp = requests.get(
+ urljoin(BACKEND_URL, endpoint), params=params, headers=headers
+ )
except requests.ConnectionError:
err_abort(500, message="Could not establish connection to backend")
try:
@@ -87,10 +87,12 @@ def backend_get(endpoint, params):
except ValueError:
err_abort(500, message="Could not parse response from backend")
if resp.status_code != 200:
- err_abort(500,
- message="Backend returned error status",
- json=response_json,
- status_code=resp.status_code)
+ err_abort(
+ 500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code
+ )
return response_json
@@ -105,22 +107,26 @@ def backend_get(endpoint, params):
def backend_post(endpoint, json):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.post(urljoin(BACKEND_URL, endpoint),
- json=json,
- headers=headers)
+ resp = requests.post(
+ urljoin(BACKEND_URL, endpoint), json=json, headers=headers
+ )
except requests.ConnectionError:
err_abort(500, message="Could not establish connection to backend")
try:
response_json = resp.json()
except ValueError:
- err_abort(500,
- message="Could not parse response from backend",
- status_code=resp.status_code)
+ err_abort(
+ 500,
+ message="Could not parse response from backend",
+ status_code=resp.status_code
+ )
if resp.status_code != 200:
- err_abort(500,
- message="Backend returned error status",
- json=response_json,
- status_code=resp.status_code)
+ err_abort(
+ 500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code
+ )
return response_json
@@ -144,9 +150,11 @@ def expect_parameter(name):
# (and execution stack!).
@app.errorhandler(Exception)
def internal_error(e):
- return flask.render_template("templates/error.html",
- message="Internal error",
- stack=traceback.format_exc())
+ return flask.render_template(
+ "templates/error.html",
+ message="Internal error",
+ stack=traceback.format_exc()
+ )
##
@@ -155,8 +163,9 @@ def internal_error(e):
# @return response object of the index page.
@app.route("/")
def index():
- return flask.render_template("templates/index.html",
- merchant_currency=CURRENCY)
+ return flask.render_template(
+ "templates/index.html", merchant_currency=CURRENCY
+ )
##
@@ -179,11 +188,13 @@ def checkout():
amount = expect_parameter("donation_amount")
donation_receiver = expect_parameter("donation_receiver")
donation_donor = expect_parameter("donation_donor")
- return flask.render_template("templates/checkout.html",
- donation_amount=amount,
- donation_receiver=donation_receiver,
- donation_donor=donation_donor,
- merchant_currency=CURRENCY)
+ return flask.render_template(
+ "templates/checkout.html",
+ donation_amount=amount,
+ donation_receiver=donation_receiver,
+ donation_donor=donation_donor,
+ merchant_currency=CURRENCY
+ )
##
@@ -211,14 +222,16 @@ def donate():
payment_system = expect_parameter("payment_system")
if payment_system != "taler":
return flask.redirect(flask.url_for("provider_not_supported"))
- fulfillment_url = flask.url_for("fulfillment",
- receiver=donation_receiver,
- _external=True)
+ fulfillment_url = flask.url_for(
+ "fulfillment", receiver=donation_receiver, _external=True
+ )
order = dict(
amount=donation_amount,
- extra=dict(donor=donation_donor,
- receiver=donation_receiver,
- amount=donation_amount),
+ extra=dict(
+ donor=donation_donor,
+ receiver=donation_receiver,
+ amount=donation_amount
+ ),
fulfillment_url=fulfillment_url,
instance=donation_receiver,
summary="Donation to {}".format(donation_receiver),
@@ -226,9 +239,10 @@ def donate():
order_resp = backend_post("order", dict(order=order))
order_id = order_resp["order_id"]
return flask.redirect(
- flask.url_for("fulfillment",
- receiver=donation_receiver,
- order_id=order_id))
+ flask.url_for(
+ "fulfillment", receiver=donation_receiver, order_id=order_id
+ )
+ )
##
@@ -250,12 +264,14 @@ def fulfillment(receiver):
if pay_status.get("paid"):
extra = pay_status["contract_terms"]["extra"]
- return flask.render_template("templates/fulfillment.html",
- donation_receiver=extra["receiver"],
- donation_amount=extra["amount"],
- donation_donor=extra["donor"],
- order_id=order_id,
- currency=CURRENCY)
+ return flask.render_template(
+ "templates/fulfillment.html",
+ donation_receiver=extra["receiver"],
+ donation_amount=extra["amount"],
+ donation_donor=extra["donor"],
+ order_id=order_id,
+ currency=CURRENCY
+ )
# no pay_redirect but article not paid, this should never happen!
err_abort(500, message="Internal error, invariant failed", json=pay_status)
diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py
index 7959ec2..1a33294 100644
--- a/talerdonations/talerconfig.py
+++ b/talerdonations/talerconfig.py
@@ -171,11 +171,13 @@ class Entry:
LOGGER.warning(
"Configuration is missing option '%s' in section '%s',\
falling back to '%s'", self.option,
- self.section, default)
+ self.section, default
+ )
else:
LOGGER.warning(
"Configuration ** is missing option '%s' in section '%s'",
- self.option.upper(), self.section.upper())
+ self.option.upper(), self.section.upper()
+ )
return default
return self.value
@@ -373,7 +375,8 @@ class TalerConfig:
# a error occurs).
def value_string(self, section, option, **kwargs) -> str:
return self.sections[section][option].value_string(
- kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
+ kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")
+ )
##
# Get a value from the config that should be a filename.
@@ -388,7 +391,8 @@ class TalerConfig:
# a error occurs).
def value_filename(self, section, option, **kwargs) -> str:
return self.sections[section][option].value_filename(
- kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
+ kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")
+ )
##
# Get a integer value from the config.
@@ -402,7 +406,8 @@ class TalerConfig:
# a error occurs).
def value_int(self, section, option, **kwargs) -> int:
return self.sections[section][option].value_int(
- kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
+ kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")
+ )
##
# Load default values from canonical locations.
@@ -477,48 +482,58 @@ class TalerConfig:
pair = line.split()
if 2 != len(pair):
LOGGER.error(
- "invalid inlined config filename given ('%s')"
- % line)
+ "invalid inlined config filename given ('%s')" %
+ line
+ )
continue
if pair[1].startswith("/"):
self.load_file(pair[1])
else:
self.load_file(
- os.path.join(os.path.dirname(filename),
- pair[1]))
+ os.path.join(
+ os.path.dirname(filename), pair[1]
+ )
+ )
continue
if line.startswith("["):
if not line.endswith("]"):
LOGGER.error(
- "invalid section header in line %s: %s",
- lineno, repr(line))
+ "invalid section header in line %s: %s", lineno,
+ repr(line)
+ )
section_name = line.strip("[]").strip().strip('"')
current_section = section_name
continue
if current_section is None:
LOGGER.error(
"option outside of section in line %s: %s", lineno,
- repr(line))
+ repr(line)
+ )
continue
pair = line.split("=", 1)
if len(pair) != 2:
- LOGGER.error("invalid option in line %s: %s", lineno,
- repr(line))
+ LOGGER.error(
+ "invalid option in line %s: %s", lineno, repr(line)
+ )
key = pair[0].strip()
value = pair[1].strip()
if value.startswith('"'):
value = value[1:]
if not value.endswith('"'):
- LOGGER.error("mismatched quotes in line %s: %s",
- lineno, repr(line))
+ LOGGER.error(
+ "mismatched quotes in line %s: %s", lineno,
+ repr(line)
+ )
else:
value = value[:-1]
- entry = Entry(self.sections,
- current_section,
- key,
- value=value,
- filename=filename,
- lineno=lineno)
+ entry = Entry(
+ self.sections,
+ current_section,
+ key,
+ value=value,
+ filename=filename,
+ lineno=lineno
+ )
sections[current_section][key] = entry
except FileNotFoundError:
# not logging here, as this interests the final user mostly.
@@ -561,26 +576,22 @@ if __name__ == "__main__":
import argparse
PARSER = argparse.ArgumentParser()
- PARSER.add_argument("--section",
- "-s",
- dest="section",
- default=None,
- metavar="SECTION")
- PARSER.add_argument("--option",
- "-o",
- dest="option",
- default=None,
- metavar="OPTION")
- PARSER.add_argument("--config",
- "-c",
- dest="config",
- default=None,
- metavar="FILE")
- PARSER.add_argument("--filename",
- "-f",
- dest="expand_filename",
- default=False,
- action='store_true')
+ PARSER.add_argument(
+ "--section", "-s", dest="section", default=None, metavar="SECTION"
+ )
+ PARSER.add_argument(
+ "--option", "-o", dest="option", default=None, metavar="OPTION"
+ )
+ PARSER.add_argument(
+ "--config", "-c", dest="config", default=None, metavar="FILE"
+ )
+ PARSER.add_argument(
+ "--filename",
+ "-f",
+ dest="expand_filename",
+ default=False,
+ action='store_true'
+ )
ARGS = PARSER.parse_args()
TC = TalerConfig.from_file(ARGS.config)
--
cgit v1.2.3
From e7c20a11fac21ab485b17feec81d0887be4cf5eb Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:09:02 +0200
Subject: url-based payments
---
talerdonations/donations/donations.py | 26 +++++++-
.../donations/templates/request_payment.html | 69 ++++++++++++++++++++++
2 files changed, 94 insertions(+), 1 deletion(-)
create mode 100644 talerdonations/donations/templates/request_payment.html
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index 220fbb7..06c6617 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -245,6 +245,16 @@ def donate():
)
+##
+# This endpoint is used by the payment request page
+# to check if the payment has been completed via the QR code.
+@app.route("/check-status/")
+def check_status(order_id, session_id):
+ pay_params = dict( instance=INSTANCE, order_id=order_id)
+ pay_status = backend_get("check-payment", pay_params)
+ return flask.jsonify(paid=pay_status["paid"])
+
+
##
# Serve the fulfillment page.
#
@@ -260,7 +270,21 @@ def fulfillment(receiver):
pay_status = backend_get("check-payment", pay_params)
if pay_status.get("payment_redirect_url"):
- return flask.redirect(pay_status["payment_redirect_url"])
+ taler_pay_uri = pay_status["taler_pay_uri"]
+ qrcode_svg = get_qrcode_svg(taler_pay_uri)
+ check_status_url_enc = urllib.parse.quote(
+ flask.url_for("check_status", order_id=order_id)
+ )
+ content = flask.render_template(
+ "templates/request_payment.html",
+ article_name=article_name,
+ taler_pay_uri=taler_pay_uri,
+ qrcode_svg=qrcode_svg,
+ check_status_url_enc=check_status_url_enc
+ )
+ headers = {"Taler": taler_pay_uri}
+ resp = flask.Response(content, status=402, headers=headers)
+ return resp
if pay_status.get("paid"):
extra = pay_status["contract_terms"]["extra"]
diff --git a/talerdonations/donations/templates/request_payment.html b/talerdonations/donations/templates/request_payment.html
new file mode 100644
index 0000000..6e050d0
--- /dev/null
+++ b/talerdonations/donations/templates/request_payment.html
@@ -0,0 +1,69 @@
+{% extends "templates/base.html" %}
+
+
+{% block meta %}
+
+{% endblock meta %}
+
+
+{% block scripts %}
+
+{% endblock scripts %}
+
+
+{% block main %}
+
+Payment Required
+
+
+
+ Looks like your browser doesn't support GNU Taler payments. You can try
+ installing a wallet browser extension.
+
+
+
+
+
+
+ You can use this QR code to pay with your mobile wallet:
+
+
+ {{ qrcode_svg | safe }}
+
+
+ Click this link to open your system's Taler wallet if it exists.
+
+
+
+
+{% endblock main %}
--
cgit v1.2.3
From e50d7d0a57dced455f93b0f462e48065a1f0b764 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:10:24 +0200
Subject: add missing files
---
.gitignore | 10 ----
Makefile | 40 +++++++++++++++
bin/taler-merchant-donations | 116 +++++++++++++++++++++++++++++++++++++++++++
configure | 87 ++++++++++++++++++++++++++++++++
4 files changed, 243 insertions(+), 10 deletions(-)
create mode 100644 Makefile
create mode 100644 bin/taler-merchant-donations
create mode 100755 configure
diff --git a/.gitignore b/.gitignore
index a0630f3..17e4b20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,6 @@
doxygen-doc/
.eggs/
-Makefile
-aclocal.m4
-autom4te.cache/
compile
-config.log
-config.status
-configure
-frontend-donations.wsgi
-install-sh
-missing
-taler-merchant-donations
talerdonations.egg-info/
talerdonations/__pycache__/
talerdonations/donations/__pycache__/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1d98268
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,40 @@
+install_global=false
+-include config.mk
+
+.PHONY: all
+all:
+ @echo "This is a python project, no compilation required"
+
+.PHONY: install
+
+ifeq ($(install_global), true)
+install: install-global
+else
+install: install-local
+endif
+
+.PHONY: install-global
+install-global:
+ pip3 install .
+
+.PHONY: install-local
+install-local:
+ pip3 install . --user
+
+# run testcases
+.PHONY: check
+check:
+ @export TALER_CONFIG_FILE=talerblog/tests.conf; \
+ python3 setup.py test
+
+.PHONY: clean
+clean:
+ @echo nothing to do
+
+.PHONY: dist
+dist:
+ git archive --format=tar.gz HEAD -o taler-merchant-donations.tar.gz
+
+.PHONY: pretty
+pretty:
+ yapf -r -i talerdonations/
diff --git a/bin/taler-merchant-donations b/bin/taler-merchant-donations
new file mode 100644
index 0000000..0bda611
--- /dev/null
+++ b/bin/taler-merchant-donations
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+
+##
+# This file is part of TALER
+# (C) 2017 INRIA
+#
+# TALER is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Affero General Public
+# License as published by the Free Software Foundation; either
+# version 3, or (at your option) any later version.
+#
+# TALER is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with TALER; see the file COPYING. If not,
+# see
+#
+# @author Florian Dold
+# @file Standalone script to run the donations site.
+
+import argparse
+import sys
+import os
+import site
+import logging
+from talerdonations.talerconfig import TalerConfig
+
+# No perfect match to our logging format, but good enough ...
+UWSGI_LOGFMT = "%(ltime) %(proto) %(method) %(uri) %(proto) => %(status)"
+
+
+##
+# This function interprets the 'serve-http' subcommand.
+# The effect it to launch the donations HTTP service.
+#
+# @param args command line options.
+def handle_serve_http(args):
+ port = args.port
+ if port is None:
+ port = TC["donations"]["http_port"].value_int(required=True)
+ spec = ":%d" % (port, )
+ os.execlp(
+ "uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format",
+ UWSGI_LOGFMT, "--http", spec, "--module", "talerdonations"
+ )
+
+
+##
+# This function interprets the 'serve-uwsgi' subcommand.
+# The effect is to launch the donations UWSGI service. This
+# type of service is usually used when the HTTP donations interface
+# is accessed via a reverse proxy (like Nginx, for example).
+#
+# @param command line options.
+def handle_serve_uwsgi(args):
+ del args # pacify PEP checkers
+ serve_uwsgi = TC["donations"]["uwsgi_serve"].value_string(required=True
+ ).lower()
+ params = [
+ "uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format",
+ UWSGI_LOGFMT, "--module", "talerdonations"
+ ]
+ if serve_uwsgi == "tcp":
+ port = TC["donations"]["uwsgi_port"].value_int(required=True)
+ spec = ":%d" % (port, )
+ params.extend(["--socket", spec])
+ elif serve_uwsgi == "unix":
+ spec = TC["donations"]["uwsgi_unixpath"].value_filename(required=True)
+ mode = TC["donations"]["uwsgi_unixpath_mode"].value_filename(
+ required=True
+ )
+ params.extend(["--socket", spec])
+ params.extend(["--chmod-socket=" + mode])
+ os.makedirs(os.path.dirname(spec), exist_ok=True)
+ logging.info("launching uwsgi with argv %s", params[1:])
+ os.execlp(*params)
+
+
+## @cond
+PARSER = argparse.ArgumentParser()
+PARSER.set_defaults(func=None)
+PARSER.add_argument(
+ '--config',
+ '-c',
+ help="configuration file to use",
+ metavar="CONFIG",
+ type=str,
+ dest="config",
+ default=None
+)
+SUB = PARSER.add_subparsers()
+
+P = SUB.add_parser('serve-http', help="Serve over HTTP")
+P.add_argument(
+ "--port", "-p", dest="port", type=int, default=None, metavar="PORT"
+)
+P.set_defaults(func=handle_serve_http)
+
+P = SUB.add_parser('serve-uwsgi', help="Serve over UWSGI")
+P.set_defaults(func=handle_serve_uwsgi)
+
+ARGS = PARSER.parse_args()
+## @endcond
+
+if getattr(ARGS, 'func', None) is None:
+ PARSER.print_help()
+ sys.exit(1)
+
+if ARGS.config is not None:
+ os.environ["TALER_CONFIG_FILE"] = ARGS.config
+
+TC = TalerConfig.from_file(os.environ.get("TALER_CONFIG_FILE"))
+ARGS.func(ARGS)
diff --git a/configure b/configure
new file mode 100755
index 0000000..469bad7
--- /dev/null
+++ b/configure
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+
+set -eu
+
+usage() {
+ echo "Usage: ./configure [OPTION]"
+ echo
+ echo "Configuration:"
+ echo " -h, --help display this help and exit"
+ echo
+ echo "Installation directories:"
+ echo " --destination=[local|global] install Python package locally or globally"
+}
+
+
+# -allow a command to fail with !’s side effect on errexit
+# -use return value from ${PIPESTATUS[0]}, because ! hosed $?
+! getopt --test > /dev/null
+if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
+ echo 'getopt not available'
+ exit 1
+fi
+
+LONGOPTS=destination:,help
+OPTIONS=h
+
+! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
+if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
+ # e.g. return value is 1
+ # then getopt has complained about wrong arguments to stdout
+ exit 2
+fi
+
+# read getopt’s output this way to handle the quoting right:
+eval set -- "$PARSED"
+
+destination="local"
+
+while true; do
+ case "$1" in
+ --destination)
+ destination="$2"
+ shift 2
+ ;;
+ -h|--help)
+ usage
+ exit 1
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ echo "Programming error"
+ exit 3
+ ;;
+ esac
+done
+
+case "$destination" in
+ local)
+ install_global=false
+ ;;
+ global)
+ install_global=true
+ ;;
+ *)
+ echo "Destination (--destination) must be 'local' or 'global', paths are not allowed."
+ exit 3
+ ;;
+esac
+
+cat << EOF > config.mk
+# this file is autogenerated by ./configure
+install_global=$install_global
+EOF
+
+
+if ! python3 --version &>/dev/null; then
+ echo 'Error: python3 missing'
+ exit 1
+fi
+
+if ! pip3 --version &>/dev/null; then
+ echo 'Error: pip3 missing'
+ exit 1
+fi
--
cgit v1.2.3
From 31a05eaab426a6121a93945f1f2e08a686987560 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:10:43 +0200
Subject: make pretty
---
talerdonations/donations/donations.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index 06c6617..886705f 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -250,7 +250,7 @@ def donate():
# to check if the payment has been completed via the QR code.
@app.route("/check-status/")
def check_status(order_id, session_id):
- pay_params = dict( instance=INSTANCE, order_id=order_id)
+ pay_params = dict(instance=INSTANCE, order_id=order_id)
pay_status = backend_get("check-payment", pay_params)
return flask.jsonify(paid=pay_status["paid"])
--
cgit v1.2.3
From c75c8b0dc295a7278b5c6ba26cea9bbdb771789c Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:11:55 +0200
Subject: no more wallet detection
---
talerdonations/donations/templates/index.html | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/talerdonations/donations/templates/index.html b/talerdonations/donations/templates/index.html
index fc956e5..68a0cb2 100644
--- a/talerdonations/donations/templates/index.html
+++ b/talerdonations/donations/templates/index.html
@@ -7,22 +7,7 @@
You are paying with an imaginary currency ({{ merchant_currency }}).
-
-
Installing the Taler wallet
- First, you need to install the Taler wallet browser extension.
- Install the wallet
-
(done)
-
- Wallets for other browsers will be provided in the near future.
-
-
-
+
Please select a project, the amount (*) of {{ merchant_currency }} you
wish to donate, and enter the name that will appear on your receipt:
--
cgit v1.2.3
From 06bf80ca7326e9e1c72b27cb4734f9eefc20f68e Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:13:16 +0200
Subject: no more redirect URL
---
talerdonations/donations/donations.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index 886705f..d4dd36d 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -269,7 +269,18 @@ def fulfillment(receiver):
pay_params = dict(instance=receiver, order_id=order_id)
pay_status = backend_get("check-payment", pay_params)
- if pay_status.get("payment_redirect_url"):
+
+ if pay_status.get("paid"):
+ extra = pay_status["contract_terms"]["extra"]
+ return flask.render_template(
+ "templates/fulfillment.html",
+ donation_receiver=extra["receiver"],
+ donation_amount=extra["amount"],
+ donation_donor=extra["donor"],
+ order_id=order_id,
+ currency=CURRENCY
+ )
+ else:
taler_pay_uri = pay_status["taler_pay_uri"]
qrcode_svg = get_qrcode_svg(taler_pay_uri)
check_status_url_enc = urllib.parse.quote(
@@ -286,16 +297,5 @@ def fulfillment(receiver):
resp = flask.Response(content, status=402, headers=headers)
return resp
- if pay_status.get("paid"):
- extra = pay_status["contract_terms"]["extra"]
- return flask.render_template(
- "templates/fulfillment.html",
- donation_receiver=extra["receiver"],
- donation_amount=extra["amount"],
- donation_donor=extra["donor"],
- order_id=order_id,
- currency=CURRENCY
- )
-
# no pay_redirect but article not paid, this should never happen!
err_abort(500, message="Internal error, invariant failed", json=pay_status)
--
cgit v1.2.3
From 8ef2843d05d57c07115dba494cc913efc3f19014 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:15:09 +0200
Subject: qrcode
---
setup.py | 2 +-
talerdonations/donations/donations.py | 9 +++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 906567c..042635f 100755
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,7 @@ setup(
author_email=['stanisci.m@gmail.com', 'dold@taler.net'],
license='GPL',
packages=find_packages(),
- install_requires=["Flask>=0.10", "requests", "uwsgi", "jsmin"],
+ install_requires=["Flask>=0.10", "requests", "uwsgi", "jsmin", "qrcode", "lxml"],
tests_require=["mock", "nose"],
test_suite="nose.collector",
package_data={
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index d4dd36d..c00844b 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -26,6 +26,9 @@ import random
import requests
import flask
import traceback
+import qrcode
+import qrcode.image.svg
+import lxml.etree
from ..talerconfig import TalerConfig
LOGGER = logging.getLogger(__name__)
@@ -255,6 +258,12 @@ def check_status(order_id, session_id):
return flask.jsonify(paid=pay_status["paid"])
+def get_qrcode_svg(data):
+ factory = qrcode.image.svg.SvgImage
+ img = qrcode.make(data, image_factory=factory)
+ return lxml.etree.tostring(img.get_image()).decode("utf-8")
+
+
##
# Serve the fulfillment page.
#
--
cgit v1.2.3
From cdd70817d77265a897e4efb1fed22e66e2c99ce9 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:15:58 +0200
Subject: urllib
---
talerdonations/donations/donations.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index c00844b..21eb76a 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -26,6 +26,7 @@ import random
import requests
import flask
import traceback
+import urllib
import qrcode
import qrcode.image.svg
import lxml.etree
--
cgit v1.2.3
From b38365fa582a52592d00f36e8dee2ee9bfca9ee6 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Thu, 29 Aug 2019 19:16:45 +0200
Subject: I want static typing
---
talerdonations/donations/donations.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index 21eb76a..d85c9a9 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -298,7 +298,6 @@ def fulfillment(receiver):
)
content = flask.render_template(
"templates/request_payment.html",
- article_name=article_name,
taler_pay_uri=taler_pay_uri,
qrcode_svg=qrcode_svg,
check_status_url_enc=check_status_url_enc
--
cgit v1.2.3
From d61ff48aa5d4c0c5642e885eadc8e3fcf1e06366 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Sat, 31 Aug 2019 16:19:02 +0200
Subject: fix test case invocation
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1d98268..6622526 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ install-local:
# run testcases
.PHONY: check
check:
- @export TALER_CONFIG_FILE=talerblog/tests.conf; \
+ @export TALER_CONFIG_FILE=talerdonations/tests.conf; \
python3 setup.py test
.PHONY: clean
--
cgit v1.2.3
From 38acb9f039fb01a7bc0aef8b93a277e919899ae9 Mon Sep 17 00:00:00 2001
From: Florian Dold
Date: Sat, 31 Aug 2019 16:59:04 +0200
Subject: use correct WSGI module
---
bin/taler-merchant-donations | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bin/taler-merchant-donations b/bin/taler-merchant-donations
index 0bda611..ccf6a4e 100644
--- a/bin/taler-merchant-donations
+++ b/bin/taler-merchant-donations
@@ -44,7 +44,7 @@ def handle_serve_http(args):
spec = ":%d" % (port, )
os.execlp(
"uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format",
- UWSGI_LOGFMT, "--http", spec, "--module", "talerdonations"
+ UWSGI_LOGFMT, "--http", spec, "--module", "talerdonations.donations:app"
)
@@ -61,7 +61,7 @@ def handle_serve_uwsgi(args):
).lower()
params = [
"uwsgi", "uwsgi", "--master", "--die-on-term", "--log-format",
- UWSGI_LOGFMT, "--module", "talerdonations"
+ UWSGI_LOGFMT, "--module", "talerdonations.donations:app"
]
if serve_uwsgi == "tcp":
port = TC["donations"]["uwsgi_port"].value_int(required=True)
--
cgit v1.2.3