├── docs ├── _static │ └── .gitignore ├── authors.rst ├── changelog.rst ├── license.rst ├── index.rst ├── Makefile └── conf.py ├── AUTHORS.rst ├── .env.default ├── CHANGELOG.rst ├── tests ├── conftest.py └── fb_duckling │ ├── test_base_class.py │ ├── test_duckling.py │ └── test_anonymizer.py ├── src └── fb_duckling │ ├── __init__.py │ ├── base_class.py │ ├── utils.py │ ├── anonymizer.py │ └── duckling.py ├── .coveragerc ├── requirements.txt ├── LICENSE.txt ├── setup.py ├── README.md ├── .gitignore ├── .travis.yml └── setup.cfg /docs/_static/.gitignore: -------------------------------------------------------------------------------- 1 | # Empty directory 2 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. _authors: 2 | .. include:: ../AUTHORS.rst 3 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. _changes: 2 | .. include:: ../CHANGELOG.rst 3 | -------------------------------------------------------------------------------- /docs/license.rst: -------------------------------------------------------------------------------- 1 | .. _license: 2 | 3 | ======= 4 | License 5 | ======= 6 | 7 | .. literalinclude:: ../LICENSE.txt 8 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributors 3 | ============ 4 | 5 | * Benjamin Breton 6 | -------------------------------------------------------------------------------- /.env.default: -------------------------------------------------------------------------------- 1 | DEFAULT_URL="http://0.0.0.0" 2 | DEFAULT_PORT=8000 3 | DEFAULT_LOCALE="en_US" 4 | DEFAULT_TIMEZONE="America/Los_Angeles" 5 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | Changelog 3 | ========= 4 | 5 | Version 0.1 6 | =========== 7 | 8 | - Feature A added 9 | - FIX: nasty bug #1729 fixed 10 | - add your changes here! 11 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Dummy conftest.py for fb_duckling. 5 | 6 | If you don't know what this is for, just leave it empty. 7 | Read more about conftest.py under: 8 | https://pytest.org/latest/plugins.html 9 | """ 10 | from __future__ import print_function, absolute_import, division 11 | 12 | # import pytest 13 | -------------------------------------------------------------------------------- /src/fb_duckling/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pkg_resources import get_distribution, DistributionNotFound 3 | 4 | try: 5 | # Change here if project is renamed and does not equal the package name 6 | dist_name = __name__ 7 | __version__ = get_distribution(dist_name).version 8 | except DistributionNotFound: 9 | __version__ = 'unknown' 10 | 11 | from .utils import get_default_locale, get_default_url, get_default_port 12 | from .base_class import BaseClass 13 | from .duckling import Duckling 14 | from .anonymizer import Anonymizer 15 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | [run] 3 | branch = True 4 | source = */fb_duckling/* 5 | # omit = bad_file.py 6 | 7 | [report] 8 | # Regexes for lines to exclude from consideration 9 | exclude_lines = 10 | # Have to re-enable the standard pragma 11 | pragma: no cover 12 | 13 | # Don't complain about missing debug-only code: 14 | def __repr__ 15 | if self\.debug 16 | 17 | # Don't complain if tests don't hit defensive assertion code: 18 | raise AssertionError 19 | raise NotImplementedError 20 | 21 | # Don't complain if non-runnable code isn't run: 22 | if 0: 23 | if __name__ == .__main__.: 24 | -------------------------------------------------------------------------------- /tests/fb_duckling/test_base_class.py: -------------------------------------------------------------------------------- 1 | from fb_duckling import BaseClass 2 | import pytest 3 | 4 | 5 | class TestBaseClass(): 6 | 7 | def test_constructor(self): 8 | 9 | # Base test 10 | base_class = BaseClass() 11 | assert base_class.locale == "en_US" 12 | assert base_class.url == "http://0.0.0.0" 13 | assert base_class.port == 8000 14 | 15 | # Modification test 16 | base_class_mod = BaseClass(locale="fr_FR", url="http://127.0.0.0", port=8001) 17 | assert base_class_mod.locale == "fr_FR" 18 | assert base_class_mod.url == "http://127.0.0.0" 19 | assert base_class_mod.port == 8001 -------------------------------------------------------------------------------- /src/fb_duckling/base_class.py: -------------------------------------------------------------------------------- 1 | from .utils import get_default_locale, get_default_url, get_default_port, get_default_timezone 2 | 3 | 4 | class BaseClass(object): 5 | 6 | default_locale = get_default_locale() # en_US 7 | default_url = get_default_url() # http://0.0.0.0 8 | default_port = get_default_port() # 8000 9 | default_timezone = get_default_timezone() # America/Los_Angeles 10 | 11 | def __init__(self, locale=default_locale, url=default_url, port=default_port, timezone=default_timezone): 12 | 13 | self.locale = locale or "en_US" 14 | self.url = url or "http://0.0.0.0" 15 | self.port = port or 8000 16 | self.timezone = timezone or "America/Los_Angeles" 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | atomicwrites==1.3.0 2 | attrs==19.1.0 3 | backcall==0.1.0 4 | certifi==2019.3.9 5 | chardet==3.0.4 6 | python-coveralls==2.9.1 7 | decorator==4.4.0 8 | gitdb2==2.0.5 9 | GitPython==2.1.11 10 | idna==2.8 11 | jedi==0.13.3 12 | numpy==1.16.2 13 | parso==0.3.4 14 | pexpect==4.6.0 15 | pickleshare==0.7.5 16 | pluggy==0.9.0 17 | prompt-toolkit==2.0.9 18 | ptyprocess==0.6.0 19 | py==1.8.0 20 | Pygments==2.3.1 21 | pytest==4.4.1 22 | pytest-cov==2.6.1 23 | pytest-cover==3.0.0 24 | pytest-coverage==0.0 25 | python-dotenv==0.10.1 26 | requests==2.21.0 27 | scikit-learn==0.20.3 28 | scipy==1.2.1 29 | six==1.12.0 30 | sklearn==0.0 31 | smmap2==2.0.5 32 | traitlets==4.3.2 33 | urllib3==1.24.2 34 | wcwidth==0.1.7 35 | setuptools==41.0.1 36 | coverage==5.0 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Benjamin Breton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Setup file for fb_duckling. 5 | 6 | This file was generated with PyScaffold 3.0.3. 7 | PyScaffold helps you to put up the scaffold of your new Python project. 8 | Learn more under: http://pyscaffold.org/ 9 | """ 10 | 11 | import sys 12 | from setuptools import setup 13 | 14 | # Add here console scripts and other entry points in ini-style format 15 | entry_points = """ 16 | [console_scripts] 17 | # script_name = fb_duckling.module:function 18 | # For example: 19 | # fibonacci = fb_duckling.skeleton:run 20 | """ 21 | 22 | with open('requirements.txt') as f: 23 | requirements = f.read().splitlines() 24 | 25 | 26 | def setup_package(): 27 | 28 | needs_sphinx = {'build_sphinx', 'upload_docs'}.intersection(sys.argv) 29 | sphinx = ['sphinx'] if needs_sphinx else [] 30 | setup(setup_requires=['pyscaffold>=2.5,<3.1a0'] + sphinx, 31 | entry_points=entry_points, 32 | use_pyscaffold=True, 33 | dependency_links=["https://github.com/facebook/duckling"], 34 | install_requires=requirements) 35 | 36 | 37 | if __name__ == "__main__": 38 | setup_package() 39 | -------------------------------------------------------------------------------- /src/fb_duckling/utils.py: -------------------------------------------------------------------------------- 1 | from dotenv import load_dotenv 2 | from os import path, getenv 3 | 4 | 5 | env_path = "./.env" 6 | env_default_path = "./.env.default" 7 | 8 | if path.isfile(env_path): 9 | load_dotenv(env_path) 10 | print("loaded env variables from: {}".format(env_path)) 11 | elif path.isfile(env_default_path): 12 | load_dotenv(env_default_path) 13 | print("loaded env variables from: {}".format(env_default_path)) 14 | 15 | 16 | def get_default_port(): 17 | port = getenv("DEFAULT_PORT") 18 | if isinstance(port, str): 19 | return int(port) 20 | elif isinstance(port, int): 21 | return port 22 | else: 23 | return None 24 | 25 | 26 | def get_default_url(): 27 | url = getenv("DEFAULT_URL") 28 | if isinstance(url, str): 29 | return str(getenv("DEFAULT_URL")) 30 | else: 31 | return None 32 | 33 | 34 | def get_default_locale(): 35 | locale = getenv("DEFAULT_LOCALE") 36 | if isinstance(locale, str): 37 | return locale 38 | else: 39 | return None 40 | 41 | 42 | def get_default_timezone(): 43 | timezone = getenv("DEFAULT_TIMEZONE") 44 | if isinstance(timezone, str): 45 | return timezone 46 | else: 47 | return None 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![version](https://img.shields.io/badge/python-3.6%20%7C%203.7-blue.svg)](https://img.shields.io/badge/python-3.6%20%7C%203.7-blue.svg) 2 | [![travis build status](https://travis-ci.org/duckling-python-wrapper/fb_duckling.svg?branch=master)](https://travis-ci.org/duckling-python-wrapper/fb_duckling) 3 | [![Coverage Status](https://coveralls.io/repos/github/duckling-python-wrapper/fb_duckling/badge.svg?branch=master)](https://coveralls.io/github/duckling-python-wrapper/fb_duckling?branch=master) 4 | 5 | # fb_duckling 6 | 7 | A python wrapper for **[facebook's duckling](https://github.com/facebook/duckling)**. 8 | 9 | ## Installation: 10 | 11 | 1. Installation of Duckling. 12 | Set the environment properly to reach your duckling server. 13 | Facebook's Duckling is a library used for feature extraction in text, and it is coded in haskell. 14 | To make it work, you need to 15 | - Install [haskell](https://www.haskell.org/platform/) to your platform. 16 | - Clone [facebook's duckling](https://github.com/facebook/duckling). 17 | - Install the project using ```stack build``` from duckling's project root. 18 | 19 | 2. Start Duckling. 20 | - Launch the duckling-server with the command ```stack exec duckling-example-exe```. 21 | 22 | 3. Install the library on python3 23 | - On **python3.6** or **python3.7** use the command ```pip install fb-duckling```. 24 | 25 | ## Using the Library 26 | 27 | ```python 28 | from fb_duckling import Duckling 29 | duckling = Duckling(locale="en_US") 30 | duckling("All work and no play makes jack@gmail.com a dull boy 0102030405") 31 | 32 | ``` 33 | ```bash 34 | { 35 | 'body': 'jack@gmail.com', 36 | 'start': 6, 37 | 'value': {'value': 'jack@gmail.com'}, 38 | 'end': 20, 39 | 'dim': 'email', 40 | 'latent': False 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /tests/fb_duckling/test_duckling.py: -------------------------------------------------------------------------------- 1 | from fb_duckling import Duckling 2 | import pytest 3 | import numpy as np 4 | 5 | 6 | @pytest.fixture 7 | def duckling(): 8 | return Duckling() 9 | 10 | 11 | class TestDuckling(object): 12 | 13 | def test_constructor(self, duckling): 14 | 15 | assert duckling.dim_list == [ 16 | 'amount-of-money', 'credit-card-number', 'distance', 'duration', 17 | 'email', 'number', 'ordinal', 'phone-number', 'quantity', 18 | 'temperature', 'time', 'time-grain', 'url', 'volume', 'regex' 19 | ] 20 | 21 | def test_create_payload(self, duckling): 22 | locale = "fr_FR" 23 | raw_text = "All work and no play makes jack@gmail.com a dull boy 0102030405" 24 | tz = "Europe/Paris" 25 | 26 | assert duckling.create_payload(raw_text, locale, tz) == { 27 | "text": raw_text, 28 | "locale": locale, 29 | "tz": tz 30 | } 31 | 32 | def test_request(self, duckling): 33 | raw_text = "hello jack@gmail.com" 34 | assert duckling.request(raw_text) == [ 35 | { 36 | 'body': 'jack@gmail.com', 37 | 'start': 6, 38 | 'value': {'value': 'jack@gmail.com'}, 39 | 'end': 20, 40 | 'dim': 'email', 41 | 'latent': False 42 | } 43 | ] 44 | 45 | def test_extract_dims(self, duckling): 46 | raw_text = "hello jack@gmail.com" 47 | assert duckling.extract_dims(raw_text) == {'email'} 48 | 49 | def test_contains_dim(self, duckling): 50 | raw_text = "hello jack@gmail.com" 51 | 52 | assert np.array_equal( 53 | duckling.contains_dim(raw_text).toarray(), 54 | np.array([[0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]]) 55 | ) 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Vscode settings 94 | .vscode/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | .idea/ 109 | duckling/* 110 | .vscode/ 111 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial # required for Python >= 3.7 2 | language: python 3 | matrix: 4 | include: 5 | - stage: test 6 | name: "Test 3.6" 7 | python: "3.6" 8 | services: docker 9 | before_install: 10 | - docker pull rasa/duckling 11 | - docker run -d -p 0.0.0.0:8000:8000 rasa/duckling 12 | install: 13 | - pip install -r requirements.txt 14 | - python setup.py install 15 | script: python3 setup.py test || python setup.py test 16 | - name: "Test 3.7" 17 | python: "3.7" 18 | services: docker 19 | before_install: 20 | - docker pull rasa/duckling 21 | - docker run -d -p 0.0.0.0:8000:8000 rasa/duckling 22 | install: 23 | - pip install -r requirements.txt 24 | - python setup.py install 25 | script: python3 setup.py test || python setup.py test 26 | - stage: deploy 27 | install: true 28 | script: skip 29 | deploy: 30 | provider: pypi 31 | distributions: sdist bdist_wheel release 32 | user: "bbreton3" 33 | password: 34 | secure: "Irrqqdv5jMbPZs9Ypxc2FM9hXw8FnVRCBJ3NFqIOt4OVwViCLySfK7sKmy+enlOl4BIMypyBgcEWIbkcN/uCwUFYdnBw7DyVrdfyvk5BuHLXS086sCmSS8/7wcADoxEirZc8dAzTFiG7R6deBVL1TANt4ArVMtQRDZUJP+5TZQ4VvYpW/IQZaoNdvfFtiBHm7GkP0cs3oNsV6br0/u/6yIrdsYMVrdfB9/T/aKHSCYKsnuoWaHO7dAbJB9shrPboYLFrhFldz4H27ieArMfVAiBbP3g4BDLGL/oRSACtm4rlJBLAMikOag1L8roRWHIhkRYYmFqmP3ybkWnux1V3tpDq0/lR+vgp2WW4EIQI8BweQjpyCh0mq7LG0rgWtGhnCC9FYj8OIshsgY8GFK6tj750noNLhZbZpSmoQv++BngtFrz2Kwkj3f9g+dDb3nvHejeBBn9p7kEC69oeOpBJE9qi5zZotWYtlm1OL+41Kz2fbTkIBeptRUo/jHWSELHTm/4Y5xPBWwiTg3ZfDXo0RSZtMSp4FJbwP/UPb/G0zY+gxMNfXfbAlsgUx7SPzeBiK1njvEivk5dbErnbTKUYCdk1RusOdcXSoUc40Wqn+Gr5Bfp5gEZuAJ+aMGcm15ZRkOb2Ve/jN8e/Z+VwjsG0XJhVuy2jV57d8lgvdPG8qu4=" 35 | on: 36 | branch: master 37 | tags: true 38 | 39 | stages: 40 | - test 41 | - deploy 42 | 43 | after_success: 44 | - coveralls 45 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | fb_duckling 3 | =========== 4 | 5 | This is the documentation of **fb_duckling**. 6 | 7 | .. note:: 8 | 9 | This is the main page of your project's `Sphinx `_ 10 | documentation. It is formatted in `reStructuredText 11 | `__. Add additional pages by creating 12 | rst-files in ``docs`` and adding them to the `toctree 13 | `_ below. Use then 14 | `references `__ in order to link 15 | them from this page, e.g. :ref:`authors ` and :ref:`changes`. 16 | 17 | It is also possible to refer to the documentation of other Python packages 18 | with the `Python domain syntax 19 | `__. By default you 20 | can reference the documentation of `Sphinx `__, 21 | `Python `__, `NumPy 22 | `__, `SciPy 23 | `__, `matplotlib 24 | `__, `Pandas 25 | `__, `Scikit-Learn 26 | `__. You can add more by 27 | extending the ``intersphinx_mapping`` in your Sphinx's ``conf.py``. 28 | 29 | The pretty useful extension `autodoc 30 | `__ is activated by 31 | default and lets you include documentation from docstrings. Docstrings can 32 | be written in `Google 33 | `__ 34 | (recommended!), `NumPy 35 | `__ 36 | and `classical 37 | `__ 38 | style. 39 | 40 | 41 | Contents 42 | ======== 43 | 44 | .. toctree:: 45 | :maxdepth: 2 46 | 47 | License 48 | Authors 49 | Changelog 50 | Module Reference 51 | 52 | 53 | Indices and tables 54 | ================== 55 | 56 | * :ref:`genindex` 57 | * :ref:`modindex` 58 | * :ref:`search` 59 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # This file is used to configure your project. 2 | # Read more about the various options under: 3 | # http://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files 4 | 5 | [metadata] 6 | name = fb_duckling 7 | description = A python wrapper for facebook s duckling. 8 | author = Benjamin Breton 9 | author-email = benjamin.breton45@gmail.com 10 | license = mit 11 | url = https://github.com/duckling-python-wrapper/fb_duckling 12 | long-description = file: README.rst 13 | # Change if running only on Windows, Mac or Linux (comma-separated) 14 | platforms = any 15 | # Add here all kinds of additional classifiers as defined under 16 | # https://pypi.python.org/pypi?%3Aaction=list_classifiers 17 | classifiers = 18 | Development Status :: 4 - Beta 19 | Programming Language :: Python 20 | 21 | [options] 22 | zip_safe = False 23 | packages = find: 24 | include_package_data = True 25 | package_dir = 26 | =src 27 | # Add here dependencies of your project (semicolon-separated), e.g. 28 | # install_requires = numpy; scipy 29 | install_requires = 30 | # Add here test requirements (semicolon-separated) 31 | tests_require = pytest; pytest-cov 32 | 33 | [options.packages.find] 34 | where = src 35 | exclude = 36 | tests 37 | 38 | [options.extras_require] 39 | # Add here additional requirements for extra features, to install with: 40 | # `pip install fb_duckling[PDF]` like: 41 | # PDF = ReportLab; RXP 42 | 43 | [test] 44 | # py.test options when running `python setup.py test` 45 | addopts = tests 46 | 47 | [tool:pytest] 48 | # Options for py.test: 49 | # Specify command line options as you would do when invoking py.test directly. 50 | # e.g. --cov-report html (or xml) for html/xml output or --junitxml junit.xml 51 | # in order to write a coverage file that can be read by Jenkins. 52 | addopts = 53 | --cov fb_duckling --cov-report term-missing 54 | --verbose 55 | norecursedirs = 56 | dist 57 | build 58 | .tox 59 | 60 | [aliases] 61 | release = sdist bdist_wheel upload 62 | 63 | [bdist_wheel] 64 | # Use this option if your package is pure-python 65 | universal = 1 66 | 67 | [build_sphinx] 68 | source_dir = docs 69 | build_dir = docs/_build 70 | 71 | [devpi:upload] 72 | # Options for the devpi: PyPI server and packaging tool 73 | # VCS export must be deactivated since we are using setuptools-scm 74 | no-vcs = 1 75 | formats = bdist_wheel 76 | 77 | [flake8] 78 | # Some sane defaults for the code style checker flake8 79 | exclude = 80 | .tox 81 | build 82 | dist 83 | .eggs 84 | docs/conf.py 85 | 86 | [pyscaffold] 87 | # PyScaffold's parameters when the project was created. 88 | # This will be used when updating. Do not change! 89 | version = 3.0.3 90 | package = fb_duckling 91 | -------------------------------------------------------------------------------- /src/fb_duckling/anonymizer.py: -------------------------------------------------------------------------------- 1 | from .base_class import BaseClass 2 | from .duckling import Duckling 3 | import re 4 | 5 | 6 | class Anonymizer(BaseClass): 7 | 8 | default_anonymization_dict = { 9 | "email": "email", 10 | "phone-number": "phone" 11 | } 12 | 13 | def __init__(self, anonymization_dict=default_anonymization_dict, 14 | *args, **kwargs): 15 | super().__init__(*args, **kwargs) 16 | 17 | self.duckling = Duckling(*args, **kwargs) 18 | self.anonymization_dict = anonymization_dict 19 | 20 | def __call__(self, text, ignore_exp=[], fixed_len=True, locale=None, tz=None, special_char="/"): 21 | result = self._duckling_request(text, locale or self.locale, tz or self.timezone) 22 | anonymized_text = self._anonymize( 23 | result, text, ignore_exp=ignore_exp, fixed_len=fixed_len, special_char=special_char) 24 | return anonymized_text 25 | 26 | def _anonymize(self, result, text, ignore_exp=[], fixed_len=True, special_char="/"): 27 | """ 28 | Text anonymization 29 | Warning: If fixed_len=False, it allows padding which use a special char, 30 | it might be incompatible with existing Tokenizer. 31 | 32 | :param result: result from duckling request 33 | :param text: text to anonymize 34 | :param ignore: list of value to ignore if found in result 35 | :param fixed_len: padding is disabled which means there is no indication 36 | on the length of the input data 37 | :param special_char: char to use in padding function 38 | 39 | :return: The anonymized version of the text 40 | """ 41 | anonymized_text = text 42 | for res in result: 43 | if fixed_len: 44 | if res["dim"] in self.anonymization_dict.keys(): 45 | if not any(exp in res["body"] for exp in ignore_exp): 46 | anonymized_text = re.sub( 47 | res["body"], "personal_" + self.anonymization_dict[res["dim"]], anonymized_text) 48 | else: 49 | if res["dim"] in self.anonymization_dict.keys(): 50 | if not any(exp in res["body"] for exp in ignore_exp): 51 | padding_len = len(res["body"]) 52 | anonymized_text = re.sub( 53 | res["body"], self._add_padding(self.anonymization_dict[res["dim"]], padding_len, special_char), anonymized_text) 54 | 55 | return anonymized_text 56 | 57 | def _duckling_request(self, text, locale=None, tz=None): 58 | result = self.duckling.request(text, locale=locale or self.locale, tz=tz or self.timezone) 59 | return result 60 | 61 | def _add_padding(self, key, length, special_char): 62 | return key.center(length, special_char) 63 | -------------------------------------------------------------------------------- /src/fb_duckling/duckling.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | I took inspiration from the DucklingHttpExtractor from rasa_nlu 4 | https://github.com/RasaHQ/rasa_nlu/blob/master/rasa_nlu/extractors/duckling_http_extractor.py 5 | The idea was to create a standalone version from 6 | this tool that could be used without rasa_nlu 7 | """ 8 | 9 | from .base_class import BaseClass 10 | from sklearn.preprocessing import OneHotEncoder 11 | import numpy as np 12 | import requests 13 | import logging 14 | 15 | logger = logging.getLogger(__name__) 16 | 17 | 18 | class Duckling(BaseClass): 19 | 20 | def __init__(self, *args, **kwargs): 21 | super().__init__(*args, **kwargs) 22 | 23 | self.dim_list = [ 24 | 'amount-of-money', 'credit-card-number', 'distance', 'duration', 25 | 'email', 'number', 'ordinal', 'phone-number', 'quantity', 26 | 'temperature', 'time', 'time-grain', 'url', 'volume', 'regex' 27 | ] 28 | 29 | self.dim_onh = OneHotEncoder() 30 | self.dim_onh.fit(np.array(self.dim_list).reshape(-1, 1)) 31 | 32 | def __call__(self, text, locale=None): 33 | return self.request(text, locale) 34 | 35 | def create_payload(self, text, locale, tz): 36 | return { 37 | "text": text, 38 | "locale": locale, 39 | "tz": tz 40 | } 41 | 42 | def request(self, text, locale=None, tz=None): 43 | 44 | headers = {"Content-Type": "application/x-www-form-urlencoded; " 45 | "charset=UTF-8"} 46 | 47 | # Payload 48 | payload = self.create_payload(text=text, locale=locale or self.locale, tz=tz or self.timezone) 49 | 50 | # Perform Request 51 | response = requests.post( 52 | "{0}:{1}/parse".format(self.url, self.port), 53 | data=payload, 54 | headers=headers 55 | ) 56 | 57 | try: 58 | if response.status_code == 200: 59 | return response.json() 60 | else: 61 | logger.error( 62 | "Failed to get a proper response from Duckling\n" 63 | "status_code: {0},\nResponse: {1}".format( 64 | response.status_code, response.text 65 | )) 66 | return [] 67 | except requests.exceptions.ConnectionError as e: 68 | logger.error("Could not connect to duckling, please make sure that" 69 | "the Duckling http server is on:\n" 70 | "https://github.com/facebook/duckling\n" 71 | "Error: {0}".format(e)) 72 | 73 | def extract_dims(self, text, locale=None, tz=None): 74 | return { 75 | x["dim"] for x in self.request(text=text, locale=locale or self.locale, tz=tz or self.timezone) 76 | } 77 | 78 | def contains_dim(self, text, locale=None, tz=None): 79 | return self.dim_onh.transform( 80 | [list(self.extract_dims(text=text, locale=locale or self.locale, tz=tz or self.timezone))] 81 | ) 82 | -------------------------------------------------------------------------------- /tests/fb_duckling/test_anonymizer.py: -------------------------------------------------------------------------------- 1 | from fb_duckling import Anonymizer 2 | import pytest 3 | 4 | 5 | @pytest.fixture 6 | def anonymizer(): 7 | return Anonymizer() 8 | 9 | 10 | class TestAnonymizer(object): 11 | 12 | def test_constructor(self, anonymizer): 13 | 14 | assert anonymizer.default_anonymization_dict == { 15 | "email": "email", 16 | "phone-number": "phone" 17 | } 18 | 19 | def test_anonymize(self, anonymizer): 20 | raw_text = "All work and no play makes jack@gmail.com a dull boy 0102030405" 21 | anonymized_text = "All work and no play makes personal_email a dull boy personal_phone" 22 | result = [{ 23 | 'body': 'jack@gmail.com', 24 | 'start': 27, 25 | 'value': {'value': 'jack@gmail.com'}, 26 | 'end': 41, 27 | 'dim': 'email', 28 | 'latent': False 29 | }, 30 | { 31 | 'body': '0102030405', 32 | 'start': 53, 33 | 'value': {'value': '0102030405'}, 34 | 'end': 63, 35 | 'dim': 'phone-number', 36 | 'latent': False 37 | }] 38 | assert anonymizer._anonymize(result, raw_text) == anonymized_text 39 | assert anonymizer(raw_text) == anonymized_text 40 | 41 | def test_anonymize_ignore(self, anonymizer): 42 | raw_text = "All work and no play makes jack@gmail.com a dull boy 0102030405" 43 | anonymized_text = "All work and no play makes personal_email a dull boy 0102030405" 44 | result = [{ 45 | 'body': 'jack@gmail.com', 46 | 'start': 27, 47 | 'value': {'value': 'jack@gmail.com'}, 48 | 'end': 41, 49 | 'dim': 'email', 50 | 'latent': False 51 | }, 52 | { 53 | 'body': '0102030405', 54 | 'start': 53, 55 | 'value': {'value': '0102030405'}, 56 | 'end': 63, 57 | 'dim': 'phone-number', 58 | 'latent': False 59 | }] 60 | assert anonymizer._anonymize(result, raw_text, ignore_exp=[ 61 | "0102030405"]) == anonymized_text 62 | 63 | def test_anonymize_padding(self, anonymizer): 64 | raw_text = "All work and no play makes jack@gmail.com a dull boy 0102030405" 65 | anonymized_text = "All work and no play makes ////email///// a dull boy //phone///" 66 | result = [{ 67 | 'body': 'jack@gmail.com', 68 | 'start': 27, 69 | 'value': {'value': 'jack@gmail.com'}, 70 | 'end': 41, 71 | 'dim': 'email', 72 | 'latent': False 73 | }, 74 | { 75 | 'body': '0102030405', 76 | 'start': 53, 77 | 'value': {'value': '0102030405'}, 78 | 'end': 63, 79 | 'dim': 'phone-number', 80 | 'latent': False 81 | }] 82 | assert anonymizer._anonymize( 83 | result, raw_text, fixed_len=False) == anonymized_text 84 | assert anonymizer(raw_text, fixed_len=False) == anonymized_text 85 | 86 | def test_request(self, anonymizer): 87 | raw_text = "All work and no play makes jack@gmail.com a dull boy 0102030405" 88 | assert anonymizer._duckling_request(raw_text) is not None 89 | 90 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | AUTODOCDIR = api 10 | AUTODOCBUILD = sphinx-apidoc 11 | PROJECT = fb_duckling 12 | MODULEDIR = ../src/fb_duckling 13 | 14 | # User-friendly check for sphinx-build 15 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $?), 1) 16 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 17 | endif 18 | 19 | # Internal variables. 20 | PAPEROPT_a4 = -D latex_paper_size=a4 21 | PAPEROPT_letter = -D latex_paper_size=letter 22 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 23 | # the i18n builder cannot share the environment and doctrees with the others 24 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 25 | 26 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext doc-requirements 27 | 28 | help: 29 | @echo "Please use \`make ' where is one of" 30 | @echo " html to make standalone HTML files" 31 | @echo " dirhtml to make HTML files named index.html in directories" 32 | @echo " singlehtml to make a single large HTML file" 33 | @echo " pickle to make pickle files" 34 | @echo " json to make JSON files" 35 | @echo " htmlhelp to make HTML files and a HTML help project" 36 | @echo " qthelp to make HTML files and a qthelp project" 37 | @echo " devhelp to make HTML files and a Devhelp project" 38 | @echo " epub to make an epub" 39 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 40 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 41 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 42 | @echo " text to make text files" 43 | @echo " man to make manual pages" 44 | @echo " texinfo to make Texinfo files" 45 | @echo " info to make Texinfo files and run them through makeinfo" 46 | @echo " gettext to make PO message catalogs" 47 | @echo " changes to make an overview of all changed/added/deprecated items" 48 | @echo " xml to make Docutils-native XML files" 49 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 50 | @echo " linkcheck to check all external links for integrity" 51 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 52 | 53 | clean: 54 | rm -rf $(BUILDDIR)/* $(AUTODOCDIR) 55 | 56 | $(AUTODOCDIR): $(MODULEDIR) 57 | mkdir -p $@ 58 | $(AUTODOCBUILD) -f -o $@ $^ 59 | 60 | doc-requirements: $(AUTODOCDIR) 61 | 62 | html: doc-requirements 63 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 64 | @echo 65 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 66 | 67 | dirhtml: doc-requirements 68 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 69 | @echo 70 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 71 | 72 | singlehtml: doc-requirements 73 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 74 | @echo 75 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 76 | 77 | pickle: doc-requirements 78 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 79 | @echo 80 | @echo "Build finished; now you can process the pickle files." 81 | 82 | json: doc-requirements 83 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 84 | @echo 85 | @echo "Build finished; now you can process the JSON files." 86 | 87 | htmlhelp: doc-requirements 88 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 89 | @echo 90 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 91 | ".hhp project file in $(BUILDDIR)/htmlhelp." 92 | 93 | qthelp: doc-requirements 94 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 95 | @echo 96 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 97 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 98 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/$(PROJECT).qhcp" 99 | @echo "To view the help file:" 100 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/$(PROJECT).qhc" 101 | 102 | devhelp: doc-requirements 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $HOME/.local/share/devhelp/$(PROJECT)" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $HOME/.local/share/devhelp/$(PROJEC)" 109 | @echo "# devhelp" 110 | 111 | epub: doc-requirements 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | patch-latex: 117 | find _build/latex -iname "*.tex" | xargs -- \ 118 | sed -i'' 's~includegraphics{~includegraphics\[keepaspectratio,max size={\\textwidth}{\\textheight}\]{~g' 119 | 120 | latex: doc-requirements 121 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 122 | $(MAKE) patch-latex 123 | @echo 124 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 125 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 126 | "(use \`make latexpdf' here to do that automatically)." 127 | 128 | latexpdf: doc-requirements 129 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 130 | $(MAKE) patch-latex 131 | @echo "Running LaTeX files through pdflatex..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | latexpdfja: doc-requirements 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo "Running LaTeX files through platex and dvipdfmx..." 138 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 139 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 140 | 141 | text: doc-requirements 142 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 143 | @echo 144 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 145 | 146 | man: doc-requirements 147 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 148 | @echo 149 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 150 | 151 | texinfo: doc-requirements 152 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 153 | @echo 154 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 155 | @echo "Run \`make' in that directory to run these through makeinfo" \ 156 | "(use \`make info' here to do that automatically)." 157 | 158 | info: doc-requirements 159 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 160 | @echo "Running Texinfo files through makeinfo..." 161 | make -C $(BUILDDIR)/texinfo info 162 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 163 | 164 | gettext: doc-requirements 165 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 166 | @echo 167 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 168 | 169 | changes: doc-requirements 170 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 171 | @echo 172 | @echo "The overview file is in $(BUILDDIR)/changes." 173 | 174 | linkcheck: doc-requirements 175 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 176 | @echo 177 | @echo "Link check complete; look for any errors in the above output " \ 178 | "or in $(BUILDDIR)/linkcheck/output.txt." 179 | 180 | doctest: doc-requirements 181 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 182 | @echo "Testing of doctests in the sources finished, look at the " \ 183 | "results in $(BUILDDIR)/doctest/output.txt." 184 | 185 | xml: doc-requirements 186 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 187 | @echo 188 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 189 | 190 | pseudoxml: doc-requirements 191 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 192 | @echo 193 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 194 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is execfile()d with the current directory set to its containing dir. 4 | # 5 | # Note that not all possible configuration values are present in this 6 | # autogenerated file. 7 | # 8 | # All configuration values have a default; values that are commented out 9 | # serve to show the default. 10 | 11 | import os 12 | import sys 13 | import inspect 14 | import shutil 15 | 16 | __location__ = os.path.join(os.getcwd(), os.path.dirname( 17 | inspect.getfile(inspect.currentframe()))) 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | sys.path.insert(0, os.path.join(__location__, '../src')) 23 | 24 | # -- Run sphinx-apidoc ------------------------------------------------------ 25 | # This hack is necessary since RTD does not issue `sphinx-apidoc` before running 26 | # `sphinx-build -b html . _build/html`. See Issue: 27 | # https://github.com/rtfd/readthedocs.org/issues/1139 28 | # DON'T FORGET: Check the box "Install your project inside a virtualenv using 29 | # setup.py install" in the RTD Advanced Settings. 30 | # Additionally it helps us to avoid running apidoc manually 31 | 32 | try: # for Sphinx >= 1.7 33 | from sphinx.ext import apidoc 34 | except ImportError: 35 | from sphinx import apidoc 36 | 37 | output_dir = os.path.join(__location__, "api") 38 | module_dir = os.path.join(__location__, "../src/fb_duckling") 39 | try: 40 | shutil.rmtree(output_dir) 41 | except FileNotFoundError: 42 | pass 43 | 44 | try: 45 | import sphinx 46 | from distutils.version import LooseVersion 47 | 48 | cmd_line_template = "sphinx-apidoc -f -o {outputdir} {moduledir}" 49 | cmd_line = cmd_line_template.format(outputdir=output_dir, moduledir=module_dir) 50 | 51 | args = cmd_line.split(" ") 52 | if LooseVersion(sphinx.__version__) >= LooseVersion('1.7'): 53 | args = args[1:] 54 | 55 | apidoc.main(args) 56 | except Exception as e: 57 | print("Running `sphinx-apidoc` failed!\n{}".format(e)) 58 | 59 | # -- General configuration ----------------------------------------------------- 60 | 61 | # If your documentation needs a minimal Sphinx version, state it here. 62 | # needs_sphinx = '1.0' 63 | 64 | # Add any Sphinx extension module names here, as strings. They can be extensions 65 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 66 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 67 | 'sphinx.ext.autosummary', 'sphinx.ext.viewcode', 'sphinx.ext.coverage', 68 | 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.mathjax', 69 | 'sphinx.ext.napoleon'] 70 | 71 | # Add any paths that contain templates here, relative to this directory. 72 | templates_path = ['_templates'] 73 | 74 | # The suffix of source filenames. 75 | source_suffix = '.rst' 76 | 77 | # The encoding of source files. 78 | # source_encoding = 'utf-8-sig' 79 | 80 | # The master toctree document. 81 | master_doc = 'index' 82 | 83 | # General information about the project. 84 | project = u'fb_duckling' 85 | copyright = u'2019, Benjamin Breton' 86 | 87 | # The version info for the project you're documenting, acts as replacement for 88 | # |version| and |release|, also used in various other places throughout the 89 | # built documents. 90 | # 91 | # The short X.Y version. 92 | version = '' # Is set by calling `setup.py docs` 93 | # The full version, including alpha/beta/rc tags. 94 | release = '' # Is set by calling `setup.py docs` 95 | 96 | # The language for content autogenerated by Sphinx. Refer to documentation 97 | # for a list of supported languages. 98 | # language = None 99 | 100 | # There are two options for replacing |today|: either, you set today to some 101 | # non-false value, then it is used: 102 | # today = '' 103 | # Else, today_fmt is used as the format for a strftime call. 104 | # today_fmt = '%B %d, %Y' 105 | 106 | # List of patterns, relative to source directory, that match files and 107 | # directories to ignore when looking for source files. 108 | exclude_patterns = ['_build'] 109 | 110 | # The reST default role (used for this markup: `text`) to use for all documents. 111 | # default_role = None 112 | 113 | # If true, '()' will be appended to :func: etc. cross-reference text. 114 | # add_function_parentheses = True 115 | 116 | # If true, the current module name will be prepended to all description 117 | # unit titles (such as .. function::). 118 | # add_module_names = True 119 | 120 | # If true, sectionauthor and moduleauthor directives will be shown in the 121 | # output. They are ignored by default. 122 | # show_authors = False 123 | 124 | # The name of the Pygments (syntax highlighting) style to use. 125 | pygments_style = 'sphinx' 126 | 127 | # A list of ignored prefixes for module index sorting. 128 | # modindex_common_prefix = [] 129 | 130 | # If true, keep warnings as "system message" paragraphs in the built documents. 131 | # keep_warnings = False 132 | 133 | 134 | # -- Options for HTML output --------------------------------------------------- 135 | 136 | # The theme to use for HTML and HTML Help pages. See the documentation for 137 | # a list of builtin themes. 138 | html_theme = 'alabaster' 139 | 140 | # Theme options are theme-specific and customize the look and feel of a theme 141 | # further. For a list of options available for each theme, see the 142 | # documentation. 143 | # html_theme_options = {} 144 | 145 | # Add any paths that contain custom themes here, relative to this directory. 146 | # html_theme_path = [] 147 | 148 | # The name for this set of Sphinx documents. If None, it defaults to 149 | # " v documentation". 150 | try: 151 | from fb_duckling import __version__ as version 152 | except ImportError: 153 | pass 154 | else: 155 | release = version 156 | 157 | # A shorter title for the navigation bar. Default is the same as html_title. 158 | # html_short_title = None 159 | 160 | # The name of an image file (relative to this directory) to place at the top 161 | # of the sidebar. 162 | # html_logo = "" 163 | 164 | # The name of an image file (within the static path) to use as favicon of the 165 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 166 | # pixels large. 167 | # html_favicon = None 168 | 169 | # Add any paths that contain custom static files (such as style sheets) here, 170 | # relative to this directory. They are copied after the builtin static files, 171 | # so a file named "default.css" will overwrite the builtin "default.css". 172 | html_static_path = ['_static'] 173 | 174 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 175 | # using the given strftime format. 176 | # html_last_updated_fmt = '%b %d, %Y' 177 | 178 | # If true, SmartyPants will be used to convert quotes and dashes to 179 | # typographically correct entities. 180 | # html_use_smartypants = True 181 | 182 | # Custom sidebar templates, maps document names to template names. 183 | # html_sidebars = {} 184 | 185 | # Additional templates that should be rendered to pages, maps page names to 186 | # template names. 187 | # html_additional_pages = {} 188 | 189 | # If false, no module index is generated. 190 | # html_domain_indices = True 191 | 192 | # If false, no index is generated. 193 | # html_use_index = True 194 | 195 | # If true, the index is split into individual pages for each letter. 196 | # html_split_index = False 197 | 198 | # If true, links to the reST sources are added to the pages. 199 | # html_show_sourcelink = True 200 | 201 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 202 | # html_show_sphinx = True 203 | 204 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 205 | # html_show_copyright = True 206 | 207 | # If true, an OpenSearch description file will be output, and all pages will 208 | # contain a tag referring to it. The value of this option must be the 209 | # base URL from which the finished HTML is served. 210 | # html_use_opensearch = '' 211 | 212 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 213 | # html_file_suffix = None 214 | 215 | # Output file base name for HTML help builder. 216 | htmlhelp_basename = 'fb_duckling-doc' 217 | 218 | 219 | # -- Options for LaTeX output -------------------------------------------------- 220 | 221 | latex_elements = { 222 | # The paper size ('letterpaper' or 'a4paper'). 223 | # 'papersize': 'letterpaper', 224 | 225 | # The font size ('10pt', '11pt' or '12pt'). 226 | # 'pointsize': '10pt', 227 | 228 | # Additional stuff for the LaTeX preamble. 229 | # 'preamble': '', 230 | } 231 | 232 | # Grouping the document tree into LaTeX files. List of tuples 233 | # (source start file, target name, title, author, documentclass [howto/manual]). 234 | latex_documents = [ 235 | ('index', 'user_guide.tex', u'fb_duckling Documentation', 236 | u'Benjamin Breton', 'manual'), 237 | ] 238 | 239 | # The name of an image file (relative to this directory) to place at the top of 240 | # the title page. 241 | # latex_logo = "" 242 | 243 | # For "manual" documents, if this is true, then toplevel headings are parts, 244 | # not chapters. 245 | # latex_use_parts = False 246 | 247 | # If true, show page references after internal links. 248 | # latex_show_pagerefs = False 249 | 250 | # If true, show URL addresses after external links. 251 | # latex_show_urls = False 252 | 253 | # Documents to append as an appendix to all manuals. 254 | # latex_appendices = [] 255 | 256 | # If false, no module index is generated. 257 | # latex_domain_indices = True 258 | 259 | # -- External mapping ------------------------------------------------------------ 260 | python_version = '.'.join(map(str, sys.version_info[0:2])) 261 | intersphinx_mapping = { 262 | 'sphinx': ('http://www.sphinx-doc.org/en/stable', None), 263 | 'python': ('https://docs.python.org/' + python_version, None), 264 | 'matplotlib': ('https://matplotlib.org', None), 265 | 'numpy': ('https://docs.scipy.org/doc/numpy', None), 266 | 'sklearn': ('http://scikit-learn.org/stable', None), 267 | 'pandas': ('http://pandas.pydata.org/pandas-docs/stable', None), 268 | 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), 269 | } 270 | --------------------------------------------------------------------------------