├── setup.cfg ├── MANIFEST.in ├── requirements.txt ├── .coveralls.yml ├── scripts └── publish.sh ├── pybea ├── __init__.py ├── pybea.py └── api.py ├── .travis.yml ├── setup.py ├── LICENSE.rst ├── README.rst ├── .gitignore └── examples └── user-guide.ipynb /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.rst 2 | recursive-include docs *.rst -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | jupyter 2 | numpy 3 | pandas 4 | requests 5 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | repo_token: vpfFbGHxA6iXZ5bRqB8stB7fsPGXOMMLH -------------------------------------------------------------------------------- /scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ev # Needed in order for Travis CI to report failure 3 | 4 | if [ $TRAVIS_BRANCH == "master" ] && [ $TRAVIS_EVENT_TYPE == "push" ] 5 | then 6 | python setup.py sdist bdist_wheel 7 | twine upload -u $PYPI_USERNAME -p $PYPI_PASSWORD dist/* 8 | else 9 | echo "No releases published for this build!" 10 | fi 11 | -------------------------------------------------------------------------------- /pybea/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyBEA imports: 3 | 4 | Objects imported here will live in the `pybea` namespace. 5 | 6 | @author : David R. Pugh 7 | @date : 2014-09-15 8 | 9 | """ 10 | 11 | __all__ = ["get_data_set_list", "get_parameter_list", "get_parameter_values", 12 | "get_data"] 13 | 14 | from . pybea import (get_data_set_list, 15 | get_parameter_list, 16 | get_parameter_values, 17 | get_data) 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: python 4 | 5 | python: 6 | - 3.6 7 | 8 | notifications: 9 | email: false 10 | 11 | env: 12 | global: 13 | - secure: "Eq7T9I/6s+z9ESn2XXvMK25VdjR3URXZw/rPh4gF1OfDu3cbXbSzXgbv28A0SHh6OQUQeK6MMFUo+EhJXmDK3Waw3f0e1DAHFN99SgRMld8Atv/7/xUDfiobYjC3XMLlX4kJHL1I/mcDm960mzwKOCu/O3sc1ql/AyNsuFRCqoU=" 14 | - secure: "R1vVXMDSWchzQ/ABgyjv2PpUq9kDSMRP+lFv7w9bdnrygdOZpekQatvbMXIhsxu27FzoVSCX1uJ0SUCcCHCs2AVMtTay6ym6Vmw2ccy68++wr4GI4HN6VQs8nqaOysw/EtBlTCdpsxUtglkaoJlSv/RvtW3Sou4a8RqmRpfNR8A=" 15 | 16 | branches: 17 | only: 18 | - master 19 | - develop 20 | 21 | # command to install dependencies 22 | install: 23 | - pip install --upgrade pip setuptools 24 | - pip install coverage coveralls twine wheel 25 | - pip install -r requirements.txt 26 | - python setup.py install 27 | 28 | # command to run tests 29 | script: nosetests --with-coverage --cover-package=pybea 30 | 31 | # command to run coveralls 32 | after_success: 33 | - coveralls 34 | - scripts/publish.sh 35 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | from distutils.core import setup 3 | 4 | 5 | CLASSIFIERS = ['Development Status :: 3 - Alpha', 6 | 'Intended Audience :: Education', 7 | 'Intended Audience :: Science/Research', 8 | 'License :: OSI Approved :: MIT License', 9 | 'Operating System :: OS Independent', 10 | 'Programming Language :: Python', 11 | 'Programming Language :: Python :: 3', 12 | 'Programming Language :: Python :: 3.6', 13 | 'Topic :: Scientific/Engineering', 14 | ] 15 | 16 | DESCRIPTION = "Python package for accessing data from the BEA data API" 17 | 18 | PACKAGES = ['pybea'] 19 | 20 | VERSION = "0.7.0-alpha" 21 | 22 | setup(name='pybea', 23 | packages=PACKAGES, 24 | version=VERSION, 25 | description=DESCRIPTION, 26 | author='David R. Pugh', 27 | author_email='drpugh@protonmail.com', 28 | url='https://github.com/davidrpugh/pyBEA', 29 | license='LICENSE.rst', 30 | classifiers=CLASSIFIERS 31 | ) 32 | -------------------------------------------------------------------------------- /LICENSE.rst: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 David R. Pugh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | pyBEA 2 | ===== 3 | 4 | |Build Status| |Coverage Status| |Latest Version| |Downloads| 5 | 6 | .. |Build Status| image:: https://travis-ci.org/davidrpugh/pyBEA.svg?branch=master 7 | :target: https://travis-ci.org/davidrpugh/pyBEA 8 | .. |Coverage Status| image:: https://coveralls.io/repos/davidrpugh/pyBEA/badge.svg?branch=master 9 | :target: https://coveralls.io/r/davidrpugh/pyBEA?branch=master 10 | .. |Latest Version| image:: https://img.shields.io/pypi/v/pyBEA.svg 11 | :target: https://pypi.python.org/pypi/pyBEA/ 12 | .. |Downloads| image:: https://img.shields.io/pypi/dm/pyBEA.svg 13 | :target: https://pypi.python.org/pypi/pyBEA/ 14 | 15 | Python package for accessing data from the U.S. Bureau of Economic Analysis (BEA) API. The pyBEA package allows users to extract relevant data from the BEA data API into a Pandas DataFrame for further analysis. 16 | 17 | Installation 18 | ------------ 19 | 20 | Assuming you have `pip`_ on your computer (as will be the case if you've `installed Anaconda`_) you can install the latest stable release of ``pybea`` by typing 21 | 22 | .. code:: bash 23 | 24 | pip install pybea 25 | 26 | at a terminal prompt. 27 | 28 | .. _pip: https://pypi.python.org/pypi/pip 29 | .. _`installed Anaconda`: http://quant-econ.net/getting_started.html#installing-anaconda 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ -------------------------------------------------------------------------------- /pybea/pybea.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions for fetching data from the Bureau of Economic Analysis (BEA) data api. 3 | 4 | """ 5 | import numpy as np 6 | import pandas as pd 7 | 8 | from . import api 9 | 10 | 11 | def get_data_set_list(UserID, ResultFormat='JSON'): 12 | """ 13 | Retrieve list of currently available data sets. 14 | 15 | Parameters 16 | ---------- 17 | UserID: str 18 | A valid UserID necessary for accessing the BEA data API. 19 | ResultFormat : str (default='JSON') 20 | The API returns data in one of two formats: JSON or XML. The 21 | ResultFormat parameter can be included on any request to specify the 22 | format of the results. 23 | 24 | Returns 25 | ------- 26 | data_set_list : Pandas.DataFrame 27 | A Pandas DataFrame containing the DatasetName and DatasetDescription 28 | attributes for all available data sets. 29 | 30 | """ 31 | tmp_request = api.DataSetListRequest(UserID=UserID, ResultFormat=ResultFormat) 32 | return tmp_request.data_set_list 33 | 34 | 35 | def get_parameter_list(UserID, DataSetName, ResultFormat='JSON'): 36 | """ 37 | Retrieve list of required and optional parameters for a given data set. 38 | 39 | Parameters 40 | ---------- 41 | UserID: str 42 | A valid UserID necessary for accessing the BEA data API. 43 | DataSetName : str 44 | A valid name of an available BEA data set. The get_data_set_list 45 | function returns a complete listing of available data sets and the 46 | associated DataSetName attributes. 47 | ResultFormat : str (default='JSON') 48 | The API returns data in one of two formats: JSON or XML. The 49 | ResultFormat parameter can be included on any request to specify the 50 | format of the results. 51 | 52 | Returns 53 | ------- 54 | parameter_list : Pandas.DataFrame 55 | A Pandas DataFrame containing the metadata associated with the 56 | parameters of the requested data set. 57 | 58 | Notes 59 | ----- 60 | The function returns the following metadata for each required and optional 61 | parameter in the specified data set. 62 | 63 | - ParameterName: the name of the parameter as used in a data request 64 | - ParameterDataType: String or Integer 65 | - ParameterDescription: a description of the parameter 66 | - ParameterIsRequired: 0 if the parameter can be omitted from a request, 1 67 | if required. 68 | - ParameterDefaultValue: the default value used for the request if the 69 | parameter is not supplied 70 | - MultipleAcceptedFlag: 0 if the parameter may only have a single value, 1 71 | if multiple values are permitted. Note that multiple values for a parameter 72 | are submitted as a comma-separated string. 73 | - AllValue: the special value for a parameter that means all valid values 74 | are used without supplying them individually. 75 | 76 | """ 77 | tmp_request = api.ParameterListRequest(UserID=UserID, 78 | DataSetName=DataSetName, 79 | ResultFormat=ResultFormat) 80 | return tmp_request.parameter_list 81 | 82 | 83 | def get_parameter_values(UserID, DataSetName, ParameterName, ResultFormat='JSON'): 84 | """ 85 | Retrieve list of valid parameter values for a given data set. 86 | 87 | Parameters 88 | ---------- 89 | UserID: str 90 | A valid UserID necessary for accessing the BEA data API. 91 | DataSetName : str 92 | A valid name of an available BEA data set. Note that the 93 | get_data_set_list function returns a complete listing of available data 94 | sets and their associated DataSetName attributes. 95 | ParameterName : str 96 | A valid parameter name for a given data set. Note that the 97 | get_parameter_list function returns a complete listing of valid 98 | parameters names for a given data set. 99 | ResultFormat : str (default='JSON') 100 | The API returns data in one of two formats: JSON or XML. The 101 | ResultFormat parameter can be included on any request to specify the 102 | format of the results. 103 | 104 | Returns 105 | ------- 106 | param_values : Pandas.DataFrame 107 | A Pandas DataFrame containing the list of valid parameter values for 108 | the given data set. 109 | 110 | """ 111 | tmp_request = api.ParameterValuesRequest(UserID=UserID, 112 | DataSetName=DataSetName, 113 | ParameterName=ParameterName, 114 | ResultFormat=ResultFormat) 115 | return tmp_request.parameter_values 116 | 117 | 118 | def get_parameter_values_filtered(UserID, DataSetName, ParameterName, 119 | ResultFormat='JSON', **kwargs): 120 | """ 121 | Retrieves a list of the valid values for a particular parameter based on 122 | other provided parameters . 123 | 124 | Parameters 125 | ---------- 126 | UserID: str 127 | A valid UserID necessary for accessing the BEA data API. 128 | DataSetName : str 129 | A valid name of an available BEA data set. Note that the 130 | get_data_set_list function returns a complete listing of available data 131 | sets and their associated DataSetName attributes. 132 | ParameterName : str 133 | A valid parameter name for a given data set. Note that the 134 | get_parameter_list function returns a complete listing of valid 135 | parameters names for a given data set. 136 | ResultFormat : str (default='JSON') 137 | The API returns data in one of two formats: JSON or XML. The 138 | ResultFormat parameter can be included on any request to specify the 139 | format of the results. 140 | kwargs : dict 141 | Additional, optional, keyword arguments. 142 | 143 | Returns 144 | ------- 145 | param_values : Pandas.DataFrame 146 | A Pandas DataFrame containing the list of valid parameter values for 147 | the given data set. 148 | 149 | """ 150 | tmp_request = api.ParameterValuesRequest(UserID=UserID, 151 | DataSetName=DataSetName, 152 | ParameterName=ParameterName, 153 | ResultFormat=ResultFormat, 154 | **kwargs) 155 | param_values = pd.DataFrame(tmp_request.parameter_values, dtype=np.int64) 156 | return param_values 157 | 158 | 159 | def get_data(UserID, DataSetName, ResultFormat='JSON', **params): 160 | r""" 161 | Retrieve data from the Bureau of Economic Analysis (BEA) data api. 162 | 163 | Parameters 164 | ---------- 165 | UserID: str 166 | A valid UserID necessary for accessing the BEA data API. 167 | DataSetName : str 168 | A valid name of an available BEA data set. The get_data_set_list 169 | function returns a complete listing of available data sets and the 170 | associated DataSetName attributes. 171 | ResultFormat : str (default='JSON') 172 | The API returns data in one of two formats: JSON or XML. The 173 | ResultFormat parameter can be included on any request to specify the 174 | format of the results. 175 | params : dict 176 | Dictionary of optional parameters. The list of valid optional 177 | parameters is data set specific. See the notes section below for more 178 | information. 179 | 180 | Returns 181 | ------- 182 | data : Pandas.DataFrame 183 | A Pandas DataFrame containing the requested data. 184 | 185 | Notes 186 | ----- 187 | As noted above the additional required and optional parameters that can be 188 | passed as parameters is data set specific. 189 | 190 | For additional information see the BEA data API `user guide`_. 191 | 192 | .. _`user guide`: https://www.bea.gov/API/bea_web_service_api_user_guide.htm 193 | 194 | """ 195 | valid_dataset_names = ['NIPA', 'NIUnderlyingDetail', 'FixedAssets', 'MNE', 196 | 'GDPbyIndustry', 'ITA', 'IIP', 'RegionalIncome', 197 | 'RegionalProduct', 'InputOutput', 198 | 'UnderlyingGDPbyIndustry', 'IntlServTrade'] 199 | if DataSetName in valid_dataset_names: 200 | tmp_request = api.DataRequest(UserID, DataSetName, ResultFormat, **params) 201 | df = tmp_request.data 202 | else: 203 | raise ValueError("Invalid DataSetName requested.") 204 | 205 | return df 206 | -------------------------------------------------------------------------------- /examples/user-guide.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Introduction\n", 8 | "\n", 9 | "The Bureau of Economic Analysis (BEA) publishes economic statistics in a variety of formats. This document describes the BEA Data Retrieval Application Programming Interface (API) – including detailed instructions for retrieving data and meta-data published by BEA using the pyBEA package. \n", 10 | "\n", 11 | "The pyBEA pacakge provides a simple interface to the BEA API and includes methods for retrieving a subset of BEA statistical data, including any meta-data describing it, and loading the results into a Pandas DataFrame object for further analysis.\n", 12 | "\n", 13 | "## Data Return Format\n", 14 | "The BEA API returns data in one of two formats: JSON or XML (with JSON being the default). Currently the pyBEA package only supports JSON requests.\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "import pybea" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "## Meta-Data API Methods\n", 31 | "\n", 32 | "The BEA API contains three methods for retrieving meta-data as follows:\n", 33 | "\n", 34 | "1. `GetDataSetList`: retrieves a list of the datasets currently offered.\n", 35 | "2. `GetParameterList`: retrieves a list of the parameters (required and optional) for a particular dataset.\n", 36 | "3. `GetParameterValues`: retrieves a list of the valid values for a particular parameter.\n", 37 | "\n", 38 | "Each of these methods has a corresponding function in the `pybea` package." 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "pybea.get_data_set_list?" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "pybea.get_parameter_list?" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "pybea.get_parameter_values?" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "## Example Usage" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "# replace this with your BEA data API key!\n", 82 | "USER_ID = ???" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": null, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "# access the BEA data API...\n", 92 | "available_datasets = pybea.get_data_set_list(USER_ID)\n", 93 | "available_datasets" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "request = pybea.api.DataSetListRequest(USER_ID,\n", 103 | " ResultFormat=\"JSON\")\n", 104 | "request.data_set_list" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "regional_income_params = pybea.get_parameter_list(USER_ID,\n", 114 | " DataSetName='RegionalIncome',\n", 115 | " ResultFormat=\"XML\")\n", 116 | "regional_income_params" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "request = pybea.api.ParameterListRequest(USER_ID,\n", 126 | " DataSetName='RegionalIncome',\n", 127 | " ResultFormat=\"JSON\")\n", 128 | "request.parameter_list" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": null, 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [ 137 | "regional_income_geofips = pybea.get_parameter_values(USER_ID,\n", 138 | " DataSetName='RegionalIncome',\n", 139 | " ParameterName='GeoFips')\n", 140 | "regional_income_geofips" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "request = pybea.api.ParameterValuesRequest(USER_ID,\n", 150 | " DataSetName='RegionalIncome',\n", 151 | " ParameterName='GeoFips')\n", 152 | "request.parameter_values" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "## Data Retrieval API Method\n", 160 | "\n", 161 | "The BEA API has one method for retrieving data: `GetData`. This method has its own function in the `pybea` package. " 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [ 170 | "pybea.get_data?" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "# NIPA (National Income and Product Accounts)\n", 178 | "\n", 179 | "This dataset contains data from the National Income and Product Accounts which include measures of the value and composition of U.S.production and the incomes generated in producing it. NIPA data is provided on a table basis; individual tables contain between fewer than 10 to more than 200 distinct data series.\n", 180 | "\n", 181 | "## Example Usage\n", 182 | "\n", 183 | "Percent change in Real Gross Domestic Product, Annually and Quarterly for all years." 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "data = pybea.get_data(USER_ID,\n", 193 | " DataSetName='NIPA',\n", 194 | " TableName='T10101',\n", 195 | " Frequency=['A', 'Q'],\n", 196 | " Year='ALL',\n", 197 | " ResultFormat=\"XML\"\n", 198 | " )" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": null, 204 | "metadata": {}, 205 | "outputs": [], 206 | "source": [ 207 | "data.head()" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "data.tail()" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": {}, 222 | "source": [ 223 | "## Example Usage\n", 224 | "\n", 225 | "Personal Income, Monthly, for 2015 and 2016." 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": null, 231 | "metadata": {}, 232 | "outputs": [], 233 | "source": [ 234 | "request = pybea.api.NIPARequest(USER_ID,\n", 235 | " TableName='T20600',\n", 236 | " Frequency='M',\n", 237 | " Year=['2015', '2016'],\n", 238 | " ResultFormat='JSON')" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": null, 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "request.data.head()" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "data.tail()" 257 | ] 258 | }, 259 | { 260 | "cell_type": "markdown", 261 | "metadata": {}, 262 | "source": [ 263 | "# NIUnderlyingDetail (National Income and Product Accounts)\n", 264 | "\n", 265 | "The DataSetName is NIUnderlyingDetail. This dataset contains underlying detail data from the National Income and Product Accounts which include measures of the value and composition of U.S.production and the incomes generated in producing it. NIPA Underlying Detail data is provided on a table basis; individual tables contain between fewer than 10 to more than 200 distinct data series.\n", 266 | "\n", 267 | "## Example Usage\n", 268 | "\n", 269 | "Personal Consumption Expenditures, Current Dollars, Annually, Quarterly and Monthly for all years." 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": null, 275 | "metadata": {}, 276 | "outputs": [], 277 | "source": [ 278 | "data = pybea.get_data(USER_ID,\n", 279 | " DataSetName='NIUnderlyingDetail',\n", 280 | " TableName='U20305',\n", 281 | " Frequency=['A', 'Q'],\n", 282 | " Year='ALL',\n", 283 | " ResultFormat='XML')" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": null, 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "data.head()" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [ 301 | "data.tail()" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "metadata": {}, 307 | "source": [ 308 | "## Example Usage\n", 309 | "\n", 310 | "Auto and Truck Unit Sales, Production, Inventories, Expenditures and Price, Monthly, for 2015 and 2016" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": null, 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "request = pybea.api.NIUnderlyingDetailRequest(USER_ID,\n", 320 | " TableName='U70205S',\n", 321 | " Frequency='M',\n", 322 | " Year=['2015', '2016'],\n", 323 | " ResultFormat='JSON')" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": null, 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [ 332 | "request.data.head()" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": null, 338 | "metadata": {}, 339 | "outputs": [], 340 | "source": [ 341 | "request.data.tail()" 342 | ] 343 | }, 344 | { 345 | "cell_type": "markdown", 346 | "metadata": {}, 347 | "source": [ 348 | "# Fixed Assets\n", 349 | "\n", 350 | "The FixedAssets dataset contains data from the standard set of Fixed Assets tables as published online." 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": null, 356 | "metadata": {}, 357 | "outputs": [], 358 | "source": [ 359 | "data = pybea.get_data(USER_ID,\n", 360 | " DataSetName='FixedAssets',\n", 361 | " TableID='16',\n", 362 | " Year='2012',\n", 363 | " ResultFormat='XML')" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": null, 369 | "metadata": {}, 370 | "outputs": [], 371 | "source": [ 372 | "data.head()" 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": null, 378 | "metadata": {}, 379 | "outputs": [], 380 | "source": [ 381 | "data.tail()" 382 | ] 383 | }, 384 | { 385 | "cell_type": "markdown", 386 | "metadata": {}, 387 | "source": [ 388 | "# ITA (International Transactions)\n", 389 | "\n", 390 | "This dataset contains data on U.S. international transactions. BEA's international transactions (balance of payments) accounts include all transactions between U.S. and foreign residents.\n", 391 | "\n", 392 | "## Example Usage\n", 393 | "\n", 394 | "Balance on goods with China for 2011 and 2012." 395 | ] 396 | }, 397 | { 398 | "cell_type": "code", 399 | "execution_count": null, 400 | "metadata": {}, 401 | "outputs": [], 402 | "source": [ 403 | "data = pybea.get_data(USER_ID,\n", 404 | " DataSetName='ITA',\n", 405 | " Indicator='BalGds',\n", 406 | " AreaOrCountry='China',\n", 407 | " Frequency='A',\n", 408 | " Year=['2011', '2012'],\n", 409 | " ResultFormat='XML')" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "metadata": {}, 416 | "outputs": [], 417 | "source": [ 418 | "data.head()" 419 | ] 420 | }, 421 | { 422 | "cell_type": "markdown", 423 | "metadata": {}, 424 | "source": [ 425 | "## Example Usage\n", 426 | "\n", 427 | "Net U.S. acquisition of portfolio investment assets (quarterly not seasonally adjusted) for 2013." 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": null, 433 | "metadata": {}, 434 | "outputs": [], 435 | "source": [ 436 | "data = pybea.get_data(USER_ID,\n", 437 | " DataSetName='ITA',\n", 438 | " Indicator='PfInvAssets',\n", 439 | " AreaOrCountry='AllCountries',\n", 440 | " Frequency='QNSA',\n", 441 | " Year='2013',\n", 442 | " ResultFormat='XML')" 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "execution_count": null, 448 | "metadata": {}, 449 | "outputs": [], 450 | "source": [ 451 | "data.head()" 452 | ] 453 | }, 454 | { 455 | "cell_type": "markdown", 456 | "metadata": {}, 457 | "source": [ 458 | "# RegionalIncome\n", 459 | "\n", 460 | "## Example Usage\n", 461 | "\n", 462 | "Fetch data on personal income for 2012 and 2013 for all counties, in JSON format" 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "execution_count": null, 468 | "metadata": {}, 469 | "outputs": [], 470 | "source": [ 471 | "data = pybea.get_data(USER_ID,\n", 472 | " DataSetName='RegionalIncome',\n", 473 | " TableName='CA1',\n", 474 | " LineCode=1,\n", 475 | " GeoFips='COUNTY',\n", 476 | " Year=['2012', '2013'],\n", 477 | " ResultFormat='JSON')" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": null, 483 | "metadata": {}, 484 | "outputs": [], 485 | "source": [ 486 | "data.head()" 487 | ] 488 | }, 489 | { 490 | "cell_type": "code", 491 | "execution_count": null, 492 | "metadata": {}, 493 | "outputs": [], 494 | "source": [ 495 | "data.tail()" 496 | ] 497 | }, 498 | { 499 | "cell_type": "markdown", 500 | "metadata": {}, 501 | "source": [ 502 | "# RegionalProduct\n", 503 | "\n", 504 | "## Example Usage\n", 505 | "\n", 506 | "Real GDP for all years for all MSAs, in JSON format" 507 | ] 508 | }, 509 | { 510 | "cell_type": "code", 511 | "execution_count": null, 512 | "metadata": {}, 513 | "outputs": [], 514 | "source": [ 515 | "data = pybea.get_data(USER_ID,\n", 516 | " DataSetName='RegionalProduct',\n", 517 | " Component=\"RGDP_MAN\",\n", 518 | " IndustryId=1,\n", 519 | " GeoFips=\"MSA\",\n", 520 | " Year=\"ALL\",\n", 521 | " ResultFormat='XML')" 522 | ] 523 | }, 524 | { 525 | "cell_type": "code", 526 | "execution_count": null, 527 | "metadata": {}, 528 | "outputs": [], 529 | "source": [ 530 | "data.head()" 531 | ] 532 | }, 533 | { 534 | "cell_type": "code", 535 | "execution_count": null, 536 | "metadata": {}, 537 | "outputs": [], 538 | "source": [ 539 | "data.tail()" 540 | ] 541 | }, 542 | { 543 | "cell_type": "markdown", 544 | "metadata": {}, 545 | "source": [ 546 | "## Example Usage\n", 547 | "\n", 548 | "GDP for 2012 and 2013 for selected Southeast states, for the Retail Trade industry." 549 | ] 550 | }, 551 | { 552 | "cell_type": "code", 553 | "execution_count": null, 554 | "metadata": {}, 555 | "outputs": [], 556 | "source": [ 557 | "southeast_states = [\"01000\", \"05000\", \"12000\", \"13000\", \"21000\", \"22000\", \n", 558 | " \"28000\", \"37000\", \"45000\", \"47000\", \"51000\", \"54000\"]\n", 559 | "data = pybea.get_data(USER_ID,\n", 560 | " DataSetName='RegionalProduct',\n", 561 | " Component=\"GDP_sAN\",\n", 562 | " IndustryId=35,\n", 563 | " GeoFips=southeast_states,\n", 564 | " Year=[\"2013\", \"2013\"],\n", 565 | " ResultFormat='XML')" 566 | ] 567 | }, 568 | { 569 | "cell_type": "code", 570 | "execution_count": null, 571 | "metadata": {}, 572 | "outputs": [], 573 | "source": [ 574 | "data.head()" 575 | ] 576 | }, 577 | { 578 | "cell_type": "code", 579 | "execution_count": null, 580 | "metadata": {}, 581 | "outputs": [], 582 | "source": [ 583 | "data.tail()" 584 | ] 585 | }, 586 | { 587 | "cell_type": "markdown", 588 | "metadata": {}, 589 | "source": [ 590 | "# InputOutput\n", 591 | "\n", 592 | "The Input-Output Statistics are contained within a dataset called InputOutput. BEA's industry accounts are used extensively by policymakers and businesses to understand industry interactions, productivity trends, and the changing structure of the U.S. economy. The input-output accounts provide a detailed view of the interrelationships between U.S. producers and users. \n", 593 | "\n", 594 | "## Example Usage\n", 595 | "\n", 596 | "Data from The Use of Commodities by Industries, Before Redefinitions (Producer’s Prices) sector level table for years 2010, 2011, and 2012." 597 | ] 598 | }, 599 | { 600 | "cell_type": "code", 601 | "execution_count": null, 602 | "metadata": {}, 603 | "outputs": [], 604 | "source": [ 605 | "data = pybea.get_data(USER_ID,\n", 606 | " DataSetName='InputOutput',\n", 607 | " TableID=2,\n", 608 | " Year=['2010', '2011', '2012', '2013'],\n", 609 | " ResultFormat='JSON')" 610 | ] 611 | }, 612 | { 613 | "cell_type": "code", 614 | "execution_count": null, 615 | "metadata": {}, 616 | "outputs": [], 617 | "source": [ 618 | "data.head()" 619 | ] 620 | }, 621 | { 622 | "cell_type": "code", 623 | "execution_count": null, 624 | "metadata": {}, 625 | "outputs": [], 626 | "source": [ 627 | "data.tail()" 628 | ] 629 | }, 630 | { 631 | "cell_type": "markdown", 632 | "metadata": {}, 633 | "source": [ 634 | "## Example Usage\n", 635 | "\n", 636 | "Data for 2007 from The Make of Commodities by Industries, Before Redefinitions sector and summary level tables." 637 | ] 638 | }, 639 | { 640 | "cell_type": "code", 641 | "execution_count": null, 642 | "metadata": {}, 643 | "outputs": [], 644 | "source": [ 645 | "data = pybea.get_data(USER_ID,\n", 646 | " DataSetName='InputOutput',\n", 647 | " TableID=[46, 47],\n", 648 | " Year='2007',\n", 649 | " ResultFormat='JSON')" 650 | ] 651 | }, 652 | { 653 | "cell_type": "code", 654 | "execution_count": null, 655 | "metadata": {}, 656 | "outputs": [], 657 | "source": [ 658 | "data.head()" 659 | ] 660 | }, 661 | { 662 | "cell_type": "code", 663 | "execution_count": null, 664 | "metadata": {}, 665 | "outputs": [], 666 | "source": [ 667 | "data.tail()" 668 | ] 669 | }, 670 | { 671 | "cell_type": "code", 672 | "execution_count": null, 673 | "metadata": {}, 674 | "outputs": [], 675 | "source": [] 676 | } 677 | ], 678 | "metadata": { 679 | "kernelspec": { 680 | "display_name": "Python 3", 681 | "language": "python", 682 | "name": "python3" 683 | }, 684 | "language_info": { 685 | "codemirror_mode": { 686 | "name": "ipython", 687 | "version": 3 688 | }, 689 | "file_extension": ".py", 690 | "mimetype": "text/x-python", 691 | "name": "python", 692 | "nbconvert_exporter": "python", 693 | "pygments_lexer": "ipython3", 694 | "version": "3.6.5" 695 | } 696 | }, 697 | "nbformat": 4, 698 | "nbformat_minor": 1 699 | } 700 | -------------------------------------------------------------------------------- /pybea/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | import xml.etree.ElementTree as ET 3 | 4 | import numpy as np 5 | import pandas as pd 6 | import requests 7 | 8 | 9 | class Request(dict): 10 | """Base class for a Request.""" 11 | 12 | _response = None 13 | 14 | base_url = 'https://apps.bea.gov/api/data' 15 | 16 | valid_formats = ['JSON', 'XML'] 17 | 18 | valid_methods = ['GetDataSetList', 19 | 'GetParameterList', 20 | 'GetParameterValues', 21 | 'GetParameterValuesFiltered', 22 | 'GetData'] 23 | 24 | def __init__(self, UserID, Method, ResultFormat='JSON', **params): 25 | # validate required keyword args 26 | valid_user_id = self._validate_user_id(UserID) 27 | valid_method = self._validate_method(Method) 28 | valid_format = self._validate_result_format(ResultFormat) 29 | 30 | required_params = {'UserID': valid_user_id, 31 | 'Method': valid_method, 32 | 'ResultFormat': valid_format} 33 | required_params.update(params) 34 | 35 | super(Request, self).__init__(**required_params) 36 | 37 | def __setitem__(self, item, value): 38 | self._response = None 39 | return super(Request, self).__setitem__(item, value) 40 | 41 | def __delitem__(self, item): 42 | self._response = None 43 | return super(Request, self).__delitem__(item) 44 | 45 | @property 46 | def _json_content(self): 47 | return self.response.json() 48 | 49 | @property 50 | def _json_request(self): 51 | raw_json = self._json_content 52 | return raw_json['BEAAPI']['Request'] 53 | 54 | @property 55 | def _json_results(self): 56 | raw_json = self._json_content 57 | return raw_json['BEAAPI']['Results'] 58 | 59 | @property 60 | def _xml_content(self): 61 | return ET.fromstring(self.response.content) 62 | 63 | @property 64 | def _xml_request(self): 65 | root = self._xml_content 66 | return root.find('Request') 67 | 68 | @property 69 | def _xml_results(self): 70 | root = self._xml_content 71 | return root.find('Results') 72 | 73 | @property 74 | def request(self): 75 | if self['ResultFormat'] == 'JSON': 76 | tmp_request = self._json_request 77 | else: 78 | tmp_request = self._xml_request 79 | return tmp_request 80 | 81 | @property 82 | def response(self): 83 | if self._response is None: 84 | self._response = requests.get(url=self.base_url, params=self) 85 | return self._response 86 | 87 | @property 88 | def results(self): 89 | if self['ResultFormat'] == 'JSON': 90 | tmp_results = self._json_results 91 | else: 92 | tmp_results = self._xml_results 93 | return tmp_results 94 | 95 | def _element_to_series(self, e, columns): 96 | """Convert an `Element` into a `Pandas.Series` instance.""" 97 | data = [e.attrib.get(col) for col in columns] 98 | series = pd.Series(data, index=columns) 99 | return series 100 | 101 | def _elements_to_dataframe(self, elements, columns): 102 | """Convert a list of `Element` instances into a `Pandas.DataFrame`.""" 103 | series = [self._element_to_series(e, columns) for e in elements] 104 | df = pd.concat(series, axis=1).T 105 | return df 106 | 107 | def _validate_method(self, method): 108 | """Validate the Method keyword argument.""" 109 | if not isinstance(method, str): 110 | mesg = "Method keyword argument must be a string, not a {}." 111 | raise AttributeError(mesg.format(method.__class__)) 112 | elif method not in self.valid_methods: 113 | mesg = "Method keyword argument must be one of {}" 114 | raise AttributeError(mesg.format(str(self.valid_methods))) 115 | else: 116 | return method 117 | 118 | def _validate_result_format(self, fmt): 119 | """Validate the ResultFormat keyword argument.""" 120 | if not isinstance(fmt, str): 121 | mesg = "ResultFormat keyword argument must be a string, not a {}." 122 | raise AttributeError(mesg.format(fmt.__class__)) 123 | elif fmt not in self.valid_formats: 124 | mesg = "ResultFormat keyword argument must be one of {}" 125 | raise AttributeError(mesg.format(str(self.valid_formats))) 126 | else: 127 | return fmt 128 | 129 | def _validate_user_id(self, user_id): 130 | """Validate the UserID keyword argument.""" 131 | if not isinstance(user_id, str): 132 | mesg = "UserID keyword argument must be a string, not a {}." 133 | raise AttributeError(mesg.format(user_id.__class__)) 134 | else: 135 | return user_id 136 | 137 | 138 | class DataSetListRequest(Request): 139 | 140 | _dtypes = {"DatasetDescription": str, "DatasetName": str} 141 | 142 | def __init__(self, UserID, ResultFormat='JSON'): 143 | """ 144 | Create an instance of the DataSetListRequest class. 145 | 146 | Parameters 147 | ---------- 148 | UserID: str 149 | A valid UserID necessary for accessing the BEA data API. 150 | ResultFormat : str (default='JSON') 151 | The API returns data in one of two formats: JSON or XML. The 152 | ResultFormat parameter can be included on any request to specify 153 | the format of the results. The valid values for ResultFormat are 154 | `JSON' and 'XML'. 155 | 156 | """ 157 | required_params = {'UserID': UserID, 158 | 'Method': 'GetDataSetList', 159 | 'ResultFormat': ResultFormat} 160 | super(DataSetListRequest, self).__init__(**required_params) 161 | 162 | @property 163 | def _json_data_set(self): 164 | return self.results['Dataset'] 165 | 166 | @property 167 | def _xml_data_set(self): 168 | return self.results.findall('Dataset') 169 | 170 | @property 171 | def data_set_list(self): 172 | if self['ResultFormat'] == 'JSON': 173 | df = pd.DataFrame(self._json_data_set) 174 | else: 175 | df = self._elements_to_dataframe(self._xml_data_set, self._dtypes.keys()) 176 | return df.astype(self._dtypes) 177 | 178 | 179 | class ParameterListRequest(Request): 180 | 181 | _dtypes = {'MultipleAcceptedFlag': np.dtype('int'), 182 | 'ParameterDataType': np.dtype('O'), 183 | 'ParameterDefaultValue': np.dtype('O'), 184 | 'ParameterDescription': np.dtype('O'), 185 | 'ParameterIsRequiredFlag': np.dtype('int'), 186 | 'ParameterName': np.dtype('O')} 187 | 188 | def __init__(self, UserID, DataSetName, ResultFormat='JSON'): 189 | """ 190 | Create an instance of the ParameterListRequest class. 191 | 192 | Parameters 193 | ---------- 194 | UserID: str 195 | A valid UserID necessary for accessing the BEA data API. 196 | DataSetName : str 197 | A valid name of an available BEA data set. 198 | ResultFormat : str (default='JSON') 199 | The API returns data in one of two formats: JSON or XML. The 200 | ResultFormat parameter can be included on any request to specify 201 | the format of the results. The valid values for ResultFormat are 202 | 'JSON' and 'XML'. 203 | 204 | """ 205 | required_params = {'UserID': UserID, 206 | 'Method': 'GetParameterList', 207 | 'DataSetName': DataSetName, 208 | 'ResultFormat': ResultFormat} 209 | super(ParameterListRequest, self).__init__(**required_params) 210 | 211 | @property 212 | def _json_parameter_list(self): 213 | return self.results['Parameter'] 214 | 215 | @property 216 | def _xml_parameter_list(self): 217 | return self.results.findall('Parameter') 218 | 219 | @property 220 | def parameter_list(self): 221 | if self['ResultFormat'] == 'JSON': 222 | df = pd.DataFrame(self._json_parameter_list) 223 | else: 224 | df = self._elements_to_dataframe(self._xml_parameter_list, self._dtypes.keys()) 225 | return df.astype(self._dtypes) 226 | 227 | 228 | class ParameterValuesRequest(Request): 229 | 230 | _dtypes = {'Desc': np.dtype('O'), "Key": np.dtype('int')} 231 | 232 | def __init__(self, UserID, DataSetName, ParameterName, ResultFormat='JSON'): 233 | """ 234 | Create an instance of the ParameterValuesRequest class. 235 | 236 | Parameters 237 | ---------- 238 | UserID: str 239 | A valid UserID necessary for accessing the BEA data API. 240 | DataSetName : str 241 | A valid name of an available BEA data set. 242 | ParameterName : str 243 | A valid parameter name for a given data set. Note that the 244 | get_parameter_list function returns a complete listing of valid 245 | parameters names for a given data set. 246 | ResultFormat : str (default='JSON') 247 | The API returns data in one of two formats: JSON or XML. The 248 | ResultFormat parameter can be included on any request to specify 249 | the format of the results. The valid values for ResultFormat are 250 | 'JSON' and 'XML'. 251 | 252 | """ 253 | required_params = {'UserID': UserID, 254 | 'Method': 'GetParameterValues', 255 | 'DataSetName': DataSetName, 256 | 'ParameterName': ParameterName, 257 | 'ResultFormat': ResultFormat} 258 | super(ParameterValuesRequest, self).__init__(**required_params) 259 | 260 | @property 261 | def _json_parameter_values(self): 262 | return self.results['ParamValue'] 263 | 264 | @property 265 | def _xml_parameter_values(self): 266 | return self.results.findall('ParamValue') 267 | 268 | @property 269 | def parameter_values(self): 270 | if self['ResultFormat'] == 'JSON': 271 | df = pd.DataFrame(self._json_parameter_values) 272 | else: 273 | df = self._elements_to_dataframe(self._xml_parameter_values, self._dtypes.keys()) 274 | return df.astype(self._dtypes) 275 | 276 | 277 | class ParameterValuesFilteredRequest(ParameterValuesRequest): 278 | 279 | def __init__(self, UserID, DataSetName, TargetParameter, ResultFormat='JSON', **params): 280 | """ 281 | Create an instance of the ParameterValuesRequest class. 282 | 283 | Parameters 284 | ---------- 285 | UserID: str 286 | A valid UserID necessary for accessing the BEA data API. 287 | DataSetName : str 288 | A valid name of an available BEA data set. 289 | TargetParameter : str 290 | A valid parameter name for a given data set. Note that the 291 | get_parameter_list function returns a complete listing of valid 292 | parameters names for a given data set. 293 | ResultFormat : str (default='JSON') 294 | The API returns data in one of two formats: JSON or XML. The 295 | ResultFormat parameter can be included on any request to specify 296 | the format of the results. The valid values for ResultFormat are 297 | 'JSON' and 'XML'. 298 | params : dict 299 | Additional, optional, keyword arguments. 300 | 301 | """ 302 | required_params = {'UserID': UserID, 303 | 'Method': 'GetParameterValuesFiltered', 304 | 'DataSetName': DataSetName, 305 | 'ParameterName': ParameterName, 306 | 'ResultFormat': ResultFormat} 307 | required_params.update(params) 308 | super(ParameterValuesRequestFiltered, self).__init__(**required_params) 309 | 310 | 311 | class DataRequest(Request): 312 | """Base class for a DataRequest.""" 313 | 314 | # 'string' and 'numeric' are the two `DataType` values used by the BEA API 315 | _dtypes = {'string': np.dtype('O'), 'numeric': np.dtype('float')} 316 | 317 | def __init__(self, UserID, DataSetName, ResultFormat='JSON', **params): 318 | """ 319 | Create an instance of the DataRequest class. 320 | 321 | Parameters 322 | ---------- 323 | UserID: str 324 | A valid UserID necessary for accessing the BEA data API. 325 | DataSetName : str 326 | A valid name of an available BEA data set. 327 | ResultFormat : str (default='JSON') 328 | The API returns data in one of two formats: JSON or XML. The 329 | ResultFormat parameter can be included on any request to specify 330 | the format of the results. The valid values for ResultFormat are 331 | `JSON' and 'XML'. 332 | 333 | """ 334 | required_params = {'UserID': UserID, 335 | 'Method': 'GetData', 336 | 'DataSetName': DataSetName, 337 | 'ResultFormat': ResultFormat} 338 | required_params.update(params) 339 | 340 | super(DataRequest, self).__init__(**required_params) 341 | 342 | @property 343 | def _json_data(self): 344 | return self.results['Data'] 345 | 346 | @property 347 | def _json_dimensions(self): 348 | return self.results['Dimensions'] 349 | 350 | @property 351 | def _json_notes(self): 352 | return self.results['Notes'] 353 | 354 | @property 355 | def _xml_data(self): 356 | return self.results.findall('Data') 357 | 358 | @property 359 | def _xml_dimensions(self): 360 | return self.results.findall('Dimensions') 361 | 362 | @property 363 | def _xml_notes(self): 364 | return self.results.findall('Notes') 365 | 366 | @property 367 | def data(self): 368 | if self['ResultFormat'] == 'JSON': 369 | dtypes = self._json_to_dtypes(self._json_dimensions) 370 | df = pd.DataFrame(self._json_data) 371 | else: 372 | dtypes = self._elements_to_dtypes(self._xml_dimensions) 373 | df = self._elements_to_dataframe(self._xml_data, dtypes.keys()) 374 | 375 | # impose some additional structure on dtypes 376 | if 'UNIT_MULT' in dtypes: 377 | dtypes['UNIT_MULT'] = np.dtype('int') 378 | if "TableID" in dtypes: 379 | dtypes["TableID"] = np.dtype("int") 380 | if "LineNumber" in dtypes: 381 | dtypes["LineNumber"] = np.dtype("int") 382 | 383 | # some ad-hoc cleaning of DataValue column is necessary 384 | df.DataValue.replace(",", "", regex=True, inplace=True) 385 | df.DataValue.replace("(NA)", "NaN", inplace=True) 386 | 387 | result = df.astype(dtypes) 388 | return result 389 | 390 | @property 391 | def notes(self): 392 | if self['ResultFormat'] == 'JSON': 393 | df = pd.DataFrame(self._json_notes) 394 | else: 395 | dtypes = self._elements_to_dtypes(self._xml_dimensions) 396 | df = self._elements_to_dataframe(self._xml_notes, dtypes.keys()) 397 | return df 398 | 399 | @classmethod 400 | def _elements_to_dtypes(cls, elements): 401 | """Converts a list of `Element` instances into a dtype dictionary.""" 402 | dtypes = {} 403 | for element in elements: 404 | k, v = element.attrib.get('Name'), element.attrib.get('DataType') 405 | dtypes[k] = cls._dtypes[v] 406 | return dtypes 407 | 408 | @classmethod 409 | def _json_to_dtypes(cls, objects): 410 | """Converts a list of JSON objects into a dtype dictionary.""" 411 | dtypes = {} 412 | for o in objects: 413 | k, v = o.get('Name'), o.get('DataType') 414 | dtypes[k] = cls._dtypes[v] 415 | return dtypes 416 | 417 | 418 | class ITARequest(DataRequest): 419 | 420 | def __init__(self, UserID, Indicator, AreaOrCountry, Frequency, Year, 421 | ResultFormat='JSON', **params): 422 | r""" 423 | Create an instance of the ITARequest class. 424 | 425 | Parameters 426 | ---------- 427 | UserID: str 428 | A valid UserID necessary for accessing the BEA data API. 429 | Indicator : str 430 | The `Indicator` parameter specifies the type of transaction. The 431 | `Indicator` parameter values correspond to lines in `ITA tables`_. 432 | Exactly one `Indicator` parameter value must be provided in all 433 | data requests unless exactly one `AreaOrCountry` parameter value 434 | other than “ALL” and “AllCountries” is requested. That is, multiple 435 | Indicators can only be specified if a single `AreaOrCountry` is 436 | specified. 437 | AreaOrCountry : str or list(str) 438 | The AreaOrCountry parameter specifies the counterparty area or 439 | country of the transactions. The default parameter value 440 | (“AllCountries”) returns the total for all countries, while “All” 441 | returns all data available by area and country. Exactly one 442 | `AreaOrCountry` parameter value must be provided in all data 443 | requests unless exactly one `Indicator` parameter value is 444 | requested. This single parameter value may not be either “ALL” or 445 | “AllCountries.” That is, a list of countries or the grand total for 446 | all countries can only be specified if a single Indicator is 447 | specified. For information on geographic area definitions, see the 448 | definitions on the `BEA website`_. 449 | Frequency : str 450 | One of `A` for annual; `QSA` for quarterly seasonally adjusted, or 451 | `QNSA` for quarterly not seasonally adjusted, depending. 452 | Year : str or list(str) 453 | A string representation of the year for which data is being 454 | requested. Multiple years are requested by specifying them as a 455 | list: `Year=['2000', '2005' , '2010']`. Data for all available 456 | years can be requested by passing 'ALL'. 457 | ResultFormat : str (default='JSON') 458 | The API returns data in one of two formats: JSON or XML. The 459 | ResultFormat parameter can be included on any request to specify 460 | the format of the results. The valid values for ResultFormat are 461 | 'JSON' and 'XML'. 462 | 463 | .. _`ITA tables`: https://www.bea.gov/iTable/iTable.cfm?reqid=62&step=2&isuri=1&6210=1#reqid=62&step=2&isuri=1&6210=1 464 | .. _`BEA website`: https://www.bea.gov/international/bp_web/geographic_area_definitions.cfm 465 | 466 | 467 | """ 468 | required_params = {'UserID': UserID, 469 | 'Method': 'GetData', 470 | 'DataSetName': 'ITA', 471 | 'Indicator': Indicator, 472 | 'AreaOrCountry': AreaOrCountry, 473 | 'Frequency': Frequency, 474 | 'Year': Year, 475 | 'ResultFormat': ResultFormat} 476 | required_params.update(params) 477 | super(ITARequest, self).__init__(**required_params) 478 | 479 | 480 | class RegionalProductRequest(DataRequest): 481 | 482 | def __init__(self, UserID, Component, IndustryId, GeoFips, ResultFormat='JSON', **params): 483 | r""" 484 | Create an instance of the RegionalProductRequest class. 485 | 486 | Parameters 487 | ---------- 488 | UserID: str 489 | A valid UserID necessary for accessing the BEA data API. 490 | Component : str 491 | Component name. 492 | IndustryId: int 493 | Industry code of the Component. 494 | GeoFips : str or list(str) 495 | Comma-delimited list of state or MSA codes. Other values are 'STATE' 496 | for all states, and 'MSA' for all Metropolitan Statistical Areas. 497 | ResultFormat : str (default='JSON') 498 | The API returns data in one of two formats: JSON or XML. The 499 | ResultFormat parameter can be included on any request to specify 500 | the format of the results. The valid values for ResultFormat are 501 | 'JSON' and 'XML'. 502 | params : dict 503 | Dictionary of optional parameters. 504 | 505 | Notes 506 | ----- 507 | The optional parameters for RegionalProductRequest are: 508 | 509 | Year : str or list(str) (default='ALL') 510 | A string representation of the year for which data is being 511 | requested. Multiple years are requested by specifying them as a 512 | list: `Year=['2000', '2005' , '2010']`. Note that Year will default 513 | to all available years, 'ALL', if the parameter is not specified. 514 | Additional options are `LAST5` and `LAST10`. 515 | 516 | """ 517 | required_params = {'UserID': UserID, 518 | 'Method': 'GetData', 519 | 'DataSetName': 'RegionalProduct', 520 | 'Component': Component, 521 | 'IndustryId': IndustryId, 522 | 'GeoFips': GeoFips, 523 | 'ResultFormat': ResultFormat} 524 | required_params.update(params) 525 | super(RegionalProductRequest, self).__init__(**required_params) 526 | 527 | 528 | class RegionalIncomeRequest(DataRequest): 529 | 530 | def __init__(self, UserID, TableName, LineCode, GeoFips, ResultFormat='JSON', **params): 531 | r""" 532 | Create an instance of the RegionalIncomeRequest class. 533 | 534 | Parameters 535 | ---------- 536 | UserID: str 537 | A valid UserID necessary for accessing the BEA data API. 538 | TableName : str 539 | Published table name. 540 | LineCode : int 541 | Line code in table. 542 | GeoFips : str or list(str) 543 | Comma-delimited list of 5-character geographic codes; 'COUNTY' for 544 | all counties, 'STATE' for all states, 'MSA' for all Metropolitan 545 | Statistical Areas, 'MIC' for all Micropolitan Areas, 'PORT' for all 546 | state metropolitan/nonmetropolitan portions, 'DIV' for all 547 | Metropolitan Divisions, 'CSA' for all Combined Statistical Areas, 548 | state post office abbreviation for all counties in one state 549 | (e.g. 'NY'). 550 | ResultFormat : str (default='JSON') 551 | The API returns data in one of two formats: JSON or XML. The 552 | ResultFormat parameter can be included on any request to specify 553 | the format of the results. The valid values for ResultFormat are 554 | 'JSON' and 'XML'. 555 | params : dict 556 | Dictionary of optional parameters. 557 | 558 | Notes 559 | ----- 560 | The optional parameters for RegionalIncomeRequest are: 561 | 562 | Year : str or list(str) (default='LAST5') 563 | A string representation of the year for which data is being 564 | requested. Multiple years are requested by specifying them as a 565 | list: `Year=['2000', '2005' , '2010']`. Note that Year will default 566 | to last five available years, 'LAST5', if the parameter is not 567 | specified. Additional options are `LAST10` and `ALL`. 568 | 569 | """ 570 | required_params = {'UserID': UserID, 571 | 'Method': 'GetData', 572 | 'DataSetName': 'RegionalIncome', 573 | 'TableName': TableName, 574 | 'LineCode': LineCode, 575 | 'GeoFips': GeoFips, 576 | 'ResultFormat': ResultFormat} 577 | required_params.update(params) 578 | super(RegionalIncomeRequest, self).__init__(**required_params) 579 | 580 | 581 | class NIPARequest(DataRequest): 582 | 583 | def __init__(self, UserID, TableName, Frequency, Year="X", ResultFormat='JSON', **params): 584 | """ 585 | Create an instance of the NIPARequest class. 586 | 587 | Parameters 588 | ---------- 589 | UserID: str 590 | A valid UserID necessary for accessing the BEA data API. 591 | TableName : str 592 | The TableID parameter is an integer that refers to a specific NIPA 593 | table. Note that the list of valid TableIDs may change depending on 594 | the monthly news release cycles. 595 | Frequency : str or list(str) 596 | The Frequency parameter is a string that refers to the time series 597 | for the requested NIPA table. Multiple frequencies are requested by 598 | specifying them as a list: `Frequency=['A', 'Q' , 'M']`. When data 599 | is requested for frequencies that don't exist for a particular NIPA 600 | table, only data that exists is returned. 601 | Year : str or list(str) (default='X' for all available years) 602 | A string representation of the year for which data is being 603 | requested. Multiple years are requested by specifying them as a 604 | list: `Year=['2000', '2005' , '2010']`. Note that Year will default 605 | to all available years if the parameter is not specified. 606 | ResultFormat : str (default='JSON') 607 | The API returns data in one of two formats: JSON or XML. The 608 | ResultFormat parameter can be included on any request to specify 609 | the format of the results. The valid values for ResultFormat are 610 | 'JSON' and 'XML'. 611 | params : dict 612 | Dictionary of optional parameters. Note that the list of valid 613 | optional parameters is data set specific. 614 | 615 | Notes 616 | ----- 617 | The optional parameters for NIPARequest are: 618 | 619 | ShowMillions : str 620 | The ShowMillions parameter is a string indicating whether the data 621 | for the requested NIPA table should be returned in million-dollar 622 | units. Million-dollar estimate data doesn't exist for all tables, 623 | and data is returned in million-dollar units only if available. 624 | When million-dollar data doesn't exist for a table, data is 625 | returned as if million-dollar data was not requested. 626 | 627 | """ 628 | required_params = {'UserID': UserID, 629 | 'Method': 'GetData', 630 | 'DataSetName': 'NIPA', 631 | 'TableName': TableName, 632 | 'Frequency': Frequency, 633 | 'Year': Year, 634 | 'ResultFormat': ResultFormat} 635 | required_params.update(params) 636 | super(NIPARequest, self).__init__(**required_params) 637 | 638 | 639 | class NIUnderlyingDetailRequest(DataRequest): 640 | 641 | def __init__(self, UserID, TableName, Frequency, Year, ResultFormat='JSON'): 642 | """ 643 | Create an instance of the NIUnderlyingDetailRequest class. 644 | 645 | Parameters 646 | ---------- 647 | UserID: str 648 | A valid UserID necessary for accessing the BEA data API. 649 | TableName : str 650 | The TableName parameter is a string that identifies a specific NIPA 651 | Underlying Detail table. Only one NIPA Underlying Detail table can 652 | be requested in each data request. Requests with an invalid 653 | combination of TableName, Frequency or Year values will result in 654 | an error. 655 | Frequency : str or list(str) 656 | The Frequency parameter is a string that refers to the time series 657 | for the requested NIPA table. Multiple frequencies are requested by 658 | specifying them as a list: `Frequency=['A', 'Q', 'M']`. When data 659 | is requested for frequencies that don't exist for a particular NIPA 660 | table, only data that exists is returned. 661 | Year : str or list(str) (default='ALL') 662 | A string representation of the year for which data is being 663 | requested. Multiple years are requested by specifying them as a 664 | list: `Year=['2000', '2005' , '2010']`. Note that Year will default 665 | to all available years if the parameter is not specified. 666 | ResultFormat : str (default='JSON') 667 | The API returns data in one of two formats: JSON or XML. The 668 | ResultFormat parameter can be included on any request to specify 669 | the format of the results. The valid values for ResultFormat are 670 | 'JSON' and 'XML'. 671 | 672 | """ 673 | required_params = {'UserID': UserID, 674 | 'Method': 'GetData', 675 | 'DataSetName': 'NIUnderlyingDetail', 676 | 'TableName': TableName, 677 | 'Frequency': Frequency, 678 | 'Year': Year, 679 | 'ResultFormat': ResultFormat} 680 | super(NIUnderlyingDetailRequest, self).__init__(**required_params) 681 | 682 | 683 | class FixedAssetsRequest(DataRequest): 684 | 685 | def __init__(self, UserID, TableID, Year, ResultFormat='JSON'): 686 | """ 687 | Create an instance of the FixedAssetsRequest class. 688 | 689 | Parameters 690 | ---------- 691 | UserID: str 692 | A valid UserID necessary for accessing the BEA data API. 693 | TableID : str 694 | The TableID parameter is an integer that refers to a specific 695 | FixedAssets table. 696 | Year : str or list(str) (default='X') 697 | A string representation of the year for which data is being 698 | requested. Multiple years are requested by specifying them as a 699 | list: `Year=['2000', '2005' , '2010']`. Note that Year will default 700 | to all available years if the parameter is not specified. 701 | ResultFormat : str (default='JSON') 702 | The API returns data in one of two formats: JSON or XML. The 703 | ResultFormat parameter can be included on any request to specify 704 | the format of the results. The valid values for ResultFormat are 705 | 'JSON' and 'XML'. 706 | 707 | """ 708 | required_params = {'UserID': UserID, 709 | 'Method': 'GetData', 710 | 'DataSetName': 'FixedAssets', 711 | 'TableID': TableID, 712 | 'Year': Year, 713 | 'ResultFormat': ResultFormat} 714 | super(FixedAssetsRequest, self).__init__(**required_params) 715 | --------------------------------------------------------------------------------