Skip to content

Commit

Permalink
Cli (#110) (#111)
Browse files Browse the repository at this point in the history
* add command line utility

* fix create --list

* WIP: add examples as package data

* use manifest file; include examples in package

* include examples in package resources

* use working_dir

* swap --version and -V

* Add run_bca.py to scripts folder

* update docs

Co-authored-by: Blake <[email protected]>
  • Loading branch information
bstabler and Blake authored Feb 27, 2020
1 parent 3db5e74 commit 4d2913a
Show file tree
Hide file tree
Showing 155 changed files with 357 additions and 239 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.ipynb_checkpoints
sandbox/
.pytest_cache
.DS_Store

~$*.xlsx

Expand Down
20 changes: 16 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ install:
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
- conda info -a
- |
conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION
- source activate test-environment
# - pip install https://github.com/ActivitySim/activitysim/zipball/dev/
- pip install pytest pytest-cov coveralls pycodestyle
- pip install .
- pip freeze
Expand All @@ -27,7 +25,21 @@ script:

after_success:
- coveralls
- bin/build_docs.sh
# Build docs
- pip install sphinx numpydoc sphinx_rtd_theme
- cd docs
- make clean
- make html
- touch build/html/.nojekyll

deploy:
provider: pages
local_dir: docs/build/html
skip_cleanup: true
github_token: $GH_TOKEN
keep_history: true
on:
branch: master

notifications:
slack:
Expand Down
4 changes: 1 addition & 3 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
include papers/*
include example_4step/*
include example_abm/*
graft bca4abm/examples
4 changes: 2 additions & 2 deletions bca4abm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import absolute_import
# bca4abm
# Copyright (C) 2016 RSG Inc
# See full license in LICENSE.txt.
Expand All @@ -7,4 +6,5 @@
from . import tables
from . import processors

__version__ = version = '0.1dev'
__version__ = '0.5'
__doc__ = 'Benefit Calculations for Travel Models'
1 change: 0 additions & 1 deletion bca4abm/bca4abm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import print_function
# bca4abm
# Copyright (C) 2016 RSG Inc
# See full license in LICENSE.txt.
Expand Down
1 change: 1 addition & 0 deletions bca4abm/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import main
197 changes: 197 additions & 0 deletions bca4abm/cli/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# bca4abm
# Copyright (C) 2016 RSG Inc
# See full license in LICENSE.txt.
"""
Welcome to bca4abm!
"""

import os
import shutil
import sys
import warnings
import logging
import argparse
import pkg_resources

from activitysim.core import tracing
from activitysim.core import pipeline
from activitysim.core import inject

from activitysim.core.config import setting

# the following import has the side-effect of registering injectables
import bca4abm


def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--version', '-V', action='version', version=bca4abm.__version__)

# print help if no subcommand is provided
parser.set_defaults(func=lambda x: parser.print_help())
subparsers = parser.add_subparsers(title='subcommands',
help='available subcommand options')

subparser_create(subparsers)
subparser_run(subparsers)

args = parser.parse_args()
args.func(args)


def subparser_create(subparsers):
"""Create command args
"""
parser_create = subparsers.add_parser('create', description=create.__doc__,
help='create a new bca4abm configuration')
create_group = parser_create.add_mutually_exclusive_group(required=True)
create_group.add_argument('-l', '--list',
action='store_true',
help='list available example directories')
create_group.add_argument('-e', '--example',
type=str,
metavar='PATH',
help='example directory to copy')
parser_create.add_argument('-d', '--destination',
type=str,
metavar='PATH',
default=os.getcwd(),
help="path to new project directory (default: %(default)s)")
parser_create.set_defaults(func=create)


def create(args):
"""
Create a new bca4abm configuration from an existing template.
Use the -l flag to view a list of example configurations, then
copy to your own working directory. These new project files can
be run with the 'bca run' command.
"""

example_dirs = pkg_resources.resource_listdir('bca4abm', 'examples')

if args.list:
print('Available examples:')
for example in example_dirs:
print("\t"+example)

sys.exit(0)

if args.example:
if args.example not in example_dirs:
sys.exit("error: could not find example '%s'" % args.example)

if os.path.isdir(args.destination):
dest_path = os.path.join(args.destination, args.example)
else:
dest_path = args.destination

resource = os.path.join('examples', args.example)
example_path = pkg_resources.resource_filename('bca4abm', resource)

print('copying files from %s...' % args.example)
shutil.copytree(example_path, dest_path)

sys.exit("copied! new project files are in %s" % os.path.abspath(dest_path))


def subparser_run(subparsers):
"""Run command args
"""
parser_run = subparsers.add_parser('run', description=run.__doc__, help='run bca4abm')
parser_run.add_argument('-w', '--working_dir',
type=str,
metavar='PATH',
help='path to example/project directory (default: %s)' % os.getcwd())
parser_run.add_argument('-c', '--config',
type=str,
metavar='PATH',
help='path to config dir')
parser_run.add_argument('-o', '--output',
type=str,
metavar='PATH',
help='path to output dir')
parser_run.add_argument('-d', '--data',
type=str,
metavar='PATH',
help='path to data dir')
parser_run.add_argument('-r', '--resume',
type=str,
metavar='STEPNAME',
help='resume after step')
parser_run.add_argument('-p', '--pipeline',
type=str,
metavar='FILE',
help='pipeline file name')
parser_run.set_defaults(func=run)


def run(args):
"""
Run bca4abm. Specify a project folder using the '--working_dir' option,
or point to the config, data, and output folders directly with
'--config', '--data', and '--output'.
"""

if args.working_dir and os.path.exists(args.working_dir):
os.chdir(args.working_dir)

if args.config:
inject.add_injectable('configs_dir', args.config)

if args.data:
inject.add_injectable('data_dir', args.data)

if args.output:
inject.add_injectable('output_dir', args.output)

for injectable in ['configs_dir', 'data_dir', 'output_dir']:
try:
dir_path = inject.get_injectable(injectable)
except RuntimeError:
sys.exit('Error: please specify either a --working_dir '
"containing 'configs', 'data', and 'output' folders "
'or all three of --config, --data, and --output')
if not os.path.exists(dir_path):
sys.exit("Could not find %s '%s'" % (injectable, os.path.abspath(dir_path)))

if args.pipeline:
inject.add_injectable('pipeline_file_name', args.pipeline)

if args.resume:
override_setting('resume_after', args.resume)

tracing.config_logger()
tracing.delete_csv_files() # only modifies output_dir
warnings.simplefilter('always')
logging.captureWarnings(capture=True)

t0 = tracing.print_elapsed_time()

# If you provide a resume_after argument to pipeline.run
# the pipeline manager will attempt to load checkpointed tables from the checkpoint store
# and resume pipeline processing on the next submodel step after the specified checkpoint
resume_after = setting('resume_after', None)

if resume_after:
print('resume_after: %s' % resume_after)

pipeline.run(models=setting('models'), resume_after=resume_after)

# tables will no longer be available after pipeline is closed
pipeline.close_pipeline()

t0 = tracing.print_elapsed_time('all models', t0)


# TODO: move to activitysim.core.config
def override_setting(key, value):
new_settings = inject.get_injectable('settings')
new_settings[key] = value
inject.add_injectable('settings', new_settings)


if __name__ == '__main__':
sys.exit(main())
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion bca4abm/processors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import absolute_import
# bca4abm
# Copyright (C) 2016 RSG Inc
# See full license in LICENSE.txt.
Expand Down
1 change: 0 additions & 1 deletion bca4abm/processors/abm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import absolute_import
from . import person_trips
from . import demographics
from . import auto_ownership
Expand Down
1 change: 0 additions & 1 deletion bca4abm/processors/four_step/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import absolute_import
from . import aggregate_demographics
from . import aggregate_zone
from . import aggregate_od
1 change: 0 additions & 1 deletion bca4abm/tables/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import absolute_import
# bca4abm
# Copyright (C) 2016 RSG Inc
# See full license in LICENSE.txt.
Expand Down
13 changes: 13 additions & 0 deletions bca4abm/tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import pytest
import subprocess

# the following import has the side-effect of registering injectables
from bca4abm import bca4abm as bca


def test_cli():

# cp = completed process
cp = subprocess.run(['bca4abm', '-h'], capture_output=True)

assert 'usage: bca4abm [-h] [--version]' in str(cp.stdout)
1 change: 0 additions & 1 deletion bca4abm/util/misc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import print_function
# bca4abm
# See full license in LICENSE.txt.

Expand Down
63 changes: 0 additions & 63 deletions bin/build_docs.sh

This file was deleted.

19 changes: 0 additions & 19 deletions bin/test_build_docs.sh

This file was deleted.

Loading

0 comments on commit 4d2913a

Please sign in to comment.