Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff8588b286 | ||
|
|
998afd2675 | ||
|
|
c2b90a8748 | ||
|
|
d9fa05499b |
-100
@@ -1,100 +0,0 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# PyCharm IDE
|
||||
.idea/
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
# Workaround for testing Python 3.7:
|
||||
# https://github.com/travis-ci/travis-ci/issues/9815
|
||||
matrix:
|
||||
include:
|
||||
- python: 3.7
|
||||
dist: xenial
|
||||
sudo: yes
|
||||
before_install:
|
||||
- pip install --upgrade setuptools pip
|
||||
- pip install --upgrade pylint pytest pytest-pylint pytest-runner
|
||||
install:
|
||||
- pip install hypothesis
|
||||
- python setup.py develop
|
||||
script:
|
||||
- python -m pytest # Run the tests without IPython.
|
||||
- pip install ipython
|
||||
- python -m pytest # Now run the tests with IPython.
|
||||
- pylint fire --ignore=test_components_py3.py,parser_fuzz_test.py,console
|
||||
@@ -1,24 +0,0 @@
|
||||
# How to contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution,
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult [GitHub Help] for more
|
||||
information on using pull requests.
|
||||
|
||||
[GitHub Help]: https://help.github.com/articles/about-pull-requests/
|
||||
@@ -1,13 +0,0 @@
|
||||
Copyright 2017 Google Inc. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1 +0,0 @@
|
||||
include LICENSE
|
||||
@@ -1,98 +0,0 @@
|
||||
# Python Fire [](https://github.com/google/python-fire)
|
||||
_Python Fire is a library for automatically generating command line interfaces
|
||||
(CLIs) from absolutely any Python object._
|
||||
|
||||
- Python Fire is a simple way to create a CLI in Python. [[1]](docs/benefits.md#simple-cli)
|
||||
- Python Fire is a helpful tool for developing and debugging Python code. [[2]](docs/benefits.md#debugging)
|
||||
- Python Fire helps with exploring existing code or turning other people's code
|
||||
into a CLI. [[3]](docs/benefits.md#exploring)
|
||||
- Python Fire makes transitioning between Bash and Python easier. [[4]](docs/benefits.md#bash)
|
||||
- Python Fire makes using a Python REPL easier by setting up the REPL with the
|
||||
modules and variables you'll need already imported and created. [[5]](docs/benefits.md#repl)
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
To install Python Fire with pip, run: `pip install fire`
|
||||
|
||||
To install Python Fire with conda, run: `conda install fire -c conda-forge`
|
||||
|
||||
To install Python Fire from source, first clone the repository and then run:
|
||||
`python setup.py install`
|
||||
|
||||
|
||||
## Basic Usage
|
||||
|
||||
You can call `Fire` on any Python object:<br>
|
||||
functions, classes, modules, objects, dictionaries, lists, tuples, etc.
|
||||
They all work!
|
||||
|
||||
Here's an example of calling Fire on a class.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class Calculator(object):
|
||||
"""A simple calculator class."""
|
||||
|
||||
def double(self, number):
|
||||
return 2 * number
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Calculator)
|
||||
```
|
||||
|
||||
Then, from the command line, you can run:
|
||||
|
||||
```bash
|
||||
python calculator.py double 10 # 20
|
||||
python calculator.py double --number=15 # 30
|
||||
```
|
||||
|
||||
To learn how Fire behaves on functions, objects, dicts, lists, etc, and to learn
|
||||
about Fire's other features, see the [Using a Fire CLI page](docs/using-cli.md).
|
||||
|
||||
For additional examples, see [The Python Fire Guide](docs/guide.md).
|
||||
|
||||
|
||||
## Why is it called Fire?
|
||||
|
||||
When you call `Fire`, it fires off (executes) your command.
|
||||
|
||||
|
||||
## Where can I learn more?
|
||||
|
||||
Please see [The Python Fire Guide](docs/guide.md).
|
||||
|
||||
|
||||
## Reference
|
||||
|
||||
| Setup | Command | Notes
|
||||
| :------ | :------------------ | :---------
|
||||
| install | `pip install fire` |
|
||||
|
||||
| Creating a CLI | Command | Notes
|
||||
| :--------------| :--------------------- | :---------
|
||||
| import | `import fire` |
|
||||
| Call | `fire.Fire()` | Turns the current module into a Fire CLI.
|
||||
| Call | `fire.Fire(component)` | Turns `component` into a Fire CLI.
|
||||
|
||||
| Using a CLI | Command | Notes
|
||||
| :------------- | :------------------------- | :---------
|
||||
| [Help](docs/using-cli.md#help-flag) | `command -- --help` |
|
||||
| [REPL](docs/using-cli.md#interactive-flag) | `command -- --interactive` | Enters interactive mode.
|
||||
| [Separator](docs/using-cli.md#separator-flag) | `command -- --separator=X` | This sets the separator to `X`. The default separator is `-`.
|
||||
| [Completion](docs/using-cli.md#completion-flag) | `command -- --completion [shell]` | Generate a completion script for the CLI.
|
||||
| [Trace](docs/using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command.
|
||||
| [Verbose](docs/using-cli.md#verbose-flag) | `command -- --verbose` |
|
||||
|
||||
_Note that flags are separated from the Fire command by an isolated `--` arg._
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the
|
||||
[Apache 2.0](https://github.com/google/python-fire/blob/master/LICENSE) License.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is not an official Google product.
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||
<title>Reference - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "Reference";
|
||||
var mkdocs_page_input_path = "api.md";
|
||||
var mkdocs_page_url = "/api/";
|
||||
</script>
|
||||
|
||||
<script src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script src="../js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href=".." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="..">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href="./">Reference</a>
|
||||
<ul class="subnav">
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="..">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="..">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>Reference</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Setup</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">install</td>
|
||||
<td align="left"><code>pip install fire</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Creating a CLI</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">import</td>
|
||||
<td align="left"><code>import fire</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Call</td>
|
||||
<td align="left"><code>fire.Fire()</code></td>
|
||||
<td align="left">Turns the current module into a Fire CLI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Call</td>
|
||||
<td align="left"><code>fire.Fire(component)</code></td>
|
||||
<td align="left">Turns <code>component</code> into a Fire CLI.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Using a CLI</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#help-flag">Help</a></td>
|
||||
<td align="left"><code>command -- --help</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#interactive-flag">REPL</a></td>
|
||||
<td align="left"><code>command -- --interactive</code></td>
|
||||
<td align="left">Enters interactive mode.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#separator-flag">Separator</a></td>
|
||||
<td align="left"><code>command -- --separator=X</code></td>
|
||||
<td align="left">This sets the separator to <code>X</code>. The default separator is <code>-</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#completion-flag">Completion</a></td>
|
||||
<td align="left"><code>command -- --completion</code></td>
|
||||
<td align="left">Generate a completion script for the CLI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#trace-flag">Trace</a></td>
|
||||
<td align="left"><code>command -- --trace</code></td>
|
||||
<td align="left">Gets a Fire trace for the command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#verbose-flag">Verbose</a></td>
|
||||
<td align="left"><code>command -- --verbose</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><em>Note that flags are separated from the Fire command by an isolated <code>--</code> arg.</em></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
|
||||
<a href="../troubleshooting/" class="btn btn-neutral" title="Troubleshooting"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
<span><a href="../troubleshooting/" style="color: #fcfcfc;">« Previous</a></span>
|
||||
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="../js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||
<title>Benefits - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "Benefits";
|
||||
var mkdocs_page_input_path = "benefits.md";
|
||||
var mkdocs_page_url = "/benefits/";
|
||||
</script>
|
||||
|
||||
<script src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script src="../js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href=".." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="..">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href="./">Benefits</a>
|
||||
<ul class="subnav">
|
||||
|
||||
<li class="toctree-l2"><a href="#benefits-of-python-fire">Benefits of Python Fire</a></li>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><a class="toctree-l3" href="#create-clis-in-python">Create CLIs in Python</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#develop-and-debug-python-code">Develop and debug Python code</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#explore-existing-code-turn-other-peoples-code-into-a-cli">Explore existing code; turn other people's code into a CLI</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#transition-between-bash-and-python">Transition between Bash and Python</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#explore-code-in-a-python-repl">Explore code in a Python REPL</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="..">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="..">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>Benefits</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<h1 id="benefits-of-python-fire">Benefits of Python Fire</h1>
|
||||
<p><a name="simple-cli"></a></p>
|
||||
<h2 id="create-clis-in-python">Create CLIs in Python</h2>
|
||||
<p>It's dead simple. Simply write the functionality you want exposed at the command
|
||||
line as a function / module / class, and then call Fire. With this addition of a
|
||||
single-line call to Fire, your CLI is ready to go.</p>
|
||||
<p><a name="debugging"></a></p>
|
||||
<h2 id="develop-and-debug-python-code">Develop and debug Python code</h2>
|
||||
<p>When you're writing a Python library, you probably want to try it out as you go.
|
||||
You could write a main method to check the functionality you're interested in,
|
||||
but then you have to change the main method with every new experiment you're
|
||||
interested in testing, and constantly updating the main method is a hassle.
|
||||
You could also open an IPython REPL and import your library there and test it,
|
||||
but then you have to deal with reloading your imports every time you change
|
||||
something.</p>
|
||||
<p>If you simply call Fire in your library, then you can run all of it's
|
||||
functionality from the command line without having to keep making changes to
|
||||
a main method. And if you use the <code>--interactive</code> flag to enter an IPython REPL
|
||||
then you don't need to load the imports or create your variables; they'll
|
||||
already be ready for use as soon as you start the REPL.</p>
|
||||
<p><a name="exploring"></a></p>
|
||||
<h2 id="explore-existing-code-turn-other-peoples-code-into-a-cli">Explore existing code; turn other people's code into a CLI</h2>
|
||||
<p>You can take an existing module, maybe even one that you don't have access to
|
||||
the source code for, and call <code>Fire</code> on it. This lets you easily see what
|
||||
functionality this code exposes, without you having to read through all the
|
||||
code.</p>
|
||||
<p>This technique can be a very simple way to create very powerful CLIs. Call
|
||||
<code>Fire</code> on the difflib library and you get a powerful diffing tool. Call <code>Fire</code>
|
||||
on the Python Imaging Library (PIL) module and you get a powerful image
|
||||
manipulation command line tool, very similar in nature to ImageMagick.</p>
|
||||
<p>The auto-generated help strings that Fire provides when you run a Fire CLI
|
||||
allow you to see all the functionality these modules provide in a concise
|
||||
manner.</p>
|
||||
<p><a name="bash"></a></p>
|
||||
<h2 id="transition-between-bash-and-python">Transition between Bash and Python</h2>
|
||||
<p>Using Fire lets you call Python directly from Bash. So you can mix your Python
|
||||
functions with the unix tools you know and love, like <code>grep</code>, <code>xargs</code>, <code>wc</code>,
|
||||
etc.</p>
|
||||
<p>Additionally since writing CLIs in Python requires only a single call to Fire,
|
||||
it is now easy to write even one-off scripts that would previously have been in
|
||||
Bash, in Python.</p>
|
||||
<p><a name="repl"></a></p>
|
||||
<h2 id="explore-code-in-a-python-repl">Explore code in a Python REPL</h2>
|
||||
<p>When you use the <code>--interactive</code> flag to enter an IPython REPL, it starts with
|
||||
variables and modules already defined for you. You don't need to waste time
|
||||
importing the modules you care about or defining the variables you're going to
|
||||
use, since Fire has already done so for you.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
<a href="../guide/" class="btn btn-neutral float-right" title="The Python Fire Guide">Next <span class="icon icon-circle-arrow-right"></span></a>
|
||||
|
||||
|
||||
<a href="../installation/" class="btn btn-neutral" title="Installation"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
<span><a href="../installation/" style="color: #fcfcfc;">« Previous</a></span>
|
||||
|
||||
|
||||
<span style="margin-left: 15px"><a href="../guide/" style="color: #fcfcfc">Next »</a></span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="../js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
This is the GitHub theme for highlight.js
|
||||
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
color: #333;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.diff .hljs-header,
|
||||
.hljs-javadoc {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.css .rule .hljs-keyword,
|
||||
.hljs-winutils,
|
||||
.nginx .hljs-title,
|
||||
.hljs-subst,
|
||||
.hljs-request,
|
||||
.hljs-status {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-hexcolor,
|
||||
.ruby .hljs-constant {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-tag .hljs-value,
|
||||
.hljs-phpdoc,
|
||||
.hljs-dartdoc,
|
||||
.tex .hljs-formula {
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-id,
|
||||
.scss .hljs-preprocessor {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-list .hljs-keyword,
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-type,
|
||||
.vhdl .hljs-literal,
|
||||
.tex .hljs-command {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-tag .hljs-title,
|
||||
.hljs-rule .hljs-property,
|
||||
.django .hljs-tag .hljs-keyword {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-attribute,
|
||||
.hljs-variable,
|
||||
.lisp .hljs-body,
|
||||
.hljs-name {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-regexp {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.ruby .hljs-symbol .hljs-string,
|
||||
.lisp .hljs-keyword,
|
||||
.clojure .hljs-keyword,
|
||||
.scheme .hljs-keyword,
|
||||
.tex .hljs-special,
|
||||
.hljs-prompt {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-preprocessor,
|
||||
.hljs-pragma,
|
||||
.hljs-pi,
|
||||
.hljs-doctype,
|
||||
.hljs-shebang,
|
||||
.hljs-cdata {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #fdd;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #dfd;
|
||||
}
|
||||
|
||||
.diff .hljs-change {
|
||||
background: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-chunk {
|
||||
color: #aaa;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Sphinx doesn't have support for section dividers like we do in
|
||||
* MkDocs, this styles the section titles in the nav
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/175
|
||||
*/
|
||||
.wy-menu-vertical span {
|
||||
line-height: 18px;
|
||||
padding: 0.4045em 1.618em;
|
||||
display: block;
|
||||
position: relative;
|
||||
font-size: 90%;
|
||||
color: #838383;
|
||||
}
|
||||
|
||||
.wy-menu-vertical .subnav a {
|
||||
padding: 0.4045em 2.427em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Long navigations run off the bottom of the screen as the nav
|
||||
* area doesn't scroll.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/pull/202
|
||||
*
|
||||
* Builds upon pull 202 https://github.com/mkdocs/mkdocs/pull/202
|
||||
* to make toc scrollbar end before navigations buttons to not be overlapping.
|
||||
*/
|
||||
.wy-nav-side {
|
||||
height: calc(100% - 45px);
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.rst-versions{
|
||||
border-top: 0;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.wy-nav-side {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* readthedocs theme hides nav items when the window height is
|
||||
* too small to contain them.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/#348
|
||||
*/
|
||||
.wy-menu-vertical ul {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrap inline code samples otherwise they shoot of the side and
|
||||
* can't be read at all.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/313
|
||||
* https://github.com/mkdocs/mkdocs/issues/233
|
||||
* https://github.com/mkdocs/mkdocs/issues/834
|
||||
*/
|
||||
code {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make code blocks display as blocks and give them the appropriate
|
||||
* font size and padding.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/855
|
||||
* https://github.com/mkdocs/mkdocs/issues/834
|
||||
* https://github.com/mkdocs/mkdocs/issues/233
|
||||
*/
|
||||
pre code {
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
display: block;
|
||||
padding: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix link colors when the link text is inline code.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/718
|
||||
*/
|
||||
a code {
|
||||
color: #2980B9;
|
||||
}
|
||||
a:hover code {
|
||||
color: #3091d1;
|
||||
}
|
||||
a:visited code {
|
||||
color: #9B59B6;
|
||||
}
|
||||
|
||||
/*
|
||||
* The CSS classes from highlight.js seem to clash with the
|
||||
* ReadTheDocs theme causing some code to be incorrectly made
|
||||
* bold and italic.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/411
|
||||
*/
|
||||
pre .cs, pre .c {
|
||||
font-weight: inherit;
|
||||
font-style: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix some issues with the theme and non-highlighted code
|
||||
* samples. Without and highlighting styles attached the
|
||||
* formatting is broken.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/319
|
||||
*/
|
||||
.no-highlight {
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Additions specific to the search functionality provided by MkDocs
|
||||
*/
|
||||
|
||||
.search-results article {
|
||||
margin-top: 23px;
|
||||
border-top: 1px solid #E1E4E5;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.search-results article:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
form .search-query {
|
||||
width: 100%;
|
||||
border-radius: 50px;
|
||||
padding: 6px 12px; /* csslint allow: box-model */
|
||||
border-color: #D1D4D5;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li ul {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li ul.subnav ul.subnav{
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.wy-menu-vertical .subnav li.current > a {
|
||||
padding-left: 2.42em;
|
||||
}
|
||||
.wy-menu-vertical .subnav li.current > ul li a {
|
||||
padding-left: 3.23em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Improve inline code blocks within admonitions.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/656
|
||||
*/
|
||||
.admonition code {
|
||||
color: #404040;
|
||||
border: 1px solid #c7c9cb;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
background: #f8fbfd;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
/*
|
||||
* Account for wide tables which go off the side.
|
||||
* Override borders to avoid wierdness on narrow tables.
|
||||
*
|
||||
* https://github.com/mkdocs/mkdocs/issues/834
|
||||
* https://github.com/mkdocs/mkdocs/pull/1034
|
||||
*/
|
||||
.rst-content .section .docutils {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
display: block;
|
||||
border: none;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 1px solid #e1e4e5 !important; /* csslint allow: important */
|
||||
border-collapse: collapse;
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
| Setup | Command | Notes
|
||||
| :------ | :------------------ | :---------
|
||||
| install | `pip install fire` |
|
||||
|
||||
| Creating a CLI | Command | Notes
|
||||
| :--------------| :--------------------- | :---------
|
||||
| import | `import fire` |
|
||||
| Call | `fire.Fire()` | Turns the current module into a Fire CLI.
|
||||
| Call | `fire.Fire(component)` | Turns `component` into a Fire CLI.
|
||||
|
||||
| Using a CLI | Command | Notes
|
||||
| :------------- | :------------------------- | :---------
|
||||
| [Help](using-cli.md#help-flag) | `command -- --help` |
|
||||
| [REPL](using-cli.md#interactive-flag) | `command -- --interactive` | Enters interactive mode.
|
||||
| [Separator](using-cli.md#separator-flag) | `command -- --separator=X` | This sets the separator to `X`. The default separator is `-`.
|
||||
| [Completion](using-cli.md#completion-flag) | `command -- --completion [shell]` | Generate a completion script for the CLI.
|
||||
| [Trace](using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command.
|
||||
| [Verbose](using-cli.md#verbose-flag) | `command -- --verbose` |
|
||||
|
||||
_Note that flags are separated from the Fire command by an isolated `--` arg._
|
||||
@@ -1,61 +0,0 @@
|
||||
# Benefits of Python Fire
|
||||
|
||||
<a name="simple-cli"></a>
|
||||
## Create CLIs in Python
|
||||
|
||||
It's dead simple. Simply write the functionality you want exposed at the command
|
||||
line as a function / module / class, and then call Fire. With this addition of a
|
||||
single-line call to Fire, your CLI is ready to go.
|
||||
|
||||
<a name="debugging"></a>
|
||||
## Develop and debug Python code
|
||||
|
||||
When you're writing a Python library, you probably want to try it out as you go.
|
||||
You could write a main method to check the functionality you're interested in,
|
||||
but then you have to change the main method with every new experiment you're
|
||||
interested in testing, and constantly updating the main method is a hassle.
|
||||
You could also open an IPython REPL and import your library there and test it,
|
||||
but then you have to deal with reloading your imports every time you change
|
||||
something.
|
||||
|
||||
If you simply call Fire in your library, then you can run all of it's
|
||||
functionality from the command line without having to keep making changes to
|
||||
a main method. And if you use the `--interactive` flag to enter an IPython REPL
|
||||
then you don't need to load the imports or create your variables; they'll
|
||||
already be ready for use as soon as you start the REPL.
|
||||
|
||||
<a name="exploring"></a>
|
||||
## Explore existing code; turn other people's code into a CLI
|
||||
|
||||
You can take an existing module, maybe even one that you don't have access to
|
||||
the source code for, and call `Fire` on it. This lets you easily see what
|
||||
functionality this code exposes, without you having to read through all the
|
||||
code.
|
||||
|
||||
This technique can be a very simple way to create very powerful CLIs. Call
|
||||
`Fire` on the difflib library and you get a powerful diffing tool. Call `Fire`
|
||||
on the Python Imaging Library (PIL) module and you get a powerful image
|
||||
manipulation command line tool, very similar in nature to ImageMagick.
|
||||
|
||||
The auto-generated help strings that Fire provides when you run a Fire CLI
|
||||
allow you to see all the functionality these modules provide in a concise
|
||||
manner.
|
||||
|
||||
<a name="bash"></a>
|
||||
## Transition between Bash and Python
|
||||
|
||||
Using Fire lets you call Python directly from Bash. So you can mix your Python
|
||||
functions with the unix tools you know and love, like `grep`, `xargs`, `wc`,
|
||||
etc.
|
||||
|
||||
Additionally since writing CLIs in Python requires only a single call to Fire,
|
||||
it is now easy to write even one-off scripts that would previously have been in
|
||||
Bash, in Python.
|
||||
|
||||
<a name="repl"></a>
|
||||
## Explore code in a Python REPL
|
||||
|
||||
When you use the `--interactive` flag to enter an IPython REPL, it starts with
|
||||
variables and modules already defined for you. You don't need to waste time
|
||||
importing the modules you care about or defining the variables you're going to
|
||||
use, since Fire has already done so for you.
|
||||
-714
@@ -1,714 +0,0 @@
|
||||
## The Python Fire Guide
|
||||
|
||||
### Introduction
|
||||
|
||||
Welcome to the Python Fire guide! Python Fire is a Python library that will turn
|
||||
any Python component into a command line interface with just a single call to
|
||||
`Fire`.
|
||||
|
||||
Let's get started!
|
||||
|
||||
### Installation
|
||||
|
||||
To install Python Fire from pypi, run:
|
||||
|
||||
`pip install fire`
|
||||
|
||||
Alternatively, to install Python Fire from source, clone the source and run:
|
||||
|
||||
`python setup.py install`
|
||||
|
||||
### Hello World
|
||||
|
||||
##### Version 1: `fire.Fire()`
|
||||
|
||||
The easiest way to use Fire is to take any Python program, and then simply call
|
||||
`fire.Fire()` at the end of the program. This will expose the full contents of
|
||||
the program to the command line.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire()
|
||||
```
|
||||
|
||||
Here's how we can run our program from the command line:
|
||||
|
||||
```bash
|
||||
$ python example.py hello World
|
||||
Hello World!
|
||||
```
|
||||
|
||||
##### Version 2: `fire.Fire(<fn>)`
|
||||
|
||||
Let's modify our program slightly to only expose the `hello` function to the
|
||||
command line.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(hello)
|
||||
```
|
||||
|
||||
Here's how we can run this from the command line:
|
||||
|
||||
```bash
|
||||
$ python example.py World
|
||||
Hello World!
|
||||
```
|
||||
|
||||
Notice we no longer have to specify to run the `hello` function, because we
|
||||
called `fire.Fire(hello)`.
|
||||
|
||||
##### Version 3: Using a main
|
||||
|
||||
We can alternatively write this program like this:
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
def main():
|
||||
fire.Fire(hello)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
Or if we're using
|
||||
[entry points](https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points),
|
||||
then simply this:
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
def main():
|
||||
fire.Fire(hello)
|
||||
```
|
||||
|
||||
### Exposing Multiple Commands
|
||||
|
||||
In the previous example, we exposed a single function to the command line. Now
|
||||
we'll look at ways of exposing multiple functions to the command line.
|
||||
|
||||
##### Version 1: `fire.Fire()`
|
||||
|
||||
The simplest way to expose multiple commands is to write multiple functions, and
|
||||
then call Fire.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire()
|
||||
```
|
||||
|
||||
We can use this like so:
|
||||
|
||||
```bash
|
||||
$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
```
|
||||
|
||||
You'll notice that Fire correctly parsed `10` and `20` as numbers, rather than
|
||||
as strings. Read more about [argument parsing here](#argument-parsing).
|
||||
|
||||
##### Version 2: `fire.Fire(<dict>)`
|
||||
|
||||
In version 1 we exposed all the program's functionality to the command line. By
|
||||
using a dict, we can selectively expose functions to the command line.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire({
|
||||
'add': add,
|
||||
'multiply': multiply,
|
||||
})
|
||||
```
|
||||
|
||||
We can use this in the same way as before:
|
||||
|
||||
```bash
|
||||
$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
```
|
||||
|
||||
##### Version 3: `fire.Fire(<object>)`
|
||||
|
||||
Fire also works on objects, as in this variant. This is a good way to expose
|
||||
multiple commands.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class Calculator(object):
|
||||
|
||||
def add(self, x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
calculator = Calculator()
|
||||
fire.Fire(calculator)
|
||||
```
|
||||
|
||||
We can use this in the same way as before:
|
||||
|
||||
```bash
|
||||
$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
```
|
||||
|
||||
|
||||
##### Version 4: `fire.Fire(<class>)`
|
||||
|
||||
Fire also works on classes. This is another good way to expose multiple
|
||||
commands.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class Calculator(object):
|
||||
|
||||
def add(self, x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Calculator)
|
||||
```
|
||||
|
||||
We can use this in the same way as before:
|
||||
|
||||
```bash
|
||||
$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
```
|
||||
|
||||
Why might you prefer a class over an object? One reason is that you can pass
|
||||
arguments for constructing the class too, as in this broken calculator example.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class BrokenCalculator(object):
|
||||
|
||||
def __init__(self, offset=1):
|
||||
self._offset = offset
|
||||
|
||||
def add(self, x, y):
|
||||
return x + y + self._offset
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y + self._offset
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(BrokenCalculator)
|
||||
```
|
||||
|
||||
When you use a broken calculator, you get wrong answers:
|
||||
|
||||
```bash
|
||||
$ python example.py add 10 20
|
||||
31
|
||||
$ python example.py multiply 10 20
|
||||
201
|
||||
```
|
||||
|
||||
But you can always fix it:
|
||||
|
||||
```bash
|
||||
$ python example.py add 10 20 --offset=0
|
||||
30
|
||||
$ python example.py multiply 10 20 --offset=0
|
||||
200
|
||||
```
|
||||
|
||||
Unlike calling ordinary functions, which can be done both with positional
|
||||
arguments and named arguments (--flag syntax), arguments to \_\_init\_\_
|
||||
functions must be passed with the --flag syntax. See the section on
|
||||
[calling functions](#calling-functions) for more.
|
||||
|
||||
### Grouping Commands
|
||||
|
||||
Here's an example of how you might make a command line interface with grouped
|
||||
commands.
|
||||
|
||||
```python
|
||||
class IngestionStage(object):
|
||||
|
||||
def run(self):
|
||||
return 'Ingesting! Nom nom nom...'
|
||||
|
||||
class DigestionStage(object):
|
||||
|
||||
def run(self, volume=1):
|
||||
return ' '.join(['Burp!'] * volume)
|
||||
|
||||
def status(self):
|
||||
return 'Satiated.'
|
||||
|
||||
class Pipeline(object):
|
||||
|
||||
def __init__(self):
|
||||
self.ingestion = IngestionStage()
|
||||
self.digestion = DigestionStage()
|
||||
|
||||
def run(self):
|
||||
self.ingestion.run()
|
||||
self.digestion.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Pipeline)
|
||||
```
|
||||
|
||||
Here's how this looks at the command line:
|
||||
|
||||
```bash
|
||||
$ python example.py run
|
||||
Ingesting! Nom nom nom...
|
||||
Burp!
|
||||
$ python example.py ingestion run
|
||||
Ingesting! Nom nom nom...
|
||||
$ python example.py digestion run
|
||||
Burp!
|
||||
$ python example.py digestion status
|
||||
Satiated.
|
||||
```
|
||||
|
||||
You can nest your commands in arbitrarily complex ways, if you're feeling grumpy
|
||||
or adventurous.
|
||||
|
||||
|
||||
### Accessing Properties
|
||||
|
||||
In the examples we've looked at so far, our invocations of `python example.py`
|
||||
have all run some function from the example program. In this example, we simply
|
||||
access a property.
|
||||
|
||||
```python
|
||||
from airports import airports
|
||||
|
||||
import fire
|
||||
|
||||
class Airport(object):
|
||||
|
||||
def __init__(self, code):
|
||||
self.code = code
|
||||
self.name = dict(airports).get(self.code)
|
||||
self.city = self.name.split(',')[0] if self.name else None
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Airport)
|
||||
```
|
||||
|
||||
Now we can use this program to learn about airport codes!
|
||||
|
||||
```bash
|
||||
$ python example.py --code=JFK code
|
||||
JFK
|
||||
$ python example.py --code=SJC name
|
||||
San Jose-Sunnyvale-Santa Clara, CA - Norman Y. Mineta San Jose International (SJC)
|
||||
$ python example.py --code=ALB city
|
||||
Albany-Schenectady-Troy
|
||||
```
|
||||
|
||||
By the way, you can find this
|
||||
[airports module here](https://github.com/trendct-data/airports.py).
|
||||
|
||||
### Chaining Function Calls
|
||||
|
||||
When you run a Fire CLI, you can take all the same actions on the _result_ of
|
||||
the call to Fire that you can take on the original object passed in.
|
||||
|
||||
For example, we can use our Airport CLI from the previous example like this:
|
||||
|
||||
```bash
|
||||
$ python example.py --code=ALB city upper
|
||||
ALBANY-SCHENECTADY-TROY
|
||||
```
|
||||
|
||||
This works since `upper` is a method on all strings.
|
||||
|
||||
So, if you want to set up your functions to chain nicely, all you have to do is
|
||||
have a class whose methods return self. Here's an example.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class BinaryCanvas(object):
|
||||
"""A canvas with which to make binary art, one bit at a time."""
|
||||
|
||||
def __init__(self, size=10):
|
||||
self.pixels = [[0] * size for _ in range(size)]
|
||||
self._size = size
|
||||
self._row = 0 # The row of the cursor.
|
||||
self._col = 0 # The column of the cursor.
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(' '.join(str(pixel) for pixel in row) for row in self.pixels)
|
||||
|
||||
def show(self):
|
||||
print(self)
|
||||
return self
|
||||
|
||||
def move(self, row, col):
|
||||
self._row = row % self._size
|
||||
self._col = col % self._size
|
||||
return self
|
||||
|
||||
def on(self):
|
||||
return self.set(1)
|
||||
|
||||
def off(self):
|
||||
return self.set(0)
|
||||
|
||||
def set(self, value):
|
||||
self.pixels[self._row][self._col] = value
|
||||
return self
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(BinaryCanvas)
|
||||
```
|
||||
|
||||
Now we can draw stuff :).
|
||||
|
||||
```bash
|
||||
$ python example.py move 3 3 on move 3 6 on move 6 3 on move 6 6 on move 7 4 on move 7 5 on __str__
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 1 0 0 1 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 1 0 0 1 0 0 0
|
||||
0 0 0 0 1 1 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
It's supposed to be a smiley face.
|
||||
|
||||
### Can we make an even simpler example than Hello World?
|
||||
|
||||
Yes, this program is even simpler than our original Hello World example.
|
||||
|
||||
```python
|
||||
import fire
|
||||
english = 'Hello World'
|
||||
spanish = 'Hola Mundo'
|
||||
fire.Fire()
|
||||
```
|
||||
|
||||
You can use it like this:
|
||||
|
||||
```bash
|
||||
$ python example.py english
|
||||
Hello World
|
||||
$ python example.py spanish
|
||||
Hola Mundo
|
||||
```
|
||||
|
||||
### Calling Functions
|
||||
|
||||
Arguments to a constructor are passed by name using flag syntax `--name=value`.
|
||||
|
||||
For example, consider this simple class:
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class Building(object):
|
||||
|
||||
def __init__(self, name, stories=1):
|
||||
self.name = name
|
||||
self.stories = stories
|
||||
|
||||
def climb_stairs(self, stairs_per_story=10):
|
||||
for story in range(self.stories):
|
||||
for stair in range(1, stairs_per_story):
|
||||
yield stair
|
||||
yield 'Phew!'
|
||||
yield 'Done!'
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Building)
|
||||
```
|
||||
|
||||
We can instantiate it as follows: `python example.py --name="Sherrerd Hall"`
|
||||
|
||||
Arguments to other functions may be passed positionally or by name using flag
|
||||
syntax.
|
||||
|
||||
To instantiate a `Building` and then run the `climb_stairs` function, the
|
||||
following commands are all valid:
|
||||
|
||||
```bash
|
||||
$ python example.py --name="Sherrerd Hall" --stories=3 climb_stairs 10
|
||||
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs_per_story=10
|
||||
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs-per-story 10
|
||||
$ python example.py climb-stairs --stairs-per-story 10 --name="Sherrerd Hall"
|
||||
```
|
||||
|
||||
You'll notice that hyphens and underscores (`-` and `_`) are interchangeable in
|
||||
member names and flag names.
|
||||
|
||||
You'll also notice that the constructor's arguments can come after the
|
||||
function's arguments or before the function.
|
||||
|
||||
You'll also notice that the equal sign between the flag name and its value is
|
||||
optional.
|
||||
|
||||
##### Functions with `*varargs` and `**kwargs`
|
||||
|
||||
Fire supports functions that take \*varargs or \*\*kwargs. Here's an example:
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
def order_by_length(*items):
|
||||
"""Orders items by length, breaking ties alphabetically."""
|
||||
sorted_items = sorted(items, key=lambda item: (len(str(item)), str(item)))
|
||||
return ' '.join(sorted_items)
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(order_by_length)
|
||||
```
|
||||
|
||||
To use it, we run:
|
||||
|
||||
```bash
|
||||
$ python example.py dog cat elephant
|
||||
cat dog elephant
|
||||
```
|
||||
|
||||
You can use a separator to indicate that you're done providing arguments to a
|
||||
function. All arguments after the separator will be used to process the result
|
||||
of the function, rather than being passed to the function itself. The default
|
||||
separator is the hyphen `-`.
|
||||
|
||||
Here's an example where we use a separator.
|
||||
|
||||
```bash
|
||||
$ python example.py dog cat elephant - upper
|
||||
CAT DOG ELEPHANT
|
||||
```
|
||||
|
||||
Without the separator, upper would have been treated as another argument.
|
||||
|
||||
```bash
|
||||
$ python example.py dog cat elephant upper
|
||||
cat dog upper elephant
|
||||
```
|
||||
|
||||
You can change the separator with the `--separator` flag. Flags are always
|
||||
separated from your Fire command by an isolated `--`. Here's an example where we
|
||||
change the separator.
|
||||
|
||||
```bash
|
||||
$ python example.py dog cat elephant X upper -- --separator=X
|
||||
CAT DOG ELEPHANT
|
||||
```
|
||||
|
||||
Separators can be useful when a function accepts \*varargs, \*\*kwargs, or
|
||||
default values that you don't want to specify. It is also important to remember
|
||||
to change the separator if you want to pass `-` as an argument.
|
||||
|
||||
|
||||
### Argument Parsing
|
||||
|
||||
The types of the arguments are determined by their values, rather than by the
|
||||
function signature where they're used. You can pass any Python literal from the
|
||||
command line: numbers, strings, tuples, lists, dictionaries, (sets are only
|
||||
supported in some versions of Python). You can also nest the collections
|
||||
arbitrarily as long as they only contain literals.
|
||||
|
||||
To demonstrate this, we'll make a small example program that tells us the type
|
||||
of any argument we give it:
|
||||
|
||||
```python
|
||||
import fire
|
||||
fire.Fire(lambda obj: type(obj).__name__)
|
||||
```
|
||||
|
||||
And we'll use it like so:
|
||||
|
||||
```bash
|
||||
$ python example.py 10
|
||||
int
|
||||
$ python example.py 10.0
|
||||
float
|
||||
$ python example.py hello
|
||||
str
|
||||
$ python example.py '(1,2)'
|
||||
tuple
|
||||
$ python example.py [1,2]
|
||||
list
|
||||
$ python example.py True
|
||||
bool
|
||||
$ python example.py {name: David}
|
||||
dict
|
||||
```
|
||||
|
||||
You'll notice in that last example that bare-words are automatically replaced
|
||||
with strings.
|
||||
|
||||
Be careful with your quotes! If you want to pass the string `"10"`, rather than
|
||||
the int `10`, you'll need to either escape or quote your quotes. Otherwise Bash
|
||||
will eat your quotes and pass an unquoted `10` to your Python program, where
|
||||
Fire will interpret it as a number.
|
||||
|
||||
|
||||
```bash
|
||||
$ python example.py 10
|
||||
int
|
||||
$ python example.py "10"
|
||||
int
|
||||
$ python example.py '"10"'
|
||||
str
|
||||
$ python example.py "'10'"
|
||||
str
|
||||
$ python example.py \"10\"
|
||||
str
|
||||
```
|
||||
|
||||
Be careful with your quotes! Remember that Bash processes your arguments first,
|
||||
and then Fire parses the result of that.
|
||||
If you wanted to pass the dict `{"name": "David Bieber"}` to your program, you
|
||||
might try this:
|
||||
|
||||
```bash
|
||||
$ python example.py '{"name": "David Bieber"}' # Good! Do this.
|
||||
dict
|
||||
$ python example.py {"name":'"David Bieber"'} # Okay.
|
||||
dict
|
||||
$ python example.py {"name":"David Bieber"} # Wrong. This is parsed as a string.
|
||||
str
|
||||
$ python example.py {"name": "David Bieber"} # Wrong. This isn't even treated as a single argument.
|
||||
<error>
|
||||
$ python example.py '{"name": "Justin Bieber"}' # Wrong. This is not the Bieber you're looking for. (The syntax is fine though :))
|
||||
dict
|
||||
```
|
||||
|
||||
##### Boolean Arguments
|
||||
|
||||
The tokens `True` and `False` are parsed as boolean values.
|
||||
|
||||
You may also specify booleans via flag syntax `--name` and `--noname`, which set
|
||||
`name` to `True` and `False` respectively.
|
||||
|
||||
Continuing the previous example, we could run any of the following:
|
||||
|
||||
```bash
|
||||
$ python example.py --obj=True
|
||||
bool
|
||||
$ python example.py --obj=False
|
||||
bool
|
||||
$ python example.py --obj
|
||||
bool
|
||||
$ python example.py --noobj
|
||||
bool
|
||||
```
|
||||
|
||||
Be careful with boolean flags! If a token other than another flag immediately
|
||||
follows a flag that's supposed to be a boolean, the flag will take on the value
|
||||
of the token rather than the boolean value. You can resolve this: by putting a
|
||||
separator after your last flag, by explicitly stating the value of the boolean
|
||||
flag (as in `--obj=True`), or by making sure there's another flag after any
|
||||
boolean flag argument.
|
||||
|
||||
|
||||
### Using Fire Flags
|
||||
|
||||
Fire CLIs all come with a number of flags. These flags should be separated from
|
||||
the Fire command by an isolated `--`. If there is at least one isolated `--`
|
||||
argument, then arguments after the final isolated `--` are treated as flags,
|
||||
whereas all arguments before the final isolated `--` are considered part of the
|
||||
Fire command.
|
||||
|
||||
One useful flag is the `--interactive` flag. Use the `--interactive` flag on any
|
||||
CLI to enter a Python REPL with all the modules and variables used in the
|
||||
context where `Fire` was called already available to you for use. Other useful
|
||||
variables, such as the result of the Fire command will also be available. Use
|
||||
this feature like this: `python example.py -- --interactive`.
|
||||
|
||||
You can add the help flag to any command to see help and usage information. Fire
|
||||
incorporates your docstrings into the help and usage information that it
|
||||
generates. Fire will try to provide help even if you omit the isolated `--`
|
||||
separating the flags from the Fire command, but may not always be able to, since
|
||||
`help` is a valid argument name. Use this feature like this:
|
||||
`python example.py -- --help`.
|
||||
|
||||
The complete set of flags available is shown below, in the reference section.
|
||||
|
||||
|
||||
### Reference
|
||||
|
||||
| Setup | Command | Notes
|
||||
| :------ | :------------------ | :---------
|
||||
| install | `pip install fire` |
|
||||
|
||||
##### Creating a CLI
|
||||
|
||||
| Creating a CLI | Command | Notes
|
||||
| :--------------| :--------------------- | :---------
|
||||
| import | `import fire` |
|
||||
| Call | `fire.Fire()` | Turns the current module into a Fire CLI.
|
||||
| Call | `fire.Fire(component)` | Turns `component` into a Fire CLI.
|
||||
|
||||
##### Flags
|
||||
|
||||
| Using a CLI | Command | Notes
|
||||
| :------------- | :------------------------- | :---------
|
||||
| [Help](using-cli.md#help-flag) | `command -- --help` | Show help and usage information for the command.
|
||||
| [REPL](using-cli.md#interactive-flag) | `command -- --interactive` | Enter interactive mode.
|
||||
| [Separator](using-cli.md#separator-flag) | `command -- --separator=X` | This sets the separator to `X`. The default separator is `-`.
|
||||
| [Completion](using-cli.md#completion-flag) | `command -- --completion [shell]` | Generate a completion script for the CLI.
|
||||
| [Trace](using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command.
|
||||
| [Verbose](using-cli.md#verbose-flag) | `command -- --verbose` | Include private members in the output.
|
||||
|
||||
_Note that flags are separated from the Fire command by an isolated `--` arg._
|
||||
|
||||
|
||||
### Disclaimer
|
||||
|
||||
Python Fire is not an official Google product.
|
||||
@@ -1,98 +0,0 @@
|
||||
# Python Fire [](https://github.com/google/python-fire)
|
||||
_Python Fire is a library for automatically generating command line interfaces
|
||||
(CLIs) from absolutely any Python object._
|
||||
|
||||
- Python Fire is a simple way to create a CLI in Python. [[1]](benefits.md#simple-cli)
|
||||
- Python Fire is a helpful tool for developing and debugging Python code. [[2]](benefits.md#debugging)
|
||||
- Python Fire helps with exploring existing code or turning other people's code
|
||||
into a CLI. [[3]](benefits.md#exploring)
|
||||
- Python Fire makes transitioning between Bash and Python easier. [[4]](benefits.md#bash)
|
||||
- Python Fire makes using a Python REPL easier by setting up the REPL with the
|
||||
modules and variables you'll need already imported and created. [[5]](benefits.md#repl)
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
To install Python Fire with pip, run: `pip install fire`
|
||||
|
||||
To install Python Fire with conda, run: `conda install fire -c conda-forge`
|
||||
|
||||
To install Python Fire from source, first clone the repository and then run:
|
||||
`python setup.py install`
|
||||
|
||||
|
||||
## Basic Usage
|
||||
|
||||
You can call `Fire` on any Python object:<br>
|
||||
functions, classes, modules, objects, dictionaries, lists, tuples, etc.
|
||||
They all work!
|
||||
|
||||
Here's an example of calling Fire on a class.
|
||||
|
||||
```python
|
||||
import fire
|
||||
|
||||
class Calculator(object):
|
||||
"""A simple calculator class."""
|
||||
|
||||
def double(self, number):
|
||||
return 2 * number
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Calculator)
|
||||
```
|
||||
|
||||
Then, from the command line, you can run:
|
||||
|
||||
```bash
|
||||
python calculator.py double 10 # 20
|
||||
python calculator.py double --number=15 # 30
|
||||
```
|
||||
|
||||
To learn how Fire behaves on functions, objects, dicts, lists, etc, and to learn
|
||||
about Fire's other features, see the [Using a Fire CLI page](using-cli.md).
|
||||
|
||||
For additional examples, see [The Python Fire Guide](guide.md).
|
||||
|
||||
|
||||
## Why is it called Fire?
|
||||
|
||||
When you call `Fire`, it fires off (executes) your command.
|
||||
|
||||
|
||||
## Where can I learn more?
|
||||
|
||||
Please see [The Python Fire Guide](guide.md).
|
||||
|
||||
|
||||
## Reference
|
||||
|
||||
| Setup | Command | Notes
|
||||
| :------ | :------------------ | :---------
|
||||
| install | `pip install fire` |
|
||||
|
||||
| Creating a CLI | Command | Notes
|
||||
| :--------------| :--------------------- | :---------
|
||||
| import | `import fire` |
|
||||
| Call | `fire.Fire()` | Turns the current module into a Fire CLI.
|
||||
| Call | `fire.Fire(component)` | Turns `component` into a Fire CLI.
|
||||
|
||||
| Using a CLI | Command | Notes
|
||||
| :------------- | :------------------------- | :---------
|
||||
| [Help](using-cli.md#help-flag) | `command -- --help` |
|
||||
| [REPL](using-cli.md#interactive-flag) | `command -- --interactive` | Enters interactive mode.
|
||||
| [Separator](using-cli.md#separator-flag) | `command -- --separator=X` | This sets the separator to `X`. The default separator is `-`.
|
||||
| [Completion](using-cli.md#completion-flag) | `command -- --completion [shell]` | Generate a completion script for the CLI.
|
||||
| [Trace](using-cli.md#trace-flag) | `command -- --trace` | Gets a Fire trace for the command.
|
||||
| [Verbose](using-cli.md#verbose-flag) | `command -- --verbose` |
|
||||
|
||||
_Note that flags are separated from the Fire command by an isolated `--` arg._
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the
|
||||
[Apache 2.0](https://github.com/google/python-fire/blob/master/LICENSE) License.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is not an official Google product.
|
||||
@@ -1,8 +0,0 @@
|
||||
# Installation
|
||||
|
||||
To install Python Fire with pip, run: `pip install fire`
|
||||
|
||||
To install Python Fire with conda, run: `conda install fire -c conda-forge`
|
||||
|
||||
To install Python Fire from source, first clone the repository and then run:
|
||||
`python setup.py install`
|
||||
@@ -1,13 +0,0 @@
|
||||
# Troubleshooting
|
||||
|
||||
This page describes known issues that users of Python Fire have run into. If you
|
||||
have an issue not resolved here, consider opening a
|
||||
[GitHub Issue](https://github.com/google/python-fire/issues).
|
||||
|
||||
### Issue [#19](https://github.com/google/python-fire/issues/19): Don't name your module "cmd"
|
||||
|
||||
If you have a module name that conflicts with the name of a builtin module, then
|
||||
when Fire goes to import the builtin module, it will import your module instead.
|
||||
This will result in an error, possibly an `AttributeError`. Specifically, do not
|
||||
name your module any of the following:
|
||||
sys, linecache, cmd, bdb, repr, os, re, pprint, traceback
|
||||
@@ -1,224 +0,0 @@
|
||||
# Using a Fire CLI
|
||||
|
||||
## Basic usage
|
||||
|
||||
Every Fire command corresponds to a Python component.
|
||||
|
||||
The simplest Fire command consists of running your program with no additional
|
||||
arguments. This command corresponds to the Python component you called the
|
||||
`Fire` function on. If you did not supply an object in the call to `Fire`, then
|
||||
the context in which `Fire` was called will be used as the Python component.
|
||||
|
||||
You can append `-- --help` to any command to see what Python component it
|
||||
corresponds to, as well as the various ways in which you can extend the command.
|
||||
Flags are always separated from the Fire command by an isolated `--` in order
|
||||
to distinguish between flags and named arguments.
|
||||
|
||||
Given a Fire command that corresponds to a Python object, you can extend that
|
||||
command to access a member of that object, call it with arguments if it is a
|
||||
function, instantiate it if it is a class, or index into it if it is a list.
|
||||
|
||||
Read on to learn about how you can write a Fire command corresponding to
|
||||
whatever Python component you're looking for.
|
||||
|
||||
|
||||
### Accessing members of an object
|
||||
|
||||
If your command corresponds to an object, you can extend your command by adding
|
||||
the name of a member of that object as a new argument to the command. The
|
||||
resulting command will correspond to that member.
|
||||
|
||||
For example, if the object your command corresponds to has a method defined on
|
||||
it named 'whack', then you can add the argument 'whack' to your command, and the
|
||||
resulting new command corresponds to the whack method.
|
||||
|
||||
As another example, if the object your command corresponds to has a property
|
||||
named high_score, then you can add the argument 'high-score' to your command,
|
||||
and the resulting new command corresponds to the value of the high_score
|
||||
property.
|
||||
|
||||
|
||||
### Accessing members of a dict
|
||||
|
||||
If your command corresponds to a dict, you can extend your command by adding
|
||||
the name of one of the dict's keys as an argument.
|
||||
|
||||
For example, `widget function-that-returns-dict key` will correspond to the
|
||||
value of the item with key `key` in the dict returned by
|
||||
`function_that_returns_dict`.
|
||||
|
||||
|
||||
### Accessing members of a list or tuple
|
||||
|
||||
If your command corresponds to a list or tuple, you can extend your command by
|
||||
adding the index of an element of the component to your command as an argument.
|
||||
|
||||
For example, `widget function-that-returns-list 2` will correspond to item 2 of
|
||||
the result of function_that_returns_list.
|
||||
|
||||
|
||||
### Calling a function
|
||||
|
||||
If your command corresponds to a function, you can extend your command by adding
|
||||
the arguments of this function. Arguments can be specified positionally, or by
|
||||
name. To specify an argument by name, use flag syntax.
|
||||
|
||||
For example, suppose your `command` corresponds to the function `double`:
|
||||
|
||||
```python
|
||||
def double(value=0):
|
||||
return 2 * value
|
||||
```
|
||||
|
||||
Then you can extend your command using named arguments as `command --value 5`,
|
||||
or using positional arguments as `command 5`. In both cases, the new command
|
||||
corresponds to the result of the function, in this case the number 10.
|
||||
|
||||
You can force a function that takes a variable number of arguments to be
|
||||
evaluated by adding a separator (the default separator is the hyphen, "-"). This
|
||||
will prevent arguments to the right of the separator from being consumed for
|
||||
calling the function. This is useful if the function has arguments with default
|
||||
values, or if the function accepts \*varargs, or if the function accepts
|
||||
\*\*kwargs.
|
||||
|
||||
See also the section on [Changing the Separator](#separator-flag).
|
||||
|
||||
|
||||
### Instantiating a class
|
||||
|
||||
If your command corresponds to a class, you can extend your command by adding
|
||||
the arguments of the class's \_\_init\_\_ function. Arguments must be specified
|
||||
by name, using the flags syntax. See the section on
|
||||
[calling a function](#calling-a-function) for more details.
|
||||
|
||||
|
||||
## Using Flags with Fire CLIs <a name="using-flags"></a>
|
||||
|
||||
Command line arguments to a Fire CLI are normally consumed by Fire, as described
|
||||
in the [Basic Usage](#basic-usage) section. In order to set Flags, put the flags
|
||||
after the final standalone `--` argument. (If there is no `--` argument, then no
|
||||
arguments are used for flags.)
|
||||
|
||||
For example, to set the alsologtostderr flag, you could run the command:
|
||||
`widget bang --noise=boom -- --alsologtostderr`. The --noise argument is
|
||||
consumed by Fire, but the --alsologtostderr argument is treated as a normal
|
||||
Flag.
|
||||
|
||||
All CLIs built with Python Fire share some flags, as described in the next
|
||||
sections.
|
||||
|
||||
|
||||
## Python Fire's Flags
|
||||
|
||||
As described in the [Using Flags](#using-flags) section, you must add an
|
||||
isolated `--` argument in order to have arguments treated as Flags rather than
|
||||
be consumed by Python Fire. All arguments to a Fire CLI after the final
|
||||
standalone `--` argument are treated as Flags.
|
||||
|
||||
The following flags are accepted by all Fire CLIs:
|
||||
[`--interactive`/`-i`](#interactive-flag),
|
||||
[`--help`/`-h`](#help-flag),
|
||||
[`--separator`](#separator-flag),
|
||||
[`--completion`](#completion-flag),
|
||||
[`--trace`](#trace-flag),
|
||||
and [`--verbose`/`-v`](#verbose-flag),
|
||||
as described in the following sections.
|
||||
|
||||
### `--interactive`: Interactive mode <a name="interactive-flag"></a>
|
||||
|
||||
Call `widget -- --interactive` or `widget -- -i` to enter interactive mode. This
|
||||
will put you in an IPython REPL, with the variable `widget` already defined.
|
||||
|
||||
You can then explore the Python object that `widget` corresponds to
|
||||
interactively using Python.
|
||||
|
||||
|
||||
### `--completion`: Generating a completion script <a name="completion-flag"></a>
|
||||
|
||||
Call `widget -- --completion` to generate a completion script for the Fire CLI
|
||||
`widget`. To save the completion script to your home directory, you could e.g.
|
||||
run `widget -- --completion > ~/.widget-completion`. You should then source this
|
||||
file; to get permanent completion, source this file from your .bashrc file.
|
||||
|
||||
Call `widget -- --completion fish` to generate a completion script for the Fish
|
||||
shell. Source this file from your fish.config.
|
||||
|
||||
If the commands available in the Fire CLI change, you'll have to regenerate the
|
||||
completion script and source it again.
|
||||
|
||||
|
||||
### `--help`: Getting help <a name="help-flag"></a>
|
||||
|
||||
Let say you have a command line tool named `widget` that was made with Fire. How
|
||||
do you use this Fire CLI?
|
||||
|
||||
The simplest way to get started is to run `widget -- --help`. This will give you
|
||||
usage information for your CLI. You can always append `-- --help` to any Fire
|
||||
command in order to get usage information for that command and any subcommands.
|
||||
|
||||
Additionally, help will be displayed if you hit an error using Fire. For
|
||||
example, if you try to pass too many or too few arguments to a function, then
|
||||
help will be displayed. Similarly, if you try to access a member that does not
|
||||
exist, or if you index into a list with too high an index, then help will be
|
||||
displayed.
|
||||
|
||||
The displayed help shows information about which Python component your command
|
||||
corresponds to, as well as usage information for how to extend that command.
|
||||
|
||||
|
||||
### `--trace`: Getting a Fire trace <a name="trace-flag"></a>
|
||||
|
||||
In order to understand what is happening when you call Python Fire, it can be
|
||||
useful to request a trace. This is done via the --trace flag, e.g.
|
||||
`widget whack 5 -- --trace`.
|
||||
|
||||
A trace provides step by step information about how the Fire command was
|
||||
executed. In includes which actions were taken, starting with the initial
|
||||
component, leading to the final component represented by the command.
|
||||
|
||||
A trace is also shown alongside the help if your Fire command reaches an error.
|
||||
|
||||
|
||||
### `--separator`: Changing the separator <a name="separator-flag"></a>
|
||||
|
||||
As described in [Calling a Function](#calling-a-function), you can use a
|
||||
separator argument when writing a command that corresponds to calling a
|
||||
function. The separator will cause the function to be evaluated or the class to
|
||||
be instantiated using only the arguments left of the separator. Arguments right
|
||||
of the separator will then be applied to the result of the function call or to
|
||||
the instantiated object.
|
||||
|
||||
The default separator is `-`.
|
||||
|
||||
If you want to supply the string "-" as an argument, then you will have to
|
||||
change the separator. You can choose a new separator by supplying the
|
||||
`--separator` flag to Fire.
|
||||
|
||||
Here's an example to demonstrate separator usage. Let's say you have a function
|
||||
that takes a variable number of args, and you want to call that function, and
|
||||
then upper case the result. Here's how to do it:
|
||||
|
||||
```python
|
||||
# Here's the Python function
|
||||
def display(arg1, arg2='!'):
|
||||
return arg1 + arg2
|
||||
```
|
||||
|
||||
```bash
|
||||
# Here's what you can do from Bash (Note: the default separator is the hyphen -)
|
||||
display hello # hello!
|
||||
display hello upper # helloupper
|
||||
display hello - upper # HELLO!
|
||||
display - SEP upper -- --separator SEP # -!
|
||||
```
|
||||
Notice how in the third and fourth lines, the separator caused the display
|
||||
function to be called with the default value for arg2. In the fourth example,
|
||||
we change the separator to the string "SEP" so that we can pass '-' as an
|
||||
argument.
|
||||
|
||||
### `--verbose`: Verbose usage <a name="verbose-flag"></a>
|
||||
|
||||
Adding the `-v` or `--verbose` flag turns on verbose mode. This will eg
|
||||
reveal private members in the usage string. Often these members will not
|
||||
actually be usable from the command line tool. As such, verbose mode should be
|
||||
considered a debugging tool, but not fully supported yet.
|
||||
@@ -1,59 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""The Caesar Shift Cipher example Fire CLI.
|
||||
|
||||
This module demonstrates the use of Fire without specifying a target component.
|
||||
Notice how the call to Fire() in the main method doesn't indicate a component.
|
||||
So, all local and global variables (including all functions defined in the
|
||||
module) are made available as part of the Fire CLI.
|
||||
|
||||
Example usage:
|
||||
cipher rot13 'Hello world!' # Uryyb jbeyq!
|
||||
cipher rot13 'Uryyb jbeyq!' # Hello world!
|
||||
cipher caesar-encode 1 'Hello world!' # Ifmmp xpsme!
|
||||
cipher caesar-decode 1 'Ifmmp xpsme!' # Hello world!
|
||||
"""
|
||||
|
||||
import fire
|
||||
|
||||
|
||||
def caesar_encode(n=0, text=''):
|
||||
return ''.join(
|
||||
_caesar_shift_char(n, char)
|
||||
for char in text
|
||||
)
|
||||
|
||||
|
||||
def caesar_decode(n=0, text=''):
|
||||
return caesar_encode(-n, text)
|
||||
|
||||
|
||||
def rot13(text):
|
||||
return caesar_encode(13, text)
|
||||
|
||||
|
||||
def _caesar_shift_char(n=0, char=' '):
|
||||
if not char.isalpha():
|
||||
return char
|
||||
if char.isupper():
|
||||
return chr((ord(char) - ord('A') + n) % 26 + ord('A'))
|
||||
return chr((ord(char) - ord('a') + n) % 26 + ord('a'))
|
||||
|
||||
|
||||
def main():
|
||||
fire.Fire(name='cipher')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,34 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the cipher module."""
|
||||
|
||||
from fire import testutils
|
||||
|
||||
from examples.cipher import cipher
|
||||
|
||||
|
||||
class CipherTest(testutils.BaseTestCase):
|
||||
|
||||
def testCipher(self):
|
||||
self.assertEqual(cipher.rot13('Hello world!'), 'Uryyb jbeyq!')
|
||||
self.assertEqual(cipher.caesar_encode(13, 'Hello world!'), 'Uryyb jbeyq!')
|
||||
self.assertEqual(cipher.caesar_decode(13, 'Uryyb jbeyq!'), 'Hello world!')
|
||||
|
||||
self.assertEqual(cipher.caesar_encode(1, 'Hello world!'), 'Ifmmp xpsme!')
|
||||
self.assertEqual(cipher.caesar_decode(1, 'Ifmmp xpsme!'), 'Hello world!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,105 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
r"""A command line tool for diffing files.
|
||||
|
||||
The Python 2.7 documentation demonstrates how to make a command line interface
|
||||
for the difflib library using optparse:
|
||||
https://docs.python.org/2/library/difflib.html#a-command-line-interface-to-difflib
|
||||
|
||||
This file demonstrates how to create a command line interface providing the same
|
||||
functionality using Python Fire.
|
||||
|
||||
Usage:
|
||||
|
||||
diff FROMFILE TOFILE COMMAND [LINES]
|
||||
|
||||
Arguments can be passed positionally or via the Flag syntax.
|
||||
Using positional arguments, the usage is:
|
||||
|
||||
diff FROMFILE TOFILE
|
||||
diff FROMFILE TOFILE context-diff [LINES]
|
||||
diff FROMFILE TOFILE unified-diff [LINES]
|
||||
diff FROMFILE TOFILE ndiff
|
||||
diff FROMFILE TOFILE make-file [CONTEXT] [LINES]
|
||||
|
||||
Using the Flag syntax, the usage is:
|
||||
|
||||
diff --fromfile=FROMFILE --tofile=TOFILE
|
||||
diff --fromfile=FROMFILE --tofile=TOFILE context-diff [--lines=LINES]
|
||||
diff --fromfile=FROMFILE --tofile=TOFILE unified-diff [--lines=LINES]
|
||||
diff --fromfile=FROMFILE --tofile=TOFILE ndiff
|
||||
diff --fromfile=FROMFILE --tofile=TOFILE make-file \
|
||||
[--context=CONTEXT] [--lines LINES]
|
||||
|
||||
As with any Fire CLI, you can append '--' followed by any Flags to any command.
|
||||
|
||||
The Flags available for all Fire CLIs are:
|
||||
--help
|
||||
--interactive
|
||||
--trace
|
||||
--separator=SEPARATOR
|
||||
--completion
|
||||
--verbose
|
||||
"""
|
||||
|
||||
import difflib
|
||||
import os
|
||||
import time
|
||||
|
||||
import fire
|
||||
|
||||
|
||||
class DiffLibWrapper(object):
|
||||
"""Provides a simple interface to the difflib module.
|
||||
|
||||
The purpose of this simple interface is to offer a limited subset of the
|
||||
difflib functionality as a command line interface.
|
||||
"""
|
||||
|
||||
def __init__(self, fromfile, tofile):
|
||||
self._fromfile = fromfile
|
||||
self._tofile = tofile
|
||||
|
||||
self.fromdate = time.ctime(os.stat(fromfile).st_mtime)
|
||||
self.todate = time.ctime(os.stat(tofile).st_mtime)
|
||||
with open(fromfile) as f:
|
||||
self.fromlines = f.readlines()
|
||||
with open(tofile) as f:
|
||||
self.tolines = f.readlines()
|
||||
|
||||
def unified_diff(self, lines=3):
|
||||
return difflib.unified_diff(
|
||||
self.fromlines, self.tolines, self._fromfile,
|
||||
self._tofile, self.fromdate, self.todate, n=lines)
|
||||
|
||||
def ndiff(self):
|
||||
return difflib.ndiff(self.fromlines, self.tolines)
|
||||
|
||||
def make_file(self, context=False, lines=3):
|
||||
return difflib.HtmlDiff().make_file(
|
||||
self.fromlines, self.tolines, self._fromfile, self._tofile,
|
||||
context=context, numlines=lines)
|
||||
|
||||
def context_diff(self, lines=3):
|
||||
return difflib.context_diff(
|
||||
self.fromlines, self.tolines, self._fromfile,
|
||||
self._tofile, self.fromdate, self.todate, n=lines)
|
||||
|
||||
|
||||
def main():
|
||||
fire.Fire(DiffLibWrapper, name='diff')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,95 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the diff and difffull modules."""
|
||||
|
||||
import tempfile
|
||||
|
||||
from fire import testutils
|
||||
|
||||
from examples.diff import diff
|
||||
from examples.diff import difffull
|
||||
|
||||
|
||||
class DiffTest(testutils.BaseTestCase):
|
||||
"""The purpose of these tests is to ensure the difflib wrappers works.
|
||||
|
||||
It is not the goal of these tests to exhaustively test difflib functionality.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.file1 = file1 = tempfile.NamedTemporaryFile()
|
||||
self.file2 = file2 = tempfile.NamedTemporaryFile()
|
||||
|
||||
file1.write(b'test\ntest1\n')
|
||||
file2.write(b'test\ntest2\nextraline\n')
|
||||
|
||||
file1.flush()
|
||||
file2.flush()
|
||||
|
||||
self.diff = diff.DiffLibWrapper(file1.name, file2.name)
|
||||
|
||||
def testSetUp(self):
|
||||
self.assertEqual(self.diff.fromlines, ['test\n', 'test1\n'])
|
||||
self.assertEqual(self.diff.tolines, ['test\n', 'test2\n', 'extraline\n'])
|
||||
|
||||
def testUnifiedDiff(self):
|
||||
results = list(self.diff.unified_diff())
|
||||
self.assertTrue(results[0].startswith('--- ' + self.file1.name))
|
||||
self.assertTrue(results[1].startswith('+++ ' + self.file2.name))
|
||||
self.assertEqual(
|
||||
results[2:],
|
||||
[
|
||||
'@@ -1,2 +1,3 @@\n',
|
||||
' test\n',
|
||||
'-test1\n',
|
||||
'+test2\n',
|
||||
'+extraline\n',
|
||||
]
|
||||
)
|
||||
|
||||
def testContextDiff(self):
|
||||
expected_lines = [
|
||||
'***************\n',
|
||||
'*** 1,2 ****\n',
|
||||
' test\n',
|
||||
'! test1\n',
|
||||
'--- 1,3 ----\n',
|
||||
' test\n',
|
||||
'! test2\n',
|
||||
'! extraline\n']
|
||||
results = list(self.diff.context_diff())
|
||||
self.assertEqual(results[2:], expected_lines)
|
||||
|
||||
def testNDiff(self):
|
||||
expected_lines = [
|
||||
' test\n',
|
||||
'- test1\n',
|
||||
'? ^\n',
|
||||
'+ test2\n',
|
||||
'? ^\n',
|
||||
'+ extraline\n']
|
||||
results = list(self.diff.ndiff())
|
||||
self.assertEqual(results, expected_lines)
|
||||
|
||||
def testMakeDiff(self):
|
||||
self.assertTrue(''.join(self.diff.make_file()).startswith('\n<!DOC'))
|
||||
|
||||
def testDiffFull(self):
|
||||
self.assertIsNotNone(difffull)
|
||||
self.assertIsNotNone(difffull.difflib)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,51 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""A command line tool for diffing files.
|
||||
|
||||
This demonstrates the simplest possible way to turn a module into a command line
|
||||
interface with Python Fire. It exemplifies the power and shortcomings of relying
|
||||
on Python Fire's simplicity.
|
||||
|
||||
See //fire/examples/diff/diff.py for another way of turning
|
||||
difflib into a CLI that requires more code, but gives the developer more control
|
||||
over the CLI's API.
|
||||
|
||||
Use the help flag to see usage for all the things this CLI can do. For example:
|
||||
|
||||
difffull -- -h
|
||||
difffull HtmlDiff -- -h # Help for the HtmlDiff class
|
||||
difffull HtmlDiff - -- -h # Help for an HtmlDiff object, not the HtmlDiff class
|
||||
|
||||
Here are some of the diff commands available:
|
||||
|
||||
difffull ndiff A B [LINEJUNK] [CHARJUNK]
|
||||
difffull context-diff A B [FROMFILE] [TOFILE] [FROMFILEDATE] [TOFILEDATE] [N]
|
||||
difffull unified-diff A B [FROMFILE] [TOFILE] [FROMFILEDATE] [TOFILEDATE] [N]
|
||||
difffull HtmlDiff - make-file FROMLINES TOLINES [FROMDESC] [TODESC] [CONTEXT]
|
||||
|
||||
For more useful versions of those last four commands using Python Fire, see
|
||||
//fire/examples/diff:diff.par
|
||||
"""
|
||||
|
||||
import difflib
|
||||
|
||||
import fire
|
||||
|
||||
|
||||
def main():
|
||||
fire.Fire(difflib, name='difffull')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,28 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""A simple command line tool for testing purposes."""
|
||||
|
||||
import fire
|
||||
|
||||
|
||||
def identity(arg=None):
|
||||
return arg, type(arg)
|
||||
|
||||
|
||||
def main(_=None):
|
||||
fire.Fire(identity, name='identity')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,38 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""As a Python Fire demo, a Collector collects widgets, and nobody knows why."""
|
||||
|
||||
import fire
|
||||
|
||||
from examples.widget import widget
|
||||
|
||||
|
||||
class Collector(object):
|
||||
"""A Collector has one Widget, but wants more."""
|
||||
|
||||
def __init__(self):
|
||||
self.widget = widget.Widget()
|
||||
self.desired_widget_count = 10
|
||||
|
||||
def collect_widgets(self):
|
||||
"""Returns all the widgets the Collector wants."""
|
||||
return [widget.Widget() for _ in range(self.desired_widget_count)]
|
||||
|
||||
|
||||
def main():
|
||||
fire.Fire(Collector(), name='collector')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the collector module."""
|
||||
|
||||
from fire import testutils
|
||||
|
||||
from examples.widget import collector
|
||||
from examples.widget import widget
|
||||
|
||||
|
||||
class CollectorTest(testutils.BaseTestCase):
|
||||
|
||||
def testCollectorHasWidget(self):
|
||||
col = collector.Collector()
|
||||
self.assertIsInstance(col.widget, widget.Widget)
|
||||
|
||||
def testCollectorWantsMoreWidgets(self):
|
||||
col = collector.Collector()
|
||||
self.assertEqual(col.desired_widget_count, 10)
|
||||
|
||||
def testCollectorGetsWantedWidgets(self):
|
||||
col = collector.Collector()
|
||||
self.assertEqual(len(col.collect_widgets()), 10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,35 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""As a simple example of Python Fire, a Widget serves no clear purpose."""
|
||||
|
||||
import fire
|
||||
|
||||
|
||||
class Widget(object):
|
||||
|
||||
def whack(self, n=1):
|
||||
"""Prints "whack!" n times."""
|
||||
return ' '.join('whack!' for _ in range(n))
|
||||
|
||||
def bang(self, noise='bang'):
|
||||
"""Makes a loud noise."""
|
||||
return '{noise} bang!'.format(noise=noise)
|
||||
|
||||
|
||||
def main():
|
||||
fire.Fire(Widget(), name='widget')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,36 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the widget module."""
|
||||
|
||||
from fire import testutils
|
||||
|
||||
from examples.widget import widget
|
||||
|
||||
|
||||
class WidgetTest(testutils.BaseTestCase):
|
||||
|
||||
def testWidgetWhack(self):
|
||||
toy = widget.Widget()
|
||||
self.assertEqual(toy.whack(), 'whack!')
|
||||
self.assertEqual(toy.whack(3), 'whack! whack! whack!')
|
||||
|
||||
def testWidgetBang(self):
|
||||
toy = widget.Widget()
|
||||
self.assertEqual(toy.bang(), 'bang bang!')
|
||||
self.assertEqual(toy.bang('boom'), 'boom bang!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,23 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""The Python Fire module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire.core import Fire
|
||||
|
||||
__all__ = ['Fire']
|
||||
@@ -1,477 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Provides tab completion functionality for CLIs built with Fire."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import inspect
|
||||
|
||||
from fire import inspectutils
|
||||
import six
|
||||
|
||||
|
||||
def Script(name, component, default_options=None, shell='bash'):
|
||||
if shell == 'fish':
|
||||
return _FishScript(name, _Commands(component), default_options)
|
||||
return _BashScript(name, _Commands(component), default_options)
|
||||
|
||||
|
||||
def _BashScript(name, commands, default_options=None):
|
||||
"""Returns a Bash script registering a completion function for the commands.
|
||||
|
||||
Args:
|
||||
name: The first token in the commands, also the name of the command.
|
||||
commands: A list of all possible commands that tab completion can complete
|
||||
to. Each command is a list or tuple of the string tokens that make up
|
||||
that command.
|
||||
default_options: A dict of options that can be used with any command. Use
|
||||
this if there are flags that can always be appended to a command.
|
||||
Returns:
|
||||
A string which is the Bash script. Source the bash script to enable tab
|
||||
completion in Bash.
|
||||
"""
|
||||
default_options = default_options or set()
|
||||
global_options, options_map, subcommands_map = _GetMaps(
|
||||
name, commands, default_options
|
||||
)
|
||||
|
||||
bash_completion_template = """# bash completion support for {name}
|
||||
# DO NOT EDIT.
|
||||
# This script is autogenerated by fire/completion.py.
|
||||
|
||||
_complete-{identifier}()
|
||||
{{
|
||||
local cur prev opts lastcommand
|
||||
COMPREPLY=()
|
||||
prev="${{COMP_WORDS[COMP_CWORD-1]}}"
|
||||
cur="${{COMP_WORDS[COMP_CWORD]}}"
|
||||
lastcommand=$(get_lastcommand)
|
||||
|
||||
opts="{default_options}"
|
||||
GLOBAL_OPTIONS="{global_options}"
|
||||
|
||||
{checks}
|
||||
|
||||
COMPREPLY=( $(compgen -W "${{opts}}" -- ${{cur}}) )
|
||||
return 0
|
||||
}}
|
||||
|
||||
get_lastcommand()
|
||||
{{
|
||||
local lastcommand i
|
||||
|
||||
lastcommand=
|
||||
for ((i=0; i < ${{#COMP_WORDS[@]}}; ++i)); do
|
||||
if [[ ${{COMP_WORDS[i]}} != -* ]] && [[ -n ${{COMP_WORDS[i]}} ]] && [[
|
||||
${{COMP_WORDS[i]}} != $cur ]]; then
|
||||
lastcommand=${{COMP_WORDS[i]}}
|
||||
fi
|
||||
done
|
||||
|
||||
echo $lastcommand
|
||||
}}
|
||||
|
||||
filter_options()
|
||||
{{
|
||||
local opts
|
||||
opts=""
|
||||
for opt in "$@"
|
||||
do
|
||||
if ! option_already_entered $opt; then
|
||||
opts="$opts $opt"
|
||||
fi
|
||||
done
|
||||
|
||||
echo $opts
|
||||
}}
|
||||
|
||||
option_already_entered()
|
||||
{{
|
||||
local opt
|
||||
for opt in ${{COMP_WORDS[@]:0:COMP_CWORD}}
|
||||
do
|
||||
if [ $1 == $opt ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}}
|
||||
|
||||
is_prev_global()
|
||||
{{
|
||||
local opt
|
||||
for opt in $GLOBAL_OPTIONS
|
||||
do
|
||||
if [ $opt == $prev ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}}
|
||||
|
||||
complete -F _complete-{identifier} {command}
|
||||
"""
|
||||
|
||||
check_wrapper = """
|
||||
case "${{lastcommand}}" in
|
||||
{lastcommand_checks}
|
||||
esac"""
|
||||
|
||||
lastcommand_check_template = """
|
||||
{command})
|
||||
{opts_assignment}
|
||||
opts=$(filter_options $opts)
|
||||
;;"""
|
||||
|
||||
opts_assignment_subcommand_template = """
|
||||
if is_prev_global; then
|
||||
opts="${{GLOBAL_OPTIONS}}"
|
||||
else
|
||||
opts="{options} ${{GLOBAL_OPTIONS}}"
|
||||
fi"""
|
||||
|
||||
opts_assignment_main_command_template = """
|
||||
opts="{options} ${{GLOBAL_OPTIONS}}" """
|
||||
|
||||
def _GetOptsAssignmentTemplate(command):
|
||||
if command == name:
|
||||
return opts_assignment_main_command_template
|
||||
else:
|
||||
return opts_assignment_subcommand_template
|
||||
|
||||
lines = []
|
||||
for command in set(subcommands_map.keys()).union(set(options_map.keys())):
|
||||
opts_assignment = _GetOptsAssignmentTemplate(command).format(
|
||||
options=' '.join(
|
||||
sorted(options_map[command].union(subcommands_map[command]))
|
||||
),
|
||||
)
|
||||
lines.append(
|
||||
lastcommand_check_template.format(
|
||||
command=command,
|
||||
opts_assignment=opts_assignment)
|
||||
)
|
||||
lastcommand_checks = '\n'.join(lines)
|
||||
|
||||
checks = check_wrapper.format(
|
||||
lastcommand_checks=lastcommand_checks,
|
||||
)
|
||||
|
||||
return (
|
||||
bash_completion_template.format(
|
||||
name=name,
|
||||
command=name,
|
||||
checks=checks,
|
||||
default_options=' '.join(default_options),
|
||||
identifier=name.replace('/', '').replace('.', '').replace(',', ''),
|
||||
global_options=' '.join(global_options),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _FishScript(name, commands, default_options=None):
|
||||
"""Returns a Fish script registering a completion function for the commands.
|
||||
|
||||
Args:
|
||||
name: The first token in the commands, also the name of the command.
|
||||
commands: A list of all possible commands that tab completion can complete
|
||||
to. Each command is a list or tuple of the string tokens that make up
|
||||
that command.
|
||||
default_options: A dict of options that can be used with any command. Use
|
||||
this if there are flags that can always be appended to a command.
|
||||
Returns:
|
||||
A string which is the Fish script. Source the fish script to enable tab
|
||||
completion in Fish.
|
||||
"""
|
||||
default_options = default_options or set()
|
||||
global_options, options_map, subcommands_map = _GetMaps(
|
||||
name, commands, default_options
|
||||
)
|
||||
|
||||
fish_source = """function __fish_using_command
|
||||
set cmd (commandline -opc)
|
||||
for i in (seq (count $cmd) 1)
|
||||
switch $cmd[$i]
|
||||
case "-*"
|
||||
case "*"
|
||||
if [ $cmd[$i] = $argv[1] ]
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function __option_entered_check
|
||||
set cmd (commandline -opc)
|
||||
for i in (seq (count $cmd))
|
||||
switch $cmd[$i]
|
||||
case "-*"
|
||||
if [ $cmd[$i] = $argv[1] ]
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function __is_prev_global
|
||||
set cmd (commandline -opc)
|
||||
set global_options {global_options}
|
||||
set prev (count $cmd)
|
||||
|
||||
for opt in $global_options
|
||||
if [ "--$opt" = $cmd[$prev] ]
|
||||
echo $prev
|
||||
return 0
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
"""
|
||||
|
||||
subcommand_template = ("complete -c {name} -n '__fish_using_command "
|
||||
"{command}' -f -a {subcommand}\n")
|
||||
flag_template = ("complete -c {name} -n "
|
||||
"'__fish_using_command {command};{prev_global_check} and "
|
||||
"__option_entered_check --{option}' -l {option}\n")
|
||||
|
||||
prev_global_check = ' and __is_prev_global;'
|
||||
for command in set(subcommands_map.keys()).union(set(options_map.keys())):
|
||||
for subcommand in subcommands_map[command]:
|
||||
fish_source += subcommand_template.format(
|
||||
name=name,
|
||||
command=command,
|
||||
subcommand=subcommand,
|
||||
)
|
||||
|
||||
for option in options_map[command].union(global_options):
|
||||
check_needed = command != name
|
||||
fish_source += flag_template.format(
|
||||
name=name,
|
||||
command=command,
|
||||
prev_global_check=prev_global_check if check_needed else '',
|
||||
option=option.lstrip('--'),
|
||||
)
|
||||
|
||||
return fish_source.format(
|
||||
global_options=' '.join(
|
||||
'"{option}"'.format(option=option)
|
||||
for option in global_options
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _IncludeMember(name, verbose):
|
||||
"""Returns whether a member should be included in auto-completion or help.
|
||||
|
||||
Determines whether a member of an object with the specified name should be
|
||||
included in auto-completion or help text(both usage and detailed help).
|
||||
|
||||
If the member starts with '__', it will always be excluded. If the member
|
||||
starts with only one '_', it will be included for all non-string types. If
|
||||
verbose is True, the members, including the private members, are always
|
||||
included.
|
||||
|
||||
Args:
|
||||
name: The name of the member.
|
||||
verbose: Whether to include private members.
|
||||
Returns
|
||||
A boolean value indicating whether the member should be included.
|
||||
|
||||
"""
|
||||
if isinstance(name, six.string_types) and name[:2] == '__':
|
||||
return False
|
||||
if verbose:
|
||||
return True
|
||||
if isinstance(name, six.string_types):
|
||||
return name and name[0] != '_'
|
||||
return True # Default to including the member
|
||||
|
||||
|
||||
def _Members(component, verbose=False):
|
||||
"""Returns a list of the members of the given component.
|
||||
|
||||
If verbose is True, then members starting with _ (normally ignored) are
|
||||
included.
|
||||
|
||||
Args:
|
||||
component: The component whose members to list.
|
||||
verbose: Whether to include private members.
|
||||
Returns:
|
||||
A list of tuples (member_name, member) of all members of the component.
|
||||
"""
|
||||
if isinstance(component, dict):
|
||||
members = component.items()
|
||||
else:
|
||||
members = inspect.getmembers(component)
|
||||
|
||||
return [
|
||||
(member_name, member)
|
||||
for member_name, member in members
|
||||
if _IncludeMember(member_name, verbose)
|
||||
]
|
||||
|
||||
|
||||
def _CompletionsFromArgs(fn_args):
|
||||
"""Takes a list of fn args and returns a list of the fn's completion strings.
|
||||
|
||||
Args:
|
||||
fn_args: A list of the args accepted by a function.
|
||||
Returns:
|
||||
A list of possible completion strings for that function.
|
||||
"""
|
||||
completions = []
|
||||
for arg in fn_args:
|
||||
arg = arg.replace('_', '-')
|
||||
completions.append('--{arg}'.format(arg=arg))
|
||||
return completions
|
||||
|
||||
|
||||
def Completions(component, verbose=False):
|
||||
"""Gives possible Fire command completions for the component.
|
||||
|
||||
A completion is a string that can be appended to a command to continue that
|
||||
command. These are used for TAB-completions in Bash for Fire CLIs.
|
||||
|
||||
Args:
|
||||
component: The component whose completions to list.
|
||||
verbose: Whether to include all completions, even private members.
|
||||
Returns:
|
||||
A list of completions for a command that would so far return the component.
|
||||
"""
|
||||
if inspect.isroutine(component) or inspect.isclass(component):
|
||||
spec = inspectutils.GetFullArgSpec(component)
|
||||
return _CompletionsFromArgs(spec.args + spec.kwonlyargs)
|
||||
|
||||
if isinstance(component, (tuple, list)):
|
||||
return [str(index) for index in range(len(component))]
|
||||
|
||||
if inspect.isgenerator(component):
|
||||
# TODO(dbieber): There are currently no commands available for generators.
|
||||
return []
|
||||
|
||||
return [
|
||||
_FormatForCommand(member_name)
|
||||
for member_name, unused_member in _Members(component, verbose)
|
||||
]
|
||||
|
||||
|
||||
def _FormatForCommand(token):
|
||||
"""Replaces underscores with hyphens, unless the token starts with a token.
|
||||
|
||||
This is because we typically prefer hyphens to underscores at the command
|
||||
line, but we reserve hyphens at the start of a token for flags. This becomes
|
||||
relevant when --verbose is activated, so that things like __str__ don't get
|
||||
transformed into --str--, which would get confused for a flag.
|
||||
|
||||
Args:
|
||||
token: The token to transform.
|
||||
Returns:
|
||||
The transformed token.
|
||||
"""
|
||||
if not isinstance(token, six.string_types):
|
||||
token = str(token)
|
||||
|
||||
if token.startswith('_'):
|
||||
return token
|
||||
|
||||
return token.replace('_', '-')
|
||||
|
||||
|
||||
def _Commands(component, depth=3):
|
||||
"""Yields tuples representing commands.
|
||||
|
||||
To use the command from Python, insert '.' between each element of the tuple.
|
||||
To use the command from the command line, insert ' ' between each element of
|
||||
the tuple.
|
||||
|
||||
Args:
|
||||
component: The component considered to be the root of the yielded commands.
|
||||
depth: The maximum depth with which to traverse the member DAG for commands.
|
||||
Yields:
|
||||
Tuples, each tuple representing one possible command for this CLI.
|
||||
Only traverses the member DAG up to a depth of depth.
|
||||
"""
|
||||
if inspect.isroutine(component) or inspect.isclass(component):
|
||||
for completion in Completions(component):
|
||||
yield (completion,)
|
||||
if inspect.isroutine(component):
|
||||
return # Don't descend into routines.
|
||||
|
||||
if depth < 1:
|
||||
return
|
||||
|
||||
for member_name, member in _Members(component):
|
||||
# TODO(dbieber): Also skip components we've already seen.
|
||||
member_name = _FormatForCommand(member_name)
|
||||
|
||||
yield (member_name,)
|
||||
|
||||
for command in _Commands(member, depth - 1):
|
||||
yield (member_name,) + command
|
||||
|
||||
|
||||
def _IsOption(arg):
|
||||
return arg.startswith('-')
|
||||
|
||||
|
||||
def _GetMaps(name, commands, default_options):
|
||||
"""Returns sets of subcommands and options for each command.
|
||||
|
||||
Args:
|
||||
name: The first token in the commands, also the name of the command.
|
||||
commands: A list of all possible commands that tab completion can complete
|
||||
to. Each command is a list or tuple of the string tokens that make up
|
||||
that command.
|
||||
default_options: A dict of options that can be used with any command. Use
|
||||
this if there are flags that can always be appended to a command.
|
||||
Returns:
|
||||
global_options: A set of all options of the first token of the command.
|
||||
subcommands_map: A dict storing set of subcommands for each
|
||||
command/subcommand.
|
||||
options_map: A dict storing set of options for each subcommand.
|
||||
"""
|
||||
global_options = copy.copy(default_options)
|
||||
options_map = collections.defaultdict(lambda: copy.copy(default_options))
|
||||
subcommands_map = collections.defaultdict(set)
|
||||
|
||||
for command in commands:
|
||||
if len(command) == 1:
|
||||
if _IsOption(command[0]):
|
||||
global_options.add(command[0])
|
||||
else:
|
||||
subcommands_map[name].add(command[0])
|
||||
|
||||
elif command:
|
||||
subcommand = command[-2]
|
||||
arg = _FormatForCommand(command[-1])
|
||||
|
||||
if _IsOption(arg):
|
||||
args_map = options_map
|
||||
else:
|
||||
args_map = subcommands_map
|
||||
|
||||
args_map[subcommand].add(arg)
|
||||
args_map[subcommand.replace('_', '-')].add(arg)
|
||||
|
||||
return global_options, options_map, subcommands_map
|
||||
@@ -1,193 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the completion module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import completion
|
||||
from fire import test_components as tc
|
||||
from fire import testutils
|
||||
|
||||
|
||||
class TabCompletionTest(testutils.BaseTestCase):
|
||||
|
||||
def testCompletionBashScript(self):
|
||||
# A sanity check test to make sure the bash completion script satisfies
|
||||
# some basic assumptions.
|
||||
commands = [
|
||||
['run'],
|
||||
['halt'],
|
||||
['halt', '--now'],
|
||||
]
|
||||
script = completion._BashScript(name='command', commands=commands) # pylint: disable=protected-access
|
||||
self.assertIn('command', script)
|
||||
self.assertIn('halt', script)
|
||||
|
||||
assert_template = '{command})'
|
||||
for last_command in ['command', 'halt']:
|
||||
self.assertIn(assert_template.format(command=last_command), script)
|
||||
|
||||
def testCompletionFishScript(self):
|
||||
# A sanity check test to make sure the fish completion script satisfies
|
||||
# some basic assumptions.
|
||||
commands = [
|
||||
['run'],
|
||||
['halt'],
|
||||
['halt', '--now'],
|
||||
]
|
||||
script = completion._FishScript(name='command', commands=commands) # pylint: disable=protected-access
|
||||
self.assertIn('command', script)
|
||||
self.assertIn('halt', script)
|
||||
self.assertIn('-l now', script)
|
||||
|
||||
def testFnCompletions(self):
|
||||
def example(one, two, three):
|
||||
return one, two, three
|
||||
|
||||
completions = completion.Completions(example)
|
||||
self.assertIn('--one', completions)
|
||||
self.assertIn('--two', completions)
|
||||
self.assertIn('--three', completions)
|
||||
|
||||
def testListCompletions(self):
|
||||
completions = completion.Completions(['red', 'green', 'blue'])
|
||||
self.assertIn('0', completions)
|
||||
self.assertIn('1', completions)
|
||||
self.assertIn('2', completions)
|
||||
self.assertNotIn('3', completions)
|
||||
|
||||
def testDictCompletions(self):
|
||||
colors = {
|
||||
'red': 'green',
|
||||
'blue': 'yellow',
|
||||
'_rainbow': True,
|
||||
}
|
||||
completions = completion.Completions(colors)
|
||||
self.assertIn('red', completions)
|
||||
self.assertIn('blue', completions)
|
||||
self.assertNotIn('green', completions)
|
||||
self.assertNotIn('yellow', completions)
|
||||
self.assertNotIn('_rainbow', completions)
|
||||
self.assertNotIn('True', completions)
|
||||
self.assertNotIn(True, completions)
|
||||
|
||||
def testDictCompletionsVerbose(self):
|
||||
colors = {
|
||||
'red': 'green',
|
||||
'blue': 'yellow',
|
||||
'_rainbow': True,
|
||||
}
|
||||
completions = completion.Completions(colors, verbose=True)
|
||||
self.assertIn('red', completions)
|
||||
self.assertIn('blue', completions)
|
||||
self.assertNotIn('green', completions)
|
||||
self.assertNotIn('yellow', completions)
|
||||
self.assertIn('_rainbow', completions)
|
||||
self.assertNotIn('True', completions)
|
||||
self.assertNotIn(True, completions)
|
||||
|
||||
def testDeepDictCompletions(self):
|
||||
deepdict = {'level1': {'level2': {'level3': {'level4': {}}}}}
|
||||
completions = completion.Completions(deepdict)
|
||||
self.assertIn('level1', completions)
|
||||
self.assertNotIn('level2', completions)
|
||||
|
||||
def testDeepDictScript(self):
|
||||
deepdict = {'level1': {'level2': {'level3': {'level4': {}}}}}
|
||||
script = completion.Script('deepdict', deepdict)
|
||||
self.assertIn('level1', script)
|
||||
self.assertIn('level2', script)
|
||||
self.assertIn('level3', script)
|
||||
self.assertNotIn('level4', script) # The default depth is 3.
|
||||
|
||||
def testFnScript(self):
|
||||
script = completion.Script('identity', tc.identity)
|
||||
self.assertIn('--arg1', script)
|
||||
self.assertIn('--arg2', script)
|
||||
self.assertIn('--arg3', script)
|
||||
self.assertIn('--arg4', script)
|
||||
|
||||
def testClassScript(self):
|
||||
script = completion.Script('', tc.MixedDefaults)
|
||||
self.assertIn('ten', script)
|
||||
self.assertIn('sum', script)
|
||||
self.assertIn('identity', script)
|
||||
self.assertIn('--alpha', script)
|
||||
self.assertIn('--beta', script)
|
||||
|
||||
def testDeepDictFishScript(self):
|
||||
deepdict = {'level1': {'level2': {'level3': {'level4': {}}}}}
|
||||
script = completion.Script('deepdict', deepdict, shell='fish')
|
||||
self.assertIn('level1', script)
|
||||
self.assertIn('level2', script)
|
||||
self.assertIn('level3', script)
|
||||
self.assertNotIn('level4', script) # The default depth is 3.
|
||||
|
||||
def testFnFishScript(self):
|
||||
script = completion.Script('identity', tc.identity, shell='fish')
|
||||
self.assertIn('arg1', script)
|
||||
self.assertIn('arg2', script)
|
||||
self.assertIn('arg3', script)
|
||||
self.assertIn('arg4', script)
|
||||
|
||||
def testClassFishScript(self):
|
||||
script = completion.Script('', tc.MixedDefaults, shell='fish')
|
||||
self.assertIn('ten', script)
|
||||
self.assertIn('sum', script)
|
||||
self.assertIn('identity', script)
|
||||
self.assertIn('alpha', script)
|
||||
self.assertIn('beta', script)
|
||||
|
||||
def testNonStringDictCompletions(self):
|
||||
completions = completion.Completions({
|
||||
10: 'green',
|
||||
3.14: 'yellow',
|
||||
('t1', 't2'): 'pink',
|
||||
})
|
||||
self.assertIn('10', completions)
|
||||
self.assertIn('3.14', completions)
|
||||
self.assertIn("('t1', 't2')", completions)
|
||||
self.assertNotIn('green', completions)
|
||||
self.assertNotIn('yellow', completions)
|
||||
self.assertNotIn('pink', completions)
|
||||
|
||||
def testGeneratorCompletions(self):
|
||||
def generator():
|
||||
x = 0
|
||||
while True:
|
||||
yield x
|
||||
x += 1
|
||||
completions = completion.Completions(generator())
|
||||
self.assertEqual(completions, [])
|
||||
|
||||
def testClassCompletions(self):
|
||||
completions = completion.Completions(tc.NoDefaults)
|
||||
self.assertEqual(completions, [])
|
||||
|
||||
def testObjectCompletions(self):
|
||||
completions = completion.Completions(tc.NoDefaults())
|
||||
self.assertIn('double', completions)
|
||||
self.assertIn('triple', completions)
|
||||
|
||||
def testMethodCompletions(self):
|
||||
completions = completion.Completions(tc.NoDefaults().double)
|
||||
self.assertNotIn('--self', completions)
|
||||
self.assertIn('--count', completions)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,3 +0,0 @@
|
||||
This is the console package from googlecloudsdk, as used by Python Fire.
|
||||
Python Fire does not accept pull requests modifying the console package; rather,
|
||||
changes to console should go through the upstream project googlecloudsdk.
|
||||
@@ -1,784 +0,0 @@
|
||||
# -*- coding: utf-8 -*- #
|
||||
|
||||
# Copyright 2015 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
r"""A module for console attributes, special characters and functions.
|
||||
|
||||
The target architectures {linux, macos, windows} support inline encoding for
|
||||
all attributes except color. Windows requires win32 calls to manipulate the
|
||||
console color state.
|
||||
|
||||
Usage:
|
||||
|
||||
# Get the console attribute state.
|
||||
out = log.out
|
||||
con = console_attr.GetConsoleAttr(out=out)
|
||||
|
||||
# Get the ISO 8879:1986//ENTITIES Box and Line Drawing characters.
|
||||
box = con.GetBoxLineCharacters()
|
||||
# Print an X inside a box.
|
||||
out.write(box.dr)
|
||||
out.write(box.h)
|
||||
out.write(box.dl)
|
||||
out.write('\n')
|
||||
out.write(box.v)
|
||||
out.write('X')
|
||||
out.write(box.v)
|
||||
out.write('\n')
|
||||
out.write(box.ur)
|
||||
out.write(box.h)
|
||||
out.write(box.ul)
|
||||
out.write('\n')
|
||||
|
||||
# Print the bullet characters.
|
||||
for c in con.GetBullets():
|
||||
out.write(c)
|
||||
out.write('\n')
|
||||
|
||||
# Print FAIL in red.
|
||||
out.write('Epic ')
|
||||
con.Colorize('FAIL', 'red')
|
||||
out.write(', my first.')
|
||||
|
||||
# Print italic and bold text.
|
||||
bold = con.GetFontCode(bold=True)
|
||||
italic = con.GetFontCode(italic=True)
|
||||
normal = con.GetFontCode()
|
||||
out.write('This is {bold}bold{normal}, this is {italic}italic{normal},'
|
||||
' and this is normal.\n'.format(bold=bold, italic=italic,
|
||||
normal=normal))
|
||||
|
||||
# Read one character from stdin with echo disabled.
|
||||
c = con.GetRawKey()
|
||||
if c is None:
|
||||
print 'EOF\n'
|
||||
|
||||
# Return the display width of a string that may contain FontCode() chars.
|
||||
display_width = con.DisplayWidth(string)
|
||||
|
||||
# Reset the memoized state.
|
||||
con = console_attr.ResetConsoleAttr()
|
||||
|
||||
# Print the console width and height in characters.
|
||||
width, height = con.GetTermSize()
|
||||
print 'width={width}, height={height}'.format(width=width, height=height)
|
||||
|
||||
# Colorize table data cells.
|
||||
fail = console_attr.Colorizer('FAIL', 'red')
|
||||
pass = console_attr.Colorizer('PASS', 'green')
|
||||
cells = ['label', fail, 'more text', pass, 'end']
|
||||
for cell in cells;
|
||||
if isinstance(cell, console_attr.Colorizer):
|
||||
cell.Render()
|
||||
else:
|
||||
out.write(cell)
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unicodedata
|
||||
|
||||
from fire.console import console_attr_os
|
||||
from fire.console import encoding as encoding_util
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class BoxLineCharacters(object):
|
||||
"""Box/line drawing characters.
|
||||
|
||||
The element names are from ISO 8879:1986//ENTITIES Box and Line Drawing//EN:
|
||||
http://www.w3.org/2003/entities/iso8879doc/isobox.html
|
||||
"""
|
||||
|
||||
|
||||
class BoxLineCharactersUnicode(BoxLineCharacters):
|
||||
"""unicode Box/line drawing characters (cp437 compatible unicode)."""
|
||||
dl = '┐'
|
||||
dr = '┌'
|
||||
h = '─'
|
||||
hd = '┬'
|
||||
hu = '┴'
|
||||
ul = '┘'
|
||||
ur = '└'
|
||||
v = '│'
|
||||
vh = '┼'
|
||||
vl = '┤'
|
||||
vr = '├'
|
||||
d_dl = '╗'
|
||||
d_dr = '╔'
|
||||
d_h = '═'
|
||||
d_hd = '╦'
|
||||
d_hu = '╩'
|
||||
d_ul = '╝'
|
||||
d_ur = '╚'
|
||||
d_v = '║'
|
||||
d_vh = '╬'
|
||||
d_vl = '╣'
|
||||
d_vr = '╠'
|
||||
|
||||
|
||||
class BoxLineCharactersAscii(BoxLineCharacters):
|
||||
"""ASCII Box/line drawing characters."""
|
||||
dl = '+'
|
||||
dr = '+'
|
||||
h = '-'
|
||||
hd = '+'
|
||||
hu = '+'
|
||||
ul = '+'
|
||||
ur = '+'
|
||||
v = '|'
|
||||
vh = '+'
|
||||
vl = '+'
|
||||
vr = '+'
|
||||
d_dl = '#'
|
||||
d_dr = '#'
|
||||
d_h = '='
|
||||
d_hd = '#'
|
||||
d_hu = '#'
|
||||
d_ul = '#'
|
||||
d_ur = '#'
|
||||
d_v = '#'
|
||||
d_vh = '#'
|
||||
d_vl = '#'
|
||||
d_vr = '#'
|
||||
|
||||
|
||||
class ProgressTrackerSymbols(object):
|
||||
"""Characters used by progress trackers."""
|
||||
|
||||
|
||||
class ProgressTrackerSymbolsUnicode(ProgressTrackerSymbols):
|
||||
"""Characters used by progress trackers."""
|
||||
|
||||
@property
|
||||
def spin_marks(self):
|
||||
return ['⠏', '⠛', '⠹', '⠼', '⠶', '⠧']
|
||||
|
||||
success = '✓'
|
||||
failed = 'X'
|
||||
interrupted = '-'
|
||||
not_started = '.'
|
||||
prefix_length = 2
|
||||
|
||||
|
||||
class ProgressTrackerSymbolsAscii(ProgressTrackerSymbols):
|
||||
"""Characters used by progress trackers."""
|
||||
|
||||
@property
|
||||
def spin_marks(self):
|
||||
return ['|', '/', '-', '\\',]
|
||||
|
||||
success = 'OK'
|
||||
failed = 'X'
|
||||
interrupted = '-'
|
||||
not_started = '.'
|
||||
prefix_length = 3
|
||||
|
||||
|
||||
class ConsoleAttr(object):
|
||||
"""Console attribute and special drawing characters and functions accessor.
|
||||
|
||||
Use GetConsoleAttr() to get a global ConsoleAttr object shared by all callers.
|
||||
Use ConsoleAttr() for abstracting multiple consoles.
|
||||
|
||||
If _out is not associated with a console, or if the console properties cannot
|
||||
be determined, the default behavior is ASCII art with no attributes.
|
||||
|
||||
Attributes:
|
||||
_ANSI_COLOR: The ANSI color control sequence dict.
|
||||
_ANSI_COLOR_RESET: The ANSI color reset control sequence string.
|
||||
_csi: The ANSI Control Sequence indicator string, '' if not supported.
|
||||
_encoding: The character encoding.
|
||||
ascii: ASCII art. This is the default.
|
||||
utf8: UTF-8 unicode.
|
||||
win: Windows code page 437.
|
||||
_font_bold: The ANSI bold font embellishment code string.
|
||||
_font_italic: The ANSI italic font embellishment code string.
|
||||
_get_raw_key: A function that reads one keypress from stdin with no echo.
|
||||
_out: The console output file stream.
|
||||
_term: TERM environment variable value.
|
||||
_term_size: The terminal (x, y) dimensions in characters.
|
||||
"""
|
||||
|
||||
_CONSOLE_ATTR_STATE = None
|
||||
|
||||
_ANSI_COLOR = {
|
||||
'red': '31;1m',
|
||||
'yellow': '33;1m',
|
||||
'green': '32m',
|
||||
'blue': '34;1m'
|
||||
}
|
||||
_ANSI_COLOR_RESET = '39;0m'
|
||||
|
||||
_BULLETS_UNICODE = ('▪', '◆', '▸', '▫', '◇', '▹')
|
||||
_BULLETS_WINDOWS = ('■', '≡', '∞', 'Φ', '·') # cp437 compatible unicode
|
||||
_BULLETS_ASCII = ('o', '*', '+', '-')
|
||||
|
||||
def __init__(self, encoding=None):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
encoding: Encoding override.
|
||||
ascii -- ASCII art. This is the default.
|
||||
utf8 -- UTF-8 unicode.
|
||||
win -- Windows code page 437.
|
||||
"""
|
||||
# Normalize the encoding name.
|
||||
if not encoding:
|
||||
encoding = self._GetConsoleEncoding()
|
||||
elif encoding == 'win':
|
||||
encoding = 'cp437'
|
||||
self._encoding = encoding or 'ascii'
|
||||
self._term = os.getenv('TERM', '').lower()
|
||||
|
||||
# ANSI "standard" attributes.
|
||||
if self.SupportsAnsi():
|
||||
# Select Graphic Rendition paramaters from
|
||||
# http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
|
||||
# Italic '3' would be nice here but its not widely supported.
|
||||
self._csi = '\x1b['
|
||||
self._font_bold = '1'
|
||||
self._font_italic = '4'
|
||||
else:
|
||||
self._csi = None
|
||||
self._font_bold = ''
|
||||
self._font_italic = ''
|
||||
|
||||
# Encoded character attributes.
|
||||
if self._encoding == 'utf8':
|
||||
self._box_line_characters = BoxLineCharactersUnicode()
|
||||
self._bullets = self._BULLETS_UNICODE
|
||||
self._progress_tracker_symbols = ProgressTrackerSymbolsUnicode()
|
||||
elif self._encoding == 'cp437':
|
||||
self._box_line_characters = BoxLineCharactersUnicode()
|
||||
self._bullets = self._BULLETS_WINDOWS
|
||||
# Windows does not suport the unicode characters used for the spinner.
|
||||
self._progress_tracker_symbols = ProgressTrackerSymbolsAscii()
|
||||
else:
|
||||
self._box_line_characters = BoxLineCharactersAscii()
|
||||
self._bullets = self._BULLETS_ASCII
|
||||
self._progress_tracker_symbols = ProgressTrackerSymbolsAscii()
|
||||
|
||||
# OS specific attributes.
|
||||
self._get_raw_key = [console_attr_os.GetRawKeyFunction()]
|
||||
self._term_size = console_attr_os.GetTermSize()
|
||||
|
||||
self._display_width_cache = {}
|
||||
|
||||
def _GetConsoleEncoding(self):
|
||||
"""Gets the encoding as declared by the stdout stream.
|
||||
|
||||
Returns:
|
||||
str, The encoding name or None if it could not be determined.
|
||||
"""
|
||||
console_encoding = getattr(sys.stdout, 'encoding', None)
|
||||
if not console_encoding:
|
||||
return None
|
||||
console_encoding = console_encoding.lower()
|
||||
if 'utf-8' in console_encoding:
|
||||
return 'utf8'
|
||||
elif 'cp437' in console_encoding:
|
||||
return 'cp437'
|
||||
return None
|
||||
|
||||
def Colorize(self, string, color, justify=None):
|
||||
"""Generates a colorized string, optionally justified.
|
||||
|
||||
Args:
|
||||
string: The string to write.
|
||||
color: The color name -- must be in _ANSI_COLOR.
|
||||
justify: The justification function, no justification if None. For
|
||||
example, justify=lambda s: s.center(10)
|
||||
|
||||
Returns:
|
||||
str, The colorized string that can be printed to the console.
|
||||
"""
|
||||
if justify:
|
||||
string = justify(string)
|
||||
if self._csi and color in self._ANSI_COLOR:
|
||||
return '{csi}{color_code}{string}{csi}{reset_code}'.format(
|
||||
csi=self._csi,
|
||||
color_code=self._ANSI_COLOR[color],
|
||||
reset_code=self._ANSI_COLOR_RESET,
|
||||
string=string)
|
||||
# TODO: Add elif self._encoding == 'cp437': code here.
|
||||
return string
|
||||
|
||||
def ConvertOutputToUnicode(self, buf):
|
||||
"""Converts a console output string buf to unicode.
|
||||
|
||||
Mainly used for testing. Allows test comparisons in unicode while ensuring
|
||||
that unicode => encoding => unicode works.
|
||||
|
||||
Args:
|
||||
buf: The console output string to convert.
|
||||
|
||||
Returns:
|
||||
The console output string buf converted to unicode.
|
||||
"""
|
||||
if isinstance(buf, six.text_type):
|
||||
buf = buf.encode(self._encoding)
|
||||
return six.text_type(buf, self._encoding, 'replace')
|
||||
|
||||
def GetBoxLineCharacters(self):
|
||||
"""Returns the box/line drawing characters object.
|
||||
|
||||
The element names are from ISO 8879:1986//ENTITIES Box and Line Drawing//EN:
|
||||
http://www.w3.org/2003/entities/iso8879doc/isobox.html
|
||||
|
||||
Returns:
|
||||
A BoxLineCharacters object for the console output device.
|
||||
"""
|
||||
return self._box_line_characters
|
||||
|
||||
def GetBullets(self):
|
||||
"""Returns the bullet characters list.
|
||||
|
||||
Use the list elements in order for best appearance in nested bullet lists,
|
||||
wrapping back to the first element for deep nesting. The list size depends
|
||||
on the console implementation.
|
||||
|
||||
Returns:
|
||||
A tuple of bullet characters.
|
||||
"""
|
||||
return self._bullets
|
||||
|
||||
def GetProgressTrackerSymbols(self):
|
||||
"""Returns the progress tracker characters object.
|
||||
|
||||
Returns:
|
||||
A ProgressTrackerSymbols object for the console output device.
|
||||
"""
|
||||
return self._progress_tracker_symbols
|
||||
|
||||
def GetControlSequenceIndicator(self):
|
||||
"""Returns the control sequence indicator string.
|
||||
|
||||
Returns:
|
||||
The conrol sequence indicator string or None if control sequences are not
|
||||
supported.
|
||||
"""
|
||||
return self._csi
|
||||
|
||||
def GetControlSequenceLen(self, buf):
|
||||
"""Returns the control sequence length at the beginning of buf.
|
||||
|
||||
Used in display width computations. Control sequences have display width 0.
|
||||
|
||||
Args:
|
||||
buf: The string to check for a control sequence.
|
||||
|
||||
Returns:
|
||||
The conrol sequence length at the beginning of buf or 0 if buf does not
|
||||
start with a control sequence.
|
||||
"""
|
||||
if not self._csi or not buf.startswith(self._csi):
|
||||
return 0
|
||||
n = 0
|
||||
for c in buf:
|
||||
n += 1
|
||||
if c.isalpha():
|
||||
break
|
||||
return n
|
||||
|
||||
def GetEncoding(self):
|
||||
"""Returns the current encoding."""
|
||||
return self._encoding
|
||||
|
||||
def GetFontCode(self, bold=False, italic=False):
|
||||
"""Returns a font code string for 0 or more embellishments.
|
||||
|
||||
GetFontCode() with no args returns the default font code string.
|
||||
|
||||
Args:
|
||||
bold: True for bold embellishment.
|
||||
italic: True for italic embellishment.
|
||||
|
||||
Returns:
|
||||
The font code string for the requested embellishments. Write this string
|
||||
to the console output to control the font settings.
|
||||
"""
|
||||
if not self._csi:
|
||||
return ''
|
||||
codes = []
|
||||
if bold:
|
||||
codes.append(self._font_bold)
|
||||
if italic:
|
||||
codes.append(self._font_italic)
|
||||
return '{csi}{codes}m'.format(csi=self._csi, codes=';'.join(codes))
|
||||
|
||||
def GetRawKey(self):
|
||||
"""Reads one key press from stdin with no echo.
|
||||
|
||||
Returns:
|
||||
The key name, None for EOF, <KEY-*> for function keys, otherwise a
|
||||
character.
|
||||
"""
|
||||
return self._get_raw_key[0]()
|
||||
|
||||
def GetTermSize(self):
|
||||
"""Returns the terminal (x, y) dimensions in characters.
|
||||
|
||||
Returns:
|
||||
(x, y): A tuple of the terminal x and y dimensions.
|
||||
"""
|
||||
return self._term_size
|
||||
|
||||
def DisplayWidth(self, buf):
|
||||
"""Returns the display width of buf, handling unicode and ANSI controls.
|
||||
|
||||
Args:
|
||||
buf: The string to count from.
|
||||
|
||||
Returns:
|
||||
The display width of buf, handling unicode and ANSI controls.
|
||||
"""
|
||||
if not isinstance(buf, six.string_types):
|
||||
# Handle non-string objects like Colorizer().
|
||||
return len(buf)
|
||||
|
||||
cached = self._display_width_cache.get(buf, None)
|
||||
if cached is not None:
|
||||
return cached
|
||||
|
||||
width = 0
|
||||
max_width = 0
|
||||
i = 0
|
||||
while i < len(buf):
|
||||
if self._csi and buf[i:].startswith(self._csi):
|
||||
i += self.GetControlSequenceLen(buf[i:])
|
||||
elif buf[i] == '\n':
|
||||
# A newline incidates the start of a new line.
|
||||
# Newline characters have 0 width.
|
||||
max_width = max(width, max_width)
|
||||
width = 0
|
||||
i += 1
|
||||
else:
|
||||
width += GetCharacterDisplayWidth(buf[i])
|
||||
i += 1
|
||||
max_width = max(width, max_width)
|
||||
|
||||
self._display_width_cache[buf] = max_width
|
||||
return max_width
|
||||
|
||||
def SplitIntoNormalAndControl(self, buf):
|
||||
"""Returns a list of (normal_string, control_sequence) tuples from buf.
|
||||
|
||||
Args:
|
||||
buf: The input string containing one or more control sequences
|
||||
interspersed with normal strings.
|
||||
|
||||
Returns:
|
||||
A list of (normal_string, control_sequence) tuples.
|
||||
"""
|
||||
if not self._csi or not buf:
|
||||
return [(buf, '')]
|
||||
seq = []
|
||||
i = 0
|
||||
while i < len(buf):
|
||||
c = buf.find(self._csi, i)
|
||||
if c < 0:
|
||||
seq.append((buf[i:], ''))
|
||||
break
|
||||
normal = buf[i:c]
|
||||
i = c + self.GetControlSequenceLen(buf[c:])
|
||||
seq.append((normal, buf[c:i]))
|
||||
return seq
|
||||
|
||||
def SplitLine(self, line, width):
|
||||
"""Splits line into width length chunks.
|
||||
|
||||
Args:
|
||||
line: The line to split.
|
||||
width: The width of each chunk except the last which could be smaller than
|
||||
width.
|
||||
|
||||
Returns:
|
||||
A list of chunks, all but the last with display width == width.
|
||||
"""
|
||||
lines = []
|
||||
chunk = ''
|
||||
w = 0
|
||||
keep = False
|
||||
for normal, control in self.SplitIntoNormalAndControl(line):
|
||||
keep = True
|
||||
while True:
|
||||
n = width - w
|
||||
w += len(normal)
|
||||
if w <= width:
|
||||
break
|
||||
lines.append(chunk + normal[:n])
|
||||
chunk = ''
|
||||
keep = False
|
||||
w = 0
|
||||
normal = normal[n:]
|
||||
chunk += normal + control
|
||||
if chunk or keep:
|
||||
lines.append(chunk)
|
||||
return lines
|
||||
|
||||
def SupportsAnsi(self):
|
||||
return (self._encoding != 'ascii' and
|
||||
('screen' in self._term or 'xterm' in self._term))
|
||||
|
||||
|
||||
class Colorizer(object):
|
||||
"""Resource string colorizer.
|
||||
|
||||
Attributes:
|
||||
_con: ConsoleAttr object.
|
||||
_color: Color name.
|
||||
_string: The string to colorize.
|
||||
_justify: The justification function, no justification if None. For example,
|
||||
justify=lambda s: s.center(10)
|
||||
"""
|
||||
|
||||
def __init__(self, string, color, justify=None):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
string: The string to colorize.
|
||||
color: Color name used to index ConsoleAttr._ANSI_COLOR.
|
||||
justify: The justification function, no justification if None. For
|
||||
example, justify=lambda s: s.center(10)
|
||||
"""
|
||||
self._con = GetConsoleAttr()
|
||||
self._color = color
|
||||
self._string = string
|
||||
self._justify = justify
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._string == six.text_type(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._string > six.text_type(other)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self._string < six.text_type(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return not self < other
|
||||
|
||||
def __le__(self, other):
|
||||
return not self > other
|
||||
|
||||
def __len__(self):
|
||||
return self._con.DisplayWidth(self._string)
|
||||
|
||||
def __str__(self):
|
||||
return self._string
|
||||
|
||||
def Render(self, stream, justify=None):
|
||||
"""Renders the string as self._color on the console.
|
||||
|
||||
Args:
|
||||
stream: The stream to render the string to. The stream given here *must*
|
||||
have the same encoding as sys.stdout for this to work properly.
|
||||
justify: The justification function, self._justify if None.
|
||||
"""
|
||||
stream.write(
|
||||
self._con.Colorize(self._string, self._color, justify or self._justify))
|
||||
|
||||
|
||||
def GetConsoleAttr(encoding=None, reset=False):
|
||||
"""Gets the console attribute state.
|
||||
|
||||
If this is the first call or reset is True or encoding is not None and does
|
||||
not match the current encoding or out is not None and does not match the
|
||||
current out then the state is (re)initialized. Otherwise the current state
|
||||
is returned.
|
||||
|
||||
This call associates the out file stream with the console. All console related
|
||||
output should go to the same stream.
|
||||
|
||||
Args:
|
||||
encoding: Encoding override.
|
||||
ascii -- ASCII. This is the default.
|
||||
utf8 -- UTF-8 unicode.
|
||||
win -- Windows code page 437.
|
||||
reset: Force re-initialization if True.
|
||||
|
||||
Returns:
|
||||
The global ConsoleAttr state object.
|
||||
"""
|
||||
attr = ConsoleAttr._CONSOLE_ATTR_STATE # pylint: disable=protected-access
|
||||
if not reset:
|
||||
if not attr:
|
||||
reset = True
|
||||
elif encoding and encoding != attr.GetEncoding():
|
||||
reset = True
|
||||
if reset:
|
||||
attr = ConsoleAttr(encoding=encoding)
|
||||
ConsoleAttr._CONSOLE_ATTR_STATE = attr # pylint: disable=protected-access
|
||||
return attr
|
||||
|
||||
|
||||
def ResetConsoleAttr(encoding=None):
|
||||
"""Resets the console attribute state to the console default.
|
||||
|
||||
Args:
|
||||
encoding: Reset to this encoding instead of the default.
|
||||
ascii -- ASCII. This is the default.
|
||||
utf8 -- UTF-8 unicode.
|
||||
win -- Windows code page 437.
|
||||
|
||||
Returns:
|
||||
The global ConsoleAttr state object.
|
||||
"""
|
||||
return GetConsoleAttr(encoding=encoding, reset=True)
|
||||
|
||||
|
||||
def GetCharacterDisplayWidth(char):
|
||||
"""Returns the monospaced terminal display width of char.
|
||||
|
||||
Assumptions:
|
||||
- monospaced display
|
||||
- ambiguous or unknown chars default to width 1
|
||||
- ASCII control char width is 1 => don't use this for control chars
|
||||
|
||||
Args:
|
||||
char: The character to determine the display width of.
|
||||
|
||||
Returns:
|
||||
The monospaced terminal display width of char: either 0, 1, or 2.
|
||||
"""
|
||||
if not isinstance(char, six.text_type):
|
||||
# Non-unicode chars have width 1. Don't use this function on control chars.
|
||||
return 1
|
||||
|
||||
# Normalize to avoid special cases.
|
||||
char = unicodedata.normalize('NFC', char)
|
||||
|
||||
if unicodedata.combining(char) != 0:
|
||||
# Modifies the previous character and does not move the cursor.
|
||||
return 0
|
||||
elif unicodedata.category(char) == 'Cf':
|
||||
# Unprintable formatting char.
|
||||
return 0
|
||||
elif unicodedata.east_asian_width(char) in 'FW':
|
||||
# Fullwidth or Wide chars take 2 character positions.
|
||||
return 2
|
||||
else:
|
||||
# Don't use this function on control chars.
|
||||
return 1
|
||||
|
||||
|
||||
def SafeText(data, encoding=None, escape=True):
|
||||
br"""Converts the data to a text string compatible with the given encoding.
|
||||
|
||||
This works the same way as Decode() below except it guarantees that any
|
||||
characters in the resulting text string can be re-encoded using the given
|
||||
encoding (or GetConsoleAttr().GetEncoding() if None is given). This means
|
||||
that the string will be safe to print to sys.stdout (for example) without
|
||||
getting codec exceptions if the user's terminal doesn't support the encoding
|
||||
used by the source of the text.
|
||||
|
||||
Args:
|
||||
data: Any bytes, string, or object that has str() or unicode() methods.
|
||||
encoding: The encoding name to ensure compatibility with. Defaults to
|
||||
GetConsoleAttr().GetEncoding().
|
||||
escape: Replace unencodable characters with a \uXXXX or \xXX equivalent if
|
||||
True. Otherwise replace unencodable characters with an appropriate unknown
|
||||
character, '?' for ASCII, and the unicode unknown replacement character
|
||||
\uFFFE for unicode.
|
||||
|
||||
Returns:
|
||||
A text string representation of the data, but modified to remove any
|
||||
characters that would result in an encoding exception with the target
|
||||
encoding. In the worst case, with escape=False, it will contain only ?
|
||||
characters.
|
||||
"""
|
||||
if data is None:
|
||||
return 'None'
|
||||
encoding = encoding or GetConsoleAttr().GetEncoding()
|
||||
string = encoding_util.Decode(data, encoding=encoding)
|
||||
|
||||
try:
|
||||
# No change needed if the string encodes to the output encoding.
|
||||
string.encode(encoding)
|
||||
return string
|
||||
except UnicodeError:
|
||||
# The string does not encode to the output encoding. Encode it with error
|
||||
# handling then convert it back into a text string (which will be
|
||||
# guaranteed to only contain characters that can be encoded later.
|
||||
return (string
|
||||
.encode(encoding, 'backslashreplace' if escape else 'replace')
|
||||
.decode(encoding))
|
||||
|
||||
|
||||
def EncodeToBytes(data):
|
||||
r"""Encode data to bytes.
|
||||
|
||||
The primary use case is for base64/mime style 7-bit ascii encoding where the
|
||||
encoder input must be bytes. "safe" means that the conversion always returns
|
||||
bytes and will not raise codec exceptions.
|
||||
|
||||
If data is text then an 8-bit ascii encoding is attempted, then the console
|
||||
encoding, and finally utf-8.
|
||||
|
||||
Args:
|
||||
data: Any bytes, string, or object that has str() or unicode() methods.
|
||||
|
||||
Returns:
|
||||
A bytes string representation of the data.
|
||||
"""
|
||||
if data is None:
|
||||
return b''
|
||||
if isinstance(data, bytes):
|
||||
# Already bytes - our work is done.
|
||||
return data
|
||||
|
||||
# Coerce to text that will be converted to bytes.
|
||||
s = six.text_type(data)
|
||||
|
||||
try:
|
||||
# Assume the text can be directly converted to bytes (8-bit ascii).
|
||||
return s.encode('iso-8859-1')
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Try the output encoding.
|
||||
return s.encode(GetConsoleAttr().GetEncoding())
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
# Punt to utf-8.
|
||||
return s.encode('utf-8')
|
||||
|
||||
|
||||
def Decode(data, encoding=None):
|
||||
"""Converts the given string, bytes, or object to a text string.
|
||||
|
||||
Args:
|
||||
data: Any bytes, string, or object that has str() or unicode() methods.
|
||||
encoding: A suggesting encoding used to decode. If this encoding doesn't
|
||||
work, other defaults are tried. Defaults to
|
||||
GetConsoleAttr().GetEncoding().
|
||||
|
||||
Returns:
|
||||
A text string representation of the data.
|
||||
"""
|
||||
encoding = encoding or GetConsoleAttr().GetEncoding()
|
||||
return encoding_util.Decode(data, encoding=encoding)
|
||||
@@ -1,260 +0,0 @@
|
||||
# -*- coding: utf-8 -*- #
|
||||
# Copyright 2015 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""OS specific console_attr helper functions."""
|
||||
# This file contains platform specific code which is not currently handled
|
||||
# by pytype.
|
||||
# pytype: skip-file
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from fire.console import encoding
|
||||
|
||||
|
||||
def GetTermSize():
|
||||
"""Gets the terminal x and y dimensions in characters.
|
||||
|
||||
_GetTermSize*() helper functions taken from:
|
||||
http://stackoverflow.com/questions/263890/
|
||||
|
||||
Returns:
|
||||
(columns, lines): A tuple containing the terminal x and y dimensions.
|
||||
"""
|
||||
xy = None
|
||||
# Believe the first helper that doesn't bail.
|
||||
for get_terminal_size in (_GetTermSizePosix,
|
||||
_GetTermSizeWindows,
|
||||
_GetTermSizeEnvironment,
|
||||
_GetTermSizeTput):
|
||||
try:
|
||||
xy = get_terminal_size()
|
||||
if xy:
|
||||
break
|
||||
except: # pylint: disable=bare-except
|
||||
pass
|
||||
return xy or (80, 24)
|
||||
|
||||
|
||||
def _GetTermSizePosix():
|
||||
"""Returns the Posix terminal x and y dimensions."""
|
||||
# pylint: disable=g-import-not-at-top
|
||||
import fcntl
|
||||
# pylint: disable=g-import-not-at-top
|
||||
import struct
|
||||
# pylint: disable=g-import-not-at-top
|
||||
import termios
|
||||
|
||||
def _GetXY(fd):
|
||||
"""Returns the terminal (x,y) size for fd.
|
||||
|
||||
Args:
|
||||
fd: The terminal file descriptor.
|
||||
|
||||
Returns:
|
||||
The terminal (x,y) size for fd or None on error.
|
||||
"""
|
||||
try:
|
||||
# This magic incantation converts a struct from ioctl(2) containing two
|
||||
# binary shorts to a (rows, columns) int tuple.
|
||||
rc = struct.unpack(b'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, 'junk'))
|
||||
return (rc[1], rc[0]) if rc else None
|
||||
except: # pylint: disable=bare-except
|
||||
return None
|
||||
|
||||
xy = _GetXY(0) or _GetXY(1) or _GetXY(2)
|
||||
if not xy:
|
||||
fd = None
|
||||
try:
|
||||
fd = os.open(os.ctermid(), os.O_RDONLY)
|
||||
xy = _GetXY(fd)
|
||||
except: # pylint: disable=bare-except
|
||||
xy = None
|
||||
finally:
|
||||
if fd is not None:
|
||||
os.close(fd)
|
||||
return xy
|
||||
|
||||
|
||||
def _GetTermSizeWindows():
|
||||
"""Returns the Windows terminal x and y dimensions."""
|
||||
# pylint:disable=g-import-not-at-top
|
||||
import struct
|
||||
# pylint: disable=g-import-not-at-top
|
||||
from ctypes import create_string_buffer
|
||||
# pylint:disable=g-import-not-at-top
|
||||
from ctypes import windll
|
||||
|
||||
# stdin handle is -10
|
||||
# stdout handle is -11
|
||||
# stderr handle is -12
|
||||
|
||||
h = windll.kernel32.GetStdHandle(-12)
|
||||
csbi = create_string_buffer(22)
|
||||
if not windll.kernel32.GetConsoleScreenBufferInfo(h, csbi):
|
||||
return None
|
||||
(unused_bufx, unused_bufy, unused_curx, unused_cury, unused_wattr,
|
||||
left, top, right, bottom,
|
||||
unused_maxx, unused_maxy) = struct.unpack(b'hhhhHhhhhhh', csbi.raw)
|
||||
x = right - left + 1
|
||||
y = bottom - top + 1
|
||||
return (x, y)
|
||||
|
||||
|
||||
def _GetTermSizeEnvironment():
|
||||
"""Returns the terminal x and y dimensions from the environment."""
|
||||
return (int(os.environ['COLUMNS']), int(os.environ['LINES']))
|
||||
|
||||
|
||||
def _GetTermSizeTput():
|
||||
"""Returns the terminal x and y dimemsions from tput(1)."""
|
||||
import subprocess # pylint: disable=g-import-not-at-top
|
||||
output = encoding.Decode(subprocess.check_output(['tput', 'cols'],
|
||||
stderr=subprocess.STDOUT))
|
||||
cols = int(output)
|
||||
output = encoding.Decode(subprocess.check_output(['tput', 'lines'],
|
||||
stderr=subprocess.STDOUT))
|
||||
rows = int(output)
|
||||
return (cols, rows)
|
||||
|
||||
|
||||
_ANSI_CSI = '\x1b' # ANSI control sequence indicator (ESC)
|
||||
_CONTROL_D = '\x04' # unix EOF (^D)
|
||||
_CONTROL_Z = '\x1a' # Windows EOF (^Z)
|
||||
_WINDOWS_CSI_1 = '\x00' # Windows control sequence indicator #1
|
||||
_WINDOWS_CSI_2 = '\xe0' # Windows control sequence indicator #2
|
||||
|
||||
|
||||
def GetRawKeyFunction():
|
||||
"""Returns a function that reads one keypress from stdin with no echo.
|
||||
|
||||
Returns:
|
||||
A function that reads one keypress from stdin with no echo or a function
|
||||
that always returns None if stdin does not support it.
|
||||
"""
|
||||
# Believe the first helper that doesn't bail.
|
||||
for get_raw_key_function in (_GetRawKeyFunctionPosix,
|
||||
_GetRawKeyFunctionWindows):
|
||||
try:
|
||||
return get_raw_key_function()
|
||||
except: # pylint: disable=bare-except
|
||||
pass
|
||||
return lambda: None
|
||||
|
||||
|
||||
def _GetRawKeyFunctionPosix():
|
||||
"""_GetRawKeyFunction helper using Posix APIs."""
|
||||
# pylint: disable=g-import-not-at-top
|
||||
import tty
|
||||
# pylint: disable=g-import-not-at-top
|
||||
import termios
|
||||
|
||||
def _GetRawKeyPosix():
|
||||
"""Reads and returns one keypress from stdin, no echo, using Posix APIs.
|
||||
|
||||
Returns:
|
||||
The key name, None for EOF, <*> for function keys, otherwise a
|
||||
character.
|
||||
"""
|
||||
ansi_to_key = {
|
||||
'A': '<UP-ARROW>',
|
||||
'B': '<DOWN-ARROW>',
|
||||
'D': '<LEFT-ARROW>',
|
||||
'C': '<RIGHT-ARROW>',
|
||||
'5': '<PAGE-UP>',
|
||||
'6': '<PAGE-DOWN>',
|
||||
'H': '<HOME>',
|
||||
'F': '<END>',
|
||||
'M': '<DOWN-ARROW>',
|
||||
'S': '<PAGE-UP>',
|
||||
'T': '<PAGE-DOWN>',
|
||||
}
|
||||
|
||||
# Flush pending output. sys.stdin.read() would do this, but it's explicitly
|
||||
# bypassed in _GetKeyChar().
|
||||
sys.stdout.flush()
|
||||
|
||||
fd = sys.stdin.fileno()
|
||||
|
||||
def _GetKeyChar():
|
||||
return encoding.Decode(os.read(fd, 1))
|
||||
|
||||
old_settings = termios.tcgetattr(fd)
|
||||
try:
|
||||
tty.setraw(fd)
|
||||
c = _GetKeyChar()
|
||||
if c == _ANSI_CSI:
|
||||
c = _GetKeyChar()
|
||||
while True:
|
||||
if c == _ANSI_CSI:
|
||||
return c
|
||||
if c.isalpha():
|
||||
break
|
||||
prev_c = c
|
||||
c = _GetKeyChar()
|
||||
if c == '~':
|
||||
c = prev_c
|
||||
break
|
||||
return ansi_to_key.get(c, '')
|
||||
except: # pylint:disable=bare-except
|
||||
c = None
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
return None if c in (_CONTROL_D, _CONTROL_Z) else c
|
||||
|
||||
return _GetRawKeyPosix
|
||||
|
||||
|
||||
def _GetRawKeyFunctionWindows():
|
||||
"""_GetRawKeyFunction helper using Windows APIs."""
|
||||
# pylint: disable=g-import-not-at-top
|
||||
import msvcrt
|
||||
|
||||
def _GetRawKeyWindows():
|
||||
"""Reads and returns one keypress from stdin, no echo, using Windows APIs.
|
||||
|
||||
Returns:
|
||||
The key name, None for EOF, <*> for function keys, otherwise a
|
||||
character.
|
||||
"""
|
||||
windows_to_key = {
|
||||
'H': '<UP-ARROW>',
|
||||
'P': '<DOWN-ARROW>',
|
||||
'K': '<LEFT-ARROW>',
|
||||
'M': '<RIGHT-ARROW>',
|
||||
'I': '<PAGE-UP>',
|
||||
'Q': '<PAGE-DOWN>',
|
||||
'G': '<HOME>',
|
||||
'O': '<END>',
|
||||
}
|
||||
|
||||
# Flush pending output. sys.stdin.read() would do this it's explicitly
|
||||
# bypassed in _GetKeyChar().
|
||||
sys.stdout.flush()
|
||||
|
||||
def _GetKeyChar():
|
||||
return encoding.Decode(msvcrt.getch())
|
||||
|
||||
c = _GetKeyChar()
|
||||
# Special function key is a two character sequence; return the second char.
|
||||
if c in (_WINDOWS_CSI_1, _WINDOWS_CSI_2):
|
||||
return windows_to_key.get(_GetKeyChar(), '')
|
||||
return None if c in (_CONTROL_D, _CONTROL_Z) else c
|
||||
|
||||
return _GetRawKeyWindows
|
||||
@@ -1,299 +0,0 @@
|
||||
# -*- coding: utf-8 -*- #
|
||||
# Copyright 2015 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Simple console pager."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
from fire.console import console_attr
|
||||
|
||||
|
||||
class Pager(object):
|
||||
"""A simple console text pager.
|
||||
|
||||
This pager requires the entire contents to be available. The contents are
|
||||
written one page of lines at a time. The prompt is written after each page of
|
||||
lines. A one character response is expected. See HELP_TEXT below for more
|
||||
info.
|
||||
|
||||
The contents are written as is. For example, ANSI control codes will be in
|
||||
effect. This is different from pagers like more(1) which is ANSI control code
|
||||
agnostic and miscalculates line lengths, and less(1) which displays control
|
||||
character names by default.
|
||||
|
||||
Attributes:
|
||||
_attr: The current ConsoleAttr handle.
|
||||
_clear: A string that clears the prompt when written to _out.
|
||||
_contents: The entire contents of the text lines to page.
|
||||
_height: The terminal height in characters.
|
||||
_out: The output stream, log.out (effectively) if None.
|
||||
_prompt: The page break prompt.
|
||||
_search_direction: The search direction command, n:forward, N:reverse.
|
||||
_search_pattern: The current forward/reverse search compiled RE.
|
||||
_width: The termonal width in characters.
|
||||
"""
|
||||
|
||||
HELP_TEXT = """
|
||||
Simple pager commands:
|
||||
|
||||
b, ^B, <PAGE-UP>, <LEFT-ARROW>
|
||||
Back one page.
|
||||
f, ^F, <SPACE>, <PAGE-DOWN>, <RIGHT-ARROW>
|
||||
Forward one page. Does not quit if there are no more lines.
|
||||
g, <HOME>
|
||||
Back to the first page.
|
||||
<number>g
|
||||
Go to <number> lines from the top.
|
||||
G, <END>
|
||||
Forward to the last page.
|
||||
<number>G
|
||||
Go to <number> lines from the bottom.
|
||||
h
|
||||
Print pager command help.
|
||||
j, +, <DOWN-ARROW>
|
||||
Forward one line.
|
||||
k, -, <UP-ARROW>
|
||||
Back one line.
|
||||
/pattern
|
||||
Forward search for pattern.
|
||||
?pattern
|
||||
Backward search for pattern.
|
||||
n
|
||||
Repeat current search.
|
||||
N
|
||||
Repeat current search in the opposite direction.
|
||||
q, Q, ^C, ^D, ^Z
|
||||
Quit return to the caller.
|
||||
any other character
|
||||
Prompt again.
|
||||
|
||||
Hit any key to continue:"""
|
||||
|
||||
PREV_POS_NXT_REPRINT = -1, -1
|
||||
|
||||
def __init__(self, contents, out=None, prompt=None):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
contents: The entire contents of the text lines to page.
|
||||
out: The output stream, log.out (effectively) if None.
|
||||
prompt: The page break prompt, a defalt prompt is used if None..
|
||||
"""
|
||||
self._contents = contents
|
||||
self._out = out or sys.stdout
|
||||
self._search_pattern = None
|
||||
self._search_direction = None
|
||||
|
||||
# prev_pos, prev_next values to force reprint
|
||||
self.prev_pos, self.prev_nxt = self.PREV_POS_NXT_REPRINT
|
||||
# Initialize the console attributes.
|
||||
self._attr = console_attr.GetConsoleAttr()
|
||||
self._width, self._height = self._attr.GetTermSize()
|
||||
|
||||
# Initialize the prompt and the prompt clear string.
|
||||
if not prompt:
|
||||
prompt = '{bold}--({{percent}}%)--{normal}'.format(
|
||||
bold=self._attr.GetFontCode(bold=True),
|
||||
normal=self._attr.GetFontCode())
|
||||
self._clear = '\r{0}\r'.format(' ' * (self._attr.DisplayWidth(prompt) - 6))
|
||||
self._prompt = prompt
|
||||
|
||||
# Initialize a list of lines with long lines split into separate display
|
||||
# lines.
|
||||
self._lines = []
|
||||
for line in contents.splitlines():
|
||||
self._lines += self._attr.SplitLine(line, self._width)
|
||||
|
||||
def _Write(self, s):
|
||||
"""Mockable helper that writes s to self._out."""
|
||||
self._out.write(s)
|
||||
|
||||
def _GetSearchCommand(self, c):
|
||||
"""Consumes a search command and returns the equivalent pager command.
|
||||
|
||||
The search pattern is an RE that is pre-compiled and cached for subsequent
|
||||
/<newline>, ?<newline>, n, or N commands.
|
||||
|
||||
Args:
|
||||
c: The search command char.
|
||||
|
||||
Returns:
|
||||
The pager command char.
|
||||
"""
|
||||
self._Write(c)
|
||||
buf = ''
|
||||
while True:
|
||||
p = self._attr.GetRawKey()
|
||||
if p in (None, '\n', '\r') or len(p) != 1:
|
||||
break
|
||||
self._Write(p)
|
||||
buf += p
|
||||
self._Write('\r' + ' ' * len(buf) + '\r')
|
||||
if buf:
|
||||
try:
|
||||
self._search_pattern = re.compile(buf)
|
||||
except re.error:
|
||||
# Silently ignore pattern errors.
|
||||
self._search_pattern = None
|
||||
return ''
|
||||
self._search_direction = 'n' if c == '/' else 'N'
|
||||
return 'n'
|
||||
|
||||
def _Help(self):
|
||||
"""Print command help and wait for any character to continue."""
|
||||
clear = self._height - (len(self.HELP_TEXT) -
|
||||
len(self.HELP_TEXT.replace('\n', '')))
|
||||
if clear > 0:
|
||||
self._Write('\n' * clear)
|
||||
self._Write(self.HELP_TEXT)
|
||||
self._attr.GetRawKey()
|
||||
self._Write('\n')
|
||||
|
||||
def Run(self):
|
||||
"""Run the pager."""
|
||||
# No paging if the contents are small enough.
|
||||
if len(self._lines) <= self._height:
|
||||
self._Write(self._contents)
|
||||
return
|
||||
|
||||
# We will not always reset previous values.
|
||||
reset_prev_values = True
|
||||
# Save room for the prompt at the bottom of the page.
|
||||
self._height -= 1
|
||||
|
||||
# Loop over all the pages.
|
||||
pos = 0
|
||||
while pos < len(self._lines):
|
||||
# Write a page of lines.
|
||||
nxt = pos + self._height
|
||||
if nxt > len(self._lines):
|
||||
nxt = len(self._lines)
|
||||
pos = nxt - self._height
|
||||
# Checks if the starting position is in between the current printed lines
|
||||
# so we don't need to reprint all the lines.
|
||||
if self.prev_pos < pos < self.prev_nxt:
|
||||
# we start where the previous page ended.
|
||||
self._Write('\n'.join(self._lines[self.prev_nxt:nxt]) + '\n')
|
||||
elif pos != self.prev_pos and nxt != self.prev_nxt:
|
||||
self._Write('\n'.join(self._lines[pos:nxt]) + '\n')
|
||||
|
||||
# Handle the prompt response.
|
||||
percent = self._prompt.format(percent=100 * nxt // len(self._lines))
|
||||
digits = ''
|
||||
while True:
|
||||
# We want to reset prev values if we just exited out of the while loop
|
||||
if reset_prev_values:
|
||||
self.prev_pos, self.prev_nxt = pos, nxt
|
||||
reset_prev_values = False
|
||||
self._Write(percent)
|
||||
c = self._attr.GetRawKey()
|
||||
self._Write(self._clear)
|
||||
|
||||
# Parse the command.
|
||||
if c in (None, # EOF.
|
||||
'q', # Quit.
|
||||
'Q', # Quit.
|
||||
'\x03', # ^C (unix & windows terminal interrupt)
|
||||
'\x1b', # ESC.
|
||||
):
|
||||
# Quit.
|
||||
return
|
||||
elif c in ('/', '?'):
|
||||
c = self._GetSearchCommand(c)
|
||||
elif c.isdigit():
|
||||
# Collect digits for operation count.
|
||||
digits += c
|
||||
continue
|
||||
|
||||
# Set the optional command count.
|
||||
if digits:
|
||||
count = int(digits)
|
||||
digits = ''
|
||||
else:
|
||||
count = 0
|
||||
|
||||
# Finally commit to command c.
|
||||
if c in ('<PAGE-UP>', '<LEFT-ARROW>', 'b', '\x02'):
|
||||
# Previous page.
|
||||
nxt = pos - self._height
|
||||
if nxt < 0:
|
||||
nxt = 0
|
||||
elif c in ('<PAGE-DOWN>', '<RIGHT-ARROW>', 'f', '\x06', ' '):
|
||||
# Next page.
|
||||
if nxt >= len(self._lines):
|
||||
continue
|
||||
nxt = pos + self._height
|
||||
if nxt >= len(self._lines):
|
||||
nxt = pos
|
||||
elif c in ('<HOME>', 'g'):
|
||||
# First page.
|
||||
nxt = count - 1
|
||||
if nxt > len(self._lines) - self._height:
|
||||
nxt = len(self._lines) - self._height
|
||||
if nxt < 0:
|
||||
nxt = 0
|
||||
elif c in ('<END>', 'G'):
|
||||
# Last page.
|
||||
nxt = len(self._lines) - count
|
||||
if nxt > len(self._lines) - self._height:
|
||||
nxt = len(self._lines) - self._height
|
||||
if nxt < 0:
|
||||
nxt = 0
|
||||
elif c == 'h':
|
||||
self._Help()
|
||||
# Special case when we want to reprint the previous display.
|
||||
self.prev_pos, self.prev_nxt = self.PREV_POS_NXT_REPRINT
|
||||
nxt = pos
|
||||
break
|
||||
elif c in ('<DOWN-ARROW>', 'j', '+', '\n', '\r'):
|
||||
# Next line.
|
||||
if nxt >= len(self._lines):
|
||||
continue
|
||||
nxt = pos + 1
|
||||
if nxt >= len(self._lines):
|
||||
nxt = pos
|
||||
elif c in ('<UP-ARROW>', 'k', '-'):
|
||||
# Previous line.
|
||||
nxt = pos - 1
|
||||
if nxt < 0:
|
||||
nxt = 0
|
||||
elif c in ('n', 'N'):
|
||||
# Next pattern match search.
|
||||
if not self._search_pattern:
|
||||
continue
|
||||
nxt = pos
|
||||
i = pos
|
||||
direction = 1 if c == self._search_direction else -1
|
||||
while True:
|
||||
i += direction
|
||||
if i < 0 or i >= len(self._lines):
|
||||
break
|
||||
if self._search_pattern.search(self._lines[i]):
|
||||
nxt = i
|
||||
break
|
||||
else:
|
||||
# Silently ignore everything else.
|
||||
continue
|
||||
if nxt != pos:
|
||||
# We will exit the while loop because position changed so we can reset
|
||||
# prev values.
|
||||
reset_prev_values = True
|
||||
break
|
||||
pos = nxt
|
||||
@@ -1,207 +0,0 @@
|
||||
# -*- coding: utf-8 -*- #
|
||||
|
||||
# Copyright 2015 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""A module for dealing with unknown string and environment encodings."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
|
||||
def Encode(string, encoding=None):
|
||||
"""Encode the text string to a byte string.
|
||||
|
||||
Args:
|
||||
string: str, The text string to encode.
|
||||
encoding: The suggested encoding if known.
|
||||
|
||||
Returns:
|
||||
str, The binary string.
|
||||
"""
|
||||
if string is None:
|
||||
return None
|
||||
if not six.PY2:
|
||||
# In Python 3, the environment sets and gets accept and return text strings
|
||||
# only, and it handles the encoding itself so this is not necessary.
|
||||
return string
|
||||
if isinstance(string, six.binary_type):
|
||||
# Already an encoded byte string, we are done
|
||||
return string
|
||||
|
||||
encoding = encoding or _GetEncoding()
|
||||
return string.encode(encoding)
|
||||
|
||||
|
||||
def Decode(data, encoding=None):
|
||||
"""Returns string with non-ascii characters decoded to UNICODE.
|
||||
|
||||
UTF-8, the suggested encoding, and the usual suspects will be attempted in
|
||||
order.
|
||||
|
||||
Args:
|
||||
data: A string or object that has str() and unicode() methods that may
|
||||
contain an encoding incompatible with the standard output encoding.
|
||||
encoding: The suggested encoding if known.
|
||||
|
||||
Returns:
|
||||
A text string representing the decoded byte string.
|
||||
"""
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
# First we are going to get the data object to be a text string.
|
||||
# Don't use six.string_types here because on Python 3 bytes is not considered
|
||||
# a string type and we want to include that.
|
||||
if isinstance(data, six.text_type) or isinstance(data, six.binary_type):
|
||||
string = data
|
||||
else:
|
||||
# Some non-string type of object.
|
||||
try:
|
||||
string = six.text_type(data)
|
||||
except (TypeError, UnicodeError):
|
||||
# The string cannot be converted to unicode -- default to str() which will
|
||||
# catch objects with special __str__ methods.
|
||||
string = str(data)
|
||||
|
||||
if isinstance(string, six.text_type):
|
||||
# Our work is done here.
|
||||
return string
|
||||
|
||||
try:
|
||||
# Just return the string if its pure ASCII.
|
||||
return string.decode('ascii')
|
||||
except UnicodeError:
|
||||
# The string is not ASCII encoded.
|
||||
pass
|
||||
|
||||
# Try the suggested encoding if specified.
|
||||
if encoding:
|
||||
try:
|
||||
return string.decode(encoding)
|
||||
except UnicodeError:
|
||||
# Bad suggestion.
|
||||
pass
|
||||
|
||||
# Try UTF-8 because the other encodings could be extended ASCII. It would
|
||||
# be exceptional if a valid extended ascii encoding with extended chars
|
||||
# were also a valid UITF-8 encoding.
|
||||
try:
|
||||
return string.decode('utf8')
|
||||
except UnicodeError:
|
||||
# Not a UTF-8 encoding.
|
||||
pass
|
||||
|
||||
# Try the filesystem encoding.
|
||||
try:
|
||||
return string.decode(sys.getfilesystemencoding())
|
||||
except UnicodeError:
|
||||
# string is not encoded for filesystem paths.
|
||||
pass
|
||||
|
||||
# Try the system default encoding.
|
||||
try:
|
||||
return string.decode(sys.getdefaultencoding())
|
||||
except UnicodeError:
|
||||
# string is not encoded using the default encoding.
|
||||
pass
|
||||
|
||||
# We don't know the string encoding.
|
||||
# This works around a Python str.encode() "feature" that throws
|
||||
# an ASCII *decode* exception on str strings that contain 8th bit set
|
||||
# bytes. For example, this sequence throws an exception:
|
||||
# string = '\xdc' # iso-8859-1 'Ü'
|
||||
# string = string.encode('ascii', 'backslashreplace')
|
||||
# even though 'backslashreplace' is documented to handle encoding
|
||||
# errors. We work around the problem by first decoding the str string
|
||||
# from an 8-bit encoding to unicode, selecting any 8-bit encoding that
|
||||
# uses all 256 bytes (such as ISO-8559-1):
|
||||
# string = string.decode('iso-8859-1')
|
||||
# Using this produces a sequence that works:
|
||||
# string = '\xdc'
|
||||
# string = string.decode('iso-8859-1')
|
||||
# string = string.encode('ascii', 'backslashreplace')
|
||||
return string.decode('iso-8859-1')
|
||||
|
||||
|
||||
def GetEncodedValue(env, name, default=None):
|
||||
"""Returns the decoded value of the env var name.
|
||||
|
||||
Args:
|
||||
env: {str: str}, The env dict.
|
||||
name: str, The env var name.
|
||||
default: The value to return if name is not in env.
|
||||
|
||||
Returns:
|
||||
The decoded value of the env var name.
|
||||
"""
|
||||
name = Encode(name)
|
||||
value = env.get(name)
|
||||
if value is None:
|
||||
return default
|
||||
# In Python 3, the environment sets and gets accept and return text strings
|
||||
# only, and it handles the encoding itself so this is not necessary.
|
||||
return Decode(value)
|
||||
|
||||
|
||||
def SetEncodedValue(env, name, value, encoding=None):
|
||||
"""Sets the value of name in env to an encoded value.
|
||||
|
||||
Args:
|
||||
env: {str: str}, The env dict.
|
||||
name: str, The env var name.
|
||||
value: str or unicode, The value for name. If None then name is removed from
|
||||
env.
|
||||
encoding: str, The encoding to use or None to try to infer it.
|
||||
"""
|
||||
# Python 2 *and* 3 unicode support falls apart at filesystem/argv/environment
|
||||
# boundaries. The encoding used for filesystem paths and environment variable
|
||||
# names/values is under user control on most systems. With one of those values
|
||||
# in hand there is no way to tell exactly how the value was encoded. We get
|
||||
# some reasonable hints from sys.getfilesystemencoding() or
|
||||
# sys.getdefaultencoding() and use them to encode values that the receiving
|
||||
# process will have a chance at decoding. Leaving the values as unicode
|
||||
# strings will cause os module Unicode exceptions. What good is a language
|
||||
# unicode model when the module support could care less?
|
||||
name = Encode(name, encoding=encoding)
|
||||
if value is None:
|
||||
env.pop(name, None)
|
||||
return
|
||||
env[name] = Encode(value, encoding=encoding)
|
||||
|
||||
|
||||
def EncodeEnv(env, encoding=None):
|
||||
"""Encodes all the key value pairs in env in preparation for subprocess.
|
||||
|
||||
Args:
|
||||
env: {str: str}, The environment you are going to pass to subprocess.
|
||||
encoding: str, The encoding to use or None to use the default.
|
||||
|
||||
Returns:
|
||||
{bytes: bytes}, The environment to pass to subprocess.
|
||||
"""
|
||||
encoding = encoding or _GetEncoding()
|
||||
return {
|
||||
Encode(k, encoding=encoding): Encode(v, encoding=encoding)
|
||||
for k, v in six.iteritems(env)}
|
||||
|
||||
|
||||
def _GetEncoding():
|
||||
"""Gets the default encoding to use."""
|
||||
return sys.getfilesystemencoding() or sys.getdefaultencoding()
|
||||
-942
@@ -1,942 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Python Fire is a library for creating CLIs from absolutely any Python object.
|
||||
|
||||
You can call Fire on any Python object:
|
||||
functions, classes, modules, objects, dictionaries, lists, tuples, etc.
|
||||
They all work!
|
||||
|
||||
Python Fire turns any Python object into a command line interface.
|
||||
Simply call the Fire function as your main method to create a CLI.
|
||||
|
||||
When using Fire to build a CLI, your main method includes a call to Fire. Eg:
|
||||
|
||||
def main(argv):
|
||||
fire.Fire(Component)
|
||||
|
||||
A Fire CLI command is run by consuming the arguments in the command in order to
|
||||
access a member of current component, call the current component (if it's a
|
||||
function), or instantiate the current component (if it's a class). The target
|
||||
component begins as Component, and at each operation the component becomes the
|
||||
result of the preceding operation.
|
||||
|
||||
For example "command fn arg1 arg2" might access the "fn" property of the initial
|
||||
target component, and then call that function with arguments 'arg1' and 'arg2'.
|
||||
Additional examples are available in the examples directory.
|
||||
|
||||
Fire Flags, common to all Fire CLIs, must go after a separating "--". For
|
||||
example, to get help for a command you might run: `command -- --help`.
|
||||
|
||||
The available flags for all Fire CLIs are:
|
||||
-v --verbose: Include private members in help and usage information.
|
||||
-h --help: Provide help and usage information for the command.
|
||||
-i --interactive: Drop into a Python REPL after running the command.
|
||||
--completion: Write the Bash completion script for the tool to stdout.
|
||||
--completion fish: Write the Fish completion script for the tool to stdout.
|
||||
--separator SEPARATOR: Use SEPARATOR in place of the default separator, '-'.
|
||||
--trace: Get the Fire Trace for the command.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import pipes
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
import types
|
||||
|
||||
from fire import completion
|
||||
from fire import decorators
|
||||
from fire import helputils
|
||||
from fire import inspectutils
|
||||
from fire import interact
|
||||
from fire import parser
|
||||
from fire import trace
|
||||
from fire import value_types
|
||||
from fire.console import console_pager
|
||||
import six
|
||||
|
||||
|
||||
def Fire(component=None, command=None, name=None):
|
||||
"""This function, Fire, is the main entrypoint for Python Fire.
|
||||
|
||||
Executes a command either from the `command` argument or from sys.argv by
|
||||
recursively traversing the target object `component`'s members consuming
|
||||
arguments, evaluating functions, and instantiating classes as it goes.
|
||||
|
||||
When building a CLI with Fire, your main method should call this function.
|
||||
|
||||
Args:
|
||||
component: The initial target component.
|
||||
command: Optional. If supplied, this is the command executed. If not
|
||||
supplied, then the command is taken from sys.argv instead. This can be
|
||||
a string or a list of strings; a list of strings is preferred.
|
||||
name: Optional. The name of the command as entered at the command line.
|
||||
Used in interactive mode and for generating the completion script.
|
||||
Returns:
|
||||
The result of executing the Fire command. Execution begins with the initial
|
||||
target component. The component is updated by using the command arguments
|
||||
to either access a member of the current component, call the current
|
||||
component (if it's a function), or instantiate the current component (if
|
||||
it's a class). When all arguments are consumed and there's no function left
|
||||
to call or class left to instantiate, the resulting current component is
|
||||
the final result.
|
||||
Raises:
|
||||
ValueError: If the command argument is supplied, but not a string or a
|
||||
sequence of arguments.
|
||||
FireExit: When Fire encounters a FireError, Fire will raise a FireExit with
|
||||
code 2. When used with the help or trace flags, Fire will raise a
|
||||
FireExit with code 0 if successful.
|
||||
"""
|
||||
name = name or os.path.basename(sys.argv[0])
|
||||
|
||||
# Get args as a list.
|
||||
if isinstance(command, six.string_types):
|
||||
args = shlex.split(command)
|
||||
elif isinstance(command, (list, tuple)):
|
||||
args = command
|
||||
elif command is None:
|
||||
# Use the command line args by default if no command is specified.
|
||||
args = sys.argv[1:]
|
||||
else:
|
||||
raise ValueError('The command argument must be a string or a sequence of '
|
||||
'arguments.')
|
||||
|
||||
# Determine the calling context.
|
||||
caller = inspect.stack()[1]
|
||||
caller_frame = caller[0]
|
||||
caller_globals = caller_frame.f_globals
|
||||
caller_locals = caller_frame.f_locals
|
||||
context = {}
|
||||
context.update(caller_globals)
|
||||
context.update(caller_locals)
|
||||
|
||||
component_trace = _Fire(component, args, context, name)
|
||||
|
||||
if component_trace.HasError():
|
||||
_DisplayError(component_trace)
|
||||
raise FireExit(2, component_trace)
|
||||
elif component_trace.show_trace and component_trace.show_help:
|
||||
output = ['Fire trace:\n{trace}\n'.format(trace=component_trace)]
|
||||
result = component_trace.GetResult()
|
||||
help_string = helputils.HelpString(
|
||||
result, component_trace, component_trace.verbose)
|
||||
output.append(help_string)
|
||||
Display(output)
|
||||
raise FireExit(0, component_trace)
|
||||
elif component_trace.show_trace:
|
||||
output = ['Fire trace:\n{trace}'.format(trace=component_trace)]
|
||||
Display(output)
|
||||
raise FireExit(0, component_trace)
|
||||
elif component_trace.show_help:
|
||||
result = component_trace.GetResult()
|
||||
help_string = helputils.HelpString(
|
||||
result, component_trace, component_trace.verbose)
|
||||
output = [help_string]
|
||||
Display(output)
|
||||
raise FireExit(0, component_trace)
|
||||
else:
|
||||
# The command succeeded normally; print the result.
|
||||
_PrintResult(component_trace, verbose=component_trace.verbose)
|
||||
result = component_trace.GetResult()
|
||||
return result
|
||||
|
||||
|
||||
def Display(lines):
|
||||
text = '\n'.join(lines) + '\n'
|
||||
pager = console_pager.Pager(text, out=sys.stderr)
|
||||
try:
|
||||
pager.Run()
|
||||
except: # pylint: disable=bare-except
|
||||
# pager.Run() fails with termios.error(25, 'Inappropriate ioctl for device')
|
||||
# for outputs that don't fit on a single screen in our test environment.
|
||||
pass
|
||||
|
||||
|
||||
def CompletionScript(name, component, shell):
|
||||
"""Returns the text of the completion script for a Fire CLI."""
|
||||
return completion.Script(name, component, shell=shell)
|
||||
|
||||
|
||||
class FireError(Exception):
|
||||
"""Exception used by Fire when a Fire command cannot be executed.
|
||||
|
||||
These exceptions are not raised by the Fire function, but rather are caught
|
||||
and added to the FireTrace.
|
||||
"""
|
||||
|
||||
|
||||
class FireExit(SystemExit): # pylint: disable=g-bad-exception-name
|
||||
"""An exception raised by Fire to the client in the case of a FireError.
|
||||
|
||||
The trace of the Fire program is available on the `trace` property.
|
||||
|
||||
This exception inherits from SystemExit, so clients may explicitly catch it
|
||||
with `except SystemExit` or `except FireExit`. If not caught, this exception
|
||||
will cause the client program to exit without a stacktrace.
|
||||
"""
|
||||
|
||||
def __init__(self, code, component_trace):
|
||||
"""Constructs a FireExit exception.
|
||||
|
||||
Args:
|
||||
code: (int) Exit code for the Fire CLI.
|
||||
component_trace: (FireTrace) The trace for the Fire command.
|
||||
"""
|
||||
super(FireExit, self).__init__(code)
|
||||
self.trace = component_trace
|
||||
|
||||
|
||||
def _IsHelpShortcut(component_trace, remaining_args):
|
||||
"""Determines if the user is trying to access help without '--' separator.
|
||||
|
||||
For example, mycmd.py --help instead of mycmd.py -- --help.
|
||||
|
||||
Args:
|
||||
component_trace: (FireTrace) The trace for the Fire command.
|
||||
remaining_args: List of remaining args that haven't been consumed yet.
|
||||
Returns:
|
||||
True if help is requested, False otherwise.
|
||||
"""
|
||||
show_help = False
|
||||
if remaining_args:
|
||||
target = remaining_args[0]
|
||||
if target in ('-h', '--help'):
|
||||
# Check if --help would be consumed as a keyword argument, or is a member.
|
||||
component = component_trace.GetResult()
|
||||
if inspect.isclass(component) or inspect.isroutine(component):
|
||||
fn_spec = inspectutils.GetFullArgSpec(component)
|
||||
_, remaining_kwargs, _ = _ParseKeywordArgs(remaining_args, fn_spec)
|
||||
show_help = target in remaining_kwargs
|
||||
else:
|
||||
members = dict(inspect.getmembers(component))
|
||||
show_help = target not in members
|
||||
|
||||
if show_help:
|
||||
component_trace.show_help = True
|
||||
command = '{cmd} -- --help'.format(cmd=component_trace.GetCommand())
|
||||
print('INFO: Showing help with the command {cmd}.\n'.format(
|
||||
cmd=pipes.quote(command)), file=sys.stderr)
|
||||
return show_help
|
||||
|
||||
|
||||
def _PrintResult(component_trace, verbose=False):
|
||||
"""Prints the result of the Fire call to stdout in a human readable way."""
|
||||
# TODO(dbieber): Design human readable deserializable serialization method
|
||||
# and move serialization to it's own module.
|
||||
result = component_trace.GetResult()
|
||||
|
||||
if isinstance(result, (list, set, types.GeneratorType)):
|
||||
for i in result:
|
||||
print(_OneLineResult(i))
|
||||
elif inspect.isgeneratorfunction(result):
|
||||
raise NotImplementedError
|
||||
elif isinstance(result, dict):
|
||||
print(_DictAsString(result, verbose))
|
||||
elif isinstance(result, tuple):
|
||||
print(_OneLineResult(result))
|
||||
elif isinstance(result, value_types.VALUE_TYPES):
|
||||
print(result)
|
||||
elif result is not None:
|
||||
print(helputils.HelpString(result, component_trace, verbose))
|
||||
|
||||
|
||||
def _DisplayError(component_trace):
|
||||
"""Prints the Fire trace and the error to stdout."""
|
||||
output = []
|
||||
for help_flag in ('-h', '--help'):
|
||||
if help_flag in component_trace.elements[-1].args:
|
||||
command = '{cmd} -- --help'.format(cmd=component_trace.GetCommand())
|
||||
message = 'INFO: Showing help with the command {cmd}.\n'.format(
|
||||
cmd=pipes.quote(command))
|
||||
output.append(message)
|
||||
output.append('Fire trace:\n{trace}\n'.format(trace=component_trace))
|
||||
result = component_trace.GetResult()
|
||||
help_string = helputils.HelpString(result, component_trace,
|
||||
component_trace.verbose)
|
||||
output.append(help_string)
|
||||
Display(output)
|
||||
|
||||
|
||||
def _DictAsString(result, verbose=False):
|
||||
"""Returns a dict as a string.
|
||||
|
||||
Args:
|
||||
result: The dict to convert to a string
|
||||
verbose: Whether to include 'hidden' members, those keys starting with _.
|
||||
Returns:
|
||||
A string representing the dict
|
||||
"""
|
||||
|
||||
# We need to do 2 iterations over the items in the result dict
|
||||
# 1) Getting visible items and the longest key for output formatting
|
||||
# 2) Actually construct the output lines
|
||||
result_visible = {key: value for key, value in result.items()
|
||||
if _ComponentVisible(key, verbose)}
|
||||
|
||||
if not result_visible:
|
||||
return '{}'
|
||||
|
||||
longest_key = max(len(str(key)) for key in result_visible.keys())
|
||||
format_string = '{{key:{padding}s}} {{value}}'.format(padding=longest_key + 1)
|
||||
|
||||
lines = []
|
||||
for key, value in result.items():
|
||||
if _ComponentVisible(key, verbose):
|
||||
line = format_string.format(key=str(key) + ':',
|
||||
value=_OneLineResult(value))
|
||||
lines.append(line)
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def _ComponentVisible(component, verbose=False):
|
||||
"""Returns whether a component should be visible in the output."""
|
||||
return (
|
||||
verbose
|
||||
or not isinstance(component, six.string_types)
|
||||
or not component.startswith('_'))
|
||||
|
||||
|
||||
def _OneLineResult(result):
|
||||
"""Returns result serialized to a single line string."""
|
||||
# TODO(dbieber): Ensure line is fewer than eg 120 characters.
|
||||
if isinstance(result, six.string_types):
|
||||
return str(result).replace('\n', ' ')
|
||||
|
||||
try:
|
||||
# Don't force conversion to ascii.
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
except (TypeError, ValueError):
|
||||
return str(result).replace('\n', ' ')
|
||||
|
||||
|
||||
def _Fire(component, args, context, name=None):
|
||||
"""Execute a Fire command on a target component using the args supplied.
|
||||
|
||||
Arguments that come after a final isolated '--' are treated as Flags, eg for
|
||||
interactive mode or completion script generation.
|
||||
|
||||
Other arguments are consumed by the execution of the Fire command, eg in the
|
||||
traversal of the members of the component, or in calling a function or
|
||||
instantiating a class found during the traversal.
|
||||
|
||||
The steps performed by this method are:
|
||||
|
||||
1. Parse any Flag args (the args after the final --)
|
||||
|
||||
2. Start with component as the current component.
|
||||
2a. If the current component is a class, instantiate it using args from args.
|
||||
2b. If the current component is a routine, call it using args from args.
|
||||
2c. Otherwise access a member from component using an arg from args.
|
||||
2d. Repeat 2a-2c until no args remain.
|
||||
|
||||
3a. Embed into ipython REPL if interactive mode is selected.
|
||||
3b. Generate a completion script if that flag is provided.
|
||||
|
||||
In step 2, arguments will only ever be consumed up to a separator; a single
|
||||
step will never consume arguments from both sides of a separator.
|
||||
The separator defaults to a hyphen (-), and can be overwritten with the
|
||||
--separator Fire argument.
|
||||
|
||||
Args:
|
||||
component: The target component for Fire.
|
||||
args: A list of args to consume in Firing on the component, usually from
|
||||
the command line.
|
||||
context: A dict with the local and global variables available at the call
|
||||
to Fire.
|
||||
name: Optional. The name of the command. Used in interactive mode and in
|
||||
the tab completion script.
|
||||
Returns:
|
||||
FireTrace of components starting with component, tracing Fire's execution
|
||||
path as it consumes args.
|
||||
Raises:
|
||||
ValueError: If there are arguments that cannot be consumed.
|
||||
ValueError: If --completion is specified but no name available.
|
||||
"""
|
||||
args, flag_args = parser.SeparateFlagArgs(args)
|
||||
|
||||
argparser = parser.CreateParser()
|
||||
parsed_flag_args, unused_args = argparser.parse_known_args(flag_args)
|
||||
verbose = parsed_flag_args.verbose
|
||||
interactive = parsed_flag_args.interactive
|
||||
separator = parsed_flag_args.separator
|
||||
show_completion = parsed_flag_args.completion
|
||||
show_help = parsed_flag_args.help
|
||||
show_trace = parsed_flag_args.trace
|
||||
|
||||
# component can be a module, class, routine, object, etc.
|
||||
if component is None:
|
||||
component = context
|
||||
|
||||
initial_component = component
|
||||
component_trace = trace.FireTrace(
|
||||
initial_component=initial_component, name=name, separator=separator,
|
||||
verbose=verbose, show_help=show_help, show_trace=show_trace)
|
||||
|
||||
instance = None
|
||||
remaining_args = args
|
||||
while True:
|
||||
last_component = component
|
||||
initial_args = remaining_args
|
||||
|
||||
if not remaining_args and (show_help or interactive or show_trace
|
||||
or show_completion is not None):
|
||||
# Don't initialize the final class or call the final function unless
|
||||
# there's a separator after it, and instead process the current component.
|
||||
break
|
||||
|
||||
if _IsHelpShortcut(component_trace, remaining_args):
|
||||
remaining_args = []
|
||||
break
|
||||
|
||||
saved_args = []
|
||||
used_separator = False
|
||||
if separator in remaining_args:
|
||||
# For the current component, only use arguments up to the separator.
|
||||
separator_index = remaining_args.index(separator)
|
||||
saved_args = remaining_args[separator_index + 1:]
|
||||
remaining_args = remaining_args[:separator_index]
|
||||
used_separator = True
|
||||
assert separator not in remaining_args
|
||||
|
||||
if inspect.isclass(component) or inspect.isroutine(component):
|
||||
# The component is a class or a routine; we'll try to initialize it or
|
||||
# call it.
|
||||
isclass = inspect.isclass(component)
|
||||
|
||||
try:
|
||||
component, remaining_args = _CallAndUpdateTrace(
|
||||
component,
|
||||
remaining_args,
|
||||
component_trace,
|
||||
treatment='class' if isclass else 'routine',
|
||||
target=component.__name__)
|
||||
except FireError as error:
|
||||
component_trace.AddError(error, initial_args)
|
||||
return component_trace
|
||||
|
||||
if last_component is initial_component:
|
||||
# If the initial component is a class, keep an instance for use with -i.
|
||||
instance = component
|
||||
|
||||
elif (isinstance(component, (list, tuple)) and remaining_args
|
||||
and not inspectutils.IsNamedTuple(component)):
|
||||
# The component is a tuple or list; we'll try to access a member.
|
||||
arg = remaining_args[0]
|
||||
try:
|
||||
index = int(arg)
|
||||
component = component[index]
|
||||
except (ValueError, IndexError):
|
||||
error = FireError(
|
||||
'Unable to index into component with argument:', arg)
|
||||
component_trace.AddError(error, initial_args)
|
||||
return component_trace
|
||||
|
||||
remaining_args = remaining_args[1:]
|
||||
filename = None
|
||||
lineno = None
|
||||
component_trace.AddAccessedProperty(
|
||||
component, index, [arg], filename, lineno)
|
||||
|
||||
elif ((isinstance(component, dict) or inspectutils.IsNamedTuple(component))
|
||||
and remaining_args):
|
||||
# The component is a dict; we'll try to access a member.
|
||||
target = remaining_args[0]
|
||||
|
||||
# Allow indexing for namedtuples.
|
||||
try:
|
||||
index = int(target)
|
||||
is_target_int = True
|
||||
except ValueError:
|
||||
is_target_int = False
|
||||
|
||||
if inspectutils.IsNamedTuple(component) and is_target_int:
|
||||
try:
|
||||
component = component[index]
|
||||
except (ValueError, IndexError):
|
||||
error = FireError(
|
||||
'Unable to index into component with argument:', target)
|
||||
component_trace.AddError(error, initial_args)
|
||||
return component_trace
|
||||
elif target in component:
|
||||
component = component[target]
|
||||
elif target.replace('-', '_') in component:
|
||||
component = component[target.replace('-', '_')]
|
||||
else:
|
||||
# The target isn't present in the dict as a string, but maybe it is as
|
||||
# another type.
|
||||
# TODO(dbieber): Consider alternatives for accessing non-string keys.
|
||||
found_target = False
|
||||
# If the component is a namedtuple, we need to convert it to dict to
|
||||
# be able to use the .items() method.
|
||||
if inspectutils.IsNamedTuple(component):
|
||||
component = component._asdict()
|
||||
for key, value in component.items():
|
||||
if target == str(key):
|
||||
component = value
|
||||
found_target = True
|
||||
break
|
||||
if not found_target:
|
||||
error = FireError(
|
||||
'Cannot find target in dict:', target, component)
|
||||
component_trace.AddError(error, initial_args)
|
||||
return component_trace
|
||||
|
||||
remaining_args = remaining_args[1:]
|
||||
filename = None
|
||||
lineno = None
|
||||
component_trace.AddAccessedProperty(
|
||||
component, target, [target], filename, lineno)
|
||||
|
||||
elif remaining_args:
|
||||
# We'll try to access a member of the component.
|
||||
try:
|
||||
target = remaining_args[0]
|
||||
|
||||
component, consumed_args, remaining_args = _GetMember(
|
||||
component, remaining_args)
|
||||
|
||||
filename, lineno = inspectutils.GetFileAndLine(component)
|
||||
|
||||
component_trace.AddAccessedProperty(
|
||||
component, target, consumed_args, filename, lineno)
|
||||
|
||||
except FireError as error:
|
||||
if not callable(component):
|
||||
component_trace.AddError(error, initial_args)
|
||||
return component_trace
|
||||
|
||||
# If we can't access the member, try to treat component as a callable.
|
||||
try:
|
||||
component, remaining_args = _CallAndUpdateTrace(component,
|
||||
remaining_args,
|
||||
component_trace,
|
||||
treatment='callable')
|
||||
except FireError as error:
|
||||
component_trace.AddError(error, initial_args)
|
||||
return component_trace
|
||||
|
||||
if used_separator:
|
||||
# Add back in the arguments from after the separator.
|
||||
if remaining_args:
|
||||
remaining_args = remaining_args + [separator] + saved_args
|
||||
elif (inspect.isclass(last_component)
|
||||
or inspect.isroutine(last_component)):
|
||||
remaining_args = saved_args
|
||||
component_trace.AddSeparator()
|
||||
elif component is not last_component:
|
||||
remaining_args = [separator] + saved_args
|
||||
else:
|
||||
# It was an unnecessary separator.
|
||||
remaining_args = saved_args
|
||||
|
||||
if component is last_component and remaining_args == initial_args:
|
||||
# We're making no progress.
|
||||
break
|
||||
|
||||
if remaining_args:
|
||||
component_trace.AddError(
|
||||
FireError('Could not consume arguments:', remaining_args),
|
||||
initial_args)
|
||||
return component_trace
|
||||
|
||||
if show_completion is not None:
|
||||
if name is None:
|
||||
raise ValueError('Cannot make completion script without command name')
|
||||
script = CompletionScript(name, initial_component, shell=show_completion)
|
||||
component_trace.AddCompletionScript(script)
|
||||
|
||||
if interactive:
|
||||
variables = context.copy()
|
||||
|
||||
if name is not None:
|
||||
variables[name] = initial_component
|
||||
variables['component'] = initial_component
|
||||
variables['result'] = component
|
||||
variables['trace'] = component_trace
|
||||
|
||||
if instance is not None:
|
||||
variables['self'] = instance
|
||||
|
||||
interact.Embed(variables, verbose)
|
||||
|
||||
component_trace.AddInteractiveMode()
|
||||
|
||||
return component_trace
|
||||
|
||||
|
||||
def _GetMember(component, args):
|
||||
"""Returns a subcomponent of component by consuming an arg from args.
|
||||
|
||||
Given a starting component and args, this function gets a member from that
|
||||
component, consuming one arg in the process.
|
||||
|
||||
Args:
|
||||
component: The component from which to get a member.
|
||||
args: Args from which to consume in the search for the next component.
|
||||
Returns:
|
||||
component: The component that was found by consuming an arg.
|
||||
consumed_args: The args that were consumed by getting this member.
|
||||
remaining_args: The remaining args that haven't been consumed yet.
|
||||
Raises:
|
||||
FireError: If we cannot consume an argument to get a member.
|
||||
"""
|
||||
members = dict(inspect.getmembers(component))
|
||||
arg = args[0]
|
||||
arg_names = [
|
||||
arg,
|
||||
arg.replace('-', '_'), # treat '-' as '_'.
|
||||
]
|
||||
|
||||
for arg_name in arg_names:
|
||||
if arg_name in members:
|
||||
return members[arg_name], [arg], args[1:]
|
||||
|
||||
raise FireError('Could not consume arg:', arg)
|
||||
|
||||
|
||||
def _CallAndUpdateTrace(component, args, component_trace, treatment='class',
|
||||
target=None):
|
||||
"""Call the component by consuming args from args, and update the FireTrace.
|
||||
|
||||
The component could be a class, a routine, or a callable object. This function
|
||||
calls the component and adds the appropriate action to component_trace.
|
||||
|
||||
Args:
|
||||
component: The component to call
|
||||
args: Args for calling the component
|
||||
component_trace: FireTrace object that contains action trace
|
||||
treatment: Type of treatment used. Indicating whether we treat the component
|
||||
as a class, a routine, or a callable.
|
||||
target: Target in FireTrace element, default is None. If the value is None,
|
||||
the component itself will be used as target.
|
||||
Returns:
|
||||
component: The object that is the result of the callable call.
|
||||
remaining_args: The remaining args that haven't been consumed yet.
|
||||
"""
|
||||
if not target:
|
||||
target = component
|
||||
filename, lineno = inspectutils.GetFileAndLine(component)
|
||||
fn = component.__call__ if treatment == 'callable' else component
|
||||
parse = _MakeParseFn(fn)
|
||||
(varargs, kwargs), consumed_args, remaining_args, capacity = parse(args)
|
||||
component = fn(*varargs, **kwargs)
|
||||
|
||||
if treatment == 'class':
|
||||
action = trace.INSTANTIATED_CLASS
|
||||
elif treatment == 'routine':
|
||||
action = trace.CALLED_ROUTINE
|
||||
else:
|
||||
action = trace.CALLED_CALLABLE
|
||||
component_trace.AddCalledComponent(
|
||||
component, target, consumed_args, filename, lineno, capacity,
|
||||
action=action)
|
||||
|
||||
return component, remaining_args
|
||||
|
||||
|
||||
def _MakeParseFn(fn):
|
||||
"""Creates a parse function for fn.
|
||||
|
||||
Args:
|
||||
fn: The function or class to create the parse function for.
|
||||
Returns:
|
||||
A parse function for fn. The parse function accepts a list of arguments
|
||||
and returns (varargs, kwargs), remaining_args. The original function fn
|
||||
can then be called with fn(*varargs, **kwargs). The remaining_args are
|
||||
the leftover args from the arguments to the parse function.
|
||||
"""
|
||||
fn_spec = inspectutils.GetFullArgSpec(fn)
|
||||
metadata = decorators.GetMetadata(fn)
|
||||
|
||||
# Note: num_required_args is the number of positional arguments without
|
||||
# default values. All of these arguments are required.
|
||||
num_required_args = len(fn_spec.args) - len(fn_spec.defaults)
|
||||
required_kwonly = set(fn_spec.kwonlyargs) - set(fn_spec.kwonlydefaults)
|
||||
|
||||
def _ParseFn(args):
|
||||
"""Parses the list of `args` into (varargs, kwargs), remaining_args."""
|
||||
kwargs, remaining_kwargs, remaining_args = _ParseKeywordArgs(args, fn_spec)
|
||||
|
||||
# Note: _ParseArgs modifies kwargs.
|
||||
parsed_args, kwargs, remaining_args, capacity = _ParseArgs(
|
||||
fn_spec.args, fn_spec.defaults, num_required_args, kwargs,
|
||||
remaining_args, metadata)
|
||||
|
||||
if fn_spec.varargs or fn_spec.varkw:
|
||||
# If we're allowed *varargs or **kwargs, there's always capacity.
|
||||
capacity = True
|
||||
|
||||
extra_kw = set(kwargs) - set(fn_spec.kwonlyargs)
|
||||
if fn_spec.varkw is None and extra_kw:
|
||||
raise FireError('Unexpected kwargs present:', extra_kw)
|
||||
|
||||
missing_kwonly = set(required_kwonly) - set(kwargs)
|
||||
if missing_kwonly:
|
||||
raise FireError('Missing required flags:', missing_kwonly)
|
||||
|
||||
# If we accept *varargs, then use all remaining arguments for *varargs.
|
||||
if fn_spec.varargs is not None:
|
||||
varargs, remaining_args = remaining_args, []
|
||||
else:
|
||||
varargs = []
|
||||
|
||||
for index, value in enumerate(varargs):
|
||||
varargs[index] = _ParseValue(value, None, None, metadata)
|
||||
|
||||
varargs = parsed_args + varargs
|
||||
remaining_args += remaining_kwargs
|
||||
|
||||
consumed_args = args[:len(args) - len(remaining_args)]
|
||||
return (varargs, kwargs), consumed_args, remaining_args, capacity
|
||||
|
||||
return _ParseFn
|
||||
|
||||
|
||||
def _ParseArgs(fn_args, fn_defaults, num_required_args, kwargs,
|
||||
remaining_args, metadata):
|
||||
"""Parses the positional and named arguments from the available supplied args.
|
||||
|
||||
Modifies kwargs, removing args as they are used.
|
||||
|
||||
Args:
|
||||
fn_args: A list of argument names that the target function accepts,
|
||||
including positional and named arguments, but not the varargs or kwargs
|
||||
names.
|
||||
fn_defaults: A list of the default values in the function argspec.
|
||||
num_required_args: The number of required arguments from the function's
|
||||
argspec. This is the number of arguments without a default value.
|
||||
kwargs: Dict with named command line arguments and their values.
|
||||
remaining_args: The remaining command line arguments, which may still be
|
||||
used as positional arguments.
|
||||
metadata: Metadata about the function, typically from Fire decorators.
|
||||
Returns:
|
||||
parsed_args: A list of values to be used as positional arguments for calling
|
||||
the target function.
|
||||
kwargs: The input dict kwargs modified with the used kwargs removed.
|
||||
remaining_args: A list of the supplied args that have not been used yet.
|
||||
capacity: Whether the call could have taken args in place of defaults.
|
||||
Raises:
|
||||
FireError: If additional positional arguments are expected, but none are
|
||||
available.
|
||||
"""
|
||||
accepts_positional_args = metadata.get(decorators.ACCEPTS_POSITIONAL_ARGS)
|
||||
capacity = False # If we see a default get used, we'll set capacity to True
|
||||
|
||||
# Select unnamed args.
|
||||
parsed_args = []
|
||||
for index, arg in enumerate(fn_args):
|
||||
value = kwargs.pop(arg, None)
|
||||
if value is not None: # A value is specified at the command line.
|
||||
value = _ParseValue(value, index, arg, metadata)
|
||||
parsed_args.append(value)
|
||||
else: # No value has been explicitly specified.
|
||||
if remaining_args and accepts_positional_args:
|
||||
# Use a positional arg.
|
||||
value = remaining_args.pop(0)
|
||||
value = _ParseValue(value, index, arg, metadata)
|
||||
parsed_args.append(value)
|
||||
elif index < num_required_args:
|
||||
raise FireError(
|
||||
'The function received no value for the required argument:', arg)
|
||||
else:
|
||||
# We're past the args for which there's no default value.
|
||||
# There's a default value for this arg.
|
||||
capacity = True
|
||||
default_index = index - num_required_args # index into the defaults.
|
||||
parsed_args.append(fn_defaults[default_index])
|
||||
|
||||
for key, value in kwargs.items():
|
||||
kwargs[key] = _ParseValue(value, None, key, metadata)
|
||||
|
||||
return parsed_args, kwargs, remaining_args, capacity
|
||||
|
||||
|
||||
def _ParseKeywordArgs(args, fn_spec):
|
||||
"""Parses the supplied arguments for keyword arguments.
|
||||
|
||||
Given a list of arguments, finds occurrences of --name value, and uses 'name'
|
||||
as the keyword and 'value' as the value. Constructs and returns a dictionary
|
||||
of these keyword arguments, and returns a list of the remaining arguments.
|
||||
|
||||
Only if fn_keywords is None, this only finds argument names used by the
|
||||
function, specified through fn_args.
|
||||
|
||||
This returns the values of the args as strings. They are later processed by
|
||||
_ParseArgs, which converts them to the appropriate type.
|
||||
|
||||
Args:
|
||||
args: A list of arguments.
|
||||
fn_spec: The inspectutils.FullArgSpec describing the given callable.
|
||||
Returns:
|
||||
kwargs: A dictionary mapping keywords to values.
|
||||
remaining_kwargs: A list of the unused kwargs from the original args.
|
||||
remaining_args: A list of the unused arguments from the original args.
|
||||
Raises:
|
||||
FireError: If a single-character flag is passed that could refer to multiple
|
||||
possible args.
|
||||
"""
|
||||
kwargs = {}
|
||||
remaining_kwargs = []
|
||||
remaining_args = []
|
||||
fn_keywords = fn_spec.varkw
|
||||
fn_args = fn_spec.args + fn_spec.kwonlyargs
|
||||
|
||||
if not args:
|
||||
return kwargs, remaining_kwargs, remaining_args
|
||||
|
||||
skip_argument = False
|
||||
|
||||
for index, argument in enumerate(args):
|
||||
if skip_argument:
|
||||
skip_argument = False
|
||||
continue
|
||||
|
||||
if _IsFlag(argument):
|
||||
# This is a named argument. We get its value from this arg or the next.
|
||||
|
||||
# Terminology:
|
||||
# argument: A full token from the command line, e.g. '--alpha=10'
|
||||
# stripped_argument: An argument without leading hyphens.
|
||||
# key: The contents of the stripped argument up to the first equal sign.
|
||||
# "shortcut flag": refers to an argument where the key is just the first
|
||||
# letter of a longer keyword.
|
||||
# keyword: The Python function argument being set by this argument.
|
||||
# value: The unparsed value for that Python function argument.
|
||||
contains_equals = '=' in argument
|
||||
stripped_argument = argument.lstrip('-')
|
||||
if contains_equals:
|
||||
key, value = stripped_argument.split('=', 1)
|
||||
else:
|
||||
key = stripped_argument
|
||||
|
||||
key = key.replace('-', '_')
|
||||
is_bool_syntax = (not contains_equals and
|
||||
(index + 1 == len(args) or _IsFlag(args[index + 1])))
|
||||
|
||||
# Determine the keyword.
|
||||
keyword = '' # Indicates no valid keyword has been found yet.
|
||||
if (key in fn_args
|
||||
or (is_bool_syntax and key.startswith('no') and key[2:] in fn_args)
|
||||
or fn_keywords):
|
||||
keyword = key
|
||||
elif len(key) == 1:
|
||||
# This may be a shortcut flag.
|
||||
matching_fn_args = [arg for arg in fn_args if arg[0] == key]
|
||||
if len(matching_fn_args) == 1:
|
||||
keyword = matching_fn_args[0]
|
||||
elif len(matching_fn_args) > 1:
|
||||
raise FireError("The argument '{}' is ambiguous as it could "
|
||||
"refer to any of the following arguments: {}".format(
|
||||
argument, matching_fn_args))
|
||||
|
||||
# Determine the value.
|
||||
if not keyword:
|
||||
got_argument = False
|
||||
elif contains_equals:
|
||||
# Already got the value above.
|
||||
got_argument = True
|
||||
elif is_bool_syntax:
|
||||
# There's no next arg or the next arg is a Flag, so we consider this
|
||||
# flag to be a boolean.
|
||||
got_argument = True
|
||||
if keyword in fn_args:
|
||||
value = 'True'
|
||||
elif keyword.startswith('no'):
|
||||
keyword = keyword[2:]
|
||||
value = 'False'
|
||||
else:
|
||||
value = 'True'
|
||||
else:
|
||||
# The assert should pass. Otherwise either contains_equals or
|
||||
# is_bool_syntax would have been True.
|
||||
assert index + 1 < len(args)
|
||||
value = args[index + 1]
|
||||
got_argument = True
|
||||
|
||||
# In order for us to consume the argument as a keyword arg, we either:
|
||||
# Need to be explicitly expecting the keyword, or we need to be
|
||||
# accepting **kwargs.
|
||||
skip_argument = not contains_equals and not is_bool_syntax
|
||||
if got_argument:
|
||||
kwargs[keyword] = value
|
||||
else:
|
||||
remaining_kwargs.append(argument)
|
||||
if skip_argument:
|
||||
remaining_kwargs.append(args[index + 1])
|
||||
else: # not _IsFlag(argument)
|
||||
remaining_args.append(argument)
|
||||
|
||||
return kwargs, remaining_kwargs, remaining_args
|
||||
|
||||
|
||||
def _IsFlag(argument):
|
||||
"""Determines if the argument is a flag argument.
|
||||
|
||||
If it starts with a hyphen and isn't a negative number, it's a flag.
|
||||
|
||||
Args:
|
||||
argument: A command line argument that may or may not be a flag.
|
||||
Returns:
|
||||
A boolean indicating whether the argument is a flag.
|
||||
"""
|
||||
return _IsSingleCharFlag(argument) or _IsMultiCharFlag(argument)
|
||||
|
||||
|
||||
def _IsSingleCharFlag(argument):
|
||||
"""Determines if the argument is a single char flag (e.g. '-a')."""
|
||||
return re.match('^-[a-zA-Z]$', argument) or re.match('^-[a-zA-Z]=', argument)
|
||||
|
||||
|
||||
def _IsMultiCharFlag(argument):
|
||||
"""Determines if the argument is a multi char flag (e.g. '--alpha')."""
|
||||
return argument.startswith('--') or re.match('^-[a-zA-Z]', argument)
|
||||
|
||||
|
||||
def _ParseValue(value, index, arg, metadata):
|
||||
"""Parses value, a string, into the appropriate type.
|
||||
|
||||
The function used to parse value is determined by the remaining arguments.
|
||||
|
||||
Args:
|
||||
value: The string value to be parsed, typically a command line argument.
|
||||
index: The index of the value in the function's argspec.
|
||||
arg: The name of the argument the value is being parsed for.
|
||||
metadata: Metadata about the function, typically from Fire decorators.
|
||||
Returns:
|
||||
value, parsed into the appropriate type for calling a function.
|
||||
"""
|
||||
parse_fn = parser.DefaultParseValue
|
||||
|
||||
# We check to see if any parse function from the fn metadata applies here.
|
||||
parse_fns = metadata.get(decorators.FIRE_PARSE_FNS)
|
||||
if parse_fns:
|
||||
default = parse_fns['default']
|
||||
positional = parse_fns['positional']
|
||||
named = parse_fns['named']
|
||||
|
||||
if index is not None and 0 <= index < len(positional):
|
||||
parse_fn = positional[index]
|
||||
elif arg in named:
|
||||
parse_fn = named[arg]
|
||||
elif default is not None:
|
||||
parse_fn = default
|
||||
|
||||
return parse_fn(value)
|
||||
@@ -1,165 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the core module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import core
|
||||
from fire import test_components as tc
|
||||
from fire import testutils
|
||||
from fire import trace
|
||||
import mock
|
||||
|
||||
|
||||
class CoreTest(testutils.BaseTestCase):
|
||||
|
||||
def testOneLineResult(self):
|
||||
self.assertEqual(core._OneLineResult(1), '1') # pylint: disable=protected-access
|
||||
self.assertEqual(core._OneLineResult('hello'), 'hello') # pylint: disable=protected-access
|
||||
self.assertEqual(core._OneLineResult({}), '{}') # pylint: disable=protected-access
|
||||
self.assertEqual(core._OneLineResult({'x': 'y'}), '{"x": "y"}') # pylint: disable=protected-access
|
||||
|
||||
def testOneLineResultCircularRef(self):
|
||||
circular_reference = tc.CircularReference()
|
||||
self.assertEqual(core._OneLineResult(circular_reference.create()), # pylint: disable=protected-access
|
||||
"{'y': {...}}")
|
||||
|
||||
@mock.patch('fire.interact.Embed')
|
||||
def testInteractiveMode(self, mock_embed):
|
||||
core.Fire(tc.TypedProperties, command=['alpha'])
|
||||
self.assertFalse(mock_embed.called)
|
||||
core.Fire(tc.TypedProperties, command=['alpha', '--', '-i'])
|
||||
self.assertTrue(mock_embed.called)
|
||||
|
||||
@mock.patch('fire.interact.Embed')
|
||||
def testInteractiveModeFullArgument(self, mock_embed):
|
||||
core.Fire(tc.TypedProperties, command=['alpha', '--', '--interactive'])
|
||||
self.assertTrue(mock_embed.called)
|
||||
|
||||
@mock.patch('fire.interact.Embed')
|
||||
def testInteractiveModeVariables(self, mock_embed):
|
||||
core.Fire(tc.WithDefaults, command=['double', '2', '--', '-i'])
|
||||
self.assertTrue(mock_embed.called)
|
||||
(variables, verbose), unused_kwargs = mock_embed.call_args
|
||||
self.assertFalse(verbose)
|
||||
self.assertEqual(variables['result'], 4)
|
||||
self.assertIsInstance(variables['self'], tc.WithDefaults)
|
||||
self.assertIsInstance(variables['trace'], trace.FireTrace)
|
||||
|
||||
@mock.patch('fire.interact.Embed')
|
||||
def testInteractiveModeVariablesWithName(self, mock_embed):
|
||||
core.Fire(tc.WithDefaults,
|
||||
command=['double', '2', '--', '-i', '-v'], name='D')
|
||||
self.assertTrue(mock_embed.called)
|
||||
(variables, verbose), unused_kwargs = mock_embed.call_args
|
||||
self.assertTrue(verbose)
|
||||
self.assertEqual(variables['result'], 4)
|
||||
self.assertIsInstance(variables['self'], tc.WithDefaults)
|
||||
self.assertEqual(variables['D'], tc.WithDefaults)
|
||||
self.assertIsInstance(variables['trace'], trace.FireTrace)
|
||||
|
||||
# TODO(dbieber): Use parameterized tests to break up repetitive tests.
|
||||
def testHelpWithClass(self):
|
||||
with self.assertRaisesFireExit(0, 'Usage:.*ARG1'):
|
||||
core.Fire(tc.InstanceVars, command=['--', '--help'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*ARG1'):
|
||||
core.Fire(tc.InstanceVars, command=['--help'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*ARG1'):
|
||||
core.Fire(tc.InstanceVars, command=['-h'])
|
||||
|
||||
def testHelpWithMember(self):
|
||||
with self.assertRaisesFireExit(0, 'Usage:.*capitalize'):
|
||||
core.Fire(tc.TypedProperties, command=['gamma', '--', '--help'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*capitalize'):
|
||||
core.Fire(tc.TypedProperties, command=['gamma', '--help'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*capitalize'):
|
||||
core.Fire(tc.TypedProperties, command=['gamma', '-h'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*delta'):
|
||||
core.Fire(tc.TypedProperties, command=['delta', '--help'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*echo'):
|
||||
core.Fire(tc.TypedProperties, command=['echo', '--help'])
|
||||
|
||||
def testHelpOnErrorInConstructor(self):
|
||||
with self.assertRaisesFireExit(0, 'Usage:.*[VALUE]'):
|
||||
core.Fire(tc.ErrorInConstructor, command=['--', '--help'])
|
||||
with self.assertRaisesFireExit(0, 'INFO:.*Usage:.*[VALUE]'):
|
||||
core.Fire(tc.ErrorInConstructor, command=['--help'])
|
||||
|
||||
def testHelpWithNamespaceCollision(self):
|
||||
# Tests cases when calling the help shortcut should not show help.
|
||||
with self.assertOutputMatches(stdout='Docstring.*', stderr=None):
|
||||
core.Fire(tc.WithHelpArg, command=['--help', 'False'])
|
||||
with self.assertOutputMatches(stdout='help in a dict', stderr=None):
|
||||
core.Fire(tc.WithHelpArg, command=['dictionary', '__help'])
|
||||
with self.assertOutputMatches(stdout='{}', stderr=None):
|
||||
core.Fire(tc.WithHelpArg, command=['dictionary', '--help'])
|
||||
with self.assertOutputMatches(stdout='False', stderr=None):
|
||||
core.Fire(tc.function_with_help, command=['False'])
|
||||
|
||||
def testInvalidParameterRaisesFireExit(self):
|
||||
with self.assertRaisesFireExit(2, 'runmisspelled'):
|
||||
core.Fire(tc.Kwargs, command=['props', '--a=1', '--b=2', 'runmisspelled'])
|
||||
|
||||
def testErrorRaising(self):
|
||||
# Errors in user code should not be caught; they should surface as normal.
|
||||
# This will lead to exit status code 1 for the client program.
|
||||
with self.assertRaises(ValueError):
|
||||
core.Fire(tc.ErrorRaiser, command=['fail'])
|
||||
|
||||
def testFireError(self):
|
||||
error = core.FireError('Example error')
|
||||
self.assertIsNotNone(error)
|
||||
|
||||
def testFireErrorMultipleValues(self):
|
||||
error = core.FireError('Example error', 'value')
|
||||
self.assertIsNotNone(error)
|
||||
|
||||
def testPrintEmptyDict(self):
|
||||
with self.assertOutputMatches(stdout='{}', stderr=None):
|
||||
core.Fire(tc.EmptyDictOutput, command=['totally_empty'])
|
||||
with self.assertOutputMatches(stdout='{}', stderr=None):
|
||||
core.Fire(tc.EmptyDictOutput, command=['nothing_printable'])
|
||||
|
||||
def testPrintOrderedDict(self):
|
||||
with self.assertOutputMatches(stdout=r'A:\s+A\s+2:\s+2\s+', stderr=None):
|
||||
core.Fire(tc.OrderedDictionary, command=['non_empty'])
|
||||
with self.assertOutputMatches(stdout='{}'):
|
||||
core.Fire(tc.OrderedDictionary, command=['empty'])
|
||||
|
||||
def testPrintNamedTupleField(self):
|
||||
with self.assertOutputMatches(stdout='11', stderr=None):
|
||||
core.Fire(tc.NamedTuple, command=['point', 'x'])
|
||||
|
||||
def testPrintNamedTupleIndex(self):
|
||||
with self.assertOutputMatches(stdout='22', stderr=None):
|
||||
core.Fire(tc.NamedTuple, command=['point', '1'])
|
||||
|
||||
def testPrintNamedTupleNegativeIndex(self):
|
||||
with self.assertOutputMatches(stdout='11', stderr=None):
|
||||
core.Fire(tc.NamedTuple, command=['point', '-2'])
|
||||
|
||||
def testCallable(self):
|
||||
with self.assertOutputMatches(stdout=r'foo:\s+foo\s+', stderr=None):
|
||||
core.Fire(tc.CallableWithKeywordArgument(), command=['--foo=foo'])
|
||||
with self.assertOutputMatches(stdout=r'foo\s+', stderr=None):
|
||||
core.Fire(tc.CallableWithKeywordArgument(), command=['print_msg', 'foo'])
|
||||
with self.assertOutputMatches(stdout=r'', stderr=None):
|
||||
core.Fire(tc.CallableWithKeywordArgument(), command=[])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,97 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""These decorators provide function metadata to Python Fire.
|
||||
|
||||
SetParseFn and SetParseFns allow you to set the functions Fire uses for parsing
|
||||
command line arguments to client code.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
|
||||
FIRE_METADATA = 'FIRE_METADATA'
|
||||
FIRE_PARSE_FNS = 'FIRE_PARSE_FNS'
|
||||
ACCEPTS_POSITIONAL_ARGS = 'ACCEPTS_POSITIONAL_ARGS'
|
||||
|
||||
|
||||
def SetParseFn(fn, *arguments):
|
||||
"""Sets the fn for Fire to use to parse args when calling the decorated fn.
|
||||
|
||||
Args:
|
||||
fn: The function to be used for parsing arguments.
|
||||
*arguments: The arguments for which to use the parse fn. If none are listed,
|
||||
then this will set the default parse function.
|
||||
Returns:
|
||||
The decorated function, which now has metadata telling Fire how to perform.
|
||||
"""
|
||||
def _Decorator(func):
|
||||
parse_fns = GetParseFns(func)
|
||||
if not arguments:
|
||||
parse_fns['default'] = fn
|
||||
else:
|
||||
for argument in arguments:
|
||||
parse_fns['named'][argument] = fn
|
||||
_SetMetadata(func, FIRE_PARSE_FNS, parse_fns)
|
||||
return func
|
||||
|
||||
return _Decorator
|
||||
|
||||
|
||||
def SetParseFns(*positional, **named):
|
||||
"""Set the fns for Fire to use to parse args when calling the decorated fn.
|
||||
|
||||
Returns a decorator, which when applied to a function adds metadata to the
|
||||
function telling Fire how to turn string command line arguments into proper
|
||||
Python arguments with which to call the function.
|
||||
|
||||
A parse function should accept a single string argument and return a value to
|
||||
be used in it's place when calling the decorated function.
|
||||
|
||||
Args:
|
||||
*positional: The functions to be used for parsing positional arguments.
|
||||
**named: The functions to be used for parsing named arguments.
|
||||
Returns:
|
||||
The decorated function, which now has metadata telling Fire how to perform.
|
||||
"""
|
||||
def _Decorator(fn):
|
||||
parse_fns = GetParseFns(fn)
|
||||
parse_fns['positional'] = positional
|
||||
parse_fns['named'].update(named)
|
||||
_SetMetadata(fn, FIRE_PARSE_FNS, parse_fns)
|
||||
return fn
|
||||
|
||||
return _Decorator
|
||||
|
||||
|
||||
def _SetMetadata(fn, attribute, value):
|
||||
metadata = GetMetadata(fn)
|
||||
metadata[attribute] = value
|
||||
setattr(fn, FIRE_METADATA, metadata)
|
||||
|
||||
|
||||
def GetMetadata(fn):
|
||||
default = {
|
||||
ACCEPTS_POSITIONAL_ARGS: not inspect.isclass(fn),
|
||||
}
|
||||
return getattr(fn, FIRE_METADATA, default)
|
||||
|
||||
|
||||
def GetParseFns(fn):
|
||||
metadata = GetMetadata(fn)
|
||||
default = dict(default=None, positional=[], named={})
|
||||
return metadata.get(FIRE_PARSE_FNS, default)
|
||||
@@ -1,174 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the decorators module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import core
|
||||
from fire import decorators
|
||||
from fire import testutils
|
||||
|
||||
|
||||
class NoDefaults(object):
|
||||
"""A class for testing decorated functions without default values."""
|
||||
|
||||
@decorators.SetParseFns(count=int)
|
||||
def double(self, count):
|
||||
return 2 * count
|
||||
|
||||
@decorators.SetParseFns(count=float)
|
||||
def triple(self, count):
|
||||
return 3 * count
|
||||
|
||||
@decorators.SetParseFns(int)
|
||||
def quadruple(self, count):
|
||||
return 4 * count
|
||||
|
||||
|
||||
@decorators.SetParseFns(int)
|
||||
def double(count):
|
||||
return 2 * count
|
||||
|
||||
|
||||
class WithDefaults(object):
|
||||
|
||||
@decorators.SetParseFns(float)
|
||||
def example1(self, arg1=10):
|
||||
return arg1, type(arg1)
|
||||
|
||||
@decorators.SetParseFns(arg1=float)
|
||||
def example2(self, arg1=10):
|
||||
return arg1, type(arg1)
|
||||
|
||||
|
||||
class MixedArguments(object):
|
||||
|
||||
@decorators.SetParseFns(float, arg2=str)
|
||||
def example3(self, arg1, arg2):
|
||||
return arg1, arg2
|
||||
|
||||
|
||||
class PartialParseFn(object):
|
||||
|
||||
@decorators.SetParseFns(arg1=str)
|
||||
def example4(self, arg1, arg2):
|
||||
return arg1, arg2
|
||||
|
||||
@decorators.SetParseFns(arg2=str)
|
||||
def example5(self, arg1, arg2):
|
||||
return arg1, arg2
|
||||
|
||||
|
||||
class WithKwargs(object):
|
||||
|
||||
@decorators.SetParseFns(mode=str, count=int)
|
||||
def example6(self, **kwargs):
|
||||
return (
|
||||
kwargs.get('mode', 'default'),
|
||||
kwargs.get('count', 0),
|
||||
)
|
||||
|
||||
|
||||
class WithVarArgs(object):
|
||||
|
||||
@decorators.SetParseFn(str)
|
||||
def example7(self, arg1, arg2=None, *varargs, **kwargs): # pylint: disable=keyword-arg-before-vararg
|
||||
return arg1, arg2, varargs, kwargs
|
||||
|
||||
|
||||
class FireDecoratorsTest(testutils.BaseTestCase):
|
||||
|
||||
def testSetParseFnsNamedArgs(self):
|
||||
self.assertEqual(core.Fire(NoDefaults, command=['double', '2']), 4)
|
||||
self.assertEqual(core.Fire(NoDefaults, command=['triple', '4']), 12.0)
|
||||
|
||||
def testSetParseFnsPositionalArgs(self):
|
||||
self.assertEqual(core.Fire(NoDefaults, command=['quadruple', '5']), 20)
|
||||
|
||||
def testSetParseFnsFnWithPositionalArgs(self):
|
||||
self.assertEqual(core.Fire(double, command=['5']), 10)
|
||||
|
||||
def testSetParseFnsDefaultsFromPython(self):
|
||||
# When called from Python, function should behave normally.
|
||||
self.assertTupleEqual(WithDefaults().example1(), (10, int))
|
||||
self.assertEqual(WithDefaults().example1(5), (5, int))
|
||||
self.assertEqual(WithDefaults().example1(12.0), (12, float))
|
||||
|
||||
def testSetParseFnsDefaultsFromFire(self):
|
||||
# Fire should use the decorator to know how to parse string arguments.
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example1']), (10, int))
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example1', '10']),
|
||||
(10, float))
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example1', '13']),
|
||||
(13, float))
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example1', '14.0']),
|
||||
(14, float))
|
||||
|
||||
def testSetParseFnsNamedDefaultsFromPython(self):
|
||||
# When called from Python, function should behave normally.
|
||||
self.assertTupleEqual(WithDefaults().example2(), (10, int))
|
||||
self.assertEqual(WithDefaults().example2(5), (5, int))
|
||||
self.assertEqual(WithDefaults().example2(12.0), (12, float))
|
||||
|
||||
def testSetParseFnsNamedDefaultsFromFire(self):
|
||||
# Fire should use the decorator to know how to parse string arguments.
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example2']), (10, int))
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example2', '10']),
|
||||
(10, float))
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example2', '13']),
|
||||
(13, float))
|
||||
self.assertEqual(core.Fire(WithDefaults, command=['example2', '14.0']),
|
||||
(14, float))
|
||||
|
||||
def testSetParseFnsPositionalAndNamed(self):
|
||||
self.assertEqual(core.Fire(MixedArguments, ['example3', '10', '10']),
|
||||
(10, '10'))
|
||||
|
||||
def testSetParseFnsOnlySomeTypes(self):
|
||||
self.assertEqual(
|
||||
core.Fire(PartialParseFn, command=['example4', '10', '10']), ('10', 10))
|
||||
self.assertEqual(
|
||||
core.Fire(PartialParseFn, command=['example5', '10', '10']), (10, '10'))
|
||||
|
||||
def testSetParseFnsForKeywordArgs(self):
|
||||
self.assertEqual(
|
||||
core.Fire(WithKwargs, command=['example6']), ('default', 0))
|
||||
self.assertEqual(
|
||||
core.Fire(WithKwargs, command=['example6', '--herring', '"red"']),
|
||||
('default', 0))
|
||||
self.assertEqual(
|
||||
core.Fire(WithKwargs, command=['example6', '--mode', 'train']),
|
||||
('train', 0))
|
||||
self.assertEqual(core.Fire(WithKwargs, command=['example6', '--mode', '3']),
|
||||
('3', 0))
|
||||
self.assertEqual(
|
||||
core.Fire(WithKwargs,
|
||||
command=['example6', '--mode', '-1', '--count', '10']),
|
||||
('-1', 10))
|
||||
self.assertEqual(
|
||||
core.Fire(WithKwargs, command=['example6', '--count', '-2']),
|
||||
('default', -2))
|
||||
|
||||
def testSetParseFn(self):
|
||||
self.assertEqual(
|
||||
core.Fire(WithVarArgs,
|
||||
command=['example7', '1', '--arg2=2', '3', '4', '--kwarg=5']),
|
||||
('1', '2', ('3', '4'), {'kwarg': '5'}))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,695 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Docstring parsing module for Python Fire.
|
||||
|
||||
The following features of docstrings are not supported.
|
||||
TODO(dbieber): Support these features.
|
||||
- numpy docstrings may begin with the function signature.
|
||||
- whitespace may be important for proper structuring of a docstring
|
||||
- I've seen `argname` (with single backticks) as a style of documenting
|
||||
arguments. The `argname` appears on one line, and the description on the next.
|
||||
- .. Sphinx directives such as .. note:: are not understood.
|
||||
- After a section ends, future contents may be included in the section. E.g.
|
||||
:returns: This is what is returned.
|
||||
Example: An example goes here.
|
||||
- @param is sometimes used. E.g.
|
||||
@param argname (type) Description
|
||||
@return (type) Description
|
||||
- The true signature of a function is not used by the docstring parser. It could
|
||||
be useful for determining whether something is a section header or an argument
|
||||
for example.
|
||||
- This example confuses types as part of the docstrings.
|
||||
Parameters
|
||||
argname : argtype
|
||||
Arg description
|
||||
- If there's no blank line after the summary, the description will be slurped
|
||||
up into the summary.
|
||||
- "Examples" should be its own section type. aka "Usage".
|
||||
- "Notes" should be a section type.
|
||||
- Some people put parenthesis around their types in RST format, e.g.
|
||||
:param (type) paramname:
|
||||
- :rtype: directive (return type)
|
||||
- Also ":rtype str" with no closing ":" has come up.
|
||||
- Return types are not supported.
|
||||
- "# Returns" as a section title style
|
||||
- ":raises ExceptionType: Description" ignores the ExceptionType currently.
|
||||
- "Defaults to X" occurs sometimes.
|
||||
- "True | False" indicates bool type.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
import collections
|
||||
import re
|
||||
|
||||
import enum
|
||||
|
||||
|
||||
class DocstringInfo(
|
||||
collections.namedtuple(
|
||||
'DocstringInfo',
|
||||
('summary', 'description', 'args', 'returns', 'yields', 'raises'))):
|
||||
pass
|
||||
DocstringInfo.__new__.__defaults__ = (None,) * len(DocstringInfo._fields)
|
||||
|
||||
|
||||
class ArgInfo(
|
||||
collections.namedtuple(
|
||||
'ArgInfo',
|
||||
('name', 'type', 'description'))):
|
||||
pass
|
||||
ArgInfo.__new__.__defaults__ = (None,) * len(ArgInfo._fields)
|
||||
|
||||
|
||||
class Namespace(dict):
|
||||
"""A dict with attribute (dot-notation) access enabled."""
|
||||
|
||||
def __getattr__(self, key):
|
||||
if key not in self:
|
||||
self[key] = Namespace()
|
||||
return self.get(key)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
self[key] = value
|
||||
|
||||
def __delattr__(self, key):
|
||||
if key in self:
|
||||
del self[key]
|
||||
|
||||
|
||||
class Sections(enum.Enum):
|
||||
ARGS = 0
|
||||
RETURNS = 1
|
||||
YIELDS = 2
|
||||
RAISES = 3
|
||||
TYPE = 4
|
||||
|
||||
|
||||
class Formats(enum.Enum):
|
||||
GOOGLE = 0
|
||||
NUMPY = 1
|
||||
RST = 2
|
||||
|
||||
|
||||
SECTION_TITLES = {
|
||||
Sections.ARGS: ('argument', 'arg', 'parameter', 'param'),
|
||||
Sections.RETURNS: ('return',),
|
||||
Sections.YIELDS: ('yield',),
|
||||
Sections.RAISES: ('raise', 'except', 'exception', 'throw', 'error', 'warn'),
|
||||
Sections.TYPE: ('type',), # rst-only
|
||||
}
|
||||
|
||||
|
||||
def parse(docstring):
|
||||
"""Returns DocstringInfo about the given docstring.
|
||||
|
||||
This parser aims to parse Google, numpy, and rst formatted docstrings. These
|
||||
are the three most common docstring styles at the time of this writing.
|
||||
|
||||
This parser aims to be permissive, working even when the docstring deviates
|
||||
from the strict recommendations of these styles.
|
||||
|
||||
This parser does not aim to fully extract all structured information from a
|
||||
docstring, since there are simply too many ways to structure information in a
|
||||
docstring. Sometimes content will remain as unstructured text and simply gets
|
||||
included in the description.
|
||||
|
||||
The Google docstring style guide is available at:
|
||||
https://github.com/google/styleguide/blob/gh-pages/pyguide.md
|
||||
|
||||
The numpy docstring style guide is available at:
|
||||
https://numpydoc.readthedocs.io/en/latest/format.html
|
||||
|
||||
Information about the rST docstring format is available at:
|
||||
https://www.python.org/dev/peps/pep-0287/
|
||||
The full set of directives such as param and type for rST docstrings are at:
|
||||
http://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html
|
||||
|
||||
Note: This function does not claim to handle all docstrings well. A list of
|
||||
limitations is available at the top of the file. It does aim to run without
|
||||
crashing in O(n) time on all strings on length n. If you find a string that
|
||||
causes this to crash or run unacceptably slowly, please consider submitting
|
||||
a pull request.
|
||||
|
||||
Args:
|
||||
docstring: The docstring to parse.
|
||||
Returns:
|
||||
A DocstringInfo containing information about the docstring.
|
||||
"""
|
||||
if docstring is None:
|
||||
return DocstringInfo()
|
||||
|
||||
lines = docstring.strip().split('\n')
|
||||
lines_len = len(lines)
|
||||
state = Namespace() # TODO(dbieber): Switch to an explicit class.
|
||||
|
||||
# Variables in state include:
|
||||
state.section.title = None
|
||||
state.section.indentation = None
|
||||
state.section.line1_indentation = None
|
||||
state.section.format = None
|
||||
state.summary.permitted = True
|
||||
state.summary.lines = []
|
||||
state.description.lines = []
|
||||
state.args = []
|
||||
state.current_arg = None
|
||||
state.returns.lines = []
|
||||
state.yields.lines = []
|
||||
state.raises.lines = []
|
||||
|
||||
for index, line in enumerate(lines):
|
||||
has_next = index + 1 < lines_len
|
||||
next_line = lines[index + 1] if has_next else None
|
||||
line_info = _create_line_info(line, next_line)
|
||||
_consume_line(line_info, state)
|
||||
|
||||
summary = ' '.join(state.summary.lines) if state.summary.lines else None
|
||||
description = _join_lines(state.description.lines)
|
||||
returns = _join_lines(state.returns.lines)
|
||||
yields = _join_lines(state.yields.lines)
|
||||
raises = _join_lines(state.raises.lines)
|
||||
|
||||
args = [
|
||||
ArgInfo(
|
||||
name=arg.name,
|
||||
type=_cast_to_known_type(_join_lines(arg.type.lines)),
|
||||
description=_join_lines(arg.description.lines),
|
||||
)
|
||||
for arg in state.args
|
||||
]
|
||||
|
||||
return DocstringInfo(
|
||||
summary=summary,
|
||||
description=description,
|
||||
args=args or None,
|
||||
returns=returns,
|
||||
raises=raises,
|
||||
yields=yields,
|
||||
)
|
||||
|
||||
|
||||
def _join_lines(lines):
|
||||
"""Joins lines with the appropriate connective whitespace.
|
||||
|
||||
This puts a single space between consecutive lines, unless there's a blank
|
||||
line, in which case a full blank line is included.
|
||||
|
||||
Args:
|
||||
lines: A list of lines to join.
|
||||
Returns:
|
||||
A string, the lines joined together.
|
||||
"""
|
||||
# TODO(dbieber): Add parameters for variations in whitespace handling.
|
||||
if not lines:
|
||||
return None
|
||||
|
||||
started = False
|
||||
group_texts = [] # Full text of each section.
|
||||
group_lines = [] # Lines within the current section.
|
||||
for line in lines:
|
||||
stripped_line = line.strip()
|
||||
if stripped_line:
|
||||
started = True
|
||||
group_lines.append(stripped_line)
|
||||
else:
|
||||
if started:
|
||||
group_text = ' '.join(group_lines)
|
||||
group_texts.append(group_text)
|
||||
group_lines = []
|
||||
|
||||
if group_lines: # Process the final group.
|
||||
group_text = ' '.join(group_lines)
|
||||
group_texts.append(group_text)
|
||||
|
||||
return '\n\n'.join(group_texts)
|
||||
|
||||
|
||||
def _get_or_create_arg_by_name(state, name):
|
||||
"""Gets or creates a new Arg.
|
||||
|
||||
These Arg objects (Namespaces) are turned into the ArgInfo namedtuples
|
||||
returned by parse. Each Arg object is used to collect the name, type, and
|
||||
description of a single argument to the docstring's function.
|
||||
|
||||
Args:
|
||||
state: The state of the parser.
|
||||
name: The name of the arg to create.
|
||||
Returns:
|
||||
The new Arg.
|
||||
"""
|
||||
for arg in state.args:
|
||||
if arg.name == name:
|
||||
return arg
|
||||
arg = Namespace() # TODO(dbieber): Switch to an explicit class.
|
||||
arg.name = name
|
||||
arg.type.lines = []
|
||||
arg.description.lines = []
|
||||
state.args.append(arg)
|
||||
return arg
|
||||
|
||||
|
||||
def _is_arg_name(name):
|
||||
"""Returns whether name is a valid arg name.
|
||||
|
||||
This is used to prevent multiple words (plaintext) from being misinterpreted
|
||||
as an argument name. So if ":" appears in the middle of a line in a docstring,
|
||||
we don't accidentally interpret the first half of that line as a single arg
|
||||
name.
|
||||
|
||||
Args:
|
||||
name: The name of the potential arg.
|
||||
Returns:
|
||||
True if name looks like an arg name, False otherwise.
|
||||
"""
|
||||
name = name.strip()
|
||||
return (name
|
||||
and ' ' not in name
|
||||
and ':' not in name)
|
||||
|
||||
|
||||
def _as_arg_name_and_type(text):
|
||||
"""Returns text as a name and type, if text looks like an arg name and type.
|
||||
|
||||
Example:
|
||||
_as_arg_name_and_type("foo (int)") == "foo", "int"
|
||||
|
||||
Args:
|
||||
text: The text, which may or may not be an arg name and type.
|
||||
Returns:
|
||||
The arg name and type, if text looks like an arg name and type.
|
||||
None otherwise.
|
||||
"""
|
||||
tokens = text.split()
|
||||
if len(tokens) < 2:
|
||||
return None
|
||||
if _is_arg_name(tokens[0]):
|
||||
type_token = ' '.join(tokens[1:])
|
||||
type_token = type_token.lstrip('{([').rstrip('])}')
|
||||
return tokens[0], type_token
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _as_arg_names(names_str):
|
||||
"""Converts names_str to a list of arg names.
|
||||
|
||||
Example:
|
||||
_as_arg_names("a, b, c") == ["a", "b", "c"]
|
||||
|
||||
Args:
|
||||
names_str: A string with multiple space or comma separated arg names.
|
||||
Returns:
|
||||
A list of arg names, or None if names_str doesn't look like a list of arg
|
||||
names.
|
||||
"""
|
||||
names = re.split(',| ', names_str)
|
||||
names = [name.strip() for name in names if name.strip()]
|
||||
for name in names:
|
||||
if not _is_arg_name(name):
|
||||
return None
|
||||
if not names:
|
||||
return None
|
||||
return names
|
||||
|
||||
|
||||
def _cast_to_known_type(name):
|
||||
"""Canonicalizes a string representing a type if possible.
|
||||
|
||||
# TODO(dbieber): Support additional canonicalization, such as string/str, and
|
||||
# boolean/bool.
|
||||
|
||||
Example:
|
||||
_cast_to_known_type("str.") == "str"
|
||||
|
||||
Args:
|
||||
name: A string representing a type, or None.
|
||||
Returns:
|
||||
A canonicalized version of the type string.
|
||||
"""
|
||||
if name is None:
|
||||
return None
|
||||
return name.rstrip('.')
|
||||
|
||||
|
||||
def _consume_google_args_line(line_info, state):
|
||||
"""Consume a single line from a Google args section."""
|
||||
split_line = line_info.remaining.split(':', 1)
|
||||
if len(split_line) > 1:
|
||||
first, second = split_line # first is either the "arg" or "arg (type)"
|
||||
if _is_arg_name(first.strip()):
|
||||
arg = _get_or_create_arg_by_name(state, first.strip())
|
||||
arg.description.lines.append(second.strip())
|
||||
state.current_arg = arg
|
||||
else:
|
||||
arg_name_and_type = _as_arg_name_and_type(first)
|
||||
if arg_name_and_type:
|
||||
arg_name, type_str = arg_name_and_type
|
||||
arg = _get_or_create_arg_by_name(state, arg_name)
|
||||
arg.type.lines.append(type_str)
|
||||
arg.description.lines.append(second.strip())
|
||||
else:
|
||||
if state.current_arg:
|
||||
state.current_arg.description.lines.append(split_line[0])
|
||||
else:
|
||||
if state.current_arg:
|
||||
state.current_arg.description.lines.append(split_line[0])
|
||||
|
||||
|
||||
def _consume_line(line_info, state):
|
||||
"""Consumes one line of text, updating the state accordingly.
|
||||
|
||||
When _consume_line is called, part of the line may already have been processed
|
||||
for header information.
|
||||
|
||||
Args:
|
||||
line_info: Information about the current and next line of the docstring.
|
||||
state: The state of the docstring parser.
|
||||
"""
|
||||
_update_section_state(line_info, state)
|
||||
|
||||
if state.section.title is None:
|
||||
if state.summary.permitted:
|
||||
if line_info.remaining:
|
||||
state.summary.lines.append(line_info.remaining)
|
||||
elif state.summary.lines:
|
||||
state.summary.permitted = False
|
||||
else:
|
||||
# We're past the end of the summary.
|
||||
# Additions now contribute to the description.
|
||||
state.description.lines.append(line_info.remaining)
|
||||
else:
|
||||
state.summary.permitted = False
|
||||
|
||||
if state.section.new and state.section.format == Formats.RST:
|
||||
# The current line starts with an RST directive, e.g. ":param arg:".
|
||||
directive = _get_directive(line_info)
|
||||
directive_tokens = directive.split()
|
||||
if state.section.title == Sections.ARGS:
|
||||
name = directive_tokens[-1]
|
||||
arg = _get_or_create_arg_by_name(state, name)
|
||||
if len(directive_tokens) == 3:
|
||||
# A param directive of the form ":param type arg:".
|
||||
arg.type.lines.append(directive_tokens[1])
|
||||
state.current_arg = arg
|
||||
elif state.section.title == Sections.TYPE:
|
||||
name = directive_tokens[-1]
|
||||
arg = _get_or_create_arg_by_name(state, name)
|
||||
state.current_arg = arg
|
||||
|
||||
if (state.section.format == Formats.NUMPY and
|
||||
_line_is_hyphens(line_info.remaining)):
|
||||
# Skip this all-hyphens line, which is part of the numpy section header.
|
||||
return
|
||||
|
||||
if state.section.title == Sections.ARGS:
|
||||
if state.section.format == Formats.GOOGLE:
|
||||
_consume_google_args_line(line_info, state)
|
||||
elif state.section.format == Formats.RST:
|
||||
state.current_arg.description.lines.append(line_info.remaining.strip())
|
||||
elif state.section.format == Formats.NUMPY:
|
||||
line_stripped = line_info.remaining.strip()
|
||||
if _is_arg_name(line_stripped):
|
||||
# Token on it's own line can either be the last word of the description
|
||||
# of the previous arg, or a new arg. TODO: Whitespace can distinguish.
|
||||
arg = _get_or_create_arg_by_name(state, line_stripped)
|
||||
state.current_arg = arg
|
||||
elif ':' in line_stripped:
|
||||
possible_args, type_data = line_stripped.split(':', 1)
|
||||
arg_names = _as_arg_names(possible_args) # re.split(' |,', s)
|
||||
if arg_names:
|
||||
for arg_name in arg_names:
|
||||
arg = _get_or_create_arg_by_name(state, arg_name)
|
||||
arg.type.lines.append(type_data)
|
||||
state.current_arg = arg # TODO(dbieber): Multiple current args.
|
||||
else: # Just an ordinary line.
|
||||
if state.current_arg:
|
||||
state.current_arg.description.lines.append(
|
||||
line_info.remaining.strip())
|
||||
else:
|
||||
# TODO(dbieber): If not a blank line, add it to the description.
|
||||
pass
|
||||
else: # Just an ordinary line.
|
||||
if state.current_arg:
|
||||
state.current_arg.description.lines.append(
|
||||
line_info.remaining.strip())
|
||||
else:
|
||||
# TODO(dbieber): If not a blank line, add it to the description.
|
||||
pass
|
||||
|
||||
elif state.section.title == Sections.RETURNS:
|
||||
state.returns.lines.append(line_info.remaining.strip())
|
||||
elif state.section.title == Sections.YIELDS:
|
||||
state.yields.lines.append(line_info.remaining.strip())
|
||||
elif state.section.title == Sections.RAISES:
|
||||
state.raises.lines.append(line_info.remaining.strip())
|
||||
elif state.section.title == Sections.TYPE:
|
||||
if state.section.format == Formats.RST:
|
||||
assert state.current_arg is not None
|
||||
state.current_arg.type.lines.append(line_info.remaining.strip())
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
def _create_line_info(line, next_line):
|
||||
"""Returns information about the current and next line of the docstring."""
|
||||
line_info = Namespace() # TODO(dbieber): Switch to an explicit class.
|
||||
line_info.line = line
|
||||
line_info.stripped = line.strip()
|
||||
line_info.remaining = line_info.stripped
|
||||
line_info.indentation = len(line) - len(line.lstrip())
|
||||
line_info.next.line = next_line
|
||||
line_info.next.stripped = next_line.strip() if next_line else None
|
||||
line_info.next.indentation = (
|
||||
len(next_line) - len(next_line.lstrip()) if next_line else None)
|
||||
# Note: This counts all whitespace equally.
|
||||
return line_info
|
||||
|
||||
|
||||
def _update_section_state(line_info, state):
|
||||
"""Uses line_info to determine the current section of the docstring.
|
||||
|
||||
Updates state and line_info.remaining.
|
||||
|
||||
Args:
|
||||
line_info: Information about the current line.
|
||||
state: The state of the parser.
|
||||
"""
|
||||
section_updated = False
|
||||
|
||||
google_section_permitted = _google_section_permitted(line_info, state)
|
||||
google_section = google_section_permitted and _google_section(line_info)
|
||||
if google_section:
|
||||
state.section.format = Formats.GOOGLE
|
||||
state.section.title = google_section
|
||||
line_info.remaining = _get_after_google_header(line_info)
|
||||
section_updated = True
|
||||
|
||||
rst_section = _rst_section(line_info)
|
||||
if rst_section:
|
||||
state.section.format = Formats.RST
|
||||
state.section.title = rst_section
|
||||
line_info.remaining = _get_after_directive(line_info)
|
||||
section_updated = True
|
||||
|
||||
numpy_section = _numpy_section(line_info)
|
||||
if numpy_section:
|
||||
state.section.format = Formats.NUMPY
|
||||
state.section.title = numpy_section
|
||||
line_info.remaining = ''
|
||||
section_updated = True
|
||||
|
||||
if section_updated:
|
||||
state.section.new = True
|
||||
state.section.indentation = line_info.indentation
|
||||
state.section.line1_indentation = line_info.next.indentation
|
||||
else:
|
||||
state.section.new = False
|
||||
|
||||
|
||||
def _google_section_permitted(line_info, state):
|
||||
"""Returns whether a new google section is permitted to start here.
|
||||
|
||||
Q: Why might a new Google section not be allowed?
|
||||
A: If we're in the middle of a Google "Args" section, then lines that start
|
||||
"param:" will usually be a new arg, rather than a new section.
|
||||
We use whitespace to determine when the Args section has actually ended.
|
||||
|
||||
A Google section ends when either:
|
||||
- A new google section begins at either
|
||||
- indentation less than indentation of line 1 of the previous section
|
||||
- or <= indentation of the previous section
|
||||
- Or the docstring terminates.
|
||||
|
||||
Args:
|
||||
line_info: Information about the current line.
|
||||
state: The state of the parser.
|
||||
Returns:
|
||||
True or False, indicating whether a new Google section is permitted at the
|
||||
current line.
|
||||
"""
|
||||
if state.section.indentation is None: # We're not in a section yet.
|
||||
return True
|
||||
return (line_info.indentation <= state.section.indentation
|
||||
or line_info.indentation < state.section.line1_indentation)
|
||||
|
||||
|
||||
def _matches_section_title(title, section_title):
|
||||
"""Returns whether title is a match for a specific section_title.
|
||||
|
||||
Example:
|
||||
_matches_section_title('Yields', 'yield') == True
|
||||
|
||||
Args:
|
||||
title: The title to check for matching.
|
||||
section_title: A specific known section title to check against.
|
||||
"""
|
||||
title = title.lower()
|
||||
section_title = section_title.lower()
|
||||
return section_title in (title, title[:-1]) # Supports plurals / some typos.
|
||||
|
||||
|
||||
def _matches_section(title, section):
|
||||
"""Returns whether title is a match any known title for a specific section.
|
||||
|
||||
Example:
|
||||
_matches_section_title('Yields', Sections.YIELDS) == True
|
||||
_matches_section_title('param', Sections.Args) == True
|
||||
|
||||
Args:
|
||||
title: The title to check for matching.
|
||||
section: A specific section to check all possible titles for.
|
||||
Returns:
|
||||
True or False, indicating whether title is a match for the specified
|
||||
section.
|
||||
"""
|
||||
for section_title in SECTION_TITLES[section]:
|
||||
if _matches_section_title(title, section_title):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _section_from_possible_title(possible_title):
|
||||
"""Returns a section matched by the possible title, or None if none match.
|
||||
|
||||
Args:
|
||||
possible_title: A string that may be the title of a new section.
|
||||
Returns:
|
||||
A Section type if one matches, or None if no section type matches.
|
||||
"""
|
||||
for section in SECTION_TITLES:
|
||||
if _matches_section(possible_title, section):
|
||||
return section
|
||||
return None
|
||||
|
||||
|
||||
def _google_section(line_info):
|
||||
"""Checks whether the current line is the start of a new Google-style section.
|
||||
|
||||
This docstring is a Google-style docstring. Google-style sections look like
|
||||
this:
|
||||
|
||||
Section Name:
|
||||
section body goes here
|
||||
|
||||
Args:
|
||||
line_info: Information about the current line.
|
||||
Returns:
|
||||
A Section type if one matches, or None if no section type matches.
|
||||
"""
|
||||
colon_index = line_info.remaining.find(':')
|
||||
possible_title = line_info.remaining[:colon_index]
|
||||
return _section_from_possible_title(possible_title)
|
||||
|
||||
|
||||
def _get_after_google_header(line_info):
|
||||
"""Gets the remainder of the line, after a Google header."""
|
||||
colon_index = line_info.remaining.find(':')
|
||||
return line_info.remaining[colon_index + 1:]
|
||||
|
||||
|
||||
def _get_directive(line_info):
|
||||
"""Gets a directive from the start of the line.
|
||||
|
||||
If the line is ":param str foo: Description of foo", then
|
||||
_get_directive(line_info) returns "param str foo".
|
||||
|
||||
Args:
|
||||
line_info: Information about the current line.
|
||||
Returns:
|
||||
The contents of a directive, or None if the line doesn't start with a
|
||||
directive.
|
||||
"""
|
||||
if line_info.stripped.startswith(':'):
|
||||
return line_info.stripped.split(':', 2)[1]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _get_after_directive(line_info):
|
||||
"""Gets the remainder of the line, after a directive."""
|
||||
sections = line_info.stripped.split(':', 2)
|
||||
if len(sections) > 2:
|
||||
return sections[-1]
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def _rst_section(line_info):
|
||||
"""Checks whether the current line is the start of a new RST-style section.
|
||||
|
||||
RST uses directives to specify information. An RST directive, which we refer
|
||||
to as a section here, are surrounded with colons. For example, :param name:.
|
||||
|
||||
Args:
|
||||
line_info: Information about the current line.
|
||||
Returns:
|
||||
A Section type if one matches, or None if no section type matches.
|
||||
"""
|
||||
directive = _get_directive(line_info)
|
||||
if directive:
|
||||
possible_title = directive.split()[0]
|
||||
return _section_from_possible_title(possible_title)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _line_is_hyphens(line):
|
||||
"""Returns whether the line is entirely hyphens (and not blank)."""
|
||||
return line and not line.strip('-')
|
||||
|
||||
|
||||
def _numpy_section(line_info):
|
||||
"""Checks whether the current line is the start of a new numpy-style section.
|
||||
|
||||
Numpy style sections are followed by a full line of hyphens, for example:
|
||||
|
||||
Section Name
|
||||
------------
|
||||
Section body goes here.
|
||||
|
||||
Args:
|
||||
line_info: Information about the current line.
|
||||
Returns:
|
||||
A Section type if one matches, or None if no section type matches.
|
||||
"""
|
||||
next_line_is_hyphens = _line_is_hyphens(line_info.next.stripped)
|
||||
if next_line_is_hyphens:
|
||||
possible_title = line_info.remaining
|
||||
return _section_from_possible_title(possible_title)
|
||||
else:
|
||||
return None
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Fuzz tests for the docstring parser module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import docstrings
|
||||
from fire import testutils
|
||||
|
||||
from hypothesis import example
|
||||
from hypothesis import given
|
||||
from hypothesis import settings
|
||||
from hypothesis import strategies as st
|
||||
|
||||
|
||||
class DocstringsFuzzTest(testutils.BaseTestCase):
|
||||
|
||||
@settings(max_examples=1000, deadline=1000)
|
||||
@given(st.text(min_size=1))
|
||||
@example('This is a one-line docstring.')
|
||||
def test_fuzz_parse(self, value):
|
||||
docstrings.parse(value)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,237 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for fire docstrings module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import docstrings
|
||||
from fire import testutils
|
||||
|
||||
|
||||
DocstringInfo = docstrings.DocstringInfo # pylint: disable=invalid-name
|
||||
ArgInfo = docstrings.ArgInfo # pylint: disable=invalid-name
|
||||
|
||||
|
||||
class DocstringsTest(testutils.BaseTestCase):
|
||||
|
||||
def test_one_line_simple(self):
|
||||
docstring = """A simple one line docstring."""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='A simple one line docstring.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_one_line_simple_whitespace(self):
|
||||
docstring = """
|
||||
A simple one line docstring.
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='A simple one line docstring.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_one_line_too_long(self):
|
||||
# pylint: disable=line-too-long
|
||||
docstring = """A one line docstring thats both a little too verbose and a little too long so it keeps going well beyond a reasonable length for a one-liner.
|
||||
"""
|
||||
# pylint: enable=line-too-long
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='A one line docstring thats both a little too verbose and '
|
||||
'a little too long so it keeps going well beyond a reasonable length '
|
||||
'for a one-liner.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_one_line_runs_over(self):
|
||||
# pylint: disable=line-too-long
|
||||
docstring = """A one line docstring thats both a little too verbose and a little too long
|
||||
so it runs onto a second line.
|
||||
"""
|
||||
# pylint: enable=line-too-long
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='A one line docstring thats both a little too verbose and '
|
||||
'a little too long so it runs onto a second line.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_one_line_runs_over_whitespace(self):
|
||||
docstring = """
|
||||
A one line docstring thats both a little too verbose and a little too long
|
||||
so it runs onto a second line.
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='A one line docstring thats both a little too verbose and '
|
||||
'a little too long so it runs onto a second line.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_google_format_args_only(self):
|
||||
docstring = """One line description.
|
||||
|
||||
Args:
|
||||
arg1: arg1_description
|
||||
arg2: arg2_description
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='One line description.',
|
||||
args=[
|
||||
ArgInfo(name='arg1', description='arg1_description'),
|
||||
ArgInfo(name='arg2', description='arg2_description'),
|
||||
]
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_google_format_arg_named_args(self):
|
||||
docstring = """
|
||||
Args:
|
||||
args: arg_description
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
args=[
|
||||
ArgInfo(name='args', description='arg_description'),
|
||||
]
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_google_format_typed_args_and_returns(self):
|
||||
docstring = """Docstring summary.
|
||||
|
||||
This is a longer description of the docstring. It spans multiple lines, as
|
||||
is allowed.
|
||||
|
||||
Args:
|
||||
param1 (int): The first parameter.
|
||||
param2 (str): The second parameter.
|
||||
|
||||
Returns:
|
||||
bool: The return value. True for success, False otherwise.
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='Docstring summary.',
|
||||
description='This is a longer description of the docstring. It spans '
|
||||
'multiple lines, as is allowed.',
|
||||
args=[
|
||||
ArgInfo(name='param1', type='int',
|
||||
description='The first parameter.'),
|
||||
ArgInfo(name='param2', type='str',
|
||||
description='The second parameter.'),
|
||||
],
|
||||
returns='bool: The return value. True for success, False otherwise.'
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_rst_format_typed_args_and_returns(self):
|
||||
docstring = """Docstring summary.
|
||||
|
||||
This is a longer description of the docstring. It spans across multiple
|
||||
lines.
|
||||
|
||||
:param arg1: Description of arg1.
|
||||
:type arg1: str.
|
||||
:param arg2: Description of arg2.
|
||||
:type arg2: bool.
|
||||
:returns: int -- description of the return value.
|
||||
:raises: AttributeError, KeyError
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='Docstring summary.',
|
||||
description='This is a longer description of the docstring. It spans '
|
||||
'across multiple lines.',
|
||||
args=[
|
||||
ArgInfo(name='arg1', type='str',
|
||||
description='Description of arg1.'),
|
||||
ArgInfo(name='arg2', type='bool',
|
||||
description='Description of arg2.'),
|
||||
],
|
||||
returns='int -- description of the return value.',
|
||||
raises='AttributeError, KeyError',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_numpy_format_typed_args_and_returns(self):
|
||||
docstring = """Docstring summary.
|
||||
|
||||
This is a longer description of the docstring. It spans across multiple
|
||||
lines.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
param1 : int
|
||||
The first parameter.
|
||||
param2 : str
|
||||
The second parameter.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
True if successful, False otherwise.
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='Docstring summary.',
|
||||
description='This is a longer description of the docstring. It spans '
|
||||
'across multiple lines.',
|
||||
args=[
|
||||
ArgInfo(name='param1', type='int',
|
||||
description='The first parameter.'),
|
||||
ArgInfo(name='param2', type='str',
|
||||
description='The second parameter.'),
|
||||
],
|
||||
# TODO(dbieber): Support return type.
|
||||
returns='bool True if successful, False otherwise.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_multisection_docstring(self):
|
||||
docstring = """Docstring summary.
|
||||
|
||||
This is the first section of a docstring description.
|
||||
|
||||
This is the second section of a docstring description. This docstring
|
||||
description has just two sections.
|
||||
"""
|
||||
docstring_info = docstrings.parse(docstring)
|
||||
expected_docstring_info = DocstringInfo(
|
||||
summary='Docstring summary.',
|
||||
description='This is the first section of a docstring description.\n\n'
|
||||
'This is the second section of a docstring description. This docstring '
|
||||
'description has just two sections.',
|
||||
)
|
||||
self.assertEqual(docstring_info, expected_docstring_info)
|
||||
|
||||
def test_ill_formed_docstring(self):
|
||||
docstring = """Docstring summary.
|
||||
|
||||
args: raises ::
|
||||
:
|
||||
pathological docstrings should not fail, and ideally should behave
|
||||
reasonably.
|
||||
"""
|
||||
docstrings.parse(docstring)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests importing the fire module."""
|
||||
|
||||
import sys
|
||||
|
||||
import fire
|
||||
from fire import testutils
|
||||
import mock
|
||||
|
||||
|
||||
class FireImportTest(testutils.BaseTestCase):
|
||||
"""Tests importing Fire."""
|
||||
|
||||
def testFire(self):
|
||||
with mock.patch.object(sys, 'argv', ['commandname']):
|
||||
fire.Fire()
|
||||
|
||||
def testFireMethods(self):
|
||||
self.assertIsNotNone(fire.Fire)
|
||||
|
||||
def testNoPrivateMethods(self):
|
||||
self.assertTrue(hasattr(fire, 'Fire'))
|
||||
self.assertFalse(hasattr(fire, '_Fire'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,688 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the fire module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import fire
|
||||
from fire import test_components as tc
|
||||
from fire import testutils
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
|
||||
class FireTest(testutils.BaseTestCase):
|
||||
|
||||
def testFire(self):
|
||||
with mock.patch.object(sys, 'argv', ['progname']):
|
||||
fire.Fire(tc.Empty)
|
||||
fire.Fire(tc.OldStyleEmpty)
|
||||
fire.Fire(tc.WithInit)
|
||||
# Test both passing command as a sequence and as a string.
|
||||
self.assertEqual(fire.Fire(tc.NoDefaults, command='triple 4'), 12)
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults, command=('double', '2')), 4)
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults, command=['triple', '4']), 12)
|
||||
self.assertEqual(fire.Fire(tc.OldStyleWithDefaults,
|
||||
command=['double', '2']), 4)
|
||||
self.assertEqual(fire.Fire(tc.OldStyleWithDefaults,
|
||||
command=['triple', '4']), 12)
|
||||
|
||||
def testFirePositionalCommand(self):
|
||||
# Test passing command as a positional argument.
|
||||
self.assertEqual(fire.Fire(tc.NoDefaults, 'double 2'), 4)
|
||||
self.assertEqual(fire.Fire(tc.NoDefaults, ['double', '2']), 4)
|
||||
|
||||
def testFireInvalidCommandArg(self):
|
||||
with self.assertRaises(ValueError):
|
||||
# This is not a valid command.
|
||||
fire.Fire(tc.WithDefaults, command=10)
|
||||
|
||||
def testFireDefaultName(self):
|
||||
with mock.patch.object(sys, 'argv',
|
||||
[os.path.join('python-fire', 'fire',
|
||||
'base_filename.py')]):
|
||||
with self.assertOutputMatches(stdout='Usage: base_filename.py',
|
||||
stderr=None):
|
||||
fire.Fire(tc.Empty)
|
||||
|
||||
def testFireNoArgs(self):
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['ten']), 10)
|
||||
|
||||
def testFireExceptions(self):
|
||||
# Exceptions of Fire are printed to stderr and a FireExit is raised.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.Empty, command=['nomethod']) # Member doesn't exist.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.NoDefaults, command=['double']) # Missing argument.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.TypedProperties, command=['delta', 'x']) # Missing key.
|
||||
|
||||
# Exceptions of the target components are still raised.
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
fire.Fire(tc.NumberDefaults, command=['reciprocal', '0.0'])
|
||||
|
||||
def testFireNamedArgs(self):
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['double', '--count', '5']), 10)
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['triple', '--count', '5']), 15)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.OldStyleWithDefaults, command=['double', '--count', '5']),
|
||||
10)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.OldStyleWithDefaults, command=['triple', '--count', '5']),
|
||||
15)
|
||||
|
||||
def testFireNamedArgsSingleHyphen(self):
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['double', '-count', '5']), 10)
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['triple', '-count', '5']), 15)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.OldStyleWithDefaults, command=['double', '-count', '5']),
|
||||
10)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.OldStyleWithDefaults, command=['triple', '-count', '5']),
|
||||
15)
|
||||
|
||||
def testFireNamedArgsWithEquals(self):
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['double', '--count=5']), 10)
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['triple', '--count=5']), 15)
|
||||
|
||||
def testFireNamedArgsWithEqualsSingleHyphen(self):
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['double', '-count=5']), 10)
|
||||
self.assertEqual(fire.Fire(tc.WithDefaults,
|
||||
command=['triple', '-count=5']), 15)
|
||||
|
||||
def testFireAllNamedArgs(self):
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['sum', '1', '2']), 5)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--alpha', '1', '2']), 5)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--beta', '1', '2']), 4)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '1', '--alpha', '2']), 4)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '1', '--beta', '2']), 5)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--alpha', '1', '--beta', '2']), 5)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--beta', '1', '--alpha', '2']), 4)
|
||||
|
||||
def testFireAllNamedArgsOneMissing(self):
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['sum']), 0)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults, command=['sum', '1']), 1)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--alpha', '1']), 1)
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--beta', '2']), 4)
|
||||
|
||||
def testFirePartialNamedArgs(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '1', '2']), (1, 2))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha', '1', '2']), (1, 2))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--beta', '1', '2']), (2, 1))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '1', '--alpha', '2']), (2, 1))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '1', '--beta', '2']), (1, 2))
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.MixedDefaults,
|
||||
command=['identity', '--alpha', '1', '--beta', '2']), (1, 2))
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.MixedDefaults,
|
||||
command=['identity', '--beta', '1', '--alpha', '2']), (2, 1))
|
||||
|
||||
def testFirePartialNamedArgsOneMissing(self):
|
||||
# Errors are written to standard out and a FireExit is raised.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity']) # Identity needs an arg.
|
||||
|
||||
with self.assertRaisesFireExit(2):
|
||||
# Identity needs a value for alpha.
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '--beta', '2'])
|
||||
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '1']), (1, '0'))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '--alpha', '1']),
|
||||
(1, '0'))
|
||||
|
||||
def testFireAnnotatedArgs(self):
|
||||
self.assertEqual(fire.Fire(tc.Annotations, command=['double', '5']), 10)
|
||||
self.assertEqual(fire.Fire(tc.Annotations, command=['triple', '5']), 15)
|
||||
|
||||
@unittest.skipIf(six.PY2, 'Keyword-only arguments not in Python 2.')
|
||||
def testFireKeywordOnlyArgs(self):
|
||||
with self.assertRaisesFireExit(2):
|
||||
# Keyword arguments must be passed with flag syntax.
|
||||
fire.Fire(tc.py3.KeywordOnly, command=['double', '5'])
|
||||
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.py3.KeywordOnly, command=['double', '--count', '5']), 10)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.py3.KeywordOnly, command=['triple', '--count', '5']), 15)
|
||||
|
||||
def testFireProperties(self):
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties, command=['alpha']), True)
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties, command=['beta']), (1, 2, 3))
|
||||
|
||||
def testFireRecursion(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.TypedProperties,
|
||||
command=['charlie', 'double', 'hello']), 'hellohello')
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties,
|
||||
command=['charlie', 'triple', 'w']), 'www')
|
||||
|
||||
def testFireVarArgs(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.VarArgs,
|
||||
command=['cumsums', 'a', 'b', 'c', 'd']),
|
||||
['a', 'ab', 'abc', 'abcd'])
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.VarArgs, command=['cumsums', '1', '2', '3', '4']),
|
||||
[1, 3, 6, 10])
|
||||
|
||||
def testFireVarArgsWithNamedArgs(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.VarArgs, command=['varchars', '1', '2', 'c', 'd']),
|
||||
(1, 2, 'cd'))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.VarArgs, command=['varchars', '3', '4', 'c', 'd', 'e']),
|
||||
(3, 4, 'cde'))
|
||||
|
||||
def testFireKeywordArgs(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.Kwargs,
|
||||
command=['props', '--name', 'David', '--age', '24']),
|
||||
{'name': 'David', 'age': 24})
|
||||
# Run this test both with a list command and a string command.
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.Kwargs,
|
||||
command=['props', '--message',
|
||||
'"This is a message it has -- in it"']), # Quotes stripped
|
||||
{'message': 'This is a message it has -- in it'})
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.Kwargs,
|
||||
command=['props', '--message',
|
||||
'This is a message it has -- in it']),
|
||||
{'message': 'This is a message it has -- in it'})
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.Kwargs,
|
||||
command='props --message "This is a message it has -- in it"'),
|
||||
{'message': 'This is a message it has -- in it'})
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Kwargs,
|
||||
command=['upper', '--alpha', 'A', '--beta', 'B']),
|
||||
'ALPHA BETA')
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.Kwargs,
|
||||
command=['upper', '--alpha', 'A', '--beta', 'B', '-', 'lower']),
|
||||
'alpha beta')
|
||||
|
||||
def testFireKeywordArgsWithMissingPositionalArgs(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Kwargs, command=['run', 'Hello', 'World', '--cell', 'is']),
|
||||
('Hello', 'World', {'cell': 'is'}))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Kwargs, command=['run', 'Hello', '--cell', 'ok']),
|
||||
('Hello', None, {'cell': 'ok'}))
|
||||
|
||||
def testFireObject(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.WithDefaults(), command=['double', '--count', '5']), 10)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.WithDefaults(), command=['triple', '--count', '5']), 15)
|
||||
|
||||
def testFireDict(self):
|
||||
component = {
|
||||
'double': lambda x=0: 2 * x,
|
||||
'cheese': 'swiss',
|
||||
}
|
||||
self.assertEqual(fire.Fire(component, command=['double', '5']), 10)
|
||||
self.assertEqual(fire.Fire(component, command=['cheese']), 'swiss')
|
||||
|
||||
def testFireObjectWithDict(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.TypedProperties, command=['delta', 'echo']), 'E')
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.TypedProperties, command=['delta', 'echo', 'lower']), 'e')
|
||||
self.assertIsInstance(
|
||||
fire.Fire(tc.TypedProperties, command=['delta', 'nest']), dict)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.TypedProperties, command=['delta', 'nest', '0']), 'a')
|
||||
|
||||
def testFireList(self):
|
||||
component = ['zero', 'one', 'two', 'three']
|
||||
self.assertEqual(fire.Fire(component, command=['2']), 'two')
|
||||
self.assertEqual(fire.Fire(component, command=['3']), 'three')
|
||||
self.assertEqual(fire.Fire(component, command=['-1']), 'three')
|
||||
|
||||
def testFireObjectWithList(self):
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties, command=['echo', '0']),
|
||||
'alex')
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties, command=['echo', '1']),
|
||||
'bethany')
|
||||
|
||||
def testFireObjectWithTuple(self):
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties, command=['fox', '0']),
|
||||
'carry')
|
||||
self.assertEqual(fire.Fire(tc.TypedProperties, command=['fox', '1']),
|
||||
'divide')
|
||||
|
||||
def testFireNoComponent(self):
|
||||
self.assertEqual(fire.Fire(command=['tc', 'WithDefaults', 'double', '10']),
|
||||
20)
|
||||
last_char = lambda text: text[-1] # pylint: disable=unused-variable
|
||||
self.assertEqual(fire.Fire(command=['last_char', '"Hello"']), 'o')
|
||||
self.assertEqual(fire.Fire(command=['last-char', '"World"']), 'd')
|
||||
rset = lambda count=0: set(range(count)) # pylint: disable=unused-variable
|
||||
self.assertEqual(fire.Fire(command=['rset', '5']), {0, 1, 2, 3, 4})
|
||||
|
||||
def testFireUnderscores(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Underscores,
|
||||
command=['underscore-example']), 'fish fingers')
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Underscores,
|
||||
command=['underscore_example']), 'fish fingers')
|
||||
|
||||
def testFireUnderscoresInArg(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Underscores,
|
||||
command=['underscore-function', 'example']), 'example')
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Underscores,
|
||||
command=['underscore_function', '--underscore-arg=score']),
|
||||
'score')
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.Underscores,
|
||||
command=['underscore_function', '--underscore_arg=score']),
|
||||
'score')
|
||||
|
||||
def testBoolParsing(self):
|
||||
self.assertEqual(fire.Fire(tc.BoolConverter, command=['as-bool', 'True']),
|
||||
True)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', 'False']), False)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', '--arg=True']), True)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', '--arg=False']), False)
|
||||
self.assertEqual(fire.Fire(tc.BoolConverter, command=['as-bool', '--arg']),
|
||||
True)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', '--noarg']), False)
|
||||
|
||||
def testBoolParsingContinued(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', 'True', 'False']), (True, False))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha=False', '10']), (False, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha', '--beta', '10']), (True, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha', '--beta=10']), (True, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--noalpha', '--beta']), (False, True))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '10', '--beta']),
|
||||
(10, True))
|
||||
|
||||
def testBoolParsingSingleHyphen(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-alpha=False', '10']), (False, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-alpha', '-beta', '10']), (True, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-alpha', '-beta=10']), (True, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-noalpha', '-beta']), (False, True))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-alpha', '-10', '-beta']), (-10, True))
|
||||
|
||||
def testBoolParsingLessExpectedCases(self):
|
||||
# Note: Does not return (True, 10).
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha', '10']), (10, '0'))
|
||||
# To get (True, 10), use one of the following:
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha', '--beta=10']),
|
||||
(True, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', 'True', '10']), (True, 10))
|
||||
|
||||
# Note: Does not return (True, '--test') or ('--test', 0).
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '--alpha', '--test'])
|
||||
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.MixedDefaults,
|
||||
command=['identity', '--alpha', 'True', '"--test"']),
|
||||
(True, '--test'))
|
||||
# To get ('--test', '0'), use one of the following:
|
||||
self.assertEqual(fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha=--test']),
|
||||
('--test', '0'))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults, command=r'identity --alpha \"--test\"'),
|
||||
('--test', '0'))
|
||||
|
||||
def testSingleCharFlagParsing(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a']), (True, '0'))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a', '--beta=10']), (True, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a', '-b']), (True, True))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a', '42', '-b']), (42, True))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a', '42', '-b', '10']), (42, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '--alpha', 'True', '-b', '10']),
|
||||
(True, 10))
|
||||
with self.assertRaisesFireExit(2):
|
||||
# This test attempts to use an ambiguous shortcut flag on a function with
|
||||
# a naming conflict for the shortcut, triggering a FireError.
|
||||
fire.Fire(tc.SimilarArgNames, command=['identity', '-b'])
|
||||
|
||||
def testSingleCharFlagParsingEqualSign(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a=True']), (True, '0'))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a=3', '--beta=10']), (3, 10))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a=False', '-b=15']), (False, 15))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a', '42', '-b=12']), (42, 12))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-a=42', '-b', '10']), (42, 10))
|
||||
|
||||
def testSingleCharFlagParsingExactMatch(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.SimilarArgNames,
|
||||
command=['identity2', '-a']), (True, None))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.SimilarArgNames,
|
||||
command=['identity2', '-a=10']), (10, None))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.SimilarArgNames,
|
||||
command=['identity2', '--a']), (True, None))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.SimilarArgNames,
|
||||
command=['identity2', '-alpha']), (None, True))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.SimilarArgNames,
|
||||
command=['identity2', '-a', '-alpha']), (True, True))
|
||||
|
||||
def testSingleCharFlagParsingCapitalLetter(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.CapitalizedArgNames,
|
||||
command=['sum', '-D', '5', '-G', '10']), 15)
|
||||
|
||||
def testBoolParsingWithNo(self):
|
||||
# In these examples --nothing always refers to the nothing argument:
|
||||
def fn1(thing, nothing):
|
||||
return thing, nothing
|
||||
|
||||
self.assertEqual(fire.Fire(fn1, command=['--thing', '--nothing']),
|
||||
(True, True))
|
||||
self.assertEqual(fire.Fire(fn1, command=['--thing', '--nonothing']),
|
||||
(True, False))
|
||||
|
||||
with self.assertRaisesFireExit(2):
|
||||
# In this case nothing=False (since rightmost setting of a flag gets
|
||||
# precedence), but it errors because thing has no value.
|
||||
fire.Fire(fn1, command=['--nothing', '--nonothing'])
|
||||
|
||||
# In these examples, --nothing sets thing=False:
|
||||
def fn2(thing, **kwargs):
|
||||
return thing, kwargs
|
||||
self.assertEqual(fire.Fire(fn2, command=['--thing']), (True, {}))
|
||||
self.assertEqual(fire.Fire(fn2, command=['--nothing']), (False, {}))
|
||||
with self.assertRaisesFireExit(2):
|
||||
# In this case, nothing=True, but it errors because thing has no value.
|
||||
fire.Fire(fn2, command=['--nothing=True'])
|
||||
self.assertEqual(fire.Fire(fn2, command=['--nothing', '--nothing=True']),
|
||||
(False, {'nothing': True}))
|
||||
|
||||
def fn3(arg, **kwargs):
|
||||
return arg, kwargs
|
||||
self.assertEqual(fire.Fire(fn3, command=['--arg=value', '--thing']),
|
||||
('value', {'thing': True}))
|
||||
self.assertEqual(fire.Fire(fn3, command=['--arg=value', '--nothing']),
|
||||
('value', {'thing': False}))
|
||||
self.assertEqual(fire.Fire(fn3, command=['--arg=value', '--nonothing']),
|
||||
('value', {'nothing': False}))
|
||||
|
||||
def testTraceFlag(self):
|
||||
with self.assertRaisesFireExit(0, 'Fire trace:\n'):
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '--trace'])
|
||||
with self.assertRaisesFireExit(0, 'Fire trace:\n'):
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '-t'])
|
||||
with self.assertRaisesFireExit(0, 'Fire trace:\n'):
|
||||
fire.Fire(tc.BoolConverter, command=['--', '--trace'])
|
||||
|
||||
def testHelpFlag(self):
|
||||
with self.assertRaisesFireExit(0):
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '--help'])
|
||||
with self.assertRaisesFireExit(0):
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '-h'])
|
||||
with self.assertRaisesFireExit(0):
|
||||
fire.Fire(tc.BoolConverter, command=['--', '--help'])
|
||||
|
||||
def testHelpFlagAndTraceFlag(self):
|
||||
with self.assertRaisesFireExit(0, 'Fire trace:\n.*Usage:'):
|
||||
fire.Fire(tc.BoolConverter,
|
||||
command=['as-bool', 'True', '--', '--help', '--trace'])
|
||||
with self.assertRaisesFireExit(0, 'Fire trace:\n.*Usage:'):
|
||||
fire.Fire(tc.BoolConverter, command=['as-bool', 'True', '--', '-h', '-t'])
|
||||
with self.assertRaisesFireExit(0, 'Fire trace:\n.*Usage:'):
|
||||
fire.Fire(tc.BoolConverter, command=['--', '-h', '--trace'])
|
||||
|
||||
def testTabCompletionNoName(self):
|
||||
completion_script = fire.Fire(tc.NoDefaults, command=['--', '--completion'])
|
||||
self.assertIn('double', completion_script)
|
||||
self.assertIn('triple', completion_script)
|
||||
|
||||
def testTabCompletion(self):
|
||||
completion_script = fire.Fire(
|
||||
tc.NoDefaults, command=['--', '--completion'], name='c')
|
||||
self.assertIn('double', completion_script)
|
||||
self.assertIn('triple', completion_script)
|
||||
|
||||
def testTabCompletionWithDict(self):
|
||||
actions = {'multiply': lambda a, b: a * b}
|
||||
completion_script = fire.Fire(
|
||||
actions, command=['--', '--completion'], name='actCLI')
|
||||
self.assertIn('actCLI', completion_script)
|
||||
self.assertIn('multiply', completion_script)
|
||||
|
||||
def testBasicSeparator(self):
|
||||
# '-' is the default separator.
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '+', '_']), ('+', '_'))
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '_', '+', '-']), ('_', '+'))
|
||||
|
||||
# If we change the separator we can use '-' as an argument.
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['identity', '-', '_', '--', '--separator', '&']),
|
||||
('-', '_'))
|
||||
|
||||
# The separator triggers a function call, but there aren't enough arguments.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.MixedDefaults, command=['identity', '-', '_', '+'])
|
||||
|
||||
def testNonComparable(self):
|
||||
"""Fire should work with classes that disallow comparisons."""
|
||||
# Make sure this test passes both with a string command or a list command.
|
||||
self.assertIsInstance(
|
||||
fire.Fire(tc.NonComparable, command=''), tc.NonComparable)
|
||||
self.assertIsInstance(
|
||||
fire.Fire(tc.NonComparable, command=[]), tc.NonComparable)
|
||||
|
||||
# The first separator instantiates the NonComparable object.
|
||||
# The second separator causes Fire to check if the separator was necessary.
|
||||
self.assertIsInstance(
|
||||
fire.Fire(tc.NonComparable, command=['-', '-']), tc.NonComparable)
|
||||
|
||||
def testExtraSeparators(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.ReturnsObj,
|
||||
command=['get-obj', 'arg1', 'arg2', '-', '-', 'as-bool', 'True']),
|
||||
True)
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.ReturnsObj,
|
||||
command=['get-obj', 'arg1', 'arg2', '-', '-', '-', 'as-bool',
|
||||
'True']),
|
||||
True)
|
||||
|
||||
def testSeparatorForChaining(self):
|
||||
# Without a separator all args are consumed by get_obj.
|
||||
self.assertIsInstance(
|
||||
fire.Fire(tc.ReturnsObj,
|
||||
command=['get-obj', 'arg1', 'arg2', 'as-bool', 'True']),
|
||||
tc.BoolConverter)
|
||||
# With a separator only the preceding args are consumed by get_obj.
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.ReturnsObj,
|
||||
command=['get-obj', 'arg1', 'arg2', '-', 'as-bool', 'True']), True)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.ReturnsObj,
|
||||
command=['get-obj', 'arg1', 'arg2', '&', 'as-bool', 'True',
|
||||
'--', '--separator', '&']),
|
||||
True)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.ReturnsObj,
|
||||
command=['get-obj', 'arg1', '$$', 'as-bool', 'True', '--',
|
||||
'--separator', '$$']),
|
||||
True)
|
||||
|
||||
def testNegativeNumbers(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--alpha', '-3', '--beta', '-4']), -11)
|
||||
|
||||
def testFloatForExpectedInt(self):
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.MixedDefaults,
|
||||
command=['sum', '--alpha', '2.2', '--beta', '3.0']), 8.2)
|
||||
self.assertEqual(
|
||||
fire.Fire(
|
||||
tc.NumberDefaults,
|
||||
command=['integer_reciprocal', '--divisor', '5.0']), 0.2)
|
||||
self.assertEqual(
|
||||
fire.Fire(tc.NumberDefaults, command=['integer_reciprocal', '4.0']),
|
||||
0.25)
|
||||
|
||||
def testClassInstantiation(self):
|
||||
self.assertIsInstance(fire.Fire(tc.InstanceVars,
|
||||
command=['--arg1=a1', '--arg2=a2']),
|
||||
tc.InstanceVars)
|
||||
with self.assertRaisesFireExit(2):
|
||||
# Cannot instantiate a class with positional args.
|
||||
fire.Fire(tc.InstanceVars, command=['a1', 'a2'])
|
||||
|
||||
def testTraceErrors(self):
|
||||
# Class needs additional value but runs out of args.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars, command=['a1'])
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars, command=['--arg1=a1'])
|
||||
|
||||
# Routine needs additional value but runs out of args.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars, command=['a1', 'a2', '-', 'run', 'b1'])
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars,
|
||||
command=['--arg1=a1', '--arg2=a2', '-', 'run b1'])
|
||||
|
||||
# Extra args cannot be consumed.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars,
|
||||
command=['a1', 'a2', '-', 'run', 'b1', 'b2', 'b3'])
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(
|
||||
tc.InstanceVars,
|
||||
command=['--arg1=a1', '--arg2=a2', '-', 'run', 'b1', 'b2', 'b3'])
|
||||
|
||||
# Cannot find member to access.
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars, command=['a1', 'a2', '-', 'jog'])
|
||||
with self.assertRaisesFireExit(2):
|
||||
fire.Fire(tc.InstanceVars, command=['--arg1=a1', '--arg2=a2', '-', 'jog'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,640 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Utility for producing help strings for use in Fire CLIs.
|
||||
|
||||
Can produce help strings suitable for display in Fire CLIs for any type of
|
||||
Python object, module, class, or function.
|
||||
|
||||
There are two types of informative strings: Usage and Help screens.
|
||||
|
||||
Usage screens are shown when the user accesses a group or accesses a command
|
||||
without calling it. A Usage screen shows information about how to use that group
|
||||
or command. Usage screens are typically short and show the minimal information
|
||||
necessary for the user to determine how to proceed.
|
||||
|
||||
Help screens are shown when the user requests help with the help flag (--help).
|
||||
Help screens are shown in a less-style console view, and contain detailed help
|
||||
information.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
|
||||
from fire import completion
|
||||
from fire import docstrings
|
||||
from fire import inspectutils
|
||||
from fire import value_types
|
||||
|
||||
|
||||
def _NormalizeField(field):
|
||||
"""Takes a field name and turns it into a human readable name for display.
|
||||
|
||||
Args:
|
||||
field: The field name, used to index into the inspection dict.
|
||||
Returns:
|
||||
The human readable name, suitable for display in a help string.
|
||||
"""
|
||||
if field == 'type_name':
|
||||
field = 'type'
|
||||
return (field[0].upper() + field[1:]).replace('_', ' ')
|
||||
|
||||
|
||||
def _DisplayValue(info, field, padding):
|
||||
"""Gets the value of field from the dict info for display.
|
||||
|
||||
Args:
|
||||
info: The dict with information about the component.
|
||||
field: The field to access for display.
|
||||
padding: Number of spaces to indent text to line up with first-line text.
|
||||
Returns:
|
||||
The value of the field for display, or None if no value should be displayed.
|
||||
"""
|
||||
value = info.get(field)
|
||||
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
skip_doc_types = ('dict', 'list', 'unicode', 'int', 'float', 'bool')
|
||||
|
||||
if field == 'docstring':
|
||||
if info.get('type_name') in skip_doc_types:
|
||||
# Don't show the boring default docstrings for these types.
|
||||
return None
|
||||
elif value == '<no docstring>':
|
||||
return None
|
||||
|
||||
elif field == 'usage':
|
||||
lines = []
|
||||
for index, line in enumerate(value.split('\n')):
|
||||
if index > 0:
|
||||
line = ' ' * padding + line
|
||||
lines.append(line)
|
||||
return '\n'.join(lines)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def _GetFields(trace=None):
|
||||
"""Returns the field names to include in the help text for a component."""
|
||||
del trace # Unused.
|
||||
return [
|
||||
'type_name',
|
||||
'string_form',
|
||||
'file',
|
||||
'line',
|
||||
'docstring',
|
||||
'init_docstring',
|
||||
'class_docstring',
|
||||
'call_docstring',
|
||||
'length',
|
||||
'usage',
|
||||
]
|
||||
|
||||
|
||||
def HelpString(component, trace=None, verbose=False):
|
||||
"""Returns a help string for a supplied component.
|
||||
|
||||
The component can be any Python class, object, function, module, etc.
|
||||
|
||||
Args:
|
||||
component: The component to determine the help string for.
|
||||
trace: The Fire trace leading to this component.
|
||||
verbose: Whether to include private members in the help string.
|
||||
Returns:
|
||||
String suitable for display giving information about the component.
|
||||
"""
|
||||
info = inspectutils.Info(component)
|
||||
# TODO(dbieber): Stop using UsageString in favor of UsageText.
|
||||
info['usage'] = UsageString(component, trace, verbose)
|
||||
info['docstring_info'] = docstrings.parse(info['docstring'])
|
||||
|
||||
is_error_screen = False
|
||||
if trace:
|
||||
is_error_screen = trace.HasError()
|
||||
|
||||
if is_error_screen:
|
||||
# TODO(dbieber): Call UsageText instead of CommonHelpText once ready.
|
||||
return _CommonHelpText(info, trace)
|
||||
else:
|
||||
return _HelpText(info, trace)
|
||||
|
||||
|
||||
def _CommonHelpText(info, trace=None):
|
||||
"""Returns help text.
|
||||
|
||||
This was a copy of previous HelpString function and will be removed once the
|
||||
correct text formatters are implemented.
|
||||
|
||||
Args:
|
||||
info: The IR object containing metadata of an object.
|
||||
trace: The Fire trace object containing all metadata of current execution.
|
||||
Returns:
|
||||
String suitable for display giving information about the component.
|
||||
"""
|
||||
# TODO(joejoevictor): Currently this is just a copy of existing
|
||||
# HelpString method. We will reimplement this further in later CLs.
|
||||
fields = _GetFields(trace)
|
||||
|
||||
try:
|
||||
max_size = max(
|
||||
len(_NormalizeField(field)) + 1
|
||||
for field in fields
|
||||
if field in info and info[field])
|
||||
format_string = '{{field:{max_size}s}} {{value}}'.format(max_size=max_size)
|
||||
except ValueError:
|
||||
return ''
|
||||
|
||||
lines = []
|
||||
for field in fields:
|
||||
value = _DisplayValue(info, field, padding=max_size + 1)
|
||||
if value:
|
||||
if lines and field == 'usage':
|
||||
lines.append('') # Ensure a blank line before usage.
|
||||
|
||||
lines.append(format_string.format(
|
||||
field=_NormalizeField(field) + ':',
|
||||
value=value,
|
||||
))
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def GetSummaryAndDescription(docstring_info):
|
||||
"""Retrieves summary and description for help text generation."""
|
||||
|
||||
# To handle both empty string and None
|
||||
summary = docstring_info.summary if docstring_info.summary else None
|
||||
description = (
|
||||
docstring_info.description if docstring_info.description else None)
|
||||
return summary, description
|
||||
|
||||
|
||||
def GetCurrentCommand(trace=None):
|
||||
"""Returns current command for the purpose of generating help text."""
|
||||
if trace:
|
||||
current_command = trace.GetCommand()
|
||||
else:
|
||||
current_command = ''
|
||||
|
||||
return current_command
|
||||
|
||||
|
||||
def HelpText(component, info, trace=None, verbose=False):
|
||||
if inspect.isroutine(component) or inspect.isclass(component):
|
||||
return HelpTextForFunction(component, info, trace)
|
||||
else:
|
||||
return HelpTextForObject(component, info, trace, verbose)
|
||||
|
||||
|
||||
def HelpTextForFunction(component, info, trace=None, verbose=False):
|
||||
"""Returns detail help text for a function component.
|
||||
|
||||
Args:
|
||||
component: Current component to generate help text for.
|
||||
info: Info containing metadata of component.
|
||||
trace: FireTrace object that leads to current component.
|
||||
verbose: Whether to display help text in verbose mode.
|
||||
|
||||
Returns:
|
||||
Formatted help text for display.
|
||||
"""
|
||||
# TODO(joejoevictor): Implement verbose related output
|
||||
del verbose
|
||||
|
||||
current_command = GetCurrentCommand(trace)
|
||||
summary, description = GetSummaryAndDescription(info['docstring_info'])
|
||||
spec = inspectutils.GetFullArgSpec(component)
|
||||
args = spec.args
|
||||
|
||||
if spec.defaults is None:
|
||||
num_defaults = 0
|
||||
else:
|
||||
num_defaults = len(spec.defaults)
|
||||
args_with_no_defaults = args[:len(args) - num_defaults]
|
||||
|
||||
# TODO(joejoevictor): Generate flag section using these
|
||||
# args_with_defaults = args[len(args) - num_defaults:]
|
||||
# flags = args_with_defaults + spec.kwonlyargs
|
||||
|
||||
output_template = """NAME
|
||||
{name_section}
|
||||
|
||||
SYNOPSIS
|
||||
{synopsis_section}
|
||||
|
||||
DESCRIPTION
|
||||
{description_section}
|
||||
{args_and_flags_section}
|
||||
NOTES
|
||||
You could also use flags syntax for POSITIONAL ARGUMENTS
|
||||
"""
|
||||
|
||||
# Name section
|
||||
name_section_template = '{current_command}{command_summary}'
|
||||
command_summary_str = ' - ' + summary if summary else ''
|
||||
name_section = name_section_template.format(
|
||||
current_command=current_command, command_summary=command_summary_str)
|
||||
|
||||
items = [arg.upper() for arg in args_with_no_defaults]
|
||||
args_and_flags = ' '.join(items)
|
||||
|
||||
# Synopsis section
|
||||
synopsis_section_template = '{current_command} {args_and_flags}'
|
||||
positional_arguments = '|'.join(args)
|
||||
if positional_arguments:
|
||||
positional_arguments = ' ' + positional_arguments
|
||||
synopsis_section = synopsis_section_template.format(
|
||||
current_command=current_command, args_and_flags=args_and_flags)
|
||||
|
||||
# Description section
|
||||
description_section = description if description else summary
|
||||
|
||||
args_and_flags_section = ''
|
||||
|
||||
# Positional arguments and flags section
|
||||
|
||||
pos_arg_template = """
|
||||
POSITIONAL ARGUMENTS
|
||||
{items}
|
||||
"""
|
||||
pos_arg_items = []
|
||||
for arg in args_with_no_defaults:
|
||||
item_template = ' {arg_name}\n {arg_description}\n'
|
||||
arg_description = None
|
||||
for arg_in_docstring in info['docstring_info'].args:
|
||||
if arg_in_docstring.name == arg:
|
||||
arg_description = arg_in_docstring.description
|
||||
|
||||
item = item_template.format(
|
||||
arg_name=arg.upper(), arg_description=arg_description)
|
||||
pos_arg_items.append(item)
|
||||
if pos_arg_items:
|
||||
args_and_flags_section += pos_arg_template.format(
|
||||
items='\n'.join(pos_arg_items).rstrip('\n'))
|
||||
|
||||
return output_template.format(
|
||||
name_section=name_section,
|
||||
synopsis_section=synopsis_section,
|
||||
description_section=description_section,
|
||||
args_and_flags_section=args_and_flags_section)
|
||||
|
||||
|
||||
def HelpTextForObject(component, info, trace=None, verbose=False):
|
||||
"""Generates help text for python objects.
|
||||
|
||||
Args:
|
||||
component: Current component to generate help text for.
|
||||
info: Info containing metadata of component.
|
||||
trace: FireTrace object that leads to current component.
|
||||
verbose: Whether to display help text in verbose mode.
|
||||
|
||||
Returns:
|
||||
Formatted help text for display.
|
||||
"""
|
||||
|
||||
output_template = """NAME
|
||||
{current_command} - {command_summary}
|
||||
|
||||
SYNOPSIS
|
||||
{synopsis}
|
||||
|
||||
DESCRIPTION
|
||||
{command_description}
|
||||
{detail_section}
|
||||
"""
|
||||
|
||||
current_command = GetCurrentCommand(trace)
|
||||
|
||||
docstring_info = info['docstring_info']
|
||||
command_summary = docstring_info.summary if docstring_info.summary else ''
|
||||
if docstring_info.description:
|
||||
command_description = docstring_info.description
|
||||
else:
|
||||
command_description = ''
|
||||
|
||||
groups = []
|
||||
commands = []
|
||||
values = []
|
||||
members = completion._Members(component, verbose) # pylint: disable=protected-access
|
||||
for member_name, member in members:
|
||||
if value_types.IsGroup(member):
|
||||
groups.append((member_name, member))
|
||||
if value_types.IsCommand(member):
|
||||
commands.append((member_name, member))
|
||||
if value_types.IsValue(member):
|
||||
values.append((member_name, member))
|
||||
|
||||
possible_actions = []
|
||||
# TODO(joejoevictor): Add global flags to here. Also, if it's a callable,
|
||||
# there will be additional flags.
|
||||
possible_flags = ''
|
||||
detail_section_string = ''
|
||||
item_template = """
|
||||
{name}
|
||||
{command_summary}
|
||||
"""
|
||||
|
||||
if groups:
|
||||
# TODO(joejoevictor): Add missing GROUPS section handling
|
||||
possible_actions.append('GROUP')
|
||||
if commands:
|
||||
possible_actions.append('COMMAND')
|
||||
commands_str_template = """
|
||||
COMMANDS
|
||||
COMMAND is one of the followings:
|
||||
{items}
|
||||
"""
|
||||
command_item_strings = []
|
||||
for command_name, command in commands:
|
||||
command_docstring_info = docstrings.parse(
|
||||
inspectutils.Info(command)['docstring'])
|
||||
command_item_strings.append(
|
||||
item_template.format(
|
||||
name=command_name,
|
||||
command_summary=command_docstring_info.summary))
|
||||
detail_section_string += commands_str_template.format(
|
||||
items=('\n'.join(command_item_strings)).rstrip('\n'))
|
||||
|
||||
if values:
|
||||
possible_actions.append('VALUES')
|
||||
values_str_template = """
|
||||
VALUES
|
||||
VALUE is one of the followings:
|
||||
{items}
|
||||
"""
|
||||
value_item_strings = []
|
||||
for value_name, value in values:
|
||||
del value
|
||||
init_docstring_info = docstrings.parse(
|
||||
inspectutils.Info(component.__class__.__init__)['docstring'])
|
||||
for arg_info in init_docstring_info.args:
|
||||
if arg_info.name == value_name:
|
||||
value_item_strings.append(
|
||||
item_template.format(
|
||||
name=value_name, command_summary=arg_info.description))
|
||||
detail_section_string += values_str_template.format(
|
||||
items=('\n'.join(value_item_strings)).rstrip('\n'))
|
||||
|
||||
possible_actions_string = ' ' + (' | '.join(possible_actions))
|
||||
|
||||
synopsis_template = '{current_command}{possible_actions}{possible_flags}'
|
||||
synopsis_string = synopsis_template.format(
|
||||
current_command=current_command,
|
||||
possible_actions=possible_actions_string,
|
||||
possible_flags=possible_flags)
|
||||
|
||||
return output_template.format(
|
||||
current_command=current_command,
|
||||
command_summary=command_summary,
|
||||
synopsis=synopsis_string,
|
||||
command_description=command_description,
|
||||
detail_section=detail_section_string)
|
||||
|
||||
|
||||
def UsageText(component, trace=None, verbose=False):
|
||||
if inspect.isroutine(component) or inspect.isclass(component):
|
||||
return UsageTextForFunction(component, trace)
|
||||
else:
|
||||
return UsageTextForObject(component, trace, verbose)
|
||||
|
||||
|
||||
def UsageTextForFunction(component, trace=None):
|
||||
"""Returns usage text for function objects.
|
||||
|
||||
Args:
|
||||
component: The component to determine the usage text for.
|
||||
trace: The Fire trace object containing all metadata of current execution.
|
||||
|
||||
Returns:
|
||||
String suitable for display in error screen.
|
||||
"""
|
||||
|
||||
output_template = """Usage: {current_command} {args_and_flags}
|
||||
{availability_lines}
|
||||
For detailed information on this command, run:
|
||||
{current_command}{hyphen_hyphen} --help
|
||||
"""
|
||||
|
||||
if trace:
|
||||
command = trace.GetCommand()
|
||||
is_help_an_arg = trace.NeedsSeparatingHyphenHyphen()
|
||||
else:
|
||||
command = None
|
||||
is_help_an_arg = False
|
||||
|
||||
if not command:
|
||||
command = ''
|
||||
|
||||
spec = inspectutils.GetFullArgSpec(component)
|
||||
args = spec.args
|
||||
if spec.defaults is None:
|
||||
num_defaults = 0
|
||||
else:
|
||||
num_defaults = len(spec.defaults)
|
||||
args_with_no_defaults = args[:len(args) - num_defaults]
|
||||
args_with_defaults = args[len(args) - num_defaults:]
|
||||
flags = args_with_defaults + spec.kwonlyargs
|
||||
|
||||
items = [arg.upper() for arg in args_with_no_defaults]
|
||||
if flags:
|
||||
items.append('<flags>')
|
||||
availability_lines = (
|
||||
'\nAvailable flags: '
|
||||
+ ' | '.join('--' + flag for flag in flags) + '\n')
|
||||
else:
|
||||
availability_lines = ''
|
||||
args_and_flags = ' '.join(items)
|
||||
|
||||
hyphen_hyphen = ' --' if is_help_an_arg else ''
|
||||
|
||||
return output_template.format(
|
||||
current_command=command,
|
||||
args_and_flags=args_and_flags,
|
||||
availability_lines=availability_lines,
|
||||
hyphen_hyphen=hyphen_hyphen)
|
||||
|
||||
|
||||
def UsageTextForObject(component, trace=None, verbose=False):
|
||||
"""Returns help text for usage screen for objects.
|
||||
|
||||
Construct help text for usage screen to inform the user about error occurred
|
||||
and correct syntax for invoking the object.
|
||||
|
||||
Args:
|
||||
component: The component to determine the usage text for.
|
||||
trace: The Fire trace object containing all metadata of current execution.
|
||||
verbose: Whether to include private members in the usage text.
|
||||
Returns:
|
||||
String suitable for display in error screen.
|
||||
"""
|
||||
output_template = """Usage: {current_command} <{possible_actions}>
|
||||
{availability_lines}
|
||||
|
||||
For detailed information on this command, run:
|
||||
{current_command} --help
|
||||
"""
|
||||
if trace:
|
||||
command = trace.GetCommand()
|
||||
else:
|
||||
command = None
|
||||
|
||||
if not command:
|
||||
command = ''
|
||||
|
||||
groups = []
|
||||
commands = []
|
||||
values = []
|
||||
|
||||
members = completion._Members(component, verbose) # pylint: disable=protected-access
|
||||
for member_name, member in members:
|
||||
if value_types.IsGroup(member):
|
||||
groups.append(member_name)
|
||||
if value_types.IsCommand(member):
|
||||
commands.append(member_name)
|
||||
if value_types.IsValue(member):
|
||||
values.append(member_name)
|
||||
|
||||
possible_actions = []
|
||||
availability_lines = []
|
||||
availability_lint_format = '{header:20s}{choices}'
|
||||
if groups:
|
||||
possible_actions.append('groups')
|
||||
groups_string = ' | '.join(groups)
|
||||
groups_text = availability_lint_format.format(
|
||||
header='available groups:',
|
||||
choices=groups_string)
|
||||
availability_lines.append(groups_text)
|
||||
if commands:
|
||||
possible_actions.append('commands')
|
||||
commands_string = ' | '.join(commands)
|
||||
commands_text = availability_lint_format.format(
|
||||
header='available commands:',
|
||||
choices=commands_string)
|
||||
availability_lines.append(commands_text)
|
||||
if values:
|
||||
possible_actions.append('values')
|
||||
values_string = ' | '.join(values)
|
||||
values_text = availability_lint_format.format(
|
||||
header='available values:',
|
||||
choices=values_string)
|
||||
availability_lines.append(values_text)
|
||||
possible_actions_string = '|'.join(possible_actions)
|
||||
availability_lines_string = '\n'.join(availability_lines)
|
||||
|
||||
return output_template.format(
|
||||
current_command=command,
|
||||
possible_actions=possible_actions_string,
|
||||
availability_lines=availability_lines_string)
|
||||
|
||||
|
||||
def _HelpText(info, trace=None):
|
||||
"""Returns help text for extensive help screen.
|
||||
|
||||
Construct help text for help screen when user explicitly requesting help by
|
||||
having -h, --help in the command sequence.
|
||||
|
||||
Args:
|
||||
info: The IR object containing metadata of an object.
|
||||
trace: The Fire trace object containing all metadata of current execution.
|
||||
Returns:
|
||||
String suitable for display in extensive help screen.
|
||||
"""
|
||||
|
||||
# TODO(joejoevictor): Implement real help text construction.
|
||||
return _CommonHelpText(info, trace)
|
||||
|
||||
|
||||
def _UsageStringFromFullArgSpec(command, spec):
|
||||
"""Get a usage string from the FullArgSpec for the given command.
|
||||
|
||||
The strings look like:
|
||||
command --arg ARG [--opt OPT] [VAR ...] [--KWARGS ...]
|
||||
|
||||
Args:
|
||||
command: The command leading up to the function.
|
||||
spec: a FullArgSpec object describing the function.
|
||||
Returns:
|
||||
The usage string for the function.
|
||||
"""
|
||||
num_required_args = len(spec.args) - len(spec.defaults)
|
||||
|
||||
help_flags = []
|
||||
help_positional = []
|
||||
for index, arg in enumerate(spec.args):
|
||||
flag = arg.replace('_', '-')
|
||||
if index < num_required_args:
|
||||
help_flags.append('--{flag} {value}'.format(flag=flag, value=arg.upper()))
|
||||
help_positional.append('{value}'.format(value=arg.upper()))
|
||||
else:
|
||||
help_flags.append('[--{flag} {value}]'.format(
|
||||
flag=flag, value=arg.upper()))
|
||||
help_positional.append('[{value}]'.format(value=arg.upper()))
|
||||
|
||||
if spec.varargs:
|
||||
help_flags.append('[{var} ...]'.format(var=spec.varargs.upper()))
|
||||
help_positional.append('[{var} ...]'.format(var=spec.varargs.upper()))
|
||||
|
||||
for arg in spec.kwonlyargs:
|
||||
if arg in spec.kwonlydefaults:
|
||||
arg_str = '[--{flag} {value}]'.format(flag=arg, value=arg.upper())
|
||||
else:
|
||||
arg_str = '--{flag} {value}'.format(flag=arg, value=arg.upper())
|
||||
help_flags.append(arg_str)
|
||||
help_positional.append(arg_str)
|
||||
|
||||
if spec.varkw:
|
||||
help_flags.append('[--{kwarg} ...]'.format(kwarg=spec.varkw.upper()))
|
||||
help_positional.append('[--{kwarg} ...]'.format(kwarg=spec.varkw.upper()))
|
||||
|
||||
commands_flags = command + ' '.join(help_flags)
|
||||
commands_positional = command + ' '.join(help_positional)
|
||||
commands = [commands_positional]
|
||||
|
||||
if commands_flags != commands_positional:
|
||||
commands.append(commands_flags)
|
||||
|
||||
return '\n'.join(commands)
|
||||
|
||||
|
||||
def UsageString(component, trace=None, verbose=False):
|
||||
"""Returns a string showing how to use the component as a Fire command."""
|
||||
if trace:
|
||||
command = trace.GetCommand()
|
||||
else:
|
||||
command = None
|
||||
|
||||
if command:
|
||||
command += ' '
|
||||
else:
|
||||
command = ''
|
||||
|
||||
if inspect.isroutine(component) or inspect.isclass(component):
|
||||
spec = inspectutils.GetFullArgSpec(component)
|
||||
return _UsageStringFromFullArgSpec(command, spec)
|
||||
|
||||
if isinstance(component, (list, tuple)):
|
||||
length = len(component)
|
||||
if length == 0:
|
||||
return command
|
||||
if length == 1:
|
||||
return command + '[0]'
|
||||
return command + '[0..{cap}]'.format(cap=length - 1)
|
||||
|
||||
completions = completion.Completions(component, verbose)
|
||||
if command:
|
||||
completions = [''] + completions
|
||||
return '\n'.join(command + end for end in completions)
|
||||
@@ -1,309 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the helputils module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
from fire import docstrings
|
||||
from fire import helputils
|
||||
from fire import inspectutils
|
||||
from fire import test_components as tc
|
||||
from fire import testutils
|
||||
from fire import trace
|
||||
import six
|
||||
|
||||
|
||||
class HelpUtilsTest(testutils.BaseTestCase):
|
||||
|
||||
def testHelpStringClass(self):
|
||||
helpstring = helputils.HelpString(tc.NoDefaults)
|
||||
self.assertIn('Type: type', helpstring)
|
||||
self.assertIn("String form: <class 'fire.test_components.NoDefaults'>",
|
||||
helpstring)
|
||||
self.assertIn('test_components.py', helpstring)
|
||||
self.assertIn('Line: ', helpstring)
|
||||
self.assertNotIn('Usage', helpstring)
|
||||
|
||||
def testHelpStringObject(self):
|
||||
obj = tc.NoDefaults()
|
||||
helpstring = helputils.HelpString(obj)
|
||||
self.assertIn('Type: NoDefaults', helpstring)
|
||||
self.assertIn('String form: <fire.test_components.NoDefaults object at ',
|
||||
helpstring)
|
||||
# TODO(dbieber): We comment this out since it only works with IPython:
|
||||
# self.assertIn('test_components.py', helpstring)
|
||||
self.assertIn('Usage: double\n'
|
||||
' triple', helpstring)
|
||||
|
||||
def testHelpStringFunction(self):
|
||||
obj = tc.NoDefaults()
|
||||
helpstring = helputils.HelpString(obj.double)
|
||||
if six.PY2:
|
||||
self.assertIn('Type: instancemethod\n', helpstring)
|
||||
else:
|
||||
self.assertIn('Type: method\n', helpstring)
|
||||
self.assertIn(
|
||||
'String form: <bound method NoDefaults.double of '
|
||||
'<fire.test_components.NoDefaults object',
|
||||
helpstring)
|
||||
self.assertIn('test_components.py', helpstring)
|
||||
self.assertIn('Line: ', helpstring)
|
||||
self.assertIn('Usage: COUNT\n'
|
||||
' --count COUNT', helpstring)
|
||||
|
||||
def testHelpStringFunctionWithDefaults(self):
|
||||
obj = tc.WithDefaults()
|
||||
helpstring = helputils.HelpString(obj.triple)
|
||||
if six.PY2:
|
||||
self.assertIn('Type: instancemethod\n', helpstring)
|
||||
else:
|
||||
self.assertIn('Type: method\n', helpstring)
|
||||
self.assertIn(
|
||||
'String form: <bound method WithDefaults.triple of '
|
||||
'<fire.test_components.WithDefaults object',
|
||||
helpstring)
|
||||
self.assertIn('test_components.py', helpstring)
|
||||
self.assertIn('Line: ', helpstring)
|
||||
self.assertIn('Usage: [COUNT]\n'
|
||||
' [--count COUNT]', helpstring)
|
||||
|
||||
def testHelpStringBuiltin(self):
|
||||
helpstring = helputils.HelpString('test'.upper)
|
||||
self.assertIn('Type: builtin_function_or_method', helpstring)
|
||||
self.assertIn('String form: <built-in method upper of', helpstring)
|
||||
|
||||
def testHelpStringIntType(self):
|
||||
helpstring = helputils.HelpString(int)
|
||||
self.assertIn('Type: type', helpstring)
|
||||
if six.PY2:
|
||||
self.assertIn("String form: <type 'int'>", helpstring)
|
||||
else:
|
||||
self.assertIn("String form: <class 'int'>", helpstring)
|
||||
self.assertNotIn('Usage', helpstring)
|
||||
|
||||
def testHelpStringEmptyList(self):
|
||||
helpstring = helputils.HelpString([])
|
||||
self.assertIn('Type: list', helpstring)
|
||||
self.assertIn('String form: []', helpstring)
|
||||
self.assertIn('Length: 0', helpstring)
|
||||
|
||||
def testHelpStringShortList(self):
|
||||
helpstring = helputils.HelpString([10])
|
||||
self.assertIn('Type: list', helpstring)
|
||||
self.assertIn('String form: [10]', helpstring)
|
||||
self.assertIn('Length: 1', helpstring)
|
||||
self.assertIn('Usage: [0]', helpstring) # [] denotes optional.
|
||||
|
||||
def testHelpStringInt(self):
|
||||
helpstring = helputils.HelpString(7)
|
||||
self.assertIn('Type: int', helpstring)
|
||||
self.assertIn('String form: 7', helpstring)
|
||||
self.assertIn('Usage: bit-length\n'
|
||||
' conjugate\n'
|
||||
' denominator\n', helpstring)
|
||||
|
||||
def testHelpClassNoInit(self):
|
||||
helpstring = helputils.HelpString(tc.OldStyleEmpty)
|
||||
if six.PY2:
|
||||
self.assertIn('Type: classobj\n', helpstring)
|
||||
else:
|
||||
self.assertIn('Type: type\n', helpstring)
|
||||
self.assertIn('String form: ', helpstring)
|
||||
self.assertIn('fire.test_components.OldStyleEmpty', helpstring)
|
||||
self.assertIn(os.path.join('fire', 'test_components.py'), helpstring)
|
||||
self.assertIn('Line: ', helpstring)
|
||||
|
||||
|
||||
class HelpScreenTest(testutils.BaseTestCase):
|
||||
|
||||
def testHelpScreen(self):
|
||||
component = tc.ClassWithDocstring()
|
||||
t = trace.FireTrace(component, name='ClassWithDocstring')
|
||||
info = inspectutils.Info(component)
|
||||
info['docstring_info'] = docstrings.parse(info['docstring'])
|
||||
help_output = helputils.HelpText(component, info, t)
|
||||
expected_output = """
|
||||
NAME
|
||||
ClassWithDocstring - Test class for testing help text output.
|
||||
|
||||
SYNOPSIS
|
||||
ClassWithDocstring COMMAND | VALUES
|
||||
|
||||
DESCRIPTION
|
||||
This is some detail description of this test class.
|
||||
|
||||
COMMANDS
|
||||
COMMAND is one of the followings:
|
||||
|
||||
print_msg
|
||||
Prints a message.
|
||||
|
||||
VALUES
|
||||
VALUE is one of the followings:
|
||||
|
||||
message
|
||||
The default message to print.
|
||||
|
||||
"""
|
||||
self.assertEqual(textwrap.dedent(expected_output).lstrip('\n'), help_output)
|
||||
|
||||
def testHelpScreenWithLineBreak(self):
|
||||
component = tc.ClassWithMultilineDocstring.example_generator
|
||||
t = trace.FireTrace(component, name='example_generator')
|
||||
info = inspectutils.Info(component)
|
||||
info['docstring_info'] = docstrings.parse(info['docstring'])
|
||||
help_output = helputils.HelpText(component, info, t)
|
||||
expected_output = """
|
||||
NAME
|
||||
example_generator - Generators have a ``Yields`` section instead of a ``Returns`` section.
|
||||
|
||||
SYNOPSIS
|
||||
example_generator N
|
||||
|
||||
DESCRIPTION
|
||||
Generators have a ``Yields`` section instead of a ``Returns`` section.
|
||||
|
||||
POSITIONAL ARGUMENTS
|
||||
N
|
||||
The upper limit of the range to generate, from 0 to `n` - 1.
|
||||
|
||||
NOTES
|
||||
You could also use flags syntax for POSITIONAL ARGUMENTS
|
||||
"""
|
||||
self.assertEqual(textwrap.dedent(expected_output).lstrip('\n'), help_output)
|
||||
|
||||
|
||||
class UsageTest(testutils.BaseTestCase):
|
||||
|
||||
def testUsageOutput(self):
|
||||
component = tc.NoDefaults()
|
||||
t = trace.FireTrace(component, name='NoDefaults')
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=False)
|
||||
expected_output = '''
|
||||
Usage: NoDefaults <commands>
|
||||
available commands: double | triple
|
||||
|
||||
For detailed information on this command, run:
|
||||
NoDefaults --help
|
||||
'''
|
||||
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
def testUsageOutputVerbose(self):
|
||||
component = tc.NoDefaults()
|
||||
t = trace.FireTrace(component, name='NoDefaults')
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=True)
|
||||
expected_output = '''
|
||||
Usage: NoDefaults <commands>
|
||||
available commands: double | triple
|
||||
|
||||
For detailed information on this command, run:
|
||||
NoDefaults --help
|
||||
'''
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
def testUsageOutputMethod(self):
|
||||
component = tc.NoDefaults().double
|
||||
t = trace.FireTrace(component, name='NoDefaults')
|
||||
t.AddAccessedProperty(component, 'double', ['double'], None, None)
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=True)
|
||||
expected_output = '''
|
||||
Usage: NoDefaults double COUNT
|
||||
|
||||
For detailed information on this command, run:
|
||||
NoDefaults double --help
|
||||
'''
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
def testUsageOutputFunctionWithHelp(self):
|
||||
component = tc.function_with_help
|
||||
t = trace.FireTrace(component, name='function_with_help')
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=True)
|
||||
expected_output = '''
|
||||
Usage: function_with_help <flags>
|
||||
|
||||
Available flags: --help
|
||||
|
||||
For detailed information on this command, run:
|
||||
function_with_help -- --help
|
||||
'''
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
def testUsageOutputFunctionWithDocstring(self):
|
||||
component = tc.multiplier_with_docstring
|
||||
t = trace.FireTrace(component, name='multiplier_with_docstring')
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=True)
|
||||
expected_output = '''
|
||||
Usage: multiplier_with_docstring NUM <flags>
|
||||
|
||||
Available flags: --rate
|
||||
|
||||
For detailed information on this command, run:
|
||||
multiplier_with_docstring --help
|
||||
'''
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
@testutils.skip('The functionality is not implemented yet')
|
||||
def testUsageOutputCallable(self):
|
||||
# This is both a group and a command!
|
||||
component = tc.CallableWithKeywordArgument
|
||||
t = trace.FireTrace(component, name='CallableWithKeywordArgument')
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=True)
|
||||
# TODO(zuhaohen): We need to handle the case for keyword args as well
|
||||
# i.e. __call__ method of CallableWithKeywordArgument
|
||||
expected_output = '''
|
||||
Usage: CallableWithKeywordArgument <commands>
|
||||
|
||||
Available commands: print_msg
|
||||
|
||||
For detailed information on this command, run:
|
||||
CallableWithKeywordArgument -- --help
|
||||
'''
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
def testUsageOutputConstructorWithParameter(self):
|
||||
component = tc.InstanceVars
|
||||
t = trace.FireTrace(component, name='InstanceVars')
|
||||
usage_output = helputils.UsageText(component, trace=t, verbose=True)
|
||||
expected_output = '''
|
||||
Usage: InstanceVars ARG1 ARG2
|
||||
|
||||
For detailed information on this command, run:
|
||||
InstanceVars --help
|
||||
'''
|
||||
self.assertEqual(
|
||||
usage_output,
|
||||
textwrap.dedent(expected_output).lstrip('\n'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,227 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Inspection utility functions for Python Fire."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class FullArgSpec(object):
|
||||
"""The arguments of a function, as in Python 3's inspect.FullArgSpec."""
|
||||
|
||||
def __init__(self, args=None, varargs=None, varkw=None, defaults=None,
|
||||
kwonlyargs=None, kwonlydefaults=None, annotations=None):
|
||||
"""Constructs a FullArgSpec with each provided attribute, or the default.
|
||||
|
||||
Args:
|
||||
args: A list of the argument names accepted by the function.
|
||||
varargs: The name of the *varargs argument or None if there isn't one.
|
||||
varkw: The name of the **kwargs argument or None if there isn't one.
|
||||
defaults: A tuple of the defaults for the arguments that accept defaults.
|
||||
kwonlyargs: A list of argument names that must be passed with a keyword.
|
||||
kwonlydefaults: A dictionary of keyword only arguments and their defaults.
|
||||
annotations: A dictionary of arguments and their annotated types.
|
||||
"""
|
||||
self.args = args or []
|
||||
self.varargs = varargs
|
||||
self.varkw = varkw
|
||||
self.defaults = defaults or ()
|
||||
self.kwonlyargs = kwonlyargs or []
|
||||
self.kwonlydefaults = kwonlydefaults or {}
|
||||
self.annotations = annotations or {}
|
||||
|
||||
|
||||
def _GetArgSpecInfo(fn):
|
||||
"""Gives information pertaining to computing the ArgSpec of fn.
|
||||
|
||||
Determines if the first arg is supplied automatically when fn is called.
|
||||
This arg will be supplied automatically if fn is a bound method or a class
|
||||
with an __init__ method.
|
||||
|
||||
Also returns the function who's ArgSpec should be used for determining the
|
||||
calling parameters for fn. This may be different from fn itself if fn is a
|
||||
class with an __init__ method.
|
||||
|
||||
Args:
|
||||
fn: The function or class of interest.
|
||||
Returns:
|
||||
A tuple with the following two items:
|
||||
fn: The function to use for determining the arg spec of this function.
|
||||
skip_arg: Whether the first argument will be supplied automatically, and
|
||||
hence should be skipped when supplying args from a Fire command.
|
||||
"""
|
||||
skip_arg = False
|
||||
if inspect.isclass(fn):
|
||||
# If the function is a class, we try to use it's init method.
|
||||
skip_arg = True
|
||||
if six.PY2 and hasattr(fn, '__init__'):
|
||||
fn = fn.__init__
|
||||
elif inspect.ismethod(fn):
|
||||
# If the function is a bound method, we skip the `self` argument.
|
||||
skip_arg = fn.__self__ is not None
|
||||
elif inspect.isbuiltin(fn):
|
||||
# If the function is a bound builtin, we skip the `self` argument.
|
||||
skip_arg = fn.__self__ is not None
|
||||
return fn, skip_arg
|
||||
|
||||
|
||||
def GetFullArgSpec(fn):
|
||||
"""Returns a FullArgSpec describing the given callable."""
|
||||
|
||||
fn, skip_arg = _GetArgSpecInfo(fn)
|
||||
|
||||
try:
|
||||
if six.PY2:
|
||||
args, varargs, varkw, defaults = inspect.getargspec(fn) # pylint: disable=deprecated-method
|
||||
kwonlyargs = kwonlydefaults = None
|
||||
annotations = getattr(fn, '__annotations__', None)
|
||||
else:
|
||||
(args, varargs, varkw, defaults,
|
||||
kwonlyargs, kwonlydefaults, annotations) = inspect.getfullargspec(fn) # pylint: disable=deprecated-method,no-member
|
||||
|
||||
except TypeError:
|
||||
# If we can't get the argspec, how do we know if the fn should take args?
|
||||
# 1. If it's a builtin, it can take args.
|
||||
# 2. If it's an implicit __init__ function (a 'slot wrapper'), take no args.
|
||||
# Are there other cases?
|
||||
if inspect.isbuiltin(fn):
|
||||
return FullArgSpec(varargs='vars', varkw='kwargs')
|
||||
return FullArgSpec()
|
||||
|
||||
if skip_arg and args:
|
||||
args.pop(0) # Remove 'self' or 'cls' from the list of arguments.
|
||||
|
||||
return FullArgSpec(args, varargs, varkw, defaults,
|
||||
kwonlyargs, kwonlydefaults, annotations)
|
||||
|
||||
|
||||
def GetFileAndLine(component):
|
||||
"""Returns the filename and line number of component.
|
||||
|
||||
Args:
|
||||
component: A component to find the source information for, usually a class
|
||||
or routine.
|
||||
Returns:
|
||||
filename: The name of the file where component is defined.
|
||||
lineno: The line number where component is defined.
|
||||
"""
|
||||
if inspect.isbuiltin(component):
|
||||
return None, None
|
||||
|
||||
try:
|
||||
filename = inspect.getsourcefile(component)
|
||||
except TypeError:
|
||||
return None, None
|
||||
|
||||
try:
|
||||
unused_code, lineindex = inspect.findsource(component)
|
||||
lineno = lineindex + 1
|
||||
except IOError:
|
||||
lineno = None
|
||||
|
||||
return filename, lineno
|
||||
|
||||
|
||||
def Info(component):
|
||||
"""Returns a dict with information about the given component.
|
||||
|
||||
The dict will have at least some of the following fields.
|
||||
type_name: The type of `component`.
|
||||
string_form: A string representation of `component`.
|
||||
file: The file in which `component` is defined.
|
||||
line: The line number at which `component` is defined.
|
||||
docstring: The docstring of `component`.
|
||||
init_docstring: The init docstring of `component`.
|
||||
class_docstring: The class docstring of `component`.
|
||||
call_docstring: The call docstring of `component`.
|
||||
length: The length of `component`.
|
||||
|
||||
Args:
|
||||
component: The component to analyze.
|
||||
Returns:
|
||||
A dict with information about the component.
|
||||
"""
|
||||
try:
|
||||
from IPython.core import oinspect # pylint: disable=g-import-not-at-top
|
||||
inspector = oinspect.Inspector()
|
||||
info = inspector.info(component)
|
||||
except ImportError:
|
||||
info = _InfoBackup(component)
|
||||
|
||||
try:
|
||||
unused_code, lineindex = inspect.findsource(component)
|
||||
info['line'] = lineindex + 1
|
||||
except (TypeError, IOError):
|
||||
info['line'] = None
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def _InfoBackup(component):
|
||||
"""Returns a dict with information about the given component.
|
||||
|
||||
This function is to be called only in the case that IPython's
|
||||
oinspect module is not available. The info dict it produces may
|
||||
contain less information that contained in the info dict produced
|
||||
by oinspect.
|
||||
|
||||
Args:
|
||||
component: The component to analyze.
|
||||
Returns:
|
||||
A dict with information about the component.
|
||||
"""
|
||||
info = {}
|
||||
|
||||
info['type_name'] = type(component).__name__
|
||||
info['string_form'] = str(component)
|
||||
|
||||
filename, lineno = GetFileAndLine(component)
|
||||
info['file'] = filename
|
||||
info['line'] = lineno
|
||||
info['docstring'] = inspect.getdoc(component)
|
||||
|
||||
try:
|
||||
info['length'] = str(len(component))
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def IsNamedTuple(component):
|
||||
"""Return true if the component is a namedtuple.
|
||||
|
||||
Unfortunately, Python offers no native way to check for a namedtuple type.
|
||||
Instead, we need to use a simple hack which should suffice for our case.
|
||||
namedtuples are internally implemented as tuples, therefore we need to:
|
||||
1. Check if the component is an instance of tuple.
|
||||
2. Check if the component has a _fields attribute which regular tuples do
|
||||
not have.
|
||||
|
||||
Args:
|
||||
component: The component to analyze.
|
||||
Returns:
|
||||
True if the component is a namedtuple or False otherwise.
|
||||
"""
|
||||
if not isinstance(component, tuple):
|
||||
return False
|
||||
|
||||
has_fields = bool(getattr(component, '_fields', None))
|
||||
return has_fields
|
||||
@@ -1,117 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the inspectutils module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from fire import inspectutils
|
||||
from fire import test_components as tc
|
||||
from fire import testutils
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class InspectUtilsTest(testutils.BaseTestCase):
|
||||
|
||||
def testGetFullArgSpec(self):
|
||||
spec = inspectutils.GetFullArgSpec(tc.identity)
|
||||
self.assertEqual(spec.args, ['arg1', 'arg2', 'arg3', 'arg4'])
|
||||
self.assertEqual(spec.defaults, (10, 20))
|
||||
self.assertEqual(spec.varargs, 'arg5')
|
||||
self.assertEqual(spec.varkw, 'arg6')
|
||||
self.assertEqual(spec.kwonlyargs, [])
|
||||
self.assertEqual(spec.kwonlydefaults, {})
|
||||
self.assertEqual(spec.annotations, {'arg2': int, 'arg4': int})
|
||||
|
||||
@unittest.skipIf(six.PY2, 'No keyword arguments in python 2')
|
||||
def testGetFullArgSpecPy3(self):
|
||||
spec = inspectutils.GetFullArgSpec(tc.py3.identity)
|
||||
self.assertEqual(spec.args, ['arg1', 'arg2', 'arg3', 'arg4'])
|
||||
self.assertEqual(spec.defaults, (10, 20))
|
||||
self.assertEqual(spec.varargs, 'arg5')
|
||||
self.assertEqual(spec.varkw, 'arg10')
|
||||
self.assertEqual(spec.kwonlyargs, ['arg6', 'arg7', 'arg8', 'arg9'])
|
||||
self.assertEqual(spec.kwonlydefaults, {'arg8': 30, 'arg9': 40})
|
||||
self.assertEqual(spec.annotations,
|
||||
{'arg2': int, 'arg4': int, 'arg7': int, 'arg9': int})
|
||||
|
||||
def testGetFullArgSpecFromBuiltin(self):
|
||||
spec = inspectutils.GetFullArgSpec('test'.upper)
|
||||
self.assertEqual(spec.args, [])
|
||||
self.assertEqual(spec.defaults, ())
|
||||
self.assertEqual(spec.kwonlyargs, [])
|
||||
self.assertEqual(spec.kwonlydefaults, {})
|
||||
self.assertEqual(spec.annotations, {})
|
||||
|
||||
def testGetFullArgSpecFromSlotWrapper(self):
|
||||
spec = inspectutils.GetFullArgSpec(tc.NoDefaults)
|
||||
self.assertEqual(spec.args, [])
|
||||
self.assertEqual(spec.defaults, ())
|
||||
self.assertEqual(spec.varargs, None)
|
||||
self.assertEqual(spec.varkw, None)
|
||||
self.assertEqual(spec.kwonlyargs, [])
|
||||
self.assertEqual(spec.kwonlydefaults, {})
|
||||
self.assertEqual(spec.annotations, {})
|
||||
|
||||
def testGetFullArgSpecFromClassNoInit(self):
|
||||
spec = inspectutils.GetFullArgSpec(tc.OldStyleEmpty)
|
||||
self.assertEqual(spec.args, [])
|
||||
self.assertEqual(spec.defaults, ())
|
||||
self.assertEqual(spec.varargs, None)
|
||||
self.assertEqual(spec.varkw, None)
|
||||
self.assertEqual(spec.kwonlyargs, [])
|
||||
self.assertEqual(spec.kwonlydefaults, {})
|
||||
self.assertEqual(spec.annotations, {})
|
||||
|
||||
def testGetFullArgSpecFromMethod(self):
|
||||
spec = inspectutils.GetFullArgSpec(tc.NoDefaults().double)
|
||||
self.assertEqual(spec.args, ['count'])
|
||||
self.assertEqual(spec.defaults, ())
|
||||
self.assertEqual(spec.varargs, None)
|
||||
self.assertEqual(spec.varkw, None)
|
||||
self.assertEqual(spec.kwonlyargs, [])
|
||||
self.assertEqual(spec.kwonlydefaults, {})
|
||||
self.assertEqual(spec.annotations, {})
|
||||
|
||||
def testInfoOne(self):
|
||||
info = inspectutils.Info(1)
|
||||
self.assertEqual(info.get('type_name'), 'int')
|
||||
self.assertEqual(info.get('file'), None)
|
||||
self.assertEqual(info.get('line'), None)
|
||||
self.assertEqual(info.get('string_form'), '1')
|
||||
|
||||
def testInfoClass(self):
|
||||
info = inspectutils.Info(tc.NoDefaults)
|
||||
self.assertEqual(info.get('type_name'), 'type')
|
||||
self.assertIn(os.path.join('fire', 'test_components.py'), info.get('file'))
|
||||
self.assertGreater(info.get('line'), 0)
|
||||
|
||||
def testInfoClassNoInit(self):
|
||||
info = inspectutils.Info(tc.OldStyleEmpty)
|
||||
if six.PY2:
|
||||
self.assertEqual(info.get('type_name'), 'classobj')
|
||||
else:
|
||||
self.assertEqual(info.get('type_name'), 'type')
|
||||
self.assertIn(os.path.join('fire', 'test_components.py'), info.get('file'))
|
||||
self.assertGreater(info.get('line'), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,99 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""This module enables interactive mode in Python Fire.
|
||||
|
||||
It uses IPython as an optional dependency. When IPython is installed, the
|
||||
interactive flag will use IPython's REPL. When IPython is not installed, the
|
||||
interactive flag will start a Python REPL with the builtin `code` module's
|
||||
InteractiveConsole class.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
|
||||
|
||||
def Embed(variables, verbose=False):
|
||||
"""Drops into a Python REPL with variables available as local variables.
|
||||
|
||||
Args:
|
||||
variables: A dict of variables to make available. Keys are variable names.
|
||||
Values are variable values.
|
||||
verbose: Whether to include 'hidden' members, those keys starting with _.
|
||||
"""
|
||||
print(_AvailableString(variables, verbose))
|
||||
|
||||
try:
|
||||
_EmbedIPython(variables)
|
||||
except ImportError:
|
||||
_EmbedCode(variables)
|
||||
|
||||
|
||||
def _AvailableString(variables, verbose=False):
|
||||
"""Returns a string describing what objects are available in the Python REPL.
|
||||
|
||||
Args:
|
||||
variables: A dict of the object to be available in the REPL.
|
||||
verbose: Whether to include 'hidden' members, those keys starting with _.
|
||||
Returns:
|
||||
A string fit for printing at the start of the REPL, indicating what objects
|
||||
are available for the user to use.
|
||||
"""
|
||||
modules = []
|
||||
other = []
|
||||
for name, value in variables.items():
|
||||
if not verbose and name.startswith('_'):
|
||||
continue
|
||||
if '-' in name or '/' in name:
|
||||
continue
|
||||
|
||||
if inspect.ismodule(value):
|
||||
modules.append(name)
|
||||
else:
|
||||
other.append(name)
|
||||
|
||||
lists = [
|
||||
('Modules', modules),
|
||||
('Objects', other)]
|
||||
liststrs = []
|
||||
for name, varlist in lists:
|
||||
if varlist:
|
||||
liststrs.append(
|
||||
'{name}: {items}'.format(name=name, items=', '.join(sorted(varlist))))
|
||||
|
||||
return (
|
||||
'Fire is starting a Python REPL with the following objects:\n'
|
||||
'{liststrs}\n'
|
||||
).format(liststrs='\n'.join(liststrs))
|
||||
|
||||
|
||||
def _EmbedIPython(variables, argv=None):
|
||||
"""Drops into an IPython REPL with variables available for use.
|
||||
|
||||
Args:
|
||||
variables: A dict of variables to make available. Keys are variable names.
|
||||
Values are variable values.
|
||||
argv: The argv to use for starting ipython. Defaults to an empty list.
|
||||
"""
|
||||
import IPython # pylint: disable=g-import-not-at-top
|
||||
argv = argv or []
|
||||
IPython.start_ipython(argv=argv, user_ns=variables)
|
||||
|
||||
|
||||
def _EmbedCode(variables):
|
||||
import code # pylint: disable=g-import-not-at-top
|
||||
code.InteractiveConsole(variables).interact()
|
||||
@@ -1,52 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the interact module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import interact
|
||||
from fire import testutils
|
||||
|
||||
import mock
|
||||
|
||||
|
||||
try:
|
||||
import IPython # pylint: disable=unused-import, g-import-not-at-top
|
||||
INTERACT_METHOD = 'IPython.start_ipython'
|
||||
except ImportError:
|
||||
INTERACT_METHOD = 'code.InteractiveConsole'
|
||||
|
||||
|
||||
class InteractTest(testutils.BaseTestCase):
|
||||
|
||||
@mock.patch(INTERACT_METHOD)
|
||||
def testInteract(self, mock_interact_method):
|
||||
self.assertFalse(mock_interact_method.called)
|
||||
interact.Embed({})
|
||||
self.assertTrue(mock_interact_method.called)
|
||||
|
||||
@mock.patch(INTERACT_METHOD)
|
||||
def testInteractVariables(self, mock_interact_method):
|
||||
self.assertFalse(mock_interact_method.called)
|
||||
interact.Embed({
|
||||
'count': 10,
|
||||
'mock': mock,
|
||||
})
|
||||
self.assertTrue(mock_interact_method.called)
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Provides parsing functionality used by Python Fire."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import ast
|
||||
|
||||
|
||||
def CreateParser():
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('--verbose', '-v', action='store_true')
|
||||
parser.add_argument('--interactive', '-i', action='store_true')
|
||||
parser.add_argument('--separator', default='-')
|
||||
parser.add_argument('--completion', nargs='?', const='bash', type=str)
|
||||
parser.add_argument('--help', '-h', action='store_true')
|
||||
parser.add_argument('--trace', '-t', action='store_true')
|
||||
# TODO(dbieber): Consider allowing name to be passed as an argument.
|
||||
return parser
|
||||
|
||||
|
||||
def SeparateFlagArgs(args):
|
||||
"""Splits a list of args into those for Flags and those for Fire.
|
||||
|
||||
If an isolated '--' arg is not present in the arg list, then all of the args
|
||||
are for Fire. If there is an isolated '--', then the args after the final '--'
|
||||
are flag args, and the rest of the args are fire args.
|
||||
|
||||
Args:
|
||||
args: The list of arguments received by the Fire command.
|
||||
Returns:
|
||||
A tuple with the Fire args (a list), followed by the Flag args (a list).
|
||||
"""
|
||||
if '--' in args:
|
||||
separator_index = len(args) - 1 - args[::-1].index('--') # index of last --
|
||||
flag_args = args[separator_index + 1:]
|
||||
args = args[:separator_index]
|
||||
return args, flag_args
|
||||
return args, []
|
||||
|
||||
|
||||
def DefaultParseValue(value):
|
||||
"""The default argument parsing function used by Fire CLIs.
|
||||
|
||||
If the value is made of only Python literals and containers, then the value
|
||||
is parsed as it's Python value. Otherwise, provided the value contains no
|
||||
quote, escape, or parenthetical characters, the value is treated as a string.
|
||||
|
||||
Args:
|
||||
value: A string from the command line to be parsed for use in a Fire CLI.
|
||||
Returns:
|
||||
The parsed value, of the type determined most appropriate.
|
||||
"""
|
||||
# Note: _LiteralEval will treat '#' as the start of a comment.
|
||||
try:
|
||||
return _LiteralEval(value)
|
||||
except (SyntaxError, ValueError):
|
||||
# If _LiteralEval can't parse the value, treat it as a string.
|
||||
return value
|
||||
|
||||
|
||||
def _LiteralEval(value):
|
||||
"""Parse value as a Python literal, or container of containers and literals.
|
||||
|
||||
First the AST of the value is updated so that bare-words are turned into
|
||||
strings. Then the resulting AST is evaluated as a literal or container of
|
||||
only containers and literals.
|
||||
|
||||
This allows for the YAML-like syntax {a: b} to represent the dict {'a': 'b'}
|
||||
|
||||
Args:
|
||||
value: A string to be parsed as a literal or container of containers and
|
||||
literals.
|
||||
Returns:
|
||||
The Python value representing the value arg.
|
||||
Raises:
|
||||
ValueError: If the value is not an expression with only containers and
|
||||
literals.
|
||||
SyntaxError: If the value string has a syntax error.
|
||||
"""
|
||||
root = ast.parse(value, mode='eval')
|
||||
if isinstance(root.body, ast.BinOp):
|
||||
raise ValueError(value)
|
||||
|
||||
for node in ast.walk(root):
|
||||
for field, child in ast.iter_fields(node):
|
||||
if isinstance(child, list):
|
||||
for index, subchild in enumerate(child):
|
||||
if isinstance(subchild, ast.Name):
|
||||
child[index] = _Replacement(subchild)
|
||||
|
||||
elif isinstance(child, ast.Name):
|
||||
replacement = _Replacement(child)
|
||||
node.__setattr__(field, replacement)
|
||||
|
||||
# ast.literal_eval supports the following types:
|
||||
# strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None
|
||||
# (bytes and set literals only starting with Python 3.2)
|
||||
return ast.literal_eval(root)
|
||||
|
||||
|
||||
def _Replacement(node):
|
||||
"""Returns a node to use in place of the supplied node in the AST.
|
||||
|
||||
Args:
|
||||
node: A node of type Name. Could be a variable, or builtin constant.
|
||||
Returns:
|
||||
A node to use in place of the supplied Node. Either the same node, or a
|
||||
String node whose value matches the Name node's id.
|
||||
"""
|
||||
value = node.id
|
||||
# These are the only builtin constants supported by literal_eval.
|
||||
if value in ('True', 'False', 'None'):
|
||||
return node
|
||||
return ast.Str(value)
|
||||
@@ -1,99 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Fuzz tests for the parser module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import parser
|
||||
from fire import testutils
|
||||
from hypothesis import example
|
||||
from hypothesis import given
|
||||
from hypothesis import settings
|
||||
from hypothesis import strategies as st
|
||||
import Levenshtein
|
||||
import six
|
||||
|
||||
|
||||
class ParserFuzzTest(testutils.BaseTestCase):
|
||||
|
||||
@settings(max_examples=10000)
|
||||
@given(st.text(min_size=1))
|
||||
@example('True')
|
||||
@example(r'"test\t\t\a\\a"')
|
||||
@example(r' "test\t\t\a\\a" ')
|
||||
@example('"(1, 2)"')
|
||||
@example('(1, 2)')
|
||||
@example('(1, 2)')
|
||||
@example('(1, 2) ')
|
||||
@example('a,b,c,d')
|
||||
@example('(a,b,c,d)')
|
||||
@example('[a,b,c,d]')
|
||||
@example('{a,b,c,d}')
|
||||
@example('test:(a,b,c,d)')
|
||||
@example('{test:(a,b,c,d)}')
|
||||
@example('{test:a,b,c,d}')
|
||||
@example('{test:a,b:(c,d)}') # Note: Edit distance may be high for dicts.
|
||||
@example('0,')
|
||||
@example('#')
|
||||
@example('A#00000') # Note: '#'' is treated as a comment.
|
||||
@example('\x80') # Note: Causes UnicodeDecodeError.
|
||||
@example(100 * '[' + '0') # Note: Causes MemoryError.
|
||||
@example('\r\r\r\r1\r\r')
|
||||
def testDefaultParseValueFuzz(self, value):
|
||||
try:
|
||||
result = parser.DefaultParseValue(value)
|
||||
except TypeError:
|
||||
# It's OK to get a TypeError if the string has the null character.
|
||||
if u'\x00' in value:
|
||||
return
|
||||
raise
|
||||
except MemoryError:
|
||||
if len(value) > 100:
|
||||
# This is not what we're testing.
|
||||
return
|
||||
raise
|
||||
|
||||
try:
|
||||
uvalue = six.text_type(value)
|
||||
uresult = six.text_type(result)
|
||||
except UnicodeDecodeError:
|
||||
# This is not what we're testing.
|
||||
return
|
||||
|
||||
# Check that the parsed value doesn't differ too much from the input.
|
||||
distance = Levenshtein.distance(uresult, uvalue)
|
||||
max_distance = (
|
||||
2 + # Quotes or parenthesis can be implicit.
|
||||
sum(c.isspace() for c in value) +
|
||||
value.count('"') + value.count("'") +
|
||||
3 * (value.count(',') + 1) + # 'a,' can expand to "'a', "
|
||||
3 * (value.count(':')) + # 'a:' can expand to "'a': "
|
||||
2 * value.count('\\'))
|
||||
if '#' in value:
|
||||
max_distance += len(value) - value.index('#')
|
||||
|
||||
if not isinstance(result, six.string_types):
|
||||
max_distance += value.count('0') # Leading 0s are stripped.
|
||||
|
||||
# Note: We don't check distance for dicts since item order can be changed.
|
||||
if '{' not in value:
|
||||
self.assertLessEqual(distance, max_distance,
|
||||
(distance, max_distance, uvalue, uresult))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,143 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the parser module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import parser
|
||||
from fire import testutils
|
||||
|
||||
|
||||
class ParserTest(testutils.BaseTestCase):
|
||||
|
||||
def testCreateParser(self):
|
||||
self.assertIsNotNone(parser.CreateParser())
|
||||
|
||||
def testSeparateFlagArgs(self):
|
||||
self.assertEqual(parser.SeparateFlagArgs([]), ([], []))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['a', 'b']), (['a', 'b'], []))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['a', 'b', '--']),
|
||||
(['a', 'b'], []))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['a', 'b', '--', 'c']),
|
||||
(['a', 'b'], ['c']))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['--']),
|
||||
([], []))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['--', 'c', 'd']),
|
||||
([], ['c', 'd']))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['a', 'b', '--', 'c', 'd']),
|
||||
(['a', 'b'], ['c', 'd']))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['a', 'b', '--', 'c', 'd', '--']),
|
||||
(['a', 'b', '--', 'c', 'd'], []))
|
||||
self.assertEqual(parser.SeparateFlagArgs(['a', 'b', '--', 'c', '--', 'd']),
|
||||
(['a', 'b', '--', 'c'], ['d']))
|
||||
|
||||
def testDefaultParseValueStrings(self):
|
||||
self.assertEqual(parser.DefaultParseValue('hello'), 'hello')
|
||||
self.assertEqual(parser.DefaultParseValue('path/file.jpg'), 'path/file.jpg')
|
||||
self.assertEqual(parser.DefaultParseValue('hello world'), 'hello world')
|
||||
self.assertEqual(parser.DefaultParseValue('--flag'), '--flag')
|
||||
|
||||
def testDefaultParseValueQuotedStrings(self):
|
||||
self.assertEqual(parser.DefaultParseValue("'hello'"), 'hello')
|
||||
self.assertEqual(parser.DefaultParseValue("'hello world'"), 'hello world')
|
||||
self.assertEqual(parser.DefaultParseValue("'--flag'"), '--flag')
|
||||
self.assertEqual(parser.DefaultParseValue('"hello"'), 'hello')
|
||||
self.assertEqual(parser.DefaultParseValue('"hello world"'), 'hello world')
|
||||
self.assertEqual(parser.DefaultParseValue('"--flag"'), '--flag')
|
||||
|
||||
def testDefaultParseValueSpecialStrings(self):
|
||||
self.assertEqual(parser.DefaultParseValue('-'), '-')
|
||||
self.assertEqual(parser.DefaultParseValue('--'), '--')
|
||||
self.assertEqual(parser.DefaultParseValue('---'), '---')
|
||||
self.assertEqual(parser.DefaultParseValue('----'), '----')
|
||||
self.assertEqual(parser.DefaultParseValue('None'), None)
|
||||
self.assertEqual(parser.DefaultParseValue("'None'"), 'None')
|
||||
|
||||
def testDefaultParseValueNumbers(self):
|
||||
self.assertEqual(parser.DefaultParseValue('23'), 23)
|
||||
self.assertEqual(parser.DefaultParseValue('-23'), -23)
|
||||
self.assertEqual(parser.DefaultParseValue('23.0'), 23.0)
|
||||
self.assertIsInstance(parser.DefaultParseValue('23'), int)
|
||||
self.assertIsInstance(parser.DefaultParseValue('23.0'), float)
|
||||
self.assertEqual(parser.DefaultParseValue('23.5'), 23.5)
|
||||
self.assertEqual(parser.DefaultParseValue('-23.5'), -23.5)
|
||||
|
||||
def testDefaultParseValueStringNumbers(self):
|
||||
self.assertEqual(parser.DefaultParseValue("'23'"), '23')
|
||||
self.assertEqual(parser.DefaultParseValue("'23.0'"), '23.0')
|
||||
self.assertEqual(parser.DefaultParseValue("'23.5'"), '23.5')
|
||||
self.assertEqual(parser.DefaultParseValue('"23"'), '23')
|
||||
self.assertEqual(parser.DefaultParseValue('"23.0"'), '23.0')
|
||||
self.assertEqual(parser.DefaultParseValue('"23.5"'), '23.5')
|
||||
|
||||
def testDefaultParseValueQuotedStringNumbers(self):
|
||||
self.assertEqual(parser.DefaultParseValue('"\'123\'"'), "'123'")
|
||||
|
||||
def testDefaultParseValueOtherNumbers(self):
|
||||
self.assertEqual(parser.DefaultParseValue('1e5'), 100000.0)
|
||||
|
||||
def testDefaultParseValueLists(self):
|
||||
self.assertEqual(parser.DefaultParseValue('[1, 2, 3]'), [1, 2, 3])
|
||||
self.assertEqual(parser.DefaultParseValue('[1, "2", 3]'), [1, '2', 3])
|
||||
self.assertEqual(parser.DefaultParseValue('[1, \'"2"\', 3]'), [1, '"2"', 3])
|
||||
self.assertEqual(parser.DefaultParseValue(
|
||||
'[1, "hello", 3]'), [1, 'hello', 3])
|
||||
|
||||
def testDefaultParseValueBareWordsLists(self):
|
||||
self.assertEqual(parser.DefaultParseValue('[one, 2, "3"]'), ['one', 2, '3'])
|
||||
|
||||
def testDefaultParseValueDict(self):
|
||||
self.assertEqual(
|
||||
parser.DefaultParseValue('{"abc": 5, "123": 1}'), {'abc': 5, '123': 1})
|
||||
|
||||
def testDefaultParseValueNone(self):
|
||||
self.assertEqual(parser.DefaultParseValue('None'), None)
|
||||
|
||||
def testDefaultParseValueBool(self):
|
||||
self.assertEqual(parser.DefaultParseValue('True'), True)
|
||||
self.assertEqual(parser.DefaultParseValue('False'), False)
|
||||
|
||||
def testDefaultParseValueBareWordsTuple(self):
|
||||
self.assertEqual(parser.DefaultParseValue('(one, 2, "3")'), ('one', 2, '3'))
|
||||
self.assertEqual(parser.DefaultParseValue('one, "2", 3'), ('one', '2', 3))
|
||||
|
||||
def testDefaultParseValueNestedContainers(self):
|
||||
self.assertEqual(
|
||||
parser.DefaultParseValue('[(A, 2, "3"), 5, {alph: 10.2, beta: "cat"}]'),
|
||||
[('A', 2, '3'), 5, {'alph': 10.2, 'beta': 'cat'}])
|
||||
|
||||
def testDefaultParseValueComments(self):
|
||||
self.assertEqual(parser.DefaultParseValue('"0#comments"'), '0#comments')
|
||||
# Comments are stripped. This behavior may change in the future.
|
||||
self.assertEqual(parser.DefaultParseValue('0#comments'), 0)
|
||||
|
||||
def testDefaultParseValueBadLiteral(self):
|
||||
# If it can't be parsed, we treat it as a string. This behavior may change.
|
||||
self.assertEqual(
|
||||
parser.DefaultParseValue('[(A, 2, "3"), 5'), '[(A, 2, "3"), 5')
|
||||
self.assertEqual(parser.DefaultParseValue('x=10'), 'x=10')
|
||||
|
||||
def testDefaultParseValueSyntaxError(self):
|
||||
# If it can't be parsed, we treat it as a string.
|
||||
self.assertEqual(parser.DefaultParseValue('"'), '"')
|
||||
|
||||
def testDefaultParseValueIgnoreBinOp(self):
|
||||
self.assertEqual(parser.DefaultParseValue('2017-10-10'), '2017-10-10')
|
||||
self.assertEqual(parser.DefaultParseValue('1+1'), '1+1')
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,349 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""This module has components that are used for testing Python Fire."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import collections
|
||||
|
||||
import six
|
||||
|
||||
if six.PY3:
|
||||
from fire import test_components_py3 as py3 # pylint: disable=unused-import,no-name-in-module,g-import-not-at-top
|
||||
|
||||
|
||||
def identity(arg1, arg2, arg3=10, arg4=20, *arg5, **arg6): # pylint: disable=keyword-arg-before-vararg
|
||||
return arg1, arg2, arg3, arg4, arg5, arg6
|
||||
|
||||
identity.__annotations__ = {'arg2': int, 'arg4': int}
|
||||
|
||||
|
||||
def multiplier_with_docstring(num, rate=2):
|
||||
"""Multiplies num by rate.
|
||||
|
||||
Args:
|
||||
num (int): the num you want to multiply
|
||||
rate (int): the rate for multiplication
|
||||
Returns:
|
||||
Multiplication of num by rate
|
||||
"""
|
||||
return num * rate
|
||||
|
||||
|
||||
def function_with_help(help=True): # pylint: disable=redefined-builtin
|
||||
return help
|
||||
|
||||
|
||||
class Empty(object):
|
||||
pass
|
||||
|
||||
|
||||
class OldStyleEmpty: # pylint: disable=old-style-class,no-init
|
||||
pass
|
||||
|
||||
|
||||
class WithInit(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
class ErrorInConstructor(object):
|
||||
|
||||
def __init__(self, value='value'):
|
||||
self.value = value
|
||||
raise ValueError('Error in constructor')
|
||||
|
||||
|
||||
class WithHelpArg(object):
|
||||
"""Test class for testing when class has a help= arg."""
|
||||
|
||||
def __init__(self, help=True): # pylint: disable=redefined-builtin
|
||||
self.has_help = help
|
||||
self.dictionary = {'__help': 'help in a dict'}
|
||||
|
||||
|
||||
class NoDefaults(object):
|
||||
|
||||
def double(self, count):
|
||||
return 2 * count
|
||||
|
||||
def triple(self, count):
|
||||
return 3 * count
|
||||
|
||||
|
||||
class WithDefaults(object):
|
||||
|
||||
def double(self, count=0):
|
||||
return 2 * count
|
||||
|
||||
def triple(self, count=0):
|
||||
return 3 * count
|
||||
|
||||
|
||||
class OldStyleWithDefaults: # pylint: disable=old-style-class,no-init
|
||||
|
||||
def double(self, count=0):
|
||||
return 2 * count
|
||||
|
||||
def triple(self, count=0):
|
||||
return 3 * count
|
||||
|
||||
|
||||
class MixedDefaults(object):
|
||||
|
||||
def ten(self):
|
||||
return 10
|
||||
|
||||
def sum(self, alpha=0, beta=0):
|
||||
return alpha + 2 * beta
|
||||
|
||||
def identity(self, alpha, beta='0'):
|
||||
return alpha, beta
|
||||
|
||||
|
||||
class SimilarArgNames(object):
|
||||
|
||||
def identity(self, bool_one=False, bool_two=False):
|
||||
return bool_one, bool_two
|
||||
|
||||
def identity2(self, a=None, alpha=None):
|
||||
return a, alpha
|
||||
|
||||
|
||||
class CapitalizedArgNames(object):
|
||||
|
||||
def sum(self, Delta=1.0, Gamma=2.0): # pylint: disable=invalid-name
|
||||
return Delta + Gamma
|
||||
|
||||
|
||||
class Annotations(object):
|
||||
|
||||
def double(self, count=0):
|
||||
return 2 * count
|
||||
|
||||
def triple(self, count=0):
|
||||
return 3 * count
|
||||
|
||||
double.__annotations__ = {'count': float}
|
||||
triple.__annotations__ = {'count': float}
|
||||
|
||||
|
||||
class TypedProperties(object):
|
||||
"""Test class for testing Python Fire with properties of various types."""
|
||||
|
||||
def __init__(self):
|
||||
self.alpha = True
|
||||
self.beta = (1, 2, 3)
|
||||
self.charlie = WithDefaults()
|
||||
self.delta = {
|
||||
'echo': 'E',
|
||||
'nest': {
|
||||
0: 'a',
|
||||
1: 'b',
|
||||
},
|
||||
}
|
||||
self.echo = ['alex', 'bethany']
|
||||
self.fox = ('carry', 'divide')
|
||||
self.gamma = 'myexcitingstring'
|
||||
|
||||
|
||||
class VarArgs(object):
|
||||
"""Test class for testing Python Fire with a property with varargs."""
|
||||
|
||||
def cumsums(self, *items):
|
||||
total = None
|
||||
sums = []
|
||||
for item in items:
|
||||
if total is None:
|
||||
total = item
|
||||
else:
|
||||
total += item
|
||||
sums.append(total)
|
||||
return sums
|
||||
|
||||
def varchars(self, alpha=0, beta=0, *chars): # pylint: disable=keyword-arg-before-vararg
|
||||
return alpha, beta, ''.join(chars)
|
||||
|
||||
|
||||
class Underscores(object):
|
||||
|
||||
def __init__(self):
|
||||
self.underscore_example = 'fish fingers'
|
||||
|
||||
def underscore_function(self, underscore_arg):
|
||||
return underscore_arg
|
||||
|
||||
|
||||
class BoolConverter(object):
|
||||
|
||||
def as_bool(self, arg=False):
|
||||
return arg
|
||||
|
||||
|
||||
class ReturnsObj(object):
|
||||
|
||||
def get_obj(self, *items):
|
||||
del items # Unused
|
||||
return BoolConverter()
|
||||
|
||||
|
||||
class NumberDefaults(object):
|
||||
|
||||
def reciprocal(self, divisor=10.0):
|
||||
return 1.0 / divisor
|
||||
|
||||
def integer_reciprocal(self, divisor=10):
|
||||
return 1.0 / divisor
|
||||
|
||||
|
||||
class InstanceVars(object):
|
||||
|
||||
def __init__(self, arg1, arg2):
|
||||
self.arg1 = arg1
|
||||
self.arg2 = arg2
|
||||
|
||||
def run(self, arg1, arg2):
|
||||
return (self.arg1, self.arg2, arg1, arg2)
|
||||
|
||||
|
||||
class Kwargs(object):
|
||||
|
||||
def props(self, **kwargs):
|
||||
return kwargs
|
||||
|
||||
def upper(self, **kwargs):
|
||||
return ' '.join(sorted(kwargs.keys())).upper()
|
||||
|
||||
def run(self, positional, named=None, **kwargs):
|
||||
return (positional, named, kwargs)
|
||||
|
||||
|
||||
class ErrorRaiser(object):
|
||||
|
||||
def fail(self):
|
||||
raise ValueError('This error is part of a test.')
|
||||
|
||||
|
||||
class NonComparable(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
raise ValueError('Instances of this class cannot be compared.')
|
||||
|
||||
def __ne__(self, other):
|
||||
raise ValueError('Instances of this class cannot be compared.')
|
||||
|
||||
|
||||
class EmptyDictOutput(object):
|
||||
|
||||
def totally_empty(self):
|
||||
return {}
|
||||
|
||||
def nothing_printable(self):
|
||||
return {'__do_not_print_me': 1}
|
||||
|
||||
|
||||
class CircularReference(object):
|
||||
|
||||
def create(self):
|
||||
x = {}
|
||||
x['y'] = x
|
||||
return x
|
||||
|
||||
|
||||
class OrderedDictionary(object):
|
||||
|
||||
def empty(self):
|
||||
return collections.OrderedDict()
|
||||
|
||||
def non_empty(self):
|
||||
ordered_dict = collections.OrderedDict()
|
||||
ordered_dict['A'] = 'A'
|
||||
ordered_dict[2] = 2
|
||||
return ordered_dict
|
||||
|
||||
|
||||
class NamedTuple(object):
|
||||
|
||||
def point(self):
|
||||
"""Point example straight from Python docs."""
|
||||
# pylint: disable=invalid-name
|
||||
Point = collections.namedtuple('Point', ['x', 'y'])
|
||||
return Point(11, y=22)
|
||||
|
||||
|
||||
class CallableWithKeywordArgument(object):
|
||||
"""Test class for supporting callable."""
|
||||
|
||||
def __call__(self, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
print('%s: %s' % (key, value))
|
||||
|
||||
def print_msg(self, msg):
|
||||
print(msg)
|
||||
|
||||
|
||||
class ClassWithDocstring(object):
|
||||
"""Test class for testing help text output.
|
||||
|
||||
This is some detail description of this test class.
|
||||
"""
|
||||
|
||||
def __init__(self, message='Hello!'):
|
||||
"""Constructor of the test class.
|
||||
|
||||
Constructs a new ClassWithDocstring object.
|
||||
|
||||
Args:
|
||||
message: The default message to print.
|
||||
"""
|
||||
self.message = message
|
||||
|
||||
def print_msg(self, msg=None):
|
||||
"""Prints a message."""
|
||||
if msg is None:
|
||||
msg = self.message
|
||||
print(msg)
|
||||
|
||||
|
||||
class ClassWithMultilineDocstring(object):
|
||||
"""Test class for testing help text output with multiline docstring.
|
||||
|
||||
This is a test class that has a long docstring description that spans across
|
||||
multiple lines for testing line breaking in help text.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def example_generator(n):
|
||||
"""Generators have a ``Yields`` section instead of a ``Returns`` section.
|
||||
|
||||
Args:
|
||||
n (int): The upper limit of the range to generate, from 0 to `n` - 1.
|
||||
|
||||
Yields:
|
||||
int: The next number in the range of 0 to `n` - 1.
|
||||
|
||||
Examples:
|
||||
Examples should be written in doctest format, and should illustrate how
|
||||
to use the function.
|
||||
|
||||
>>> print([i for i in example_generator(4)])
|
||||
[0, 1, 2, 3]
|
||||
|
||||
"""
|
||||
for i in range(n):
|
||||
yield i
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""This module has components that use Python 3 specific syntax."""
|
||||
|
||||
|
||||
def identity(arg1, arg2: int, arg3=10, arg4: int = 20, *arg5,
|
||||
arg6, arg7: int, arg8=30, arg9: int = 40, **arg10):
|
||||
return arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10
|
||||
|
||||
|
||||
class KeywordOnly(object):
|
||||
|
||||
def double(self, *, count):
|
||||
return count * 2
|
||||
|
||||
def triple(self, *, count):
|
||||
return count * 3
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the test_components module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import test_components as tc
|
||||
from fire import testutils
|
||||
|
||||
|
||||
class TestComponentsTest(testutils.BaseTestCase):
|
||||
"""Tests to verify that the test components are importable and okay."""
|
||||
|
||||
def testTestComponents(self):
|
||||
self.assertIsNotNone(tc.Empty)
|
||||
self.assertIsNotNone(tc.OldStyleEmpty)
|
||||
|
||||
def testNonComparable(self):
|
||||
with self.assertRaises(ValueError):
|
||||
tc.NonComparable() != 2 # pylint: disable=expression-not-assigned
|
||||
with self.assertRaises(ValueError):
|
||||
tc.NonComparable() == 2 # pylint: disable=expression-not-assigned
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,101 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Utilities for Python Fire's tests."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import contextlib
|
||||
import re
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from fire import core
|
||||
from fire import trace
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
"""Shared test case for Python Fire tests."""
|
||||
|
||||
@contextlib.contextmanager
|
||||
def assertOutputMatches(self, stdout='.*', stderr='.*', capture=True):
|
||||
"""Asserts that the context generates stdout and stderr matching regexps.
|
||||
|
||||
Note: If wrapped code raises an exception, stdout and stderr will not be
|
||||
checked.
|
||||
|
||||
Args:
|
||||
stdout: (str) regexp to match against stdout (None will check no stdout)
|
||||
stderr: (str) regexp to match against stderr (None will check no stderr)
|
||||
capture: (bool, default True) do not bubble up stdout or stderr
|
||||
Yields:
|
||||
Yields to the wrapped context.
|
||||
"""
|
||||
stdout_fp = six.StringIO()
|
||||
stderr_fp = six.StringIO()
|
||||
try:
|
||||
with mock.patch.object(sys, 'stdout', stdout_fp):
|
||||
with mock.patch.object(sys, 'stderr', stderr_fp):
|
||||
yield
|
||||
finally:
|
||||
if not capture:
|
||||
sys.stdout.write(stdout_fp.getvalue())
|
||||
sys.stderr.write(stderr_fp.getvalue())
|
||||
|
||||
for name, regexp, fp in [('stdout', stdout, stdout_fp),
|
||||
('stderr', stderr, stderr_fp)]:
|
||||
value = fp.getvalue()
|
||||
if regexp is None:
|
||||
if value:
|
||||
raise AssertionError('%s: Expected no output. Got: %r' %
|
||||
(name, value))
|
||||
else:
|
||||
if not re.search(regexp, value, re.DOTALL | re.MULTILINE):
|
||||
raise AssertionError('%s: Expected %r to match %r' %
|
||||
(name, value, regexp))
|
||||
|
||||
@contextlib.contextmanager
|
||||
def assertRaisesFireExit(self, code, regexp='.*'):
|
||||
"""Asserts that a FireExit error is raised in the context.
|
||||
|
||||
Allows tests to check that Fire's wrapper around SystemExit is raised
|
||||
and that a regexp is matched in the output.
|
||||
|
||||
Args:
|
||||
code: The status code that the FireExit should contain.
|
||||
regexp: stdout must match this regex.
|
||||
Yields:
|
||||
Yields to the wrapped context.
|
||||
"""
|
||||
with self.assertOutputMatches(stderr=regexp):
|
||||
with self.assertRaises(core.FireExit):
|
||||
try:
|
||||
yield
|
||||
except core.FireExit as exc:
|
||||
if exc.code != code:
|
||||
raise AssertionError('Incorrect exit code: %r != %r' % (exc.code,
|
||||
code))
|
||||
self.assertIsInstance(exc.trace, trace.FireTrace)
|
||||
raise
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
main = unittest.main
|
||||
skip = unittest.skip
|
||||
# pylint: enable=invalid-name
|
||||
@@ -1,59 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Test the test utilities for Fire's tests."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
from fire import testutils
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class TestTestUtils(testutils.BaseTestCase):
|
||||
"""Let's get meta."""
|
||||
|
||||
def testNoCheckOnException(self):
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertOutputMatches(stdout='blah'):
|
||||
raise ValueError()
|
||||
|
||||
def testCheckStdoutOrStderrNone(self):
|
||||
with six.assertRaisesRegex(self, AssertionError, 'stdout:'):
|
||||
with self.assertOutputMatches(stdout=None):
|
||||
print('blah')
|
||||
|
||||
with six.assertRaisesRegex(self, AssertionError, 'stderr:'):
|
||||
with self.assertOutputMatches(stderr=None):
|
||||
print('blah', file=sys.stderr)
|
||||
|
||||
with six.assertRaisesRegex(self, AssertionError, 'stderr:'):
|
||||
with self.assertOutputMatches(stdout='apple', stderr=None):
|
||||
print('apple')
|
||||
print('blah', file=sys.stderr)
|
||||
|
||||
def testCorrectOrderingOfAssertRaises(self):
|
||||
# Check to make sure FireExit tests are correct.
|
||||
with self.assertOutputMatches(stdout='Yep.*first.*second'):
|
||||
with self.assertRaises(ValueError):
|
||||
print('Yep, this is the first line.\nThis is the second.')
|
||||
raise ValueError()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
-305
@@ -1,305 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""This module has classes for tracing the execution of a Fire execution.
|
||||
|
||||
A FireTrace consists of a sequence of FireTraceElement objects. Each element
|
||||
represents an action taken by Fire during a single Fire execution. An action may
|
||||
be instantiating a class, calling a routine, or accessing a property.
|
||||
|
||||
Each action consumes args and results in a new component. The final component
|
||||
is serialized to stdout by Fire as well as returned by the Fire method. If
|
||||
a Fire usage error occurs, such as insufficient arguments being provided to call
|
||||
a function, then that error will be captured in the trace and the final
|
||||
component will be None.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import pipes
|
||||
from fire import inspectutils
|
||||
|
||||
INITIAL_COMPONENT = 'Initial component'
|
||||
INSTANTIATED_CLASS = 'Instantiated class'
|
||||
CALLED_ROUTINE = 'Called routine'
|
||||
CALLED_CALLABLE = 'Called callable'
|
||||
ACCESSED_PROPERTY = 'Accessed property'
|
||||
COMPLETION_SCRIPT = 'Generated completion script'
|
||||
INTERACTIVE_MODE = 'Entered interactive mode'
|
||||
|
||||
|
||||
class FireTrace(object):
|
||||
"""A FireTrace represents the steps taken during a single Fire execution.
|
||||
|
||||
A FireTrace consists of a sequence of FireTraceElement objects. Each element
|
||||
represents an action taken by Fire during a single Fire execution. An action
|
||||
may be instantiating a class, calling a routine, or accessing a property.
|
||||
"""
|
||||
|
||||
def __init__(self, initial_component, name=None, separator='-', verbose=False,
|
||||
show_help=False, show_trace=False):
|
||||
initial_trace_element = FireTraceElement(
|
||||
component=initial_component,
|
||||
action=INITIAL_COMPONENT,
|
||||
)
|
||||
|
||||
self.name = name
|
||||
self.separator = separator
|
||||
self.elements = [initial_trace_element]
|
||||
self.verbose = verbose
|
||||
self.show_help = show_help
|
||||
self.show_trace = show_trace
|
||||
|
||||
def GetResult(self):
|
||||
"""Returns the component from the last element of the trace."""
|
||||
return self.GetLastHealthyElement().component
|
||||
|
||||
def GetLastHealthyElement(self):
|
||||
"""Returns the last element of the trace that is not an error.
|
||||
|
||||
This element will contain the final component indicated by the trace.
|
||||
|
||||
Returns:
|
||||
The last element of the trace that is not an error.
|
||||
"""
|
||||
for element in reversed(self.elements):
|
||||
if not element.HasError():
|
||||
return element
|
||||
return None
|
||||
|
||||
def HasError(self):
|
||||
"""Returns whether the Fire execution encountered a Fire usage error."""
|
||||
return self.elements[-1].HasError()
|
||||
|
||||
def AddAccessedProperty(self, component, target, args, filename, lineno):
|
||||
element = FireTraceElement(
|
||||
component=component,
|
||||
action=ACCESSED_PROPERTY,
|
||||
target=target,
|
||||
args=args,
|
||||
filename=filename,
|
||||
lineno=lineno,
|
||||
)
|
||||
self.elements.append(element)
|
||||
|
||||
def AddCalledComponent(self, component, target, args, filename, lineno,
|
||||
capacity, action=CALLED_CALLABLE):
|
||||
"""Adds an element to the trace indicating that a component was called.
|
||||
|
||||
Also applies to instantiating a class.
|
||||
|
||||
Args:
|
||||
component: The result of calling the callable.
|
||||
target: The name of the callable.
|
||||
args: The args consumed in order to call this callable.
|
||||
filename: The file in which the callable is defined, or None if N/A.
|
||||
lineno: The line number on which the callable is defined, or None if N/A.
|
||||
capacity: (bool) Whether the callable could have accepted additional args.
|
||||
action: The value to include as the action in the FireTraceElement.
|
||||
"""
|
||||
element = FireTraceElement(
|
||||
component=component,
|
||||
action=action,
|
||||
target=target,
|
||||
args=args,
|
||||
filename=filename,
|
||||
lineno=lineno,
|
||||
capacity=capacity,
|
||||
)
|
||||
self.elements.append(element)
|
||||
|
||||
def AddCompletionScript(self, script):
|
||||
element = FireTraceElement(
|
||||
component=script,
|
||||
action=COMPLETION_SCRIPT,
|
||||
)
|
||||
self.elements.append(element)
|
||||
|
||||
def AddInteractiveMode(self):
|
||||
element = FireTraceElement(action=INTERACTIVE_MODE)
|
||||
self.elements.append(element)
|
||||
|
||||
def AddError(self, error, args):
|
||||
element = FireTraceElement(error=error, args=args)
|
||||
self.elements.append(element)
|
||||
|
||||
def AddSeparator(self):
|
||||
"""Marks that the most recent element of the trace used a separator.
|
||||
|
||||
A separator is an argument you can pass to a Fire CLI to separate args left
|
||||
of the separator from args right of the separator.
|
||||
|
||||
Here's an example to demonstrate the separator. Let's say you have a
|
||||
function that takes a variable number of args, and you want to call that
|
||||
function, and then upper case the result. Here's how to do it:
|
||||
|
||||
# in Python
|
||||
def display(arg1, arg2='!'):
|
||||
return arg1 + arg2
|
||||
|
||||
# from Bash (the default separator is the hyphen -)
|
||||
display hello # hello!
|
||||
display hello upper # helloupper
|
||||
display hello - upper # HELLO!
|
||||
|
||||
Note how the separator caused the display function to be called with the
|
||||
default value for arg2.
|
||||
"""
|
||||
self.elements[-1].AddSeparator()
|
||||
|
||||
def _Quote(self, arg):
|
||||
if arg.startswith('--') and '=' in arg:
|
||||
prefix, value = arg.split('=', 1)
|
||||
return pipes.quote(prefix) + '=' + pipes.quote(value)
|
||||
return pipes.quote(arg)
|
||||
|
||||
def GetCommand(self):
|
||||
"""Returns the command representing the trace up to this point.
|
||||
|
||||
Returns:
|
||||
A string representing a Fire CLI command that would produce this trace.
|
||||
"""
|
||||
args = []
|
||||
if self.name:
|
||||
args.append(self.name)
|
||||
|
||||
for element in self.elements:
|
||||
if element.HasError():
|
||||
continue
|
||||
if element.args:
|
||||
args.extend(element.args)
|
||||
if element.HasSeparator():
|
||||
args.append(self.separator)
|
||||
|
||||
if self.NeedsSeparator():
|
||||
args.append(self.separator)
|
||||
|
||||
return ' '.join(self._Quote(arg) for arg in args)
|
||||
|
||||
def NeedsSeparator(self):
|
||||
"""Returns whether a separator should be added to the command.
|
||||
|
||||
If the command is a function call, then adding an additional argument to the
|
||||
command sometimes would add an extra arg to the function call, and sometimes
|
||||
would add an arg acting on the result of the function call.
|
||||
|
||||
This function tells us whether we should add a separator to the command
|
||||
before adding additional arguments in order to make sure the arg is applied
|
||||
to the result of the function call, and not the function call itself.
|
||||
|
||||
Returns:
|
||||
Whether a separator should be added to the command if order to keep the
|
||||
component referred to by the command the same when adding additional args.
|
||||
"""
|
||||
element = self.GetLastHealthyElement()
|
||||
return element.HasCapacity() and not element.HasSeparator()
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(
|
||||
'{index}. {trace_string}'.format(
|
||||
index=index + 1,
|
||||
trace_string=element,
|
||||
)
|
||||
for index, element in enumerate(self.elements)
|
||||
)
|
||||
|
||||
def NeedsSeparatingHyphenHyphen(self, flag='help'):
|
||||
"""Returns whether a the trace need '--' before '--help'.
|
||||
|
||||
'--' is needed when the component takes keyword arguments, when the value of
|
||||
flag matches one of the argument of the component, or the component takes in
|
||||
keyword-only arguments(e.g. argument with default value).
|
||||
|
||||
Args:
|
||||
flag: the flag available for the trace
|
||||
|
||||
Returns:
|
||||
True for needed '--', False otherwise.
|
||||
|
||||
"""
|
||||
element = self.GetLastHealthyElement()
|
||||
component = element.component
|
||||
spec = inspectutils.GetFullArgSpec(component)
|
||||
return (spec.varkw is not None
|
||||
or flag in spec.args
|
||||
or flag in spec.kwonlyargs)
|
||||
|
||||
|
||||
class FireTraceElement(object):
|
||||
"""A FireTraceElement represents a single step taken by a Fire execution.
|
||||
|
||||
Examples of a FireTraceElement are the instantiation of a class or the
|
||||
accessing of an object member.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
component=None,
|
||||
action=None,
|
||||
target=None,
|
||||
args=None,
|
||||
filename=None,
|
||||
lineno=None,
|
||||
error=None,
|
||||
capacity=None):
|
||||
"""Instantiates a FireTraceElement.
|
||||
|
||||
Args:
|
||||
component: The result of this element of the trace.
|
||||
action: The type of action (eg instantiating a class) taking place.
|
||||
target: (string) The name of the component being acted upon.
|
||||
args: The args consumed by the represented action.
|
||||
filename: The file in which the action is defined, or None if N/A.
|
||||
lineno: The line number on which the action is defined, or None if N/A.
|
||||
error: The error represented by the action, or None if N/A.
|
||||
capacity: (bool) Whether the action could have accepted additional args.
|
||||
"""
|
||||
self.component = component
|
||||
self._action = action
|
||||
self._target = target
|
||||
self.args = args
|
||||
self._filename = filename
|
||||
self._lineno = lineno
|
||||
self._error = error
|
||||
self._separator = False
|
||||
self._capacity = capacity
|
||||
|
||||
def HasError(self):
|
||||
return self._error is not None
|
||||
|
||||
def HasCapacity(self):
|
||||
return self._capacity
|
||||
|
||||
def HasSeparator(self):
|
||||
return self._separator
|
||||
|
||||
def AddSeparator(self):
|
||||
self._separator = True
|
||||
|
||||
def __str__(self):
|
||||
if not self.HasError():
|
||||
# Format is: {action} "{target}" ({filename}:{lineno})
|
||||
string = self._action
|
||||
if self._target is not None:
|
||||
string += ' "{target}"'.format(target=self._target)
|
||||
if self._filename is not None:
|
||||
path = self._filename
|
||||
if self._lineno is not None:
|
||||
path += ':{lineno}'.format(lineno=self._lineno)
|
||||
|
||||
string += ' ({path})'.format(path=path)
|
||||
return string
|
||||
else:
|
||||
return str(self._error)
|
||||
@@ -1,154 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tests for the trace module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from fire import testutils
|
||||
from fire import trace
|
||||
|
||||
|
||||
class FireTraceTest(testutils.BaseTestCase):
|
||||
|
||||
def testFireTraceInitialization(self):
|
||||
t = trace.FireTrace(10)
|
||||
self.assertIsNotNone(t)
|
||||
self.assertIsNotNone(t.elements)
|
||||
|
||||
def testFireTraceGetResult(self):
|
||||
t = trace.FireTrace('start')
|
||||
self.assertEqual(t.GetResult(), 'start')
|
||||
t.AddAccessedProperty('t', 'final', None, 'example.py', 10)
|
||||
self.assertEqual(t.GetResult(), 't')
|
||||
|
||||
def testFireTraceHasError(self):
|
||||
t = trace.FireTrace('start')
|
||||
self.assertFalse(t.HasError())
|
||||
t.AddAccessedProperty('t', 'final', None, 'example.py', 10)
|
||||
self.assertFalse(t.HasError())
|
||||
t.AddError(ValueError('example error'), ['arg'])
|
||||
self.assertTrue(t.HasError())
|
||||
|
||||
def testAddAccessedProperty(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('example', 'args')
|
||||
t.AddAccessedProperty('new component', 'prop', args, 'sample.py', 12)
|
||||
self.assertEqual(
|
||||
str(t),
|
||||
'1. Initial component\n2. Accessed property "prop" (sample.py:12)')
|
||||
|
||||
def testAddCalledCallable(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('example', 'args')
|
||||
t.AddCalledComponent('result', 'cell', args, 'sample.py', 10, False,
|
||||
action=trace.CALLED_CALLABLE)
|
||||
self.assertEqual(
|
||||
str(t),
|
||||
'1. Initial component\n2. Called callable "cell" (sample.py:10)')
|
||||
|
||||
def testAddCalledRoutine(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('example', 'args')
|
||||
t.AddCalledComponent('result', 'run', args, 'sample.py', 12, False,
|
||||
action=trace.CALLED_ROUTINE)
|
||||
self.assertEqual(
|
||||
str(t),
|
||||
'1. Initial component\n2. Called routine "run" (sample.py:12)')
|
||||
|
||||
def testAddInstantiatedClass(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('example', 'args')
|
||||
t.AddCalledComponent(
|
||||
'Classname', 'classname', args, 'sample.py', 12, False,
|
||||
action=trace.INSTANTIATED_CLASS)
|
||||
target = """1. Initial component
|
||||
2. Instantiated class "classname" (sample.py:12)"""
|
||||
self.assertEqual(str(t), target)
|
||||
|
||||
def testAddCompletionScript(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
t.AddCompletionScript('This is the completion script string.')
|
||||
self.assertEqual(
|
||||
str(t),
|
||||
'1. Initial component\n2. Generated completion script')
|
||||
|
||||
def testAddInteractiveMode(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
t.AddInteractiveMode()
|
||||
self.assertEqual(
|
||||
str(t),
|
||||
'1. Initial component\n2. Entered interactive mode')
|
||||
|
||||
def testGetCommand(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('example', 'args')
|
||||
t.AddCalledComponent('result', 'run', args, 'sample.py', 12, False,
|
||||
action=trace.CALLED_ROUTINE)
|
||||
self.assertEqual(t.GetCommand(), 'example args')
|
||||
|
||||
def testGetCommandWithQuotes(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('example', 'spaced arg')
|
||||
t.AddCalledComponent('result', 'run', args, 'sample.py', 12, False,
|
||||
action=trace.CALLED_ROUTINE)
|
||||
self.assertEqual(t.GetCommand(), "example 'spaced arg'")
|
||||
|
||||
def testGetCommandWithFlagQuotes(self):
|
||||
t = trace.FireTrace('initial object')
|
||||
args = ('--example=spaced arg',)
|
||||
t.AddCalledComponent('result', 'run', args, 'sample.py', 12, False,
|
||||
action=trace.CALLED_ROUTINE)
|
||||
self.assertEqual(t.GetCommand(), "--example='spaced arg'")
|
||||
|
||||
|
||||
class FireTraceElementTest(testutils.BaseTestCase):
|
||||
|
||||
def testFireTraceElementHasError(self):
|
||||
el = trace.FireTraceElement()
|
||||
self.assertFalse(el.HasError())
|
||||
|
||||
el = trace.FireTraceElement(error=ValueError('example error'))
|
||||
self.assertTrue(el.HasError())
|
||||
|
||||
def testFireTraceElementAsStringNoMetadata(self):
|
||||
el = trace.FireTraceElement(
|
||||
component='Example',
|
||||
action='Fake action',
|
||||
)
|
||||
self.assertEqual(str(el), 'Fake action')
|
||||
|
||||
def testFireTraceElementAsStringWithTarget(self):
|
||||
el = trace.FireTraceElement(
|
||||
component='Example',
|
||||
action='Created toy',
|
||||
target='Beaker',
|
||||
)
|
||||
self.assertEqual(str(el), 'Created toy "Beaker"')
|
||||
|
||||
def testFireTraceElementAsStringWithTargetAndLineNo(self):
|
||||
el = trace.FireTraceElement(
|
||||
component='Example',
|
||||
action='Created toy',
|
||||
target='Beaker',
|
||||
filename='beaker.py',
|
||||
lineno=10,
|
||||
)
|
||||
self.assertEqual(str(el), 'Created toy "Beaker" (beaker.py:10)')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
testutils.main()
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Types of values."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
|
||||
import six
|
||||
|
||||
|
||||
VALUE_TYPES = (bool, six.string_types, six.integer_types, float, complex)
|
||||
|
||||
|
||||
def IsGroup(component):
|
||||
# TODO(dbieber): Check if there are any subcomponents.
|
||||
return not IsCommand(component) and not IsValue(component)
|
||||
|
||||
|
||||
def IsCommand(component):
|
||||
return inspect.isroutine(component) or inspect.isclass(component)
|
||||
|
||||
|
||||
def IsValue(component):
|
||||
return isinstance(component, VALUE_TYPES)
|
||||
Executable
BIN
Binary file not shown.
Executable
+399
@@ -0,0 +1,399 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="fontawesomeregular" horiz-adv-x="1536" >
|
||||
<font-face units-per-em="1792" ascent="1536" descent="-256" />
|
||||
<missing-glyph horiz-adv-x="448" />
|
||||
<glyph unicode=" " horiz-adv-x="448" />
|
||||
<glyph unicode="	" horiz-adv-x="448" />
|
||||
<glyph unicode=" " horiz-adv-x="448" />
|
||||
<glyph unicode="¨" horiz-adv-x="1792" />
|
||||
<glyph unicode="©" horiz-adv-x="1792" />
|
||||
<glyph unicode="®" horiz-adv-x="1792" />
|
||||
<glyph unicode="´" horiz-adv-x="1792" />
|
||||
<glyph unicode="Æ" horiz-adv-x="1792" />
|
||||
<glyph unicode=" " horiz-adv-x="768" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="768" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="512" />
|
||||
<glyph unicode=" " horiz-adv-x="384" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
<glyph unicode=" " horiz-adv-x="192" />
|
||||
<glyph unicode=" " horiz-adv-x="307" />
|
||||
<glyph unicode=" " horiz-adv-x="85" />
|
||||
<glyph unicode=" " horiz-adv-x="307" />
|
||||
<glyph unicode=" " horiz-adv-x="384" />
|
||||
<glyph unicode="™" horiz-adv-x="1792" />
|
||||
<glyph unicode="∞" horiz-adv-x="1792" />
|
||||
<glyph unicode="≠" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
|
||||
<glyph unicode="" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
|
||||
<glyph unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280zM768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z " />
|
||||
<glyph unicode="" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
|
||||
<glyph unicode="" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
|
||||
<glyph unicode="" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
|
||||
<glyph unicode="" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
|
||||
<glyph unicode="" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
|
||||
<glyph unicode="" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M725 977l-170 -450q73 -1 153.5 -2t119 -1.5t52.5 -0.5l29 2q-32 95 -92 241q-53 132 -92 211zM21 -128h-21l2 79q22 7 80 18q89 16 110 31q20 16 48 68l237 616l280 724h75h53l11 -21l205 -480q103 -242 124 -297q39 -102 96 -235q26 -58 65 -164q24 -67 65 -149 q22 -49 35 -57q22 -19 69 -23q47 -6 103 -27q6 -39 6 -57q0 -14 -1 -26q-80 0 -192 8q-93 8 -189 8q-79 0 -135 -2l-200 -11l-58 -2q0 45 4 78l131 28q56 13 68 23q12 12 12 27t-6 32l-47 114l-92 228l-450 2q-29 -65 -104 -274q-23 -64 -23 -84q0 -31 17 -43 q26 -21 103 -32q3 0 13.5 -2t30 -5t40.5 -6q1 -28 1 -58q0 -17 -2 -27q-66 0 -349 20l-48 -8q-81 -14 -167 -14z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M555 15q76 -32 140 -32q131 0 216 41t122 113q38 70 38 181q0 114 -41 180q-58 94 -141 126q-80 32 -247 32q-74 0 -101 -10v-144l-1 -173l3 -270q0 -15 12 -44zM541 761q43 -7 109 -7q175 0 264 65t89 224q0 112 -85 187q-84 75 -255 75q-52 0 -130 -13q0 -44 2 -77 q7 -122 6 -279l-1 -98q0 -43 1 -77zM0 -128l2 94q45 9 68 12q77 12 123 31q17 27 21 51q9 66 9 194l-2 497q-5 256 -9 404q-1 87 -11 109q-1 4 -12 12q-18 12 -69 15q-30 2 -114 13l-4 83l260 6l380 13l45 1q5 0 14 0.5t14 0.5q1 0 21.5 -0.5t40.5 -0.5h74q88 0 191 -27 q43 -13 96 -39q57 -29 102 -76q44 -47 65 -104t21 -122q0 -70 -32 -128t-95 -105q-26 -20 -150 -77q177 -41 267 -146q92 -106 92 -236q0 -76 -29 -161q-21 -62 -71 -117q-66 -72 -140 -108q-73 -36 -203 -60q-82 -15 -198 -11l-197 4q-84 2 -298 -11q-33 -3 -272 -11z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M0 -126l17 85q4 1 77 20q76 19 116 39q29 37 41 101l27 139l56 268l12 64q8 44 17 84.5t16 67t12.5 46.5t9 30.5t3.5 11.5l29 157l16 63l22 135l8 50v38q-41 22 -144 28q-28 2 -38 4l19 103l317 -14q39 -2 73 -2q66 0 214 9q33 2 68 4.5t36 2.5q-2 -19 -6 -38 q-7 -29 -13 -51q-55 -19 -109 -31q-64 -16 -101 -31q-12 -31 -24 -88q-9 -44 -13 -82q-44 -199 -66 -306l-61 -311l-38 -158l-43 -235l-12 -45q-2 -7 1 -27q64 -15 119 -21q36 -5 66 -10q-1 -29 -7 -58q-7 -31 -9 -41q-18 0 -23 -1q-24 -2 -42 -2q-9 0 -28 3q-19 4 -145 17 l-198 2q-41 1 -174 -11q-74 -7 -98 -9z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l215 -1h293l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -42.5 2t-103.5 -1t-111 -1 q-34 0 -67 -5q-10 -97 -8 -136l1 -152v-332l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-88 0 -233 -14q-48 -4 -70 -4q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q8 192 6 433l-5 428q-1 62 -0.5 118.5t0.5 102.5t-2 57t-6 15q-6 5 -14 6q-38 6 -148 6q-43 0 -100 -13.5t-73 -24.5q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1744 128q33 0 42 -18.5t-11 -44.5 l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80z" />
|
||||
<glyph unicode="" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l446 -1h318l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -58.5 2t-138.5 -1t-128 -1 q-94 0 -127 -5q-10 -97 -8 -136l1 -152v52l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-82 0 -233 -13q-45 -5 -70 -5q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q6 137 6 433l-5 44q0 265 -2 278q-2 11 -6 15q-6 5 -14 6q-38 6 -148 6q-50 0 -168.5 -14t-132.5 -24q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1505 113q26 -20 26 -49t-26 -49l-162 -126 q-26 -20 -44.5 -11t-18.5 42v80h-1024v-80q0 -33 -18.5 -42t-44.5 11l-162 126q-26 20 -26 49t26 49l162 126q26 20 44.5 11t18.5 -42v-80h1024v80q0 33 18.5 42t44.5 -11z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
|
||||
<glyph unicode="" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
|
||||
<glyph unicode="" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
|
||||
<glyph unicode="" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M742 -37l-652 651q-37 37 -37 90.5t37 90.5l652 651q37 37 90.5 37t90.5 -37l75 -75q37 -37 37 -90.5t-37 -90.5l-486 -486l486 -485q37 -38 37 -91t-37 -90l-75 -75q-37 -37 -90.5 -37t-90.5 37z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1099 704q0 -52 -37 -91l-652 -651q-37 -37 -90 -37t-90 37l-76 75q-37 39 -37 91q0 53 37 90l486 486l-486 485q-37 39 -37 91q0 53 37 90l76 75q36 38 90 38t90 -38l652 -651q37 -37 37 -90z" />
|
||||
<glyph unicode="" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
|
||||
<glyph unicode="" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
|
||||
<glyph unicode="" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
|
||||
<glyph unicode="" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
|
||||
<glyph unicode="" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
|
||||
<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
|
||||
<glyph unicode="" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
|
||||
<glyph unicode="" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1611 320q0 -53 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-486 485l-486 -485q-36 -38 -90 -38t-90 38l-75 75q-38 36 -38 90q0 53 38 91l651 651q37 37 90 37q52 0 91 -37l650 -651q38 -38 38 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1611 832q0 -53 -37 -90l-651 -651q-38 -38 -91 -38q-54 0 -90 38l-651 651q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l486 -486l486 486q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
|
||||
<glyph unicode="" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M512 512v-384h-256v384h256zM896 1024v-896h-256v896h256zM1280 768v-640h-256v640h256zM1664 1152v-1024h-256v1024h256zM1792 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5z M1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1307 618l23 219h-198v109q0 49 15.5 68.5t71.5 19.5h110v219h-175q-152 0 -218 -72t-66 -213v-131h-131v-219h131v-635h262v635h175zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
|
||||
<glyph unicode="" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
|
||||
<glyph unicode="" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
|
||||
<glyph unicode="" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
|
||||
<glyph unicode="" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
|
||||
<glyph unicode="" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
|
||||
<glyph unicode="" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
|
||||
<glyph unicode="" horiz-adv-x="768" d="M511 980h257l-30 -284h-227v-824h-341v824h-170v284h170v171q0 182 86 275.5t283 93.5h227v-284h-142q-39 0 -62.5 -6.5t-34 -23.5t-13.5 -34.5t-3 -49.5v-142z" />
|
||||
<glyph unicode="" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
|
||||
<glyph unicode="" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM183 128h1298q-164 181 -246.5 411.5t-82.5 484.5q0 256 -320 256t-320 -256q0 -254 -82.5 -484.5t-246.5 -411.5zM1664 128q0 -52 -38 -90t-90 -38 h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
|
||||
<glyph unicode="" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
|
||||
<glyph unicode="" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
|
||||
<glyph unicode="" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
|
||||
<glyph unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
|
||||
<glyph unicode="" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
|
||||
<glyph unicode="" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
|
||||
<glyph unicode="" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
|
||||
<glyph unicode="" d="M678 -57q0 -38 -10 -71h-380q-95 0 -171.5 56.5t-103.5 147.5q24 45 69 77.5t100 49.5t107 24t107 7q32 0 49 -2q6 -4 30.5 -21t33 -23t31 -23t32 -25.5t27.5 -25.5t26.5 -29.5t21 -30.5t17.5 -34.5t9.5 -36t4.5 -40.5zM385 294q-234 -7 -385 -85v433q103 -118 273 -118 q32 0 70 5q-21 -61 -21 -86q0 -67 63 -149zM558 805q0 -100 -43.5 -160.5t-140.5 -60.5q-51 0 -97 26t-78 67.5t-56 93.5t-35.5 104t-11.5 99q0 96 51.5 165t144.5 69q66 0 119 -41t84 -104t47 -130t16 -128zM1536 896v-736q0 -119 -84.5 -203.5t-203.5 -84.5h-468 q39 73 39 157q0 66 -22 122.5t-55.5 93t-72 71t-72 59.5t-55.5 54.5t-22 59.5q0 36 23 68t56 61.5t65.5 64.5t55.5 93t23 131t-26.5 145.5t-75.5 118.5q-6 6 -14 11t-12.5 7.5t-10 9.5t-10.5 17h135l135 64h-437q-138 0 -244.5 -38.5t-182.5 -133.5q0 126 81 213t207 87h960 q119 0 203.5 -84.5t84.5 -203.5v-96h-256v256h-128v-256h-256v-128h256v-256h128v256h256z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M876 71q0 21 -4.5 40.5t-9.5 36t-17.5 34.5t-21 30.5t-26.5 29.5t-27.5 25.5t-32 25.5t-31 23t-33 23t-30.5 21q-17 2 -50 2q-54 0 -106 -7t-108 -25t-98 -46t-69 -75t-27 -107q0 -68 35.5 -121.5t93 -84t120.5 -45.5t127 -15q59 0 112.5 12.5t100.5 39t74.5 73.5 t27.5 110zM756 933q0 60 -16.5 127.5t-47 130.5t-84 104t-119.5 41q-93 0 -144 -69t-51 -165q0 -47 11.5 -99t35.5 -104t56 -93.5t78 -67.5t97 -26q97 0 140.5 60.5t43.5 160.5zM625 1408h437l-135 -79h-135q71 -45 110 -126t39 -169q0 -74 -23 -131.5t-56 -92.5t-66 -64.5 t-56 -61t-23 -67.5q0 -26 16.5 -51t43 -48t58.5 -48t64 -55.5t58.5 -66t43 -85t16.5 -106.5q0 -160 -140 -282q-152 -131 -420 -131q-59 0 -119.5 10t-122 33.5t-108.5 58t-77 89t-30 121.5q0 61 37 135q32 64 96 110.5t145 71t155 36t150 13.5q-64 83 -64 149q0 12 2 23.5 t5 19.5t8 21.5t7 21.5q-40 -5 -70 -5q-149 0 -255.5 98t-106.5 246q0 140 95 250.5t234 141.5q94 20 187 20zM1664 1152v-128h-256v-256h-128v256h-256v128h256v256h128v-256h256z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
|
||||
<glyph unicode="" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
|
||||
<glyph unicode="" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
|
||||
<glyph unicode="" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1664 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5 q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1024 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1024 608v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280z M768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
|
||||
<glyph unicode="" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
|
||||
<glyph unicode="" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
|
||||
<glyph unicode="" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
|
||||
<glyph unicode="" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M896 608v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h224q14 0 23 -9t9 -23zM1024 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 -28 t-28 -68v-704q0 -40 28 -68t68 -28h704q40 0 68 28t28 68zM1152 928v-704q0 -92 -65.5 -158t-158.5 -66h-704q-93 0 -158.5 66t-65.5 158v704q0 93 65.5 158.5t158.5 65.5h704q93 0 158.5 -65.5t65.5 -158.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M928 1152q93 0 158.5 -65.5t65.5 -158.5v-704q0 -92 -65.5 -158t-158.5 -66h-704q-93 0 -158.5 66t-65.5 158v704q0 93 65.5 158.5t158.5 65.5h704zM1024 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 -28t-28 -68v-704q0 -40 28 -68t68 -28h704q40 0 68 28t28 68z M864 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576z" />
|
||||
<glyph unicode="" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
|
||||
<glyph unicode="" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
|
||||
<glyph unicode="" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
|
||||
<glyph unicode="" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1708 881l-188 -881h-304l181 849q4 21 1 43q-4 20 -16 35q-10 14 -28 24q-18 9 -40 9h-197l-205 -960h-303l204 960h-304l-205 -960h-304l272 1280h1139q157 0 245 -118q86 -116 52 -281z" />
|
||||
<glyph unicode="" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
|
||||
<glyph unicode="" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
|
||||
<glyph unicode="" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
|
||||
<glyph unicode="" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
|
||||
<glyph unicode="" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
|
||||
<glyph unicode="" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1664 352v-32q0 -132 -94 -226t-226 -94h-128q-132 0 -226 94t-94 226v480h-224q-2 -102 -14.5 -190.5t-30.5 -156t-48.5 -126.5t-57 -99.5t-67.5 -77.5t-69.5 -58.5t-74 -44t-69 -32t-65.5 -25.5q-4 -2 -32 -13q-8 -2 -12 -2q-22 0 -30 20l-71 178q-5 13 0 25t17 17 q7 3 20 7.5t18 6.5q31 12 46.5 18.5t44.5 20t45.5 26t42 32.5t40.5 42.5t34.5 53.5t30.5 68.5t22.5 83.5t17 103t6.5 123h-256q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h1216q14 0 23 -9t9 -23v-160q0 -14 -9 -23t-23 -9h-224v-512q0 -26 19 -45t45 -19h128q26 0 45 19t19 45 v64q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1280 1376v-160q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h960q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1024 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1024 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28 t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
|
||||
<glyph unicode="" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
|
||||
<glyph unicode="" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
|
||||
<glyph unicode="" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
|
||||
<glyph unicode="" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
|
||||
<glyph unicode="" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
|
||||
<glyph unicode="" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
|
||||
<glyph unicode="" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M390 1408h219v-388h364v-241h-364v-394q0 -136 14 -172q13 -37 52 -60q50 -31 117 -31q117 0 232 76v-242q-102 -48 -178 -65q-77 -19 -173 -19q-105 0 -186 27q-78 25 -138 75q-58 51 -79 105q-22 54 -22 161v539h-170v217q91 30 155 84q64 55 103 132q39 78 54 196z " />
|
||||
<glyph unicode="" d="M1123 127v181q-88 -56 -174 -56q-51 0 -88 23q-29 17 -39 45q-11 30 -11 129v295h274v181h-274v291h-164q-11 -90 -40 -147t-78 -99q-48 -40 -116 -63v-163h127v-404q0 -78 17 -121q17 -42 59 -78q43 -37 104 -57q62 -20 140 -20q67 0 129 14q57 13 134 49zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
|
||||
<glyph unicode="" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
|
||||
<glyph unicode="" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
|
||||
<glyph unicode="" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
|
||||
<glyph unicode="" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
|
||||
<glyph unicode="" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1483 512l-587 -587q-52 -53 -127.5 -53t-128.5 53l-587 587q-53 53 -53 128t53 128l587 587q53 53 128 53t128 -53l265 -265l-398 -399l-188 188q-42 42 -99 42q-59 0 -100 -41l-120 -121q-42 -40 -42 -99q0 -58 42 -100l406 -408q30 -28 67 -37l6 -4h28q60 0 99 41 l619 619l2 -3q53 -53 53 -128t-53 -128zM1406 1138l120 -120q14 -15 14 -36t-14 -36l-730 -730q-17 -15 -37 -15v0q-4 0 -6 1q-18 2 -30 14l-407 408q-14 15 -14 36t14 35l121 120q13 15 35 15t36 -15l252 -252l574 575q15 15 36 15t36 -15z" />
|
||||
<glyph unicode="" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
|
||||
<glyph unicode="" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
|
||||
<glyph unicode="" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
|
||||
<glyph unicode="" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1920" d="M805 163q-122 -67 -261 -67q-141 0 -261 67q98 61 167 149t94 191q25 -103 94 -191t167 -149zM453 1176v-344q0 -179 -89.5 -326t-234.5 -217q-129 152 -129 351q0 200 129.5 352t323.5 184zM958 991q-128 -152 -128 -351q0 -201 128 -351q-145 70 -234.5 218t-89.5 328 v341q196 -33 324 -185zM1638 163q-122 -67 -261 -67q-141 0 -261 67q98 61 167 149t94 191q25 -103 94 -191t167 -149zM1286 1176v-344q0 -179 -91 -326t-237 -217v0q133 154 133 351q0 195 -133 351q129 151 328 185zM1920 640q0 -201 -129 -351q-145 70 -234.5 218 t-89.5 328v341q194 -32 323.5 -184t129.5 -352z" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
<glyph unicode="" horiz-adv-x="1792" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 193 KiB |
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,836 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||
<title>The Python Fire Guide - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "The Python Fire Guide";
|
||||
var mkdocs_page_input_path = "guide.md";
|
||||
var mkdocs_page_url = "/guide/";
|
||||
</script>
|
||||
|
||||
<script src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script src="../js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href=".." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="..">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href="./">The Python Fire Guide</a>
|
||||
<ul class="subnav">
|
||||
|
||||
<li class="toctree-l2"><a href="#the-python-fire-guide">The Python Fire Guide</a></li>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><a class="toctree-l3" href="#introduction">Introduction</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#installation">Installation</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#hello-world">Hello World</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#exposing-multiple-commands">Exposing Multiple Commands</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#grouping-commands">Grouping Commands</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#accessing-properties">Accessing Properties</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#chaining-function-calls">Chaining Function Calls</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#can-we-make-an-even-simpler-example-than-hello-world">Can we make an even simpler example than Hello World?</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#calling-functions">Calling Functions</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#argument-parsing">Argument Parsing</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#using-fire-flags">Using Fire Flags</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#reference">Reference</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#disclaimer">Disclaimer</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="..">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="..">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>The Python Fire Guide</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<h2 id="the-python-fire-guide">The Python Fire Guide</h2>
|
||||
<h3 id="introduction">Introduction</h3>
|
||||
<p>Welcome to the Python Fire guide! Python Fire is a Python library that will turn
|
||||
any Python component into a command line interface with just a single call to
|
||||
<code>Fire</code>.</p>
|
||||
<p>Let's get started!</p>
|
||||
<h3 id="installation">Installation</h3>
|
||||
<p>To install Python Fire from pypi, run:</p>
|
||||
<p><code>pip install fire</code></p>
|
||||
<p>Alternatively, to install Python Fire from source, clone the source and run:</p>
|
||||
<p><code>python setup.py install</code></p>
|
||||
<h3 id="hello-world">Hello World</h3>
|
||||
<h5 id="version-1-firefire">Version 1: <code>fire.Fire()</code></h5>
|
||||
<p>The easiest way to use Fire is to take any Python program, and then simply call
|
||||
<code>fire.Fire()</code> at the end of the program. This will expose the full contents of
|
||||
the program to the command line.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire()
|
||||
</code></pre>
|
||||
|
||||
<p>Here's how we can run our program from the command line:</p>
|
||||
<pre><code class="bash">$ python example.py hello World
|
||||
Hello World!
|
||||
</code></pre>
|
||||
|
||||
<h5 id="version-2-firefirefn">Version 2: <code>fire.Fire(<fn>)</code></h5>
|
||||
<p>Let's modify our program slightly to only expose the <code>hello</code> function to the
|
||||
command line.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(hello)
|
||||
</code></pre>
|
||||
|
||||
<p>Here's how we can run this from the command line:</p>
|
||||
<pre><code class="bash">$ python example.py World
|
||||
Hello World!
|
||||
</code></pre>
|
||||
|
||||
<p>Notice we no longer have to specify to run the <code>hello</code> function, because we
|
||||
called <code>fire.Fire(hello)</code>.</p>
|
||||
<h5 id="version-3-using-a-main">Version 3: Using a main</h5>
|
||||
<p>We can alternatively write this program like this:</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
def main():
|
||||
fire.Fire(hello)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
</code></pre>
|
||||
|
||||
<p>Or if we're using
|
||||
<a href="https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points">entry points</a>,
|
||||
then simply this:</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def hello(name):
|
||||
return 'Hello {name}!'.format(name=name)
|
||||
|
||||
def main():
|
||||
fire.Fire(hello)
|
||||
</code></pre>
|
||||
|
||||
<h3 id="exposing-multiple-commands">Exposing Multiple Commands</h3>
|
||||
<p>In the previous example, we exposed a single function to the command line. Now
|
||||
we'll look at ways of exposing multiple functions to the command line.</p>
|
||||
<h5 id="version-1-firefire_1">Version 1: <code>fire.Fire()</code></h5>
|
||||
<p>The simplest way to expose multiple commands is to write multiple functions, and
|
||||
then call Fire.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire()
|
||||
</code></pre>
|
||||
|
||||
<p>We can use this like so:</p>
|
||||
<pre><code class="bash">$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
</code></pre>
|
||||
|
||||
<p>You'll notice that Fire correctly parsed <code>10</code> and <code>20</code> as numbers, rather than
|
||||
as strings. Read more about <a href="#argument-parsing">argument parsing here</a>.</p>
|
||||
<h5 id="version-2-firefiredict">Version 2: <code>fire.Fire(<dict>)</code></h5>
|
||||
<p>In version 1 we exposed all the program's functionality to the command line. By
|
||||
using a dict, we can selectively expose functions to the command line.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire({
|
||||
'add': add,
|
||||
'multiply': multiply,
|
||||
})
|
||||
</code></pre>
|
||||
|
||||
<p>We can use this in the same way as before:</p>
|
||||
<pre><code class="bash">$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
</code></pre>
|
||||
|
||||
<h5 id="version-3-firefireobject">Version 3: <code>fire.Fire(<object>)</code></h5>
|
||||
<p>Fire also works on objects, as in this variant. This is a good way to expose
|
||||
multiple commands.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
class Calculator(object):
|
||||
|
||||
def add(self, x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
calculator = Calculator()
|
||||
fire.Fire(calculator)
|
||||
</code></pre>
|
||||
|
||||
<p>We can use this in the same way as before:</p>
|
||||
<pre><code class="bash">$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
</code></pre>
|
||||
|
||||
<h5 id="version-4-firefireclass">Version 4: <code>fire.Fire(<class>)</code></h5>
|
||||
<p>Fire also works on classes. This is another good way to expose multiple
|
||||
commands.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
class Calculator(object):
|
||||
|
||||
def add(self, x, y):
|
||||
return x + y
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Calculator)
|
||||
</code></pre>
|
||||
|
||||
<p>We can use this in the same way as before:</p>
|
||||
<pre><code class="bash">$ python example.py add 10 20
|
||||
30
|
||||
$ python example.py multiply 10 20
|
||||
200
|
||||
</code></pre>
|
||||
|
||||
<p>Why might you prefer a class over an object? One reason is that you can pass
|
||||
arguments for constructing the class too, as in this broken calculator example.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
class BrokenCalculator(object):
|
||||
|
||||
def __init__(self, offset=1):
|
||||
self._offset = offset
|
||||
|
||||
def add(self, x, y):
|
||||
return x + y + self._offset
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y + self._offset
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(BrokenCalculator)
|
||||
</code></pre>
|
||||
|
||||
<p>When you use a broken calculator, you get wrong answers:</p>
|
||||
<pre><code class="bash">$ python example.py add 10 20
|
||||
31
|
||||
$ python example.py multiply 10 20
|
||||
201
|
||||
</code></pre>
|
||||
|
||||
<p>But you can always fix it:</p>
|
||||
<pre><code class="bash">$ python example.py add 10 20 --offset=0
|
||||
30
|
||||
$ python example.py multiply 10 20 --offset=0
|
||||
200
|
||||
</code></pre>
|
||||
|
||||
<p>Unlike calling ordinary functions, which can be done both with positional
|
||||
arguments and named arguments (--flag syntax), arguments to __init__
|
||||
functions must be passed with the --flag syntax. See the section on
|
||||
<a href="#calling-functions">calling functions</a> for more.</p>
|
||||
<h3 id="grouping-commands">Grouping Commands</h3>
|
||||
<p>Here's an example of how you might make a command line interface with grouped
|
||||
commands.</p>
|
||||
<pre><code class="python">class IngestionStage(object):
|
||||
|
||||
def run(self):
|
||||
return 'Ingesting! Nom nom nom...'
|
||||
|
||||
class DigestionStage(object):
|
||||
|
||||
def run(self, volume=1):
|
||||
return ' '.join(['Burp!'] * volume)
|
||||
|
||||
def status(self):
|
||||
return 'Satiated.'
|
||||
|
||||
class Pipeline(object):
|
||||
|
||||
def __init__(self):
|
||||
self.ingestion = IngestionStage()
|
||||
self.digestion = DigestionStage()
|
||||
|
||||
def run(self):
|
||||
self.ingestion.run()
|
||||
self.digestion.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Pipeline)
|
||||
</code></pre>
|
||||
|
||||
<p>Here's how this looks at the command line:</p>
|
||||
<pre><code class="bash">$ python example.py run
|
||||
Ingesting! Nom nom nom...
|
||||
Burp!
|
||||
$ python example.py ingestion run
|
||||
Ingesting! Nom nom nom...
|
||||
$ python example.py digestion run
|
||||
Burp!
|
||||
$ python example.py digestion status
|
||||
Satiated.
|
||||
</code></pre>
|
||||
|
||||
<p>You can nest your commands in arbitrarily complex ways, if you're feeling grumpy
|
||||
or adventurous.</p>
|
||||
<h3 id="accessing-properties">Accessing Properties</h3>
|
||||
<p>In the examples we've looked at so far, our invocations of <code>python example.py</code>
|
||||
have all run some function from the example program. In this example, we simply
|
||||
access a property.</p>
|
||||
<pre><code class="python">from airports import airports
|
||||
|
||||
import fire
|
||||
|
||||
class Airport(object):
|
||||
|
||||
def __init__(self, code):
|
||||
self.code = code
|
||||
self.name = dict(airports).get(self.code)
|
||||
self.city = self.name.split(',')[0] if self.name else None
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Airport)
|
||||
</code></pre>
|
||||
|
||||
<p>Now we can use this program to learn about airport codes!</p>
|
||||
<pre><code class="bash">$ python example.py --code=JFK code
|
||||
JFK
|
||||
$ python example.py --code=SJC name
|
||||
San Jose-Sunnyvale-Santa Clara, CA - Norman Y. Mineta San Jose International (SJC)
|
||||
$ python example.py --code=ALB city
|
||||
Albany-Schenectady-Troy
|
||||
</code></pre>
|
||||
|
||||
<p>By the way, you can find this
|
||||
<a href="https://github.com/trendct-data/airports.py">airports module here</a>.</p>
|
||||
<h3 id="chaining-function-calls">Chaining Function Calls</h3>
|
||||
<p>When you run a Fire CLI, you can take all the same actions on the <em>result</em> of
|
||||
the call to Fire that you can take on the original object passed in.</p>
|
||||
<p>For example, we can use our Airport CLI from the previous example like this:</p>
|
||||
<pre><code class="bash">$ python example.py --code=ALB city upper
|
||||
ALBANY-SCHENECTADY-TROY
|
||||
</code></pre>
|
||||
|
||||
<p>This works since <code>upper</code> is a method on all strings.</p>
|
||||
<p>So, if you want to set up your functions to chain nicely, all you have to do is
|
||||
have a class whose methods return self. Here's an example.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
class BinaryCanvas(object):
|
||||
"""A canvas with which to make binary art, one bit at a time."""
|
||||
|
||||
def __init__(self, size=10):
|
||||
self.pixels = [[0] * size for _ in range(size)]
|
||||
self._size = size
|
||||
self._row = 0 # The row of the cursor.
|
||||
self._col = 0 # The column of the cursor.
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(' '.join(str(pixel) for pixel in row) for row in self.pixels)
|
||||
|
||||
def show(self):
|
||||
print(self)
|
||||
return self
|
||||
|
||||
def move(self, row, col):
|
||||
self._row = row % self._size
|
||||
self._col = col % self._size
|
||||
return self
|
||||
|
||||
def on(self):
|
||||
return self.set(1)
|
||||
|
||||
def off(self):
|
||||
return self.set(0)
|
||||
|
||||
def set(self, value):
|
||||
self.pixels[self._row][self._col] = value
|
||||
return self
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(BinaryCanvas)
|
||||
</code></pre>
|
||||
|
||||
<p>Now we can draw stuff :).</p>
|
||||
<pre><code class="bash">$ python example.py move 3 3 on move 3 6 on move 6 3 on move 6 6 on move 7 4 on move 7 5 on __str__
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 1 0 0 1 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 1 0 0 1 0 0 0
|
||||
0 0 0 0 1 1 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
</code></pre>
|
||||
|
||||
<p>It's supposed to be a smiley face.</p>
|
||||
<h3 id="can-we-make-an-even-simpler-example-than-hello-world">Can we make an even simpler example than Hello World?</h3>
|
||||
<p>Yes, this program is even simpler than our original Hello World example.</p>
|
||||
<pre><code class="python">import fire
|
||||
english = 'Hello World'
|
||||
spanish = 'Hola Mundo'
|
||||
fire.Fire()
|
||||
</code></pre>
|
||||
|
||||
<p>You can use it like this:</p>
|
||||
<pre><code class="bash">$ python example.py english
|
||||
Hello World
|
||||
$ python example.py spanish
|
||||
Hola Mundo
|
||||
</code></pre>
|
||||
|
||||
<h3 id="calling-functions">Calling Functions</h3>
|
||||
<p>Arguments to a constructor are passed by name using flag syntax <code>--name=value</code>.</p>
|
||||
<p>For example, consider this simple class:</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
class Building(object):
|
||||
|
||||
def __init__(self, name, stories=1):
|
||||
self.name = name
|
||||
self.stories = 1
|
||||
|
||||
def climb_stairs(self, stairs_per_story=10):
|
||||
for story in range(self.stories):
|
||||
for stair in range(1, stairs_per_story):
|
||||
yield stair
|
||||
yield 'Phew!'
|
||||
yield 'Done!'
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Building)
|
||||
</code></pre>
|
||||
|
||||
<p>We can instantiate it as follows: <code>python example.py --name="Sherrerd Hall"</code></p>
|
||||
<p>Arguments to other functions may be passed positionally or by name using flag
|
||||
syntax.</p>
|
||||
<p>To instantiate a <code>Building</code> and then run the <code>climb_stairs</code> function, the
|
||||
following commands are all valid:</p>
|
||||
<pre><code class="bash">$ python example.py --name="Sherrerd Hall" --stories=3 climb_stairs 10
|
||||
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs_per_story=10
|
||||
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs-per-story 10
|
||||
$ python example.py climb-stairs --stairs-per-story 10 --name="Sherrerd Hall"
|
||||
</code></pre>
|
||||
|
||||
<p>You'll notice that hyphens and underscores (<code>-</code> and <code>_</code>) are interchangeable in
|
||||
member names and flag names.</p>
|
||||
<p>You'll also notice that the constructor's arguments can come after the
|
||||
function's arguments or before the function.</p>
|
||||
<p>You'll also notice that the equal sign between the flag name and its value is
|
||||
optional.</p>
|
||||
<h5 id="functions-with-varargs-and-kwargs">Functions with <code>*varargs</code> and <code>**kwargs</code></h5>
|
||||
<p>Fire supports functions that take *varargs or **kwargs. Here's an example:</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
def order_by_length(*items):
|
||||
"""Orders items by length, breaking ties alphabetically."""
|
||||
sorted_items = sorted(items, key=lambda item: (len(str(item)), str(item)))
|
||||
return ' '.join(sorted_items)
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(order_by_length)
|
||||
</code></pre>
|
||||
|
||||
<p>To use it, we run:</p>
|
||||
<pre><code class="bash">$ python example.py dog cat elephant
|
||||
cat dog elephant
|
||||
</code></pre>
|
||||
|
||||
<p>You can use a separator to indicate that you're done providing arguments to a
|
||||
function. All arguments after the separator will be used to process the result
|
||||
of the function, rather than being passed to the function itself. The default
|
||||
separator is the hyphen <code>-</code>.</p>
|
||||
<p>Here's an example where we use a separator.</p>
|
||||
<pre><code class="bash">$ python example.py dog cat elephant - upper
|
||||
CAT DOG ELEPHANT
|
||||
</code></pre>
|
||||
|
||||
<p>Without the separator, upper would have been treated as another argument.</p>
|
||||
<pre><code class="bash">$ python example.py dog cat elephant upper
|
||||
cat dog upper elephant
|
||||
</code></pre>
|
||||
|
||||
<p>You can change the separator with the <code>--separator</code> flag. Flags are always
|
||||
separated from your Fire command by an isolated <code>--</code>. Here's an example where we
|
||||
change the separator.</p>
|
||||
<pre><code class="bash">$ python example.py dog cat elephant X upper -- --separator=X
|
||||
CAT DOG ELEPHANT
|
||||
</code></pre>
|
||||
|
||||
<p>Separators can be useful when a function accepts *varargs, **kwargs, or
|
||||
default values that you don't want to specify. It is also important to remember
|
||||
to change the separator if you want to pass <code>-</code> as an argument.</p>
|
||||
<h3 id="argument-parsing">Argument Parsing</h3>
|
||||
<p>The types of the arguments are determined by their values, rather than by the
|
||||
function signature where they're used. You can pass any Python literal from the
|
||||
command line: numbers, strings, tuples, lists, dictionaries, (sets are only
|
||||
supported in some versions of Python). You can also nest the collections
|
||||
arbitrarily as long as they only contain literals.</p>
|
||||
<p>To demonstrate this, we'll make a small example program that tells us the type
|
||||
of any argument we give it:</p>
|
||||
<pre><code class="python">import fire
|
||||
fire.Fire(lambda obj: type(obj).__name__)
|
||||
</code></pre>
|
||||
|
||||
<p>And we'll use it like so:</p>
|
||||
<pre><code class="bash">$ python example.py 10
|
||||
int
|
||||
$ python example.py 10.0
|
||||
float
|
||||
$ python example.py hello
|
||||
str
|
||||
$ python example.py '(1,2)'
|
||||
tuple
|
||||
$ python example.py [1,2]
|
||||
list
|
||||
$ python example.py True
|
||||
bool
|
||||
$ python example.py {name: David}
|
||||
dict
|
||||
</code></pre>
|
||||
|
||||
<p>You'll notice in that last example that bare-words are automatically replaced
|
||||
with strings.</p>
|
||||
<p>Be careful with your quotes! If you want to pass the string <code>"10"</code>, rather than
|
||||
the int <code>10</code>, you'll need to either escape or quote your quotes. Otherwise Bash
|
||||
will eat your quotes and pass an unquoted <code>10</code> to your Python program, where
|
||||
Fire will interpret it as a number.</p>
|
||||
<pre><code class="bash">$ python example.py 10
|
||||
int
|
||||
$ python example.py "10"
|
||||
int
|
||||
$ python example.py '"10"'
|
||||
str
|
||||
$ python example.py "'10'"
|
||||
str
|
||||
$ python example.py \"10\"
|
||||
str
|
||||
</code></pre>
|
||||
|
||||
<p>Be careful with your quotes! Remember that Bash processes your arguments first,
|
||||
and then Fire parses the result of that.
|
||||
If you wanted to pass the dict <code>{"name": "David Bieber"}</code> to your program, you
|
||||
might try this:</p>
|
||||
<pre><code class="bash">$ python example.py '{"name": "David Bieber"}' # Good! Do this.
|
||||
dict
|
||||
$ python example.py {"name":'"David Bieber"'} # Okay.
|
||||
dict
|
||||
$ python example.py {"name":"David Bieber"} # Wrong. This is parsed as a string.
|
||||
str
|
||||
$ python example.py {"name": "David Bieber"} # Wrong. This isn't even treated as a single argument.
|
||||
<error>
|
||||
$ python example.py '{"name": "Justin Bieber"}' # Wrong. This is not the Bieber you're looking for. (The syntax is fine though :))
|
||||
dict
|
||||
</code></pre>
|
||||
|
||||
<h5 id="boolean-arguments">Boolean Arguments</h5>
|
||||
<p>The tokens <code>True</code> and <code>False</code> are parsed as boolean values.</p>
|
||||
<p>You may also specify booleans via flag syntax <code>--name</code> and <code>--noname</code>, which set
|
||||
<code>name</code> to <code>True</code> and <code>False</code> respectively.</p>
|
||||
<p>Continuing the previous example, we could run any of the following:</p>
|
||||
<pre><code class="bash">$ python example.py --obj=True
|
||||
bool
|
||||
$ python example.py --obj=False
|
||||
bool
|
||||
$ python example.py --obj
|
||||
bool
|
||||
$ python example.py --noobj
|
||||
bool
|
||||
</code></pre>
|
||||
|
||||
<p>Be careful with boolean flags! If a token other than another flag immediately
|
||||
follows a flag that's supposed to be a boolean, the flag will take on the value
|
||||
of the token rather than the boolean value. You can resolve this: by putting a
|
||||
separator after your last flag, by explicitly stating the value of the boolean
|
||||
flag (as in <code>--obj=True</code>), or by making sure there's another flag after any
|
||||
boolean flag argument.</p>
|
||||
<h3 id="using-fire-flags">Using Fire Flags</h3>
|
||||
<p>Fire CLIs all come with a number of flags. These flags should be separated from
|
||||
the Fire command by an isolated <code>--</code>. If there is at least one isolated <code>--</code>
|
||||
argument, then arguments after the final isolated <code>--</code> are treated as flags,
|
||||
whereas all arguments before the final isolated <code>--</code> are considered part of the
|
||||
Fire command.</p>
|
||||
<p>One useful flag is the <code>--interactive</code> flag. Use the <code>--interactive</code> flag on any
|
||||
CLI to enter a Python REPL with all the modules and variables used in the
|
||||
context where <code>Fire</code> was called already available to you for use. Other useful
|
||||
variables, such as the result of the Fire command will also be available. Use
|
||||
this feature like this: <code>python example.py -- --interactive</code>.</p>
|
||||
<p>You can add the help flag to any command to see help and usage information. Fire
|
||||
incorporates your docstrings into the help and usage information that it
|
||||
generates. Fire will try to provide help even if you omit the isolated <code>--</code>
|
||||
separating the flags from the Fire command, but may not always be able to, since
|
||||
<code>help</code> is a valid argument name. Use this feature like this:
|
||||
<code>python example.py -- --help</code>.</p>
|
||||
<p>The complete set of flags available is shown below, in the reference section.</p>
|
||||
<h3 id="reference">Reference</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Setup</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">install</td>
|
||||
<td align="left"><code>pip install fire</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h5 id="creating-a-cli">Creating a CLI</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Creating a CLI</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">import</td>
|
||||
<td align="left"><code>import fire</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Call</td>
|
||||
<td align="left"><code>fire.Fire()</code></td>
|
||||
<td align="left">Turns the current module into a Fire CLI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Call</td>
|
||||
<td align="left"><code>fire.Fire(component)</code></td>
|
||||
<td align="left">Turns <code>component</code> into a Fire CLI.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h5 id="flags">Flags</h5>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Using a CLI</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#help-flag">Help</a></td>
|
||||
<td align="left"><code>command -- --help</code></td>
|
||||
<td align="left">Show help and usage information for the command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#interactive-flag">REPL</a></td>
|
||||
<td align="left"><code>command -- --interactive</code></td>
|
||||
<td align="left">Enter interactive mode.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#separator-flag">Separator</a></td>
|
||||
<td align="left"><code>command -- --separator=X</code></td>
|
||||
<td align="left">This sets the separator to <code>X</code>. The default separator is <code>-</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#completion-flag">Completion</a></td>
|
||||
<td align="left"><code>command -- --completion</code></td>
|
||||
<td align="left">Generate a completion script for the CLI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#trace-flag">Trace</a></td>
|
||||
<td align="left"><code>command -- --trace</code></td>
|
||||
<td align="left">Gets a Fire trace for the command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="../using-cli/#verbose-flag">Verbose</a></td>
|
||||
<td align="left"><code>command -- --verbose</code></td>
|
||||
<td align="left">Include private members in the output.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><em>Note that flags are separated from the Fire command by an isolated <code>--</code> arg.</em></p>
|
||||
<h3 id="disclaimer">Disclaimer</h3>
|
||||
<p>Python Fire is not an official Google product.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
<a href="../using-cli/" class="btn btn-neutral float-right" title="Using a CLI">Next <span class="icon icon-circle-arrow-right"></span></a>
|
||||
|
||||
|
||||
<a href="../benefits/" class="btn btn-neutral" title="Benefits"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
<span><a href="../benefits/" style="color: #fcfcfc;">« Previous</a></span>
|
||||
|
||||
|
||||
<span style="margin-left: 15px"><a href="../using-cli/" style="color: #fcfcfc">Next »</a></span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="../js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
+319
@@ -0,0 +1,319 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="None">
|
||||
|
||||
<link rel="shortcut icon" href="./img/favicon.ico">
|
||||
<title>Overview - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="./css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="./css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="./css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "Overview";
|
||||
var mkdocs_page_input_path = "index.md";
|
||||
var mkdocs_page_url = "/";
|
||||
</script>
|
||||
|
||||
<script src="./js/jquery-2.1.1.min.js"></script>
|
||||
<script src="./js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="./js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href="." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="./search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href=".">Overview</a>
|
||||
<ul class="subnav">
|
||||
|
||||
<li class="toctree-l2"><a href="#python-fire">Python Fire</a></li>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><a class="toctree-l3" href="#installation">Installation</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#basic-usage">Basic Usage</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#why-is-it-called-fire">Why is it called Fire?</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#where-can-i-learn-more">Where can I learn more?</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#reference">Reference</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#disclaimer">Disclaimer</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href=".">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href=".">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>Overview</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<h1 id="python-fire">Python Fire <a href="https://github.com/google/python-fire"><img alt="PyPI" src="https://img.shields.io/pypi/pyversions/fire.svg?style=plastic" /></a></h1>
|
||||
<p><em>Python Fire is a library for automatically generating command line interfaces
|
||||
(CLIs) from absolutely any Python object.</em></p>
|
||||
<ul>
|
||||
<li>Python Fire is a simple way to create a CLI in Python. <a href="benefits/#simple-cli">[1]</a></li>
|
||||
<li>Python Fire is a helpful tool for developing and debugging Python code. <a href="benefits/#debugging">[2]</a></li>
|
||||
<li>Python Fire helps with exploring existing code or turning other people's code
|
||||
into a CLI. <a href="benefits/#exploring">[3]</a></li>
|
||||
<li>Python Fire makes transitioning between Bash and Python easier. <a href="benefits/#bash">[4]</a></li>
|
||||
<li>Python Fire makes using a Python REPL easier by setting up the REPL with the
|
||||
modules and variables you'll need already imported and created. <a href="benefits/#repl">[5]</a></li>
|
||||
</ul>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>To install Python Fire with pip, run: <code>pip install fire</code></p>
|
||||
<p>To install Python Fire with conda, run: <code>conda install fire -c conda-forge</code></p>
|
||||
<p>To install Python Fire from source, first clone the repository and then run:
|
||||
<code>python setup.py install</code></p>
|
||||
<h2 id="basic-usage">Basic Usage</h2>
|
||||
<p>You can call <code>Fire</code> on any Python object:<br>
|
||||
functions, classes, modules, objects, dictionaries, lists, tuples, etc.
|
||||
They all work!</p>
|
||||
<p>Here's an example of calling Fire on a class.</p>
|
||||
<pre><code class="python">import fire
|
||||
|
||||
class Calculator(object):
|
||||
"""A simple calculator class."""
|
||||
|
||||
def double(self, number):
|
||||
return 2 * number
|
||||
|
||||
if __name__ == '__main__':
|
||||
fire.Fire(Calculator)
|
||||
</code></pre>
|
||||
|
||||
<p>Then, from the command line, you can run:</p>
|
||||
<pre><code class="bash">python calculator.py double 10 # 20
|
||||
python calculator.py double --number=15 # 30
|
||||
</code></pre>
|
||||
|
||||
<p>To learn how Fire behaves on functions, objects, dicts, lists, etc, and to learn
|
||||
about Fire's other features, see the <a href="using-cli/">Using a Fire CLI page</a>.</p>
|
||||
<p>For additional examples, see <a href="guide/">The Python Fire Guide</a>.</p>
|
||||
<h2 id="why-is-it-called-fire">Why is it called Fire?</h2>
|
||||
<p>When you call <code>Fire</code>, it fires off (executes) your command.</p>
|
||||
<h2 id="where-can-i-learn-more">Where can I learn more?</h2>
|
||||
<p>Please see <a href="guide/">The Python Fire Guide</a>.</p>
|
||||
<h2 id="reference">Reference</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Setup</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">install</td>
|
||||
<td align="left"><code>pip install fire</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Creating a CLI</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">import</td>
|
||||
<td align="left"><code>import fire</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Call</td>
|
||||
<td align="left"><code>fire.Fire()</code></td>
|
||||
<td align="left">Turns the current module into a Fire CLI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">Call</td>
|
||||
<td align="left"><code>fire.Fire(component)</code></td>
|
||||
<td align="left">Turns <code>component</code> into a Fire CLI.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Using a CLI</th>
|
||||
<th align="left">Command</th>
|
||||
<th align="left">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left"><a href="using-cli/#help-flag">Help</a></td>
|
||||
<td align="left"><code>command -- --help</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="using-cli/#interactive-flag">REPL</a></td>
|
||||
<td align="left"><code>command -- --interactive</code></td>
|
||||
<td align="left">Enters interactive mode.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="using-cli/#separator-flag">Separator</a></td>
|
||||
<td align="left"><code>command -- --separator=X</code></td>
|
||||
<td align="left">This sets the separator to <code>X</code>. The default separator is <code>-</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="using-cli/#completion-flag">Completion</a></td>
|
||||
<td align="left"><code>command -- --completion</code></td>
|
||||
<td align="left">Generate a completion script for the CLI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="using-cli/#trace-flag">Trace</a></td>
|
||||
<td align="left"><code>command -- --trace</code></td>
|
||||
<td align="left">Gets a Fire trace for the command.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="using-cli/#verbose-flag">Verbose</a></td>
|
||||
<td align="left"><code>command -- --verbose</code></td>
|
||||
<td align="left"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><em>Note that flags are separated from the Fire command by an isolated <code>--</code> arg.</em></p>
|
||||
<h2 id="disclaimer">Disclaimer</h2>
|
||||
<p>This is not an official Google product.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
<a href="installation/" class="btn btn-neutral float-right" title="Installation">Next <span class="icon icon-circle-arrow-right"></span></a>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
|
||||
<span style="margin-left: 15px"><a href="installation/" style="color: #fcfcfc">Next »</a></span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="./js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!--
|
||||
MkDocs version : 0.16.3
|
||||
Build Date UTC : 2018-02-23 18:38:01
|
||||
-->
|
||||
@@ -0,0 +1,174 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||
<title>Installation - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "Installation";
|
||||
var mkdocs_page_input_path = "installation.md";
|
||||
var mkdocs_page_url = "/installation/";
|
||||
</script>
|
||||
|
||||
<script src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script src="../js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href=".." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="..">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href="./">Installation</a>
|
||||
<ul class="subnav">
|
||||
|
||||
<li class="toctree-l2"><a href="#installation">Installation</a></li>
|
||||
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="..">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="..">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>Installation</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<h1 id="installation">Installation</h1>
|
||||
<p>To install Python Fire with pip, run: <code>pip install fire</code></p>
|
||||
<p>To install Python Fire with conda, run: <code>conda install fire -c conda-forge</code></p>
|
||||
<p>To install Python Fire from source, first clone the repository and then run:
|
||||
<code>python setup.py install</code></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
<a href="../benefits/" class="btn btn-neutral float-right" title="Benefits">Next <span class="icon icon-circle-arrow-right"></span></a>
|
||||
|
||||
|
||||
<a href=".." class="btn btn-neutral" title="Overview"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
<span><a href=".." style="color: #fcfcfc;">« Previous</a></span>
|
||||
|
||||
|
||||
<span style="margin-left: 15px"><a href="../benefits/" style="color: #fcfcfc">Next »</a></span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="../js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
Vendored
+4
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+82
@@ -0,0 +1,82 @@
|
||||
$( document ).ready(function() {
|
||||
// Shift nav in mobile when clicking the menu.
|
||||
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
|
||||
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||
});
|
||||
|
||||
// Close menu when you click a link.
|
||||
$(document).on('click', ".wy-menu-vertical .current ul li a", function() {
|
||||
$("[data-toggle='wy-nav-shift']").removeClass("shift");
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift");
|
||||
});
|
||||
|
||||
$(document).on('click', "[data-toggle='rst-current-version']", function() {
|
||||
$("[data-toggle='rst-versions']").toggleClass("shift-up");
|
||||
});
|
||||
|
||||
// Make tables responsive
|
||||
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
|
||||
|
||||
hljs.initHighlightingOnLoad();
|
||||
|
||||
$('table').addClass('docutils');
|
||||
});
|
||||
|
||||
window.SphinxRtdTheme = (function (jquery) {
|
||||
var stickyNav = (function () {
|
||||
var navBar,
|
||||
win,
|
||||
stickyNavCssClass = 'stickynav',
|
||||
applyStickNav = function () {
|
||||
if (navBar.height() <= win.height()) {
|
||||
navBar.addClass(stickyNavCssClass);
|
||||
} else {
|
||||
navBar.removeClass(stickyNavCssClass);
|
||||
}
|
||||
},
|
||||
enable = function () {
|
||||
applyStickNav();
|
||||
win.on('resize', applyStickNav);
|
||||
},
|
||||
init = function () {
|
||||
navBar = jquery('nav.wy-nav-side:first');
|
||||
win = jquery(window);
|
||||
};
|
||||
jquery(init);
|
||||
return {
|
||||
enable : enable
|
||||
};
|
||||
}());
|
||||
return {
|
||||
StickyNav : stickyNav
|
||||
};
|
||||
}($));
|
||||
|
||||
// The code below is a copy of @seanmadsen code posted Jan 10, 2017 on issue 803.
|
||||
// https://github.com/mkdocs/mkdocs/issues/803
|
||||
// This just incorporates the auto scroll into the theme itself without
|
||||
// the need for additional custom.js file.
|
||||
//
|
||||
$(function() {
|
||||
$.fn.isFullyWithinViewport = function(){
|
||||
var viewport = {};
|
||||
viewport.top = $(window).scrollTop();
|
||||
viewport.bottom = viewport.top + $(window).height();
|
||||
var bounds = {};
|
||||
bounds.top = this.offset().top;
|
||||
bounds.bottom = bounds.top + this.outerHeight();
|
||||
return ( ! (
|
||||
(bounds.top <= viewport.top) ||
|
||||
(bounds.bottom >= viewport.bottom)
|
||||
) );
|
||||
};
|
||||
if( $('li.toctree-l1.current').length && !$('li.toctree-l1.current').isFullyWithinViewport() ) {
|
||||
$('.wy-nav-side')
|
||||
.scrollTop(
|
||||
$('li.toctree-l1.current').offset().top -
|
||||
$('.wy-nav-side').offset().top -
|
||||
60
|
||||
);
|
||||
}
|
||||
});
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
site_name: Python Fire
|
||||
theme: readthedocs
|
||||
markdown_extensions: [fenced_code]
|
||||
pages:
|
||||
- Overview: index.md
|
||||
- Installation: installation.md
|
||||
- Benefits: benefits.md
|
||||
- The Python Fire Guide: guide.md
|
||||
- Using a CLI: using-cli.md
|
||||
- Troubleshooting: troubleshooting.md
|
||||
- Reference: api.md
|
||||
Vendored
+7
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
RequireJS 2.1.16 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
var requirejs,require,define;
|
||||
(function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function T(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function t(b,c){return fa.call(b,c)}function m(b,c){return t(b,c)&&b[c]}function B(b,c){for(var d in b)if(t(b,d)&&c(b[d],d))break}function U(b,c,d,e){c&&B(c,function(c,g){if(d||!t(b,g))e&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
|
||||
RegExp)?(b[g]||(b[g]={}),U(b[g],c,d,e)):b[g]=c});return b}function u(b,c){return function(){return c.apply(b,arguments)}}function ca(b){throw b;}function da(b){if(!b)return b;var c=ba;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,e){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=e;d&&(c.originalError=d);return c}function ga(b){function c(a,k,b){var f,l,c,d,e,g,i,p,k=k&&k.split("/"),h=j.map,n=h&&h["*"];if(a){a=a.split("/");l=a.length-1;j.nodeIdCompat&&
|
||||
Q.test(a[l])&&(a[l]=a[l].replace(Q,""));"."===a[0].charAt(0)&&k&&(l=k.slice(0,k.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)if(d=l[c],"."===d)l.splice(c,1),c-=1;else if(".."===d&&!(0===c||1==c&&".."===l[2]||".."===l[c-1])&&0<c)l.splice(c-1,2),c-=2;a=a.join("/")}if(b&&h&&(k||n)){l=a.split("/");c=l.length;a:for(;0<c;c-=1){e=l.slice(0,c).join("/");if(k)for(d=k.length;0<d;d-=1)if(b=m(h,k.slice(0,d).join("/")))if(b=m(b,e)){f=b;g=c;break a}!i&&(n&&m(n,e))&&(i=m(n,e),p=c)}!f&&i&&(f=i,g=p);f&&(l.splice(0,
|
||||
g,f),a=l.join("/"))}return(f=m(j.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(k){if(k.getAttribute("data-requiremodule")===a&&k.getAttribute("data-requirecontext")===i.contextName)return k.parentNode.removeChild(k),!0})}function e(a){var k=m(j.paths,a);if(k&&H(k)&&1<k.length)return k.shift(),i.require.undef(a),i.makeRequire(null,{skipMap:!0})([a]),!0}function n(a){var k,c=a?a.indexOf("!"):-1;-1<c&&(k=a.substring(0,c),a=a.substring(c+1,a.length));return[k,a]}function p(a,
|
||||
k,b,f){var l,d,e=null,g=k?k.name:null,j=a,p=!0,h="";a||(p=!1,a="_@r"+(K+=1));a=n(a);e=a[0];a=a[1];e&&(e=c(e,g,f),d=m(r,e));a&&(e?h=d&&d.normalize?d.normalize(a,function(a){return c(a,g,f)}):-1===a.indexOf("!")?c(a,g,f):a:(h=c(a,g,f),a=n(h),e=a[0],h=a[1],b=!0,l=i.nameToUrl(h)));b=e&&!d&&!b?"_unnormalized"+(O+=1):"";return{prefix:e,name:h,parentMap:k,unnormalized:!!b,url:l,originalName:j,isDefine:p,id:(e?e+"!"+h:h)+b}}function s(a){var k=a.id,b=m(h,k);b||(b=h[k]=new i.Module(a));return b}function q(a,
|
||||
k,b){var f=a.id,c=m(h,f);if(t(r,f)&&(!c||c.defineEmitComplete))"defined"===k&&b(r[f]);else if(c=s(a),c.error&&"error"===k)b(c.error);else c.on(k,b)}function w(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(v(c,function(b){if(b=m(h,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)g.onError(a)}function x(){R.length&&(ha.apply(A,[A.length,0].concat(R)),R=[])}function y(a){delete h[a];delete V[a]}function F(a,b,c){var f=a.map.id;a.error?a.emit("error",a.error):(b[f]=!0,v(a.depMaps,function(f,
|
||||
d){var e=f.id,g=m(h,e);g&&(!a.depMatched[d]&&!c[e])&&(m(b,e)?(a.defineDep(d,r[e]),a.check()):F(g,b,c))}),c[f]=!0)}function D(){var a,b,c=(a=1E3*j.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],l=[],g=!1,h=!0;if(!W){W=!0;B(V,function(a){var i=a.map,j=i.id;if(a.enabled&&(i.isDefine||l.push(a),!a.error))if(!a.inited&&c)e(j)?g=b=!0:(f.push(j),d(j));else if(!a.inited&&(a.fetched&&i.isDefine)&&(g=!0,!i.prefix))return h=!1});if(c&&f.length)return a=C("timeout","Load timeout for modules: "+f,null,
|
||||
f),a.contextName=i.contextName,w(a);h&&v(l,function(a){F(a,{},{})});if((!c||b)&&g)if((z||ea)&&!X)X=setTimeout(function(){X=0;D()},50);W=!1}}function E(a){t(r,a[0])||s(p(a[0],null,!0)).init(a[1],a[2])}function I(a){var a=a.currentTarget||a.srcElement,b=i.onScriptLoad;a.detachEvent&&!Y?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=i.onScriptError;(!a.detachEvent||Y)&&a.removeEventListener("error",b,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function J(){var a;
|
||||
for(x();A.length;){a=A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var W,Z,i,L,X,j={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},h={},V={},$={},A=[],r={},S={},aa={},K=1,O=1;L={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports=r[a.map.id]={}},module:function(a){return a.module?
|
||||
a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return m(j.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};Z=function(a){this.events=m($,a.id)||{};this.map=a;this.shim=m(j.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Z.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=u(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=
|
||||
c;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],u(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
|
||||
this.map.url;S[a]||(S[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
|
||||
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
|
||||
this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
|
||||
if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
|
||||
"fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
|
||||
a);this.check()}));this.errback?q(a,"error",u(this,this.errback)):this.events.error&&q(a,"error",u(this,function(a){this.emit("error",a)}))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,
|
||||
registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);
|
||||
b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,
|
||||
q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,
|
||||
e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==e&&(!("."===k||".."===k)||1<e))d=b.substring(e,b.length),b=b.substring(0,e);return i.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b){return t(r,p(b,a,!1,!0).id)},specified:function(b){b=p(b,a,!1,!0).id;return t(r,b)||t(h,b)}});a||(j.undef=function(b){x();var c=p(b,a,!0),e=m(h,b);d(b);delete r[b];delete S[c.url];delete $[b];T(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&($[b]=e.events),y(b))});return j},enable:function(a){m(h,a.id)&&
|
||||
s(a).enable()},completeLoad:function(a){var b,c,d=m(j.shim,a)||{},g=d.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=m(h,a);if(!b&&!t(r,a)&&c&&!c.inited){if(j.enforceDefine&&(!g||!da(g)))return e(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,d.deps||[],d.exportsFn])}D()},nameToUrl:function(a,b,c){var d,e,h;(d=m(j.pkgs,a))&&(a=d);if(d=m(aa,a))return i.nameToUrl(d,b,c);if(g.jsExtRegExp.test(a))d=a+(b||"");else{d=j.paths;
|
||||
a=a.split("/");for(e=a.length;0<e;e-=1)if(h=a.slice(0,e).join("/"),h=m(d,h)){H(h)&&(h=h[0]);a.splice(0,e,h);break}d=a.join("/");d+=b||(/^data\:|\?/.test(d)||c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+d}return j.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+j.urlArgs):d},load:function(a,b){g.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ja.test((a.currentTarget||a.srcElement).readyState))N=null,a=I(a),i.completeLoad(a.id)},
|
||||
onScriptError:function(a){var b=I(a);if(!e(b.id))return w(C("scripterror","Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var g,x,y,D,I,E,N,J,s,O,ka=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,la=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,Q=/\.js$/,ia=/^\.\//;x=Object.prototype;var K=x.toString,fa=x.hasOwnProperty,ha=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),ea=!z&&"undefined"!==typeof importScripts,ja=
|
||||
z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,Y="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},q={},R=[],M=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;q=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(q=require,require=void 0);g=requirejs=function(b,c,d,e){var n,p="_";!H(b)&&"string"!==typeof b&&(n=b,H(c)?(b=c,c=d,d=e):b=[]);n&&n.context&&(p=n.context);(e=m(F,p))||(e=F[p]=g.s.newContext(p));
|
||||
n&&e.configure(n);return e.require(b,c,d)};g.config=function(b){return g(b)};g.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=g);g.version="2.1.16";g.jsExtRegExp=/^\/|:|\?|\.js$/;g.isBrowser=z;x=g.s={contexts:F,newContext:ga};g({});v(["toUrl","undef","defined","specified"],function(b){g[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=
|
||||
x.head=D.parentNode;g.onError=ca;g.createNode=function(b){var c=b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};g.load=function(b,c,d){var e=b&&b.config||{};if(z)return e=g.createNode(e,c,d),e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",c),e.attachEvent&&!(e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code"))&&
|
||||
!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),
|
||||
s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===
|
||||
b.readyState)return N=b}),e=N;e&&(b||(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);
|
||||
@@ -0,0 +1,4 @@
|
||||
<article>
|
||||
<h3><a href="{{location}}">{{title}}</a></h3>
|
||||
<p>{{summary}}</p>
|
||||
</article>
|
||||
@@ -0,0 +1,88 @@
|
||||
require([
|
||||
base_url + '/mkdocs/js/mustache.min.js',
|
||||
base_url + '/mkdocs/js/lunr.min.js',
|
||||
'text!search-results-template.mustache',
|
||||
'text!../search_index.json',
|
||||
], function (Mustache, lunr, results_template, data) {
|
||||
"use strict";
|
||||
|
||||
function getSearchTerm()
|
||||
{
|
||||
var sPageURL = window.location.search.substring(1);
|
||||
var sURLVariables = sPageURL.split('&');
|
||||
for (var i = 0; i < sURLVariables.length; i++)
|
||||
{
|
||||
var sParameterName = sURLVariables[i].split('=');
|
||||
if (sParameterName[0] == 'q')
|
||||
{
|
||||
return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var index = lunr(function () {
|
||||
this.field('title', {boost: 10});
|
||||
this.field('text');
|
||||
this.ref('location');
|
||||
});
|
||||
|
||||
data = JSON.parse(data);
|
||||
var documents = {};
|
||||
|
||||
for (var i=0; i < data.docs.length; i++){
|
||||
var doc = data.docs[i];
|
||||
doc.location = base_url + doc.location;
|
||||
index.add(doc);
|
||||
documents[doc.location] = doc;
|
||||
}
|
||||
|
||||
var search = function(){
|
||||
|
||||
var query = document.getElementById('mkdocs-search-query').value;
|
||||
var search_results = document.getElementById("mkdocs-search-results");
|
||||
while (search_results.firstChild) {
|
||||
search_results.removeChild(search_results.firstChild);
|
||||
}
|
||||
|
||||
if(query === ''){
|
||||
return;
|
||||
}
|
||||
|
||||
var results = index.search(query);
|
||||
|
||||
if (results.length > 0){
|
||||
for (var i=0; i < results.length; i++){
|
||||
var result = results[i];
|
||||
doc = documents[result.ref];
|
||||
doc.base_url = base_url;
|
||||
doc.summary = doc.text.substring(0, 200);
|
||||
var html = Mustache.to_html(results_template, doc);
|
||||
search_results.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
} else {
|
||||
search_results.insertAdjacentHTML('beforeend', "<p>No results found</p>");
|
||||
}
|
||||
|
||||
if(jQuery){
|
||||
/*
|
||||
* We currently only automatically hide bootstrap models. This
|
||||
* requires jQuery to work.
|
||||
*/
|
||||
jQuery('#mkdocs_search_modal a').click(function(){
|
||||
jQuery('#mkdocs_search_modal').modal('hide');
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var search_input = document.getElementById('mkdocs-search-query');
|
||||
|
||||
var term = getSearchTerm();
|
||||
if (term){
|
||||
search_input.value = term;
|
||||
search();
|
||||
}
|
||||
|
||||
search_input.addEventListener("keyup", search);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,390 @@
|
||||
/**
|
||||
* @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT or new BSD license.
|
||||
* see: http://github.com/requirejs/text for details
|
||||
*/
|
||||
/*jslint regexp: true */
|
||||
/*global require, XMLHttpRequest, ActiveXObject,
|
||||
define, window, process, Packages,
|
||||
java, location, Components, FileUtils */
|
||||
|
||||
define(['module'], function (module) {
|
||||
'use strict';
|
||||
|
||||
var text, fs, Cc, Ci, xpcIsWindows,
|
||||
progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
|
||||
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
|
||||
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
|
||||
hasLocation = typeof location !== 'undefined' && location.href,
|
||||
defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
|
||||
defaultHostName = hasLocation && location.hostname,
|
||||
defaultPort = hasLocation && (location.port || undefined),
|
||||
buildMap = {},
|
||||
masterConfig = (module.config && module.config()) || {};
|
||||
|
||||
text = {
|
||||
version: '2.0.12',
|
||||
|
||||
strip: function (content) {
|
||||
//Strips <?xml ...?> declarations so that external SVG and XML
|
||||
//documents can be added to a document without worry. Also, if the string
|
||||
//is an HTML document, only the part inside the body tag is returned.
|
||||
if (content) {
|
||||
content = content.replace(xmlRegExp, "");
|
||||
var matches = content.match(bodyRegExp);
|
||||
if (matches) {
|
||||
content = matches[1];
|
||||
}
|
||||
} else {
|
||||
content = "";
|
||||
}
|
||||
return content;
|
||||
},
|
||||
|
||||
jsEscape: function (content) {
|
||||
return content.replace(/(['\\])/g, '\\$1')
|
||||
.replace(/[\f]/g, "\\f")
|
||||
.replace(/[\b]/g, "\\b")
|
||||
.replace(/[\n]/g, "\\n")
|
||||
.replace(/[\t]/g, "\\t")
|
||||
.replace(/[\r]/g, "\\r")
|
||||
.replace(/[\u2028]/g, "\\u2028")
|
||||
.replace(/[\u2029]/g, "\\u2029");
|
||||
},
|
||||
|
||||
createXhr: masterConfig.createXhr || function () {
|
||||
//Would love to dump the ActiveX crap in here. Need IE 6 to die first.
|
||||
var xhr, i, progId;
|
||||
if (typeof XMLHttpRequest !== "undefined") {
|
||||
return new XMLHttpRequest();
|
||||
} else if (typeof ActiveXObject !== "undefined") {
|
||||
for (i = 0; i < 3; i += 1) {
|
||||
progId = progIds[i];
|
||||
try {
|
||||
xhr = new ActiveXObject(progId);
|
||||
} catch (e) {}
|
||||
|
||||
if (xhr) {
|
||||
progIds = [progId]; // so faster next time
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xhr;
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a resource name into its component parts. Resource names
|
||||
* look like: module/name.ext!strip, where the !strip part is
|
||||
* optional.
|
||||
* @param {String} name the resource name
|
||||
* @returns {Object} with properties "moduleName", "ext" and "strip"
|
||||
* where strip is a boolean.
|
||||
*/
|
||||
parseName: function (name) {
|
||||
var modName, ext, temp,
|
||||
strip = false,
|
||||
index = name.indexOf("."),
|
||||
isRelative = name.indexOf('./') === 0 ||
|
||||
name.indexOf('../') === 0;
|
||||
|
||||
if (index !== -1 && (!isRelative || index > 1)) {
|
||||
modName = name.substring(0, index);
|
||||
ext = name.substring(index + 1, name.length);
|
||||
} else {
|
||||
modName = name;
|
||||
}
|
||||
|
||||
temp = ext || modName;
|
||||
index = temp.indexOf("!");
|
||||
if (index !== -1) {
|
||||
//Pull off the strip arg.
|
||||
strip = temp.substring(index + 1) === "strip";
|
||||
temp = temp.substring(0, index);
|
||||
if (ext) {
|
||||
ext = temp;
|
||||
} else {
|
||||
modName = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
moduleName: modName,
|
||||
ext: ext,
|
||||
strip: strip
|
||||
};
|
||||
},
|
||||
|
||||
xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
|
||||
|
||||
/**
|
||||
* Is an URL on another domain. Only works for browser use, returns
|
||||
* false in non-browser environments. Only used to know if an
|
||||
* optimized .js version of a text resource should be loaded
|
||||
* instead.
|
||||
* @param {String} url
|
||||
* @returns Boolean
|
||||
*/
|
||||
useXhr: function (url, protocol, hostname, port) {
|
||||
var uProtocol, uHostName, uPort,
|
||||
match = text.xdRegExp.exec(url);
|
||||
if (!match) {
|
||||
return true;
|
||||
}
|
||||
uProtocol = match[2];
|
||||
uHostName = match[3];
|
||||
|
||||
uHostName = uHostName.split(':');
|
||||
uPort = uHostName[1];
|
||||
uHostName = uHostName[0];
|
||||
|
||||
return (!uProtocol || uProtocol === protocol) &&
|
||||
(!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&
|
||||
((!uPort && !uHostName) || uPort === port);
|
||||
},
|
||||
|
||||
finishLoad: function (name, strip, content, onLoad) {
|
||||
content = strip ? text.strip(content) : content;
|
||||
if (masterConfig.isBuild) {
|
||||
buildMap[name] = content;
|
||||
}
|
||||
onLoad(content);
|
||||
},
|
||||
|
||||
load: function (name, req, onLoad, config) {
|
||||
//Name has format: some.module.filext!strip
|
||||
//The strip part is optional.
|
||||
//if strip is present, then that means only get the string contents
|
||||
//inside a body tag in an HTML string. For XML/SVG content it means
|
||||
//removing the <?xml ...?> declarations so the content can be inserted
|
||||
//into the current doc without problems.
|
||||
|
||||
// Do not bother with the work if a build and text will
|
||||
// not be inlined.
|
||||
if (config && config.isBuild && !config.inlineText) {
|
||||
onLoad();
|
||||
return;
|
||||
}
|
||||
|
||||
masterConfig.isBuild = config && config.isBuild;
|
||||
|
||||
var parsed = text.parseName(name),
|
||||
nonStripName = parsed.moduleName +
|
||||
(parsed.ext ? '.' + parsed.ext : ''),
|
||||
url = req.toUrl(nonStripName),
|
||||
useXhr = (masterConfig.useXhr) ||
|
||||
text.useXhr;
|
||||
|
||||
// Do not load if it is an empty: url
|
||||
if (url.indexOf('empty:') === 0) {
|
||||
onLoad();
|
||||
return;
|
||||
}
|
||||
|
||||
//Load the text. Use XHR if possible and in a browser.
|
||||
if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
|
||||
text.get(url, function (content) {
|
||||
text.finishLoad(name, parsed.strip, content, onLoad);
|
||||
}, function (err) {
|
||||
if (onLoad.error) {
|
||||
onLoad.error(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//Need to fetch the resource across domains. Assume
|
||||
//the resource has been optimized into a JS module. Fetch
|
||||
//by the module name + extension, but do not include the
|
||||
//!strip part to avoid file system issues.
|
||||
req([nonStripName], function (content) {
|
||||
text.finishLoad(parsed.moduleName + '.' + parsed.ext,
|
||||
parsed.strip, content, onLoad);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
write: function (pluginName, moduleName, write, config) {
|
||||
if (buildMap.hasOwnProperty(moduleName)) {
|
||||
var content = text.jsEscape(buildMap[moduleName]);
|
||||
write.asModule(pluginName + "!" + moduleName,
|
||||
"define(function () { return '" +
|
||||
content +
|
||||
"';});\n");
|
||||
}
|
||||
},
|
||||
|
||||
writeFile: function (pluginName, moduleName, req, write, config) {
|
||||
var parsed = text.parseName(moduleName),
|
||||
extPart = parsed.ext ? '.' + parsed.ext : '',
|
||||
nonStripName = parsed.moduleName + extPart,
|
||||
//Use a '.js' file name so that it indicates it is a
|
||||
//script that can be loaded across domains.
|
||||
fileName = req.toUrl(parsed.moduleName + extPart) + '.js';
|
||||
|
||||
//Leverage own load() method to load plugin value, but only
|
||||
//write out values that do not have the strip argument,
|
||||
//to avoid any potential issues with ! in file names.
|
||||
text.load(nonStripName, req, function (value) {
|
||||
//Use own write() method to construct full module value.
|
||||
//But need to create shell that translates writeFile's
|
||||
//write() to the right interface.
|
||||
var textWrite = function (contents) {
|
||||
return write(fileName, contents);
|
||||
};
|
||||
textWrite.asModule = function (moduleName, contents) {
|
||||
return write.asModule(moduleName, fileName, contents);
|
||||
};
|
||||
|
||||
text.write(pluginName, nonStripName, textWrite, config);
|
||||
}, config);
|
||||
}
|
||||
};
|
||||
|
||||
if (masterConfig.env === 'node' || (!masterConfig.env &&
|
||||
typeof process !== "undefined" &&
|
||||
process.versions &&
|
||||
!!process.versions.node &&
|
||||
!process.versions['node-webkit'])) {
|
||||
//Using special require.nodeRequire, something added by r.js.
|
||||
fs = require.nodeRequire('fs');
|
||||
|
||||
text.get = function (url, callback, errback) {
|
||||
try {
|
||||
var file = fs.readFileSync(url, 'utf8');
|
||||
//Remove BOM (Byte Mark Order) from utf8 files if it is there.
|
||||
if (file.indexOf('\uFEFF') === 0) {
|
||||
file = file.substring(1);
|
||||
}
|
||||
callback(file);
|
||||
} catch (e) {
|
||||
if (errback) {
|
||||
errback(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if (masterConfig.env === 'xhr' || (!masterConfig.env &&
|
||||
text.createXhr())) {
|
||||
text.get = function (url, callback, errback, headers) {
|
||||
var xhr = text.createXhr(), header;
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
//Allow plugins direct access to xhr headers
|
||||
if (headers) {
|
||||
for (header in headers) {
|
||||
if (headers.hasOwnProperty(header)) {
|
||||
xhr.setRequestHeader(header.toLowerCase(), headers[header]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Allow overrides specified in config
|
||||
if (masterConfig.onXhr) {
|
||||
masterConfig.onXhr(xhr, url);
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = function (evt) {
|
||||
var status, err;
|
||||
//Do not explicitly handle errors, those should be
|
||||
//visible via console output in the browser.
|
||||
if (xhr.readyState === 4) {
|
||||
status = xhr.status || 0;
|
||||
if (status > 399 && status < 600) {
|
||||
//An http 4xx or 5xx error. Signal an error.
|
||||
err = new Error(url + ' HTTP status: ' + status);
|
||||
err.xhr = xhr;
|
||||
if (errback) {
|
||||
errback(err);
|
||||
}
|
||||
} else {
|
||||
callback(xhr.responseText);
|
||||
}
|
||||
|
||||
if (masterConfig.onXhrComplete) {
|
||||
masterConfig.onXhrComplete(xhr, url);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
};
|
||||
} else if (masterConfig.env === 'rhino' || (!masterConfig.env &&
|
||||
typeof Packages !== 'undefined' && typeof java !== 'undefined')) {
|
||||
//Why Java, why is this so awkward?
|
||||
text.get = function (url, callback) {
|
||||
var stringBuffer, line,
|
||||
encoding = "utf-8",
|
||||
file = new java.io.File(url),
|
||||
lineSeparator = java.lang.System.getProperty("line.separator"),
|
||||
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
|
||||
content = '';
|
||||
try {
|
||||
stringBuffer = new java.lang.StringBuffer();
|
||||
line = input.readLine();
|
||||
|
||||
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
|
||||
// http://www.unicode.org/faq/utf_bom.html
|
||||
|
||||
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
|
||||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
|
||||
if (line && line.length() && line.charAt(0) === 0xfeff) {
|
||||
// Eat the BOM, since we've already found the encoding on this file,
|
||||
// and we plan to concatenating this buffer with others; the BOM should
|
||||
// only appear at the top of a file.
|
||||
line = line.substring(1);
|
||||
}
|
||||
|
||||
if (line !== null) {
|
||||
stringBuffer.append(line);
|
||||
}
|
||||
|
||||
while ((line = input.readLine()) !== null) {
|
||||
stringBuffer.append(lineSeparator);
|
||||
stringBuffer.append(line);
|
||||
}
|
||||
//Make sure we return a JavaScript string and not a Java string.
|
||||
content = String(stringBuffer.toString()); //String
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
callback(content);
|
||||
};
|
||||
} else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&
|
||||
typeof Components !== 'undefined' && Components.classes &&
|
||||
Components.interfaces)) {
|
||||
//Avert your gaze!
|
||||
Cc = Components.classes;
|
||||
Ci = Components.interfaces;
|
||||
Components.utils['import']('resource://gre/modules/FileUtils.jsm');
|
||||
xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);
|
||||
|
||||
text.get = function (url, callback) {
|
||||
var inStream, convertStream, fileObj,
|
||||
readData = {};
|
||||
|
||||
if (xpcIsWindows) {
|
||||
url = url.replace(/\//g, '\\');
|
||||
}
|
||||
|
||||
fileObj = new FileUtils.File(url);
|
||||
|
||||
//XPCOM, you so crazy
|
||||
try {
|
||||
inStream = Cc['@mozilla.org/network/file-input-stream;1']
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
inStream.init(fileObj, 1, 0, false);
|
||||
|
||||
convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
|
||||
.createInstance(Ci.nsIConverterInputStream);
|
||||
convertStream.init(inStream, "utf-8", inStream.available(),
|
||||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
|
||||
convertStream.readString(inStream.available(), readData);
|
||||
convertStream.close();
|
||||
inStream.close();
|
||||
callback(readData.value);
|
||||
} catch (e) {
|
||||
throw new Error((fileObj && fileObj.path || '') + ': ' + e);
|
||||
}
|
||||
};
|
||||
}
|
||||
return text;
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -1,228 +0,0 @@
|
||||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Profiled execution.
|
||||
profile=no
|
||||
|
||||
# Add <file or directory> to the black list. It should be a base name, not a
|
||||
# path. You may set this option multiple times.
|
||||
ignore=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
enable=indexing-exception,old-raise-syntax
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,wrong-import-order,useless-object-inheritance,no-else-return
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html
|
||||
output-format=text
|
||||
|
||||
# Include message's id in output
|
||||
include-ids=no
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (R0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Add a comment according to your evaluation note. This is used by the global
|
||||
# evaluation report (R0004).
|
||||
comment=no
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching names used for dummy variables (i.e. not used).
|
||||
dummy-variables-rgx=\*{0,2}(_$|unused_|dummy_)
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=map,filter,apply,input,reduce
|
||||
|
||||
# Regular expression which should only match correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression which should only match correct module level names
|
||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression which should only match correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression which should only match correct function names
|
||||
function-rgx=^(?:(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
|
||||
|
||||
# Regular expression which should only match correct method names
|
||||
method-rgx=^(?:(?P<exempt>__[a-z0-9_]+__|next)|(?P<camel_case>_{0,2}(?:test|assert)?[A-Z][a-zA-Z0-9]*)|(?:_{0,2}[a-z][a-z0-9_]*))$
|
||||
|
||||
# Regular expression which should only match correct instance attribute names
|
||||
attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression which should only match correct argument names
|
||||
argument-rgx=^[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression which should only match correct variable names
|
||||
variable-rgx=^[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression which should only match correct list comprehension /
|
||||
# generator expression variable names
|
||||
inlinevar-rgx=^[a-z][a-z0-9_]*$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,main,Run,_
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Regular expression which should only match functions or classes name which do
|
||||
# not require a docstring
|
||||
no-docstring-rgx=(__.*__|main|test.*|.*Test)
|
||||
|
||||
# Minimum length for a docstring
|
||||
docstring-min-length=10
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=80
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=99999
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of classes names for which member attributes should not be checked
|
||||
# (useful for classes with attributes dynamically set).
|
||||
ignored-classes=
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E0201 when accessed.
|
||||
generated-members=
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branchs=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
||||
@@ -1 +0,0 @@
|
||||
.
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="./img/favicon.ico">
|
||||
<title>Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="./css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="./css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="./css/highlight.css">
|
||||
|
||||
<script src="./js/jquery-2.1.1.min.js"></script>
|
||||
<script src="./js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="./js/highlight.pack.js"></script>
|
||||
<script>var base_url = '.';</script>
|
||||
<script data-main="./mkdocs/js/search.js" src="./mkdocs/js/require.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href="." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="./search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href=".">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href=".">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href=".">Docs</a> »</li>
|
||||
|
||||
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
|
||||
<h1 id="search">Search Results</h1>
|
||||
|
||||
<form id="content_search" action="search.html">
|
||||
<span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span>
|
||||
<input name="q" id="mkdocs-search-query" type="text" class="search_input search-query ui-autocomplete-input" placeholder="Search the Docs" autocomplete="off" autofocus>
|
||||
</form>
|
||||
|
||||
<div id="mkdocs-search-results" class="search-results">
|
||||
Searching...
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="./js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,11 +0,0 @@
|
||||
[metadata]
|
||||
license-file = LICENSE
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
||||
|
||||
[aliases]
|
||||
test = pytest
|
||||
|
||||
[tool:pytest]
|
||||
addopts = --ignore=fire/test_components_py3.py --ignore=fire/parser_fuzz_test.py
|
||||
@@ -1,84 +0,0 @@
|
||||
# Copyright (C) 2018 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""The setup.py file for Python Fire."""
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
LONG_DESCRIPTION = """
|
||||
Python Fire is a library for automatically generating command line interfaces
|
||||
(CLIs) with a single line of code.
|
||||
|
||||
It will turn any Python module, class, object, function, etc. (any Python
|
||||
component will work!) into a CLI. It's called Fire because when you call Fire(),
|
||||
it fires off your command.
|
||||
""".strip()
|
||||
|
||||
SHORT_DESCRIPTION = """
|
||||
A library for automatically generating command line interfaces.""".strip()
|
||||
|
||||
DEPENDENCIES = [
|
||||
'six',
|
||||
]
|
||||
|
||||
TEST_DEPENDENCIES = [
|
||||
'hypothesis',
|
||||
'mock',
|
||||
'python-Levenshtein',
|
||||
]
|
||||
|
||||
VERSION = '0.1.3'
|
||||
URL = 'https://github.com/google/python-fire'
|
||||
|
||||
setup(
|
||||
name='fire',
|
||||
version=VERSION,
|
||||
description=SHORT_DESCRIPTION,
|
||||
long_description=LONG_DESCRIPTION,
|
||||
url=URL,
|
||||
|
||||
author='David Bieber',
|
||||
author_email='dbieber@google.com',
|
||||
license='Apache Software License',
|
||||
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
|
||||
'Intended Audience :: Developers',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
|
||||
'Operating System :: OS Independent',
|
||||
'Operating System :: POSIX',
|
||||
'Operating System :: MacOS',
|
||||
'Operating System :: Unix',
|
||||
],
|
||||
|
||||
keywords='command line interface cli python fire interactive bash tool',
|
||||
|
||||
packages=['fire'],
|
||||
|
||||
install_requires=DEPENDENCIES,
|
||||
tests_require=TEST_DEPENDENCIES,
|
||||
)
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/installation/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/benefits/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/guide/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/using-cli/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/troubleshooting/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
|
||||
<url>
|
||||
<loc>/api/</loc>
|
||||
<lastmod>2018-02-23</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
|
||||
|
||||
</urlset>
|
||||
@@ -0,0 +1,185 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||
<title>Troubleshooting - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "Troubleshooting";
|
||||
var mkdocs_page_input_path = "troubleshooting.md";
|
||||
var mkdocs_page_url = "/troubleshooting/";
|
||||
</script>
|
||||
|
||||
<script src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script src="../js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href=".." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="..">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../using-cli/">Using a CLI</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href="./">Troubleshooting</a>
|
||||
<ul class="subnav">
|
||||
|
||||
<li class="toctree-l2"><a href="#troubleshooting">Troubleshooting</a></li>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><a class="toctree-l3" href="#issue-19-dont-name-your-module-cmd">Issue #19: Don't name your module "cmd"</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="..">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="..">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>Troubleshooting</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<h1 id="troubleshooting">Troubleshooting</h1>
|
||||
<p>This page describes known issues that users of Python Fire have run into. If you
|
||||
have an issue not resolved here, consider opening a
|
||||
<a href="https://github.com/google/python-fire/issues">GitHub Issue</a>.</p>
|
||||
<h3 id="issue-19-dont-name-your-module-cmd">Issue <a href="https://github.com/google/python-fire/issues/19">#19</a>: Don't name your module "cmd"</h3>
|
||||
<p>If you have a module name that conflicts with the name of a builtin module, then
|
||||
when Fire goes to import the builtin module, it will import your module instead.
|
||||
This will result in an error, possibly an <code>AttributeError</code>. Specifically, do not
|
||||
name your module any of the following:
|
||||
sys, linecache, cmd, bdb, repr, os, re, pprint, traceback</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
<a href="../api/" class="btn btn-neutral float-right" title="Reference">Next <span class="icon icon-circle-arrow-right"></span></a>
|
||||
|
||||
|
||||
<a href="../using-cli/" class="btn btn-neutral" title="Using a CLI"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
<span><a href="../using-cli/" style="color: #fcfcfc;">« Previous</a></span>
|
||||
|
||||
|
||||
<span style="margin-left: 15px"><a href="../api/" style="color: #fcfcfc">Next »</a></span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="../js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||
<title>Using a CLI - Python Fire</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../css/highlight.css">
|
||||
|
||||
<script>
|
||||
// Current page data
|
||||
var mkdocs_page_name = "Using a CLI";
|
||||
var mkdocs_page_input_path = "using-cli.md";
|
||||
var mkdocs_page_url = "/using-cli/";
|
||||
</script>
|
||||
|
||||
<script src="../js/jquery-2.1.1.min.js"></script>
|
||||
<script src="../js/modernizr-2.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="../js/highlight.pack.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="wy-body-for-nav" role="document">
|
||||
|
||||
<div class="wy-grid-for-nav">
|
||||
|
||||
|
||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
|
||||
<div class="wy-side-nav-search">
|
||||
<a href=".." class="icon icon-home"> Python Fire</a>
|
||||
<div role="search">
|
||||
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
|
||||
<input type="text" name="q" placeholder="Search docs" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||
<ul class="current">
|
||||
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="..">Overview</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../installation/">Installation</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../benefits/">Benefits</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../guide/">The Python Fire Guide</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1 current">
|
||||
|
||||
<a class="current" href="./">Using a CLI</a>
|
||||
<ul class="subnav">
|
||||
|
||||
<li class="toctree-l2"><a href="#using-a-fire-cli">Using a Fire CLI</a></li>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><a class="toctree-l3" href="#basic-usage">Basic usage</a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#using-flags-with-fire-clis">Using Flags with Fire CLIs </a></li>
|
||||
|
||||
<li><a class="toctree-l3" href="#python-fires-flags">Python Fire's Flags</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../troubleshooting/">Troubleshooting</a>
|
||||
</li>
|
||||
|
||||
<li class="toctree-l1">
|
||||
|
||||
<a class="" href="../api/">Reference</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||
|
||||
|
||||
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
|
||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||
<a href="..">Python Fire</a>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="wy-nav-content">
|
||||
<div class="rst-content">
|
||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||
<ul class="wy-breadcrumbs">
|
||||
<li><a href="..">Docs</a> »</li>
|
||||
|
||||
|
||||
|
||||
<li>Using a CLI</li>
|
||||
<li class="wy-breadcrumbs-aside">
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
</div>
|
||||
<div role="main">
|
||||
<div class="section">
|
||||
|
||||
<h1 id="using-a-fire-cli">Using a Fire CLI</h1>
|
||||
<h2 id="basic-usage">Basic usage</h2>
|
||||
<p>Every Fire command corresponds to a Python component.</p>
|
||||
<p>The simplest Fire command consists of running your program with no additional
|
||||
arguments. This command corresponds to the Python component you called the
|
||||
<code>Fire</code> function on. If you did not supply an object in the call to <code>Fire</code>, then
|
||||
the context in which <code>Fire</code> was called will be used as the Python component.</p>
|
||||
<p>You can append <code>-- --help</code> to any command to see what Python component it
|
||||
corresponds to, as well as the various ways in which you can extend the command.
|
||||
Flags are always separated from the Fire command by an isolated <code>--</code> in order
|
||||
to distinguish between flags and named arguments.</p>
|
||||
<p>Given a Fire command that corresponds to a Python object, you can extend that
|
||||
command to access a member of that object, call it with arguments if it is a
|
||||
function, instantiate it if it is a class, or index into it if it is a list.</p>
|
||||
<p>Read on to learn about how you can write a Fire command corresponding to
|
||||
whatever Python component you're looking for.</p>
|
||||
<h3 id="accessing-members-of-an-object">Accessing members of an object</h3>
|
||||
<p>If your command corresponds to an object, you can extend your command by adding
|
||||
the name of a member of that object as a new argument to the command. The
|
||||
resulting command will correspond to that member.</p>
|
||||
<p>For example, if the object your command corresponds to has a method defined on
|
||||
it named 'whack', then you can add the argument 'whack' to your command, and the
|
||||
resulting new command corresponds to the whack method.</p>
|
||||
<p>As another example, if the object your command corresponds to has a property
|
||||
named high_score, then you can add the argument 'high-score' to your command,
|
||||
and the resulting new command corresponds to the value of the high_score
|
||||
property.</p>
|
||||
<h3 id="accessing-members-of-a-dict">Accessing members of a dict</h3>
|
||||
<p>If your command corresponds to a dict, you can extend your command by adding
|
||||
the name of one of the dict's keys as an argument.</p>
|
||||
<p>For example, <code>widget function-that-returns-dict key</code> will correspond to the
|
||||
value of the item with key <code>key</code> in the dict returned by
|
||||
<code>function_that_returns_dict</code>.</p>
|
||||
<h3 id="accessing-members-of-a-list-or-tuple">Accessing members of a list or tuple</h3>
|
||||
<p>If your command corresponds to a list or tuple, you can extend your command by
|
||||
adding the index of an element of the component to your command as an argument.</p>
|
||||
<p>For example, <code>widget function-that-returns-list 2</code> will correspond to item 2 of
|
||||
the result of function_that_returns_list.</p>
|
||||
<h3 id="calling-a-function">Calling a function</h3>
|
||||
<p>If your command corresponds to a function, you can extend your command by adding
|
||||
the arguments of this function. Arguments can be specified positionally, or by
|
||||
name. To specify an argument by name, use flag syntax.</p>
|
||||
<p>For example, suppose your <code>command</code> corresponds to the function <code>double</code>:</p>
|
||||
<pre><code class="python">def double(value=0):
|
||||
return 2 * value
|
||||
</code></pre>
|
||||
|
||||
<p>Then you can extend your command using named arguments as <code>command --value 5</code>,
|
||||
or using positional arguments as <code>command 5</code>. In both cases, the new command
|
||||
corresponds to the result of the function, in this case the number 10.</p>
|
||||
<p>You can force a function that takes a variable number of arguments to be
|
||||
evaluated by adding a separator (the default separator is the hyphen, "-"). This
|
||||
will prevent arguments to the right of the separator from being consumed for
|
||||
calling the function. This is useful if the function has arguments with default
|
||||
values, or if the function accepts *varargs, or if the function accepts
|
||||
**kwargs.</p>
|
||||
<p>See also the section on <a href="#separator-flag">Changing the Separator</a>.</p>
|
||||
<h3 id="instantiating-a-class">Instantiating a class</h3>
|
||||
<p>If your command corresponds to a class, you can extend your command by adding
|
||||
the arguments of the class's __init__ function. Arguments must be specified
|
||||
by name, using the flags syntax. See the section on
|
||||
<a href="#calling-a-function">calling a function</a> for more details.</p>
|
||||
<h2 id="using-flags-with-fire-clis">Using Flags with Fire CLIs <a name="using-flags"></a></h2>
|
||||
<p>Command line arguments to a Fire CLI are normally consumed by Fire, as described
|
||||
in the <a href="#basic-usage">Basic Usage</a> section. In order to set Flags, put the flags
|
||||
after the final standalone <code>--</code> argument. (If there is no <code>--</code> argument, then no
|
||||
arguments are used for flags.)</p>
|
||||
<p>For example, to set the alsologtostderr flag, you could run the command:
|
||||
<code>widget bang --noise=boom -- --alsologtostderr</code>. The --noise argument is
|
||||
consumed by Fire, but the --alsologtostderr argument is treated as a normal
|
||||
Flag.</p>
|
||||
<p>All CLIs built with Python Fire share some flags, as described in the next
|
||||
sections.</p>
|
||||
<h2 id="python-fires-flags">Python Fire's Flags</h2>
|
||||
<p>As described in the <a href="#using-flags">Using Flags</a> section, you must add an
|
||||
isolated <code>--</code> argument in order to have arguments treated as Flags rather than
|
||||
be consumed by Python Fire. All arguments to a Fire CLI after the final
|
||||
standalone <code>--</code> argument are treated as Flags.</p>
|
||||
<p>The following flags are accepted by all Fire CLIs:
|
||||
<a href="#interactive-flag"><code>--interactive</code>/<code>-i</code></a>,
|
||||
<a href="#help-flag"><code>--help</code>/<code>-h</code></a>,
|
||||
<a href="#separator-flag"><code>--separator</code></a>,
|
||||
<a href="#completion-flag"><code>--completion</code></a>,
|
||||
<a href="#trace-flag"><code>--trace</code></a>,
|
||||
and <a href="#verbose-flag"><code>--verbose</code>/<code>-v</code></a>,
|
||||
as described in the following sections.</p>
|
||||
<h3 id="-interactive-interactive-mode"><code>--interactive</code>: Interactive mode <a name="interactive-flag"></a></h3>
|
||||
<p>Call <code>widget -- --interactive</code> or <code>widget -- -i</code> to enter interactive mode. This
|
||||
will put you in an IPython REPL, with the variable <code>widget</code> already defined.</p>
|
||||
<p>You can then explore the Python object that <code>widget</code> corresponds to
|
||||
interactively using Python.</p>
|
||||
<h3 id="-completion-generating-a-completion-script"><code>--completion</code>: Generating a completion script <a name="completion-flag"></a></h3>
|
||||
<p>Call <code>widget -- --completion</code> to generate a completion script for the Fire CLI
|
||||
<code>widget</code>. To save the completion script to your home directory, you could e.g.
|
||||
run <code>widget -- --completion > ~/.widget-completion</code>. You should then source this
|
||||
file; to get permanent completion, source this file from your .bashrc file.</p>
|
||||
<p>If the commands available in the Fire CLI change, you'll have to regenerate the
|
||||
completion script and source it again.</p>
|
||||
<h3 id="-help-getting-help"><code>--help</code>: Getting help <a name="help-flag"></a></h3>
|
||||
<p>Let say you have a command line tool named <code>widget</code> that was made with Fire. How
|
||||
do you use this Fire CLI?</p>
|
||||
<p>The simplest way to get started is to run <code>widget -- --help</code>. This will give you
|
||||
usage information for your CLI. You can always append <code>-- --help</code> to any Fire
|
||||
command in order to get usage information for that command and any subcommands.</p>
|
||||
<p>Additionally, help will be displayed if you hit an error using Fire. For
|
||||
example, if you try to pass too many or too few arguments to a function, then
|
||||
help will be displayed. Similarly, if you try to access a member that does not
|
||||
exist, or if you index into a list with too high an index, then help will be
|
||||
displayed.</p>
|
||||
<p>The displayed help shows information about which Python component your command
|
||||
corresponds to, as well as usage information for how to extend that command.</p>
|
||||
<h3 id="-trace-getting-a-fire-trace"><code>--trace</code>: Getting a Fire trace <a name="trace-flag"></a></h3>
|
||||
<p>In order to understand what is happening when you call Python Fire, it can be
|
||||
useful to request a trace. This is done via the --trace flag, e.g.
|
||||
<code>widget whack 5 -- --trace</code>.</p>
|
||||
<p>A trace provides step by step information about how the Fire command was
|
||||
executed. In includes which actions were taken, starting with the initial
|
||||
component, leading to the final component represented by the command.</p>
|
||||
<p>A trace is also shown alongside the help if your Fire command reaches an error.</p>
|
||||
<h3 id="-separator-changing-the-separator"><code>--separator</code>: Changing the separator <a name="separator-flag"></a></h3>
|
||||
<p>As described in <a href="#calling-a-function">Calling a Function</a>, you can use a
|
||||
separator argument when writing a command that corresponds to calling a
|
||||
function. The separator will cause the function to be evaluated or the class to
|
||||
be instantiated using only the arguments left of the separator. Arguments right
|
||||
of the separator will then be applied to the result of the function call or to
|
||||
the instantiated object.</p>
|
||||
<p>The default separator is <code>-</code>.</p>
|
||||
<p>If you want to supply the string "-" as an argument, then you will have to
|
||||
change the separator. You can choose a new separator by supplying the
|
||||
<code>--separator</code> flag to Fire.</p>
|
||||
<p>Here's an example to demonstrate separator usage. Let's say you have a function
|
||||
that takes a variable number of args, and you want to call that function, and
|
||||
then upper case the result. Here's how to do it:</p>
|
||||
<pre><code class="python"># Here's the Python function
|
||||
def display(arg1, arg2='!'):
|
||||
return arg1 + arg2
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="bash"># Here's what you can do from Bash (Note: the default separator is the hyphen -)
|
||||
display hello # hello!
|
||||
display hello upper # helloupper
|
||||
display hello - upper # HELLO!
|
||||
display - SEP upper -- --separator SEP # -!
|
||||
</code></pre>
|
||||
|
||||
<p>Notice how in the third and fourth lines, the separator caused the display
|
||||
function to be called with the default value for arg2. In the fourth example,
|
||||
we change the separator to the string "SEP" so that we can pass '-' as an
|
||||
argument.</p>
|
||||
<h3 id="-verbose-verbose-usage"><code>--verbose</code>: Verbose usage <a name="verbose-flag"></a></h3>
|
||||
<p>Adding the <code>-v</code> or <code>--verbose</code> flag turns on verbose mode. This will eg
|
||||
reveal private members in the usage string. Often these members will not
|
||||
actually be usable from the command line tool. As such, verbose mode should be
|
||||
considered a debugging tool, but not fully supported yet.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||
|
||||
<a href="../troubleshooting/" class="btn btn-neutral float-right" title="Troubleshooting">Next <span class="icon icon-circle-arrow-right"></span></a>
|
||||
|
||||
|
||||
<a href="../guide/" class="btn btn-neutral" title="The Python Fire Guide"><span class="icon icon-circle-arrow-left"></span> Previous</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<div role="contentinfo">
|
||||
<!-- Copyright etc -->
|
||||
|
||||
</div>
|
||||
|
||||
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="rst-versions" role="note" style="cursor: pointer">
|
||||
<span class="rst-current-version" data-toggle="rst-current-version">
|
||||
|
||||
|
||||
<span><a href="../guide/" style="color: #fcfcfc;">« Previous</a></span>
|
||||
|
||||
|
||||
<span style="margin-left: 15px"><a href="../troubleshooting/" style="color: #fcfcfc">Next »</a></span>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<script src="../js/theme.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user