Skip to content

Commit

Permalink
feat(cli): Add CLI and add validation commands
Browse files Browse the repository at this point in the history
Adding a CLI that can validate Dragonfly schema JSONs and can be extended by estensions.
  • Loading branch information
chriswmackey authored and Chris Mackey committed Jan 25, 2020
1 parent 1806c15 commit 60ec048
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 12 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tox.ini
/.vscode
.eggs
*.code-workspace
dragonfly.log*
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@
Dragonfly is collection of libraries to model and analyze urban climate, energy use, and daylight.
It extends the capabilites of [honeybee-core](https://github.com/ladybug-tools/honeybee-core) for the urban scale.

This repository is the core repository that provides dragonfly's common functionalities.
To extend these functionalities you should install available Dragonfly extensions or write
your own.

Here are a number of frequently used extensions for Dragonfly:
- [dragonfly-energy](https://github.com/ladybug-tools/dragonfly-energy): Adds Energy simulation to Dragonfly.


## Installation
```console
pip install dragonfly-core
```

## QuickStart
```python
import dragonfly
`pip install -U dragonfly-core`

```
If you want to also include the command line interface try:

`pip install -U dragonfly-core[cli]`

To check if Dragonfly command line is installed correctly try `dragonfly viz` and you
should get a `viiiiiiiiiiiiizzzzzzzzz!` back in response! :bee:

## [API Documentation](https://www.ladybug.tools/dragonfly-core/docs/)

Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ coverage==4.5.2
coveralls==1.5.1
pytest==4.1.0
pytest-cov==2.6.1
click>=5.1
Sphinx==1.8.5
sphinx-bootstrap-theme==0.6.5
sphinxcontrib-fulltoc==1.2.0
Expand Down
6 changes: 6 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dragonfly command line interface
===============================

.. click:: dragonfly.cli:main
:prog: dragonfly
:show-nested:
5 changes: 3 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import sys
import datetime
now = datetime.datetime.now()
sys.path.insert(0, os.path.abspath('../'))
sys.path.insert(0, os.path.abspath('..'))

# -- Project information -----------------------------------------------------

Expand Down Expand Up @@ -49,7 +49,8 @@
'sphinx.ext.viewcode',
'sphinx.ext.githubpages',
'sphinxcontrib.fulltoc',
'sphinx.ext.napoleon'
'sphinx.ext.napoleon',
'sphinx_click.ext'
]

# Add any paths that contain templates here, relative to this directory.
Expand Down
36 changes: 34 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
Welcome to dragonfly-core's documentation!
===================================
Welcome to Dragonfly's documentation!
=========================================

.. image:: http://www.ladybug.tools/assets/img/dragonfly.png

Dragonfly is collection of libraries to model and analyze urban climate, energy
use, and daylight. It extends the capabilites of
`honeybee-core <https://github.com/ladybug-tools/honeybee-core/>`_ for the urban scale.


Installation
============

To install the core library try ``pip install -U dragonfly-core``.

If you want to also include the command line interface try ``pip install -U dragonfly-core[cli]``.

To check if the Dragonfly command line is installed correctly try ``dragonfly viz`` and you
should get a ``viiiiiiiiiiiiizzzzzzzzz!`` back in response!


Documentation
=============

This document includes `Dragonfly API documentation <#dragonfly>`_ and
`Dragonfly Command Line Interface <#id1>`_ documentation for ``dragonfly core`` and does
not include the documentation for dragonfly extensions. For each extension refer to
extension's documentation page.

Here are a number of popular Dragonfly extensions:

- `dragonfly-energy <https://ladybug.tools/dragonfly-energy/docs>`_


.. toctree::
:maxdepth: 2
:caption: Contents:

.. include:: modules.rst
.. include:: cli.rst


Indices and tables
Expand Down
4 changes: 4 additions & 0 deletions dragonfly/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from dragonfly.cli import main

if __name__ == '__main__':
main()
82 changes: 82 additions & 0 deletions dragonfly/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""
Command Line Interface (CLI) entry point for dragonfly and dragonfly extensions.
Use this file only to add commands related to dragonfly-core. For adding extra commands
from each extention see below.
Dragonfly is using click (https://click.palletsprojects.com/en/7.x/) for creating the CLI.
You can extend the command line interface from inside each extention by following these
steps:
1. Create a ``cli`` folder in your extension.
2. Import the ``main`` function from this ``dragonfly.cli``.
3. Add your commands and command groups to main using add_command method.
4. Add ``import [your-extention].cli`` to ``__init__.py`` file to the commands are added
to the cli when the module is loaded.
Good practice is to group all your extention commands in a command group named after
the extension. This will make the commands organized under extension namespace. For
instance commands for `dragonfly-energy` will be called like ``dragonfly energy [energy-command]``.
.. code-block:: python
import click
from dragonfly.cli import main
@click.group()
def energy():
pass
# add commands to energy group
@energy.command('to-idf')
# ...
def to_idf():
pass
# finally add the newly created commands to dragonfly cli
main.add_command(energy)
# do not forget to import this module in __init__.py otherwise it will not be added
# to dragonfly commands.
Note:
For extension with several commands you can use a folder structure instead of a single
file.
"""

try:
import click
except ImportError:
raise ImportError(
'click module is not installed. Try `pip install dragonfly-core[cli]` command.'
)

from dragonfly.cli.validate import validate

import sys
import os
import logging
import json


_logger = logging.getLogger(__name__)


@click.group()
@click.version_option()
def main():
pass


@main.command('viz')
def viz():
"""Check if dragonfly is flying!"""
click.echo('viiiiiiiiiiiiizzzzzzzzz!')


main.add_command(validate)


if __name__ == "__main__":
main()
56 changes: 56 additions & 0 deletions dragonfly/cli/validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""dragonfly validation commands."""

try:
import click
except ImportError:
raise ImportError(
'click is not installed. Try `pip install . [cli]` command.'
)

from dragonfly.model import Model

import sys
import os
import logging
import json

_logger = logging.getLogger(__name__)

try:
import dragonfly_schema.model as schema_model
except ImportError:
_logger.exception(
'dragonfly_schema is not installed. Try `pip install . [cli]` command.'
)


@click.group(help='Commands for validating Dragonfly JSON files.')
def validate():
pass

@validate.command('model')
@click.argument('model-json')
def validate_model(model_json):
"""Validate a Model JSON file against the Dragonfly schema.
\b
Args:
model_json: Full path to a Model JSON file.
"""
try:
assert os.path.isfile(model_json), 'No JSON file found at {}.'.format(model_json)

# validate the Model JSON
click.echo('Validating Model JSON ...')
schema_model.Model.parse_file(model_json)
click.echo('Pydantic validation passed.')
with open(model_json) as json_file:
data = json.load(json_file)
parsed_model = Model.from_dict(data)
parsed_model.check_missing_adjacencies(raise_exception=True)
click.echo('Python re-serialization passed.')
click.echo('Congratulations! Yout Model JSON is valid!')
except Exception as e:
_logger.exception('Model validation failed.\n{}'.format(e))
sys.exit(1)
else:
sys.exit(0)
8 changes: 7 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

setuptools.setup(
name="dragonfly-core",
use_scm_version = True,
use_scm_version=True,
setup_requires=['setuptools_scm'],
author="Ladybug Tools",
author_email="[email protected]",
Expand All @@ -20,6 +20,12 @@
url="https://github.com/ladybug-tools/dragonfly-core",
packages=setuptools.find_packages(exclude=["tests"]),
install_requires=requirements,
extra_requires={
'cli': ['click>=5.1', 'dragonfly-schema>=1.2.0']
},
entry_points={
"console_scripts": ["dragonfly = dragonfly.cli:main"]
},
classifiers=[
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.6",
Expand Down
12 changes: 12 additions & 0 deletions tests/cli_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Test cli."""

from click.testing import CliRunner
from dragonfly.cli import viz


def test_viz():
runner = CliRunner()
result = runner.invoke(viz)
assert result.exit_code == 0
assert result.output.startswith('vi')
assert result.output.endswith('z!\n')

0 comments on commit 60ec048

Please sign in to comment.