diff --git a/README.rst b/README.rst index a1fc552651b3a02bf210c6075e58edccd0e26427..255e3d3d6fd99a880824f2119788837a806b5e64 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ All these steps of the PAD system are given as configuration files. In this base class implementation, only a core functionality is implemented. The specialized algorithms should be provided by other packages, which are usually in the ``bob.pad`` namespace, such as: -* `bob.pad.speech for speech-related PAD algorithms +* `bob.pad.voice for speech-related PAD algorithms Installation diff --git a/bob/pad/base/database/database.py b/bob/pad/base/database/database.py index f316f3b5369e17eb174b3b9ae56cb312bea04e56..fa7440466b98cd988a461fb422e2858dbb7909f7 100644 --- a/bob/pad/base/database/database.py +++ b/bob/pad/base/database/database.py @@ -7,9 +7,39 @@ import abc import bob.bio.base.database +import bob.pad.base.database class PadDatabase(bob.bio.base.database.BioDatabase): + """This class represents the basic API for database access. + Please use this class as a base class for your database access classes. + Do not forget to call the constructor of this base class in your derived class. + + **Parameters:** + + name : str + A unique name for the database. + + all_files_options : dict + Dictionary of options passed to the second-level database query when retrieving all data. + + check_original_files_for_existence : bool + Enables to test for the original data files when querying the database. + + original_directory : str + The directory where the original data of the database are stored. + + original_extension : str + The file name extension of the original data. + + protocol : str or ``None`` + The name of the protocol that defines the default experimental setup for this database. + + kwargs : ``key=value`` pairs + The arguments of the :py:class:`bob.bio.base.database.BioDatabase` base class constructor. + + """ + def __init__( self, name, @@ -20,34 +50,6 @@ class PadDatabase(bob.bio.base.database.BioDatabase): protocol='Default', **kwargs # The rest of the default parameters of the base class ): - """This class represents the basic API for database access. - Please use this class as a base class for your database access classes. - Do not forget to call the constructor of this base class in your derived class. - - **Parameters:** - - name : str - A unique name for the database. - - all_files_options : dict - Dictionary of options passed to the second-level database query when retrieving all data. - - check_original_files_for_existence : bool - Enables to test for the original data files when querying the database. - - original_directory : str - The directory where the original data of the database are stored. - - original_extension : str - The file name extension of the original data. - - protocol : str or ``None`` - The name of the protocol that defines the default experimental setup for this database. - - kwargs : ``key=value`` pairs - The arguments of the :py:class:`bob.bio.base.BioDatabase` base class constructor. - - """ super(PadDatabase, self).__init__(name=name, all_files_options=all_files_options, check_original_files_for_existence=check_original_files_for_existence, original_directory=original_directory, original_extension=original_extension, protocol=protocol, **kwargs) def original_file_names(self, files): @@ -57,7 +59,7 @@ class PadDatabase(bob.bio.base.database.BioDatabase): **Parameters:** - files : [[:py:class:`bob.pad.db.PadFile`], [:py:class:`bob.pad.db.PadFile`] + files : [[:py:class:`bob.pad.base.database.PadFile`], [:py:class:`bob.pad.base.database.PadFile`] The list of lists ([real, attack]) of file object to retrieve the original data file names for. **Returns:** @@ -130,7 +132,7 @@ class PadDatabase(bob.bio.base.database.BioDatabase): **Returns:** - files : [:py:class:`File`] + files : [:py:class:`bob.pad.base.database.PadFile`] The sorted and unique list of all files of the database. """ realset = self.sort(self.objects(protocol=self.protocol, groups=groups, purposes='real', **self.all_files_options)) @@ -148,7 +150,7 @@ class PadDatabase(bob.bio.base.database.BioDatabase): **Returns:** - files : [:py:class:`File`] or [[:py:class:`File`]] + files : [:py:class:`bob.pad.base.database.PadFile`] or [[:py:class:`bob.pad.base.database.PadFile`]] The (arranged) list of files used for the training. """ diff --git a/doc/conf.py b/doc/conf.py index 23e7702a88dc0560b167f0aab3da608a2cfefbc0..b7a67575e217ec78ac0f4436deac2d8c0192d708 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,46 +1,67 @@ #!/usr/bin/env python # vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Mon 13 Aug 2012 12:38:15 CEST -# -# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland import os import sys import glob import pkg_resources -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.3' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.pngmath', - 'sphinx.ext.ifconfig', - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - ] + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.ifconfig', + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.doctest', + 'sphinx.ext.graphviz', + 'sphinx.ext.intersphinx', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', + ] -# The viewcode extension appeared only on Sphinx >= 1.0.0 import sphinx -if sphinx.__version__ >= "1.0": - extensions.append('sphinx.ext.viewcode') +if sphinx.__version__ >= "1.4.1": + extensions.append('sphinx.ext.imgmath') + imgmath_image_format = 'svg' +else: + extensions.append('sphinx.ext.pngmath') + +# Be picky about warnings +nitpicky = True + +# Ignores stuff we can't easily resolve on other project's sphinx manuals +nitpick_ignore = [] + +# Allows the user to override warnings from a separate file +if os.path.exists('nitpick-exceptions.txt'): + for line in open('nitpick-exceptions.txt'): + if line.strip() == "" or line.startswith("#"): + continue + dtype, target = line.split(None, 1) + target = target.strip() + try: # python 2.x + target = unicode(target) + except NameError: + pass + nitpick_ignore.append((dtype, target)) # Always includes todos todo_include_todos = True +# Generates auto-summary automatically +autosummary_generate = True + +# Create numbers on figures with captions +numfig = True + # If we are on OSX, the 'dvipng' path maybe different dvipng_osx = '/opt/local/libexec/texlive/binaries/dvipng' if os.path.exists(dvipng_osx): pngmath_dvipng = dvipng_osx @@ -58,12 +79,12 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'Bobs interface for running biometric recognition experiments' +project = u'bob.pad.base' import time copyright = u'%s, Idiap Research Institute' % time.strftime('%Y') # Grab the setup entry -distribution = pkg_resources.require('bob.pad.base')[0] +distribution = pkg_resources.require(project)[0] # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -108,13 +129,18 @@ pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] +# Some variables which are useful for generated material +project_variable = project.replace('.', '_') +short_description = u'Bob framework for running presentation attack detection experiments' +owner = [u'Idiap Research Institute'] + # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -if sphinx.__version__ >= "1.0": - html_theme = 'nature' +import sphinx_rtd_theme +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -122,14 +148,14 @@ if sphinx.__version__ >= "1.0": #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. If None, it defaults to # "<project> v<release> documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = 'bob' +#html_short_title = project_variable # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -187,105 +213,53 @@ html_favicon = 'img/favicon.ico' #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'bob_spoof_base_doc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -latex_paper_size = 'a4' - -# The font size ('10pt', '11pt' or '12pt'). -latex_font_size = '10pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'bob_spoof_base.tex', u'Bob', - u'Biometrics Group, Idiap Research Institute', 'manual'), -] +htmlhelp_basename = project_variable + u'_doc' -# The name of an image file (relative to this directory) to place at the top of -# the title page. -latex_logo = '' -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Additional stuff for the LaTeX preamble. -#latex_preamble = '' - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True +# -- Post configuration -------------------------------------------------------- # Included after all input documents -rst_epilog = '' - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'bob.pad.base', u'Base tools to run presentation attack detection experiments', [u'Idiap Research Institute'], 1) -] +rst_epilog = """ +.. |project| replace:: Bob +.. |version| replace:: %s +.. |current-year| date:: %%Y +""" % (version,) # Default processing flags for sphinx -autoclass_content = 'both' +autoclass_content = 'class' autodoc_member_order = 'bysource' -autodoc_default_flags = ['members', 'inherited-members', 'show-inheritance'] +autodoc_default_flags = [ + 'members', + 'undoc-members', + 'inherited-members', + 'show-inheritance', + ] # For inter-documentation mapping: -from bob.extension.utils import link_documentation -intersphinx_mapping = link_documentation(['python', 'numpy', 'bob.pad.speech', 'gridtk', 'bob.db.avspoof']) - - -def skip(app, what, name, obj, skip, options): - # Do not skip the __call__ and the __str__ functions as we have special implementations for them. - if name in ("__str__", "__call__"): - return False - return skip - -# getting dictionaries printed nicely. -# see: http://stackoverflow.com/questions/7250659/python-code-to-generate-part-of-sphinx-documentation-is-it-possible/18143318#18143318 -try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -from sphinx.util.compat import Directive -from docutils import nodes, statemachine - -class ExecDirective(Directive): - """Execute the specified python code and insert the output into the document""" - has_content = True - - def run(self): - oldStdout, sys.stdout = sys.stdout, StringIO() - - tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) - source = self.state_machine.input_lines.source(self.lineno - self.state_machine.input_offset - 1) - - try: - exec('\n'.join(self.content)) - text = sys.stdout.getvalue() - lines = statemachine.string2lines(text, tab_width, convert_whitespace=True) - self.state_machine.insert_input(lines, source) - return [] - except Exception: - return [nodes.error(None, nodes.paragraph(text = "Unable to execute python code at %s:%d:" % (os.path.basename(source), self.lineno)), nodes.paragraph(text = str(sys.exc_info()[1])))] - finally: - sys.stdout = oldStdout +from bob.extension.utils import link_documentation, load_requirements +sphinx_requirements = "extra-intersphinx.txt" +if os.path.exists(sphinx_requirements): + intersphinx_mapping = link_documentation(additional_packages=load_requirements(sphinx_requirements)) +else: + intersphinx_mapping = link_documentation() + + +# We want to remove all private (i.e. _. or __.__) members +# that are not in the list of accepted functions +accepted_private_functions = ['__array__'] + +def member_function_test(app, what, name, obj, skip, options): + # test if we have a private function + if len(name) > 1 and name[0] == '_': + # test if this private function should be allowed + if name not in accepted_private_functions: + # omit privat functions that are not in the list of accepted private functions + return skip + else: + # test if the method is documented + if not hasattr(obj, '__doc__') or not obj.__doc__: + return skip + return False def setup(app): - app.connect("autodoc-skip-member", skip) - app.add_directive('exec', ExecDirective) + app.connect('autodoc-skip-member', member_function_test) \ No newline at end of file diff --git a/doc/experiments.rst b/doc/experiments.rst index a483f90cf6b0afa4054db971df161864e9bc3762..71f6ca440c06d671ea7b6ba0ba5ead842d96af79 100644 --- a/doc/experiments.rst +++ b/doc/experiments.rst @@ -94,7 +94,7 @@ So, a typical PAD experiment (in this case, attacks detection in speech) could l $ ./bin/spoof.py --database avspoof --preprocessor vad_energy --extractor lbp_hist --algorithm logregr --sub-directory pad_speech -vv .. note:: - To be able to run exactly the command line from above, it requires to have :ref:`bob.pad.speech <bob.pad.speech>` installed. + To be able to run exactly the command line from above, it requires to have :ref:`bob.pad.voice <bob.pad.voice>` installed. Before running an experiment, it is recommended to add the ``--dry-run`` option, so that it will only print, which steps would be executed, without actually executing them, and make sure that everything works as expected. diff --git a/doc/extra-intersphinx.txt b/doc/extra-intersphinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c404fefc5f12ef67eedb5cae51966573256b589 --- /dev/null +++ b/doc/extra-intersphinx.txt @@ -0,0 +1,11 @@ +python +numpy +bob.bio.face +bob.bio.speaker +bob.bio.gmm +bob.bio.video +bob.bio.csu +bob.bio.spear +bob.learn.linear +gridtk +bob.db.base \ No newline at end of file diff --git a/doc/implementation.rst b/doc/implementation.rst index 64293d29b599b9137535f8350c3218089b6269f9..586e0f3b15aed426a441b6222e13ad96a00742ac 100644 --- a/doc/implementation.rst +++ b/doc/implementation.rst @@ -93,7 +93,7 @@ Implemented Tools Example implementations of the base classes can be found in all of the ``bob.pad`` packages. Here is the current list of implementations: -* :ref:`bob.pad.speech <bob.pad.speech>` : :ref:`bob.pad.speech.implemented` +* :ref:`bob.pad.voice <bob.pad.voice>` : :ref:`bob.pad.voice` .. todo:: complete this list, once the other packages are documented as well. @@ -112,20 +112,20 @@ Anti-spoofing Database Interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For most of the data sets, we rely on the database interfaces from Bob_. -Particularly, all databases that are derived from the :py:class:`bob.pad.db` (click :ref:`here <spoofing_databases>` for a list of implemented databases) are supported. +Particularly, all databases that are derived from the :py:class:`bob.pad.base.database.PadDatabase` (click `here <https://gitlab.idiap.ch/bob/bob/wikis/Packages>`_ for a list of implemented databases) are supported. Defining your own Database ~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to define you own database, you are welcome to write your own database wrapper class. -In this case, you have to derive your class from the :py:class:`bob.pad.db`, +In this case, you have to derive your class from the :py:class:`bob.pad.base.database.PadDatabase`, and provide only the following functions: * ``__init__(self, <your-parameters>, **kwargs)``: Constructor of your database interface. - Please call the base class constructor, providing all the required parameters, e.g. by ``bob.pad.db.PadDatabase.__init__(self, **kwargs)``. -* ``objects(self, , groups=None, protocol=None, purposes=None, model_ids=None, **kwargs)``: Expected to return a list of :py:class:`bob.pad.db.PadFile` objects of the database given the specified parameters. + Please call the base class constructor, providing all the required parameters, e.g. by ``bob.pad.base.database.PadDatabase.__init__(self, **kwargs)``. +* ``objects(self, , groups=None, protocol=None, purposes=None, model_ids=None, **kwargs)``: Expected to return a list of :py:class:`bob.pad.base.database.PadFile` objects of the database given the specified parameters. The list needs to be sorted by the file id (you can use the ``self.sort(files)`` function for sorting). -* ``training_files(self, step, arrange_by_client = False)``: A sorted list of the :py:class:`bob.bio.base.database.File` objects that is used for training. +* ``training_files(self, step, arrange_by_client = False)``: A sorted list of the :py:class:`bob.bio.base.database.BioFile` objects that is used for training. You should have ``arrange_by_clients`` disabled. @@ -141,7 +141,7 @@ In ``bob.pad`` (similarly to ``bob.bio``) this is achieved by providing these pa In these files, an *instance* of one of the tools is generated, and assigned to a variable with a specific name. These variable names are: -* ``database`` for an instance of a (derivation of a) :py:class:`bob.pad.db.PadDatabase` +* ``database`` for an instance of a (derivation of a) :py:class:`bob.pad.base.database.PadDatabase` * ``preprocessor`` for an instance of a (derivation of a) :py:class:`bob.bio.base.preprocessor.Preprocessor` * ``extractor`` for an instance of a (derivation of a) :py:class:`bob.bio.base.extractor.Extractor` * ``algorithm`` for an instance of a (derivation of a) :py:class:`bob.pad.base.algorithm.Algorithm` @@ -153,14 +153,14 @@ These variable names are: Resources --------- -Finally, some of the configuration files, which sit in the ``bob/spoof/*/config`` directories, are registered as *resources*. +Finally, some of the configuration files, which sit in the ``bob/pad/*/config`` directories, are registered as *resources*. This means that a resource is nothing else than a short name for a registered instance of one of the tools (database, preprocessor, extractor, algorithm or grid configuration) of ``bob.pad``, which has a pre-defined set of parameters. The process of registering a resource is relatively easy. We use the SetupTools_ mechanism of registering so-called entry points in the ``setup.py`` file of the according ``bob.pad`` package. Particularly, we use a specific list of entry points, which are: -* ``bob.pad.db`` to register an instance of a (derivation of a) :py:class:`bob.pad.db.PadDatabase` +* ``bob.pad.base.database.PadDatabase`` to register an instance of a (derivation of a) :py:class:`bob.pad.base.database.PadDatabase` * ``bob.bio.preprocessor`` to register an instance of a (derivation of a) :py:class:`bob.bio.base.preprocessor.Preprocessor` * ``bob.bio.extractor`` to register an instance of a (derivation of a) :py:class:`bob.bio.base.extractor.Extractor` * ``bob.pad.algorithm`` to register an instance of a (derivation of a) :py:class:`bob.pad.base.algorithm.Algorithm` diff --git a/doc/implemented.rst b/doc/implemented.rst index f1409551b117aaa043ecd53d88905af5ec6c44d6..535bc7a202a444a3ae72a5dc685c87bef0b007d5 100644 --- a/doc/implemented.rst +++ b/doc/implemented.rst @@ -18,6 +18,12 @@ Only one base class that is presentation attack detection specific, ``Algorithm` .. autosummary:: bob.pad.base.algorithm.Algorithm +Implementations +~~~~~~~~~~~~~~~ + +.. autosummary:: + bob.pad.base.database.PadDatabase + bob.pad.base.database.PadFile Preprocessors ------------- @@ -38,6 +44,10 @@ Algorithms .. automodule:: bob.pad.base.algorithm +Databases +--------- + +.. automodule:: bob.pad.base.database Grid Configuration ------------------ diff --git a/doc/index.rst b/doc/index.rst index fecf40f030075e49e3deba403953ca4c4ecaa64f..4397356f45da6420b7915a54b37c876c907536c0 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -25,7 +25,7 @@ This results in a nearly infinite amount of possible experiments that can be run But it is also possible to use your own database, preprocessor, feature extractor, or PAD algorithm and test this against the baseline algorithms implemented in the our packages. .. note:: - The ``bob.pad`` packages are derived from the `bob.bio <http://pypi.python.org/pypi/bob.bio.base>`__, packages that are designed for biometric recognition experiments. + The ``bob.pad.*`` packages are derived from the `bob.bio.* <http://pypi.python.org/pypi/bob.bio.base>`__, packages that are designed for biometric recognition experiments. This package :py:mod:`bob.pad.base` includes the basic definition of a PAD experiment, as well as a generic script, which can execute the full experiment in a single command line. Changing the employed tolls such as the database, protocol, preprocessor, feature extractor or a PAD algorithm is as simple as changing a command line parameter. @@ -34,7 +34,7 @@ The implementation of (most of) the tools is separated into other packages in th All these packages can be easily combined. Here is a growing list of derived packages: -* :ref:`bob.pad.speech <bob.pad.speech>` Tools to run presentation attack detection experiments for speech, including Cepstral-based feature and LBP-based feature extraction, GMM-based and logistic regression based algorithms, plot processing and score fusion scripts. +* :ref:`bob.pad.voice <bob.pad.voice>` Tools to run presentation attack detection experiments for speech, including Cepstral-based feature and LBP-based feature extraction, GMM-based and logistic regression based algorithms, plot processing and score fusion scripts. If you are interested, please continue reading: diff --git a/doc/installation.rst b/doc/installation.rst index a08824fe42cd43126bf14be1985e45c569f55042..c53f6b985f743db99392d022cc1319a1e531c23a 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -24,15 +24,15 @@ There, in the ``eggs`` section of the ``buildout.cfg`` file, simply list the ``b .. code-block:: python eggs = bob.pad.base - bob.pad.speech + bob.pad.voice bob.db.avspoof gridtk in order to download and install all packages that are required for your experiments. In the example above, you might want to run a simple speech presentation attack detection -experiment using the :py:class:`bob.pad.speech.preprocessor.EnergyBandsPreprocessor` and -the :py:class:`bob.pad.speech.extractor.LBPExtractor` feature extractor -defined in :ref:`bob.pad.speech <bob.pad.speech>`, using the AVspoof database interface defined in :ref:`bob.db.avspoof <bob.db.avspoof>`. +experiment using the :py:class:`bob.pad.voice.preprocessor.EnergyBandsPreprocessor` and +the :py:class:`bob.pad.voice.extractor.LBPExtractor` feature extractor +defined in :ref:`bob.pad.voice <bob.pad.voice>`, using the AVspoof database interface defined in :ref:`bob.db.avspoof <bob.db.avspoof>`. Running the simple command line: .. code-block:: sh @@ -49,7 +49,7 @@ Databases With ``bob.pad`` you will run biometric recognition experiments using databases that contain presentation attacks. Though the PAD protocols are implemented in ``bob.pad``, the original data are **not included**. To download the original data of the databases, please refer to the according Web-pages. -For a list of supported databases including their download URLs, please refer to the :ref:`spoofing_databases`. +For a list of supported databases including their download URLs, please refer to the `spoofing_databases <https://gitlab.idiap.ch/bob/bob/wikis/Packages>`_. After downloading the original data for the databases, you will need to tell ``bob.pad``, where these databases can be found. For this purpose, we have decided to implement a special file, where you can set your directories. @@ -67,7 +67,7 @@ Please use ``./bin/databases.py`` for a list of known databases, where you can s .. note:: - If you have installed only ``bob.pad.base``, there is no database listed -- as all databases are included in other packages, such as :ref:`bob.pad.speech <bob.pad.speech>`. + If you have installed only ``bob.pad.base``, there is no database listed -- as all databases are included in other packages, such as :ref:`bob.pad.voice <bob.pad.voice>`. Test your Installation @@ -79,7 +79,7 @@ To verify your installation, you should run the script running the nose tests fo .. code-block:: sh $ ./bin/nosetests -vs bob.pad.base - $ ./bin/nosetests -vs bob.pad.speech + $ ./bin/nosetests -vs bob.pad.voice ... In case any of the tests fail for unexplainable reasons, please file a bug report through the `GitHub bug reporting system`_. diff --git a/requirements.txt b/requirements.txt index b1790d77325582c5aa5cdf3f5f0510efa2308755..5f1a473a96e6af28496bf6c1b897763cd0988281 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ setuptools bob.extension bob.db.base bob.bio.base +bob.io.base \ No newline at end of file diff --git a/test-requirements.txt b/test-requirements.txt index 0c381fc79f7662672b32a04782b9fdef9d995125..3867dcc79e33492721c6b3ce7e91d9db268b4f49 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,3 @@ bob.io.image -bob.io.base matplotlib gridtk