├── .github └── workflows │ ├── format.yml │ ├── publish.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── _quarto.yml ├── changelog.md ├── docs ├── data │ ├── GENDER_EQUALITY.GE_GII.csv │ ├── GENDER_EQUALITY.pickle │ ├── IFS.LP_PE_NUM.csv │ ├── IFS.NGDP_D_SA_IX.csv │ ├── IFS.NGDP_XDC.csv │ ├── IFS.pickle │ └── databases.csv ├── databases.qmd ├── datasets.qmd ├── demo.qmd ├── installation.qmd ├── parameters.qmd ├── rate_limits.qmd ├── static │ ├── Headshot.jpg │ └── llms.txt └── usage.qmd ├── experimental ├── download_databases.py └── download_indicators.py ├── imfp ├── __init__.py ├── admin.py ├── data.py └── utils.py ├── index.qmd ├── mypy.ini ├── pyproject.toml ├── tests ├── __init__.py ├── responses │ ├── 0492d2c673234c8b4351a965d177830557855c6504d064eff10276e374f733a2.json │ ├── 0be2d7f908e4361ab4b280c6420aaa2ac48024f8b65421550b97ade655bb275c.json │ ├── 167923e1a4ca6c4b2d753ee87c4bf37c3f343b5145ccb2d9af37e73445b3014a.json │ ├── 18e38acf912c48c22a91c29c71110f6918ddc8530da18fc195a70344835c2658.json │ ├── 1a87bb86263c3393b6e9161caebb5413b96eff9d8bb7e799ed0ad544504b8a3e.json │ ├── 2dad10767ce9632931baf439dd88c766eb346c4d89d5849014a2e0f69ad4cc5c.json │ ├── 4421ce6d93ac13daa2466aee1db3c90be8091e9fdcec4591f312b2036afc4d0e.json │ ├── 54d693d531be56db0b2c65dcfcd1feeadf5ca875afafa8d4d81390a7a46c0269.json │ ├── 5b8ea149be6a417c3417540fed63f39f51027ded7603192d65624a3cef5f70f6.json │ ├── 6c0dda700dcbbd487f4a0abee7e6c0541848b5b254806b24d84d01acea280156.json │ ├── 70da50370c93a6db03ecb77506c0d8d99c1edebc4715b121f72817db77d2dec8.json │ ├── 71ea273f717cde44a36f207915a2d4c125ce0db250075fdf67ff8c6278dcbf6a.json │ ├── 74c9d030bf0d4671bed26b0c8c4b5d9ba99137916bdeafcaa09c9bf015f14040.json │ ├── 7a5eb96e0fb69d0163be56543efcc84681fa4aa714b346be3a324df709eea90e.json │ ├── 7e89af364cdf5466341cee28b1e5ab022f102c9deb60975e51e9b6357a2cd0b6.json │ ├── 853b070a5f371baa0266ac85dc18fef90f49d5b7f46634e365373b0396e6a825.json │ ├── 88d4c959bf3cb72af608f998e6073a21ede6976ad5a135cfe354f44e1b8ef158.json │ ├── 9389b5b12ec2506f945561b5cd2677e344b7669f311d5889f4d492898b1b8c82.json │ ├── 96418874c9efcc78c9c6f32b6b2db71b181b5b13cefa60a87500945e070ddf1c.json │ ├── 9729441e62b866b218f2c3b2d46e130715880dcecf9601c785d435bb0a650187.json │ ├── 99011ca9d9c0254302eda9eae9a11cf84547b5da409f2b9f835e84d553c8f6de.json │ ├── 994ba19449a36d5309efc65d1897497c8b2276000346eb33ac4fb412a8ee107b.json │ ├── 9c0f19b539fdf2fef0eaf7d13b710db9dfea34545a7b8c77207ab9a061b35bde.json │ ├── 9cb6d469264c3143b4cd8728ea57a8674a5449356a36a3a3914ce4e8c16b23d5.json │ ├── 9d084971a2602e85454daed6f45c2e435f38a3226af0e255ef1e2512a63e427d.json │ ├── 9efd32c5e4f2add3934730a10bb1f379e4b8335e55ee9a3fa79339e7e3f3c32b.json │ ├── aa3ebaaaada203bc41db5f152079c52351ad29421c80502f2437dd163ff8cc75.json │ ├── b9aa21417de4354522d04ac2d6fd6bdcfbc3ccaa161d5f35a888284d2c813240.json │ ├── be998e19a868fd4831a1a7d6c8bebfba443e40a028b8d75270ee9926fe930ca5.json │ ├── bf3c686e3ee1c7c75d3b9a1d9780c12c0d83eff3dccb0d2aaacc8a482095e857.json │ ├── bf90c1b9d850a6a425a5bb73a91aea4bb6c40b88ce898a90ccbc6f73829a729c.json │ ├── c1e6b5a48b9c67f127af854207ff7c147b8a19faa5b1aec08e88b5a57bdded96.json │ ├── d133587671c1b64ef12f30b841c507c85b17d52f81d367856f101245e9779cf2.json │ ├── d6bd4b36396414f070a68802fe9e509fdc82928d88a6dc3821a48f4e40542ce7.json │ ├── d6d401840c0745c103a251d427313a183f5a2ce869c3a0886bc8de1e3641cafd.json │ ├── ded599b2f832bd8b9d12f624a9242a9288da39e05f1e583769bf8183929ac525.json │ ├── dee06a4674a0979ad4a97e21dc84d886a4d25d2756e2cffff61f6082cfaabee4.json │ ├── e10427a320166a298902487c055d4ee2acd79f2eee51d76f63eea44f40a80c06.json │ ├── ecbb2d76546e44deb863594037713496e56b2a7971c475bd4717c6025d9c5bf3.json │ ├── ef0761bdfbcbcaf1511b72e4da8af31614e70cd8342c403a718117cef9335479.json │ ├── ef2557079983e2791002a31aad1f884431fa0c82965370dcedae49a27f780635.json │ ├── f47414735adbb906b7aa69135a9df5f59b72fe4800de3c9e36adf0d1308dd804.json │ ├── f7c5e13484c7c15cef7b062d32a36695aa30de4ae2557e284b54b1f35c98211e.json │ ├── fdbe33d7b2ea97afdf898c7a2cc55b4affcbe7a565c494fee410d2fd33a32759.json │ └── fddfa660fef62f5f457f207de95739738f207c8bc128ac29fb99203f8d3b84bb.json ├── test_admin.py ├── test_data.py └── test_utils.py └── uv.lock /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: format 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | format: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: write 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - uses: rickstaa/action-black@v1 15 | with: 16 | black_args: "." 17 | 18 | - name: Commit and push changes to repository 19 | uses: stefanzweifel/git-auto-commit-action@v5 20 | with: 21 | commit_message: 'Automated code format' 22 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | push: 5 | branches: main 6 | 7 | jobs: 8 | publish-documentation: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: write 12 | steps: 13 | - name: Check out repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Install uv 17 | uses: astral-sh/setup-uv@v5 18 | 19 | - name: "Set up Python" 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version-file: "pyproject.toml" 23 | 24 | - name: Install dependencies 25 | run: uv sync 26 | 27 | - name: Set up Quarto 28 | uses: quarto-dev/quarto-actions/setup@v2 29 | 30 | - name: Configure Git 31 | run: | 32 | git config --global user.name "github-actions[bot]" 33 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 34 | 35 | - name: Render and Publish 36 | run: uv run quarto publish gh-pages --no-prompt --no-browser -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | permissions: 8 | id-token: write 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Generate token for version incrementer app 16 | id: create_token 17 | uses: tibdex/github-app-token@v2 18 | with: 19 | app_id: ${{ secrets.APP_ID }} 20 | private_key: ${{ secrets.PRIVATE_KEY }} 21 | 22 | - name: Setup | Checkout Repository at workflow sha 23 | uses: actions/checkout@v4 24 | with: 25 | fetch-depth: 0 26 | ref: ${{ github.sha }} 27 | token: ${{ steps.create_token.outputs.token }} 28 | 29 | - name: Setup | Force correct release branch on workflow sha 30 | run: | 31 | git checkout -B ${{ github.ref_name }} ${{ github.sha }} 32 | 33 | - name: Install uv 34 | uses: astral-sh/setup-uv@v5 35 | 36 | - name: "Set up Python" 37 | uses: actions/setup-python@v5 38 | with: 39 | python-version-file: "pyproject.toml" 40 | 41 | - name: Install dependencies 42 | run: | 43 | uv sync 44 | 45 | - name: Python Semantic Release 46 | id: release 47 | uses: python-semantic-release/python-semantic-release@v9.16.1 48 | with: 49 | github_token: ${{ secrets.GITHUB_TOKEN }} 50 | commit: false 51 | 52 | - name: Build project wheel and test that it installs without errors 53 | run: | 54 | uv build 55 | uv sync 56 | uv pip install dist/imfp-*.whl 57 | 58 | - name: Run tests 59 | run: | 60 | uv run pytest 61 | 62 | - name: Release to PyPI 63 | uses: pypa/gh-action-pypi-publish@release/v1 64 | with: 65 | packages-dir: dist/ 66 | 67 | - name: Publish | Upload to GitHub Release Assets 68 | uses: python-semantic-release/publish-action@v9.16.1 69 | if: steps.release.outputs.released == 'true' 70 | with: 71 | github_token: ${{ secrets.GITHUB_TOKEN }} 72 | tag: ${{ steps.release.outputs.tag }} 73 | 74 | - name: Commit version change 75 | uses: stefanzweifel/git-auto-commit-action@v5 76 | with: 77 | commit_message: "Release ${{ steps.release.outputs.tag }} [skip ci]" 78 | branch: ${{ github.ref_name }} 79 | file_pattern: "pyproject.toml changelog.md uv.lock" 80 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | test: 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | python-version: ["3.10", "3.13"] 12 | os: [ubuntu-latest] 13 | defaults: 14 | run: 15 | shell: bash 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - name: Install uv 21 | uses: astral-sh/setup-uv@v5 22 | 23 | - uses: actions/setup-python@v5 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | 27 | - name: Set up Quarto 28 | uses: quarto-dev/quarto-actions/setup@v2 29 | 30 | - name: Install dependencies and test that documentation renders and tests pass 31 | run: | 32 | uv sync 33 | uv run quarto render 34 | uv run pytest tests 35 | outputs: 36 | matrix: ${{ toJson(matrix) }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # VSCode files 2 | .vscode 3 | 4 | # Byte-compiled / optimized / DLL files 5 | *__pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 89 | __pypackages__/ 90 | 91 | # Celery stuff 92 | celerybeat-schedule 93 | celerybeat.pid 94 | 95 | # SageMath parsed files 96 | *.sage.py 97 | 98 | # Environments 99 | .env 100 | .venv 101 | env/ 102 | venv/ 103 | ENV/ 104 | env.bak/ 105 | venv.bak/ 106 | 107 | # Spyder project settings 108 | .spyderproject 109 | .spyproject 110 | 111 | # Rope project settings 112 | .ropeproject 113 | 114 | # rendered documentation 115 | _site/ 116 | 117 | # mypy 118 | .mypy_cache/ 119 | .dmypy.json 120 | dmypy.json 121 | 122 | # Pyre type checker 123 | .pyre/ 124 | 125 | # pytype static type analyzer 126 | .pytype/ 127 | 128 | # Cython debug symbols 129 | cython_debug/ 130 | 131 | # Quarto 132 | /.quarto/ 133 | 134 | # AI chat histories 135 | .specstory 136 | 137 | # Mac 138 | .DS_Store 139 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imfp 2 | 3 | [![Tests](https://github.com/Promptly-Technologies-LLC/imfp/actions/workflows/test.yml/badge.svg)](https://github.com/Promptly-Technologies-LLC/imfp/actions/workflows/test.yml) 4 | [![PyPI Version](https://img.shields.io/pypi/v/imfp.svg)](https://pypi.python.org/pypi/imfp) 5 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 6 | 7 | `imfp`, by Christopher C. Smith, is a Python package for downloading data from the [International Monetary Fund's](http://data.imf.org/) RESTful JSON API. 8 | 9 | **[📚 Full Documentation](https://promptlytechnologies.com/imfp/)** 10 | 11 | ## Installation 12 | 13 | ```bash 14 | pip install -q --upgrade imfp 15 | ``` 16 | 17 | ## Quick Start 18 | 19 | ```python 20 | import imfp 21 | 22 | # Get list of available databases 23 | databases = imfp.imf_databases() 24 | 25 | # Get parameters for a specific database (e.g., PCPS - Primary Commodity Price System) 26 | params = imfp.imf_parameters("PCPS") 27 | 28 | # Fetch data with specific parameters 29 | df = imfp.imf_dataset( 30 | database_id="PCPS", 31 | freq=["A"], 32 | start_year=2000, 33 | end_year=2015 34 | ) 35 | ``` 36 | 37 | ## Key Features 38 | 39 | - Comprehensive access to IMF's extensive economic databases 40 | - Parameter discovery 41 | - Rate limit and bandwidth management 42 | - Returns data in pandas DataFrames 43 | 44 | ## Contributing 45 | 46 | We welcome contributions to improve `imfp`! Here's how you can help: 47 | 48 | 1. If you find a bug, please open an issue 49 | 2. To fix a bug: 50 | - Fork and clone the repository and open a terminal in the repository directory 51 | - Install [uv](https://astral.sh/setup-uv/) with `curl -LsSf https://astral.sh/uv/install.sh | sh` 52 | - Install the dependencies with `uv sync` 53 | - Install a git hook to enforce conventional commits with `curl -o- https://raw.githubusercontent.com/chriscarrollsmith/conventional-commits-git-hook/master/scripts/install.sh | sh` 54 | - Create a fix, commit it with an ["Angular-style Conventional Commit"](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) message, and push it to your fork 55 | - Open a pull request to our `main` branch 56 | 57 | Note that if you want to change and preview the documentation, you will need to install the [Quarto CLI tool](https://quarto.org/docs/download/). 58 | 59 | Version incrementing, package building, testing, changelog generation, documentation rendering, publishing to PyPI, and Github release creation is handled automatically by the GitHub Actions workflow based on the commit messages. 60 | -------------------------------------------------------------------------------- /_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | output-dir: _site 4 | render: 5 | - "*.qmd" 6 | - "!changelog.md" 7 | 8 | website: 9 | title: "imfp" 10 | search: true 11 | navbar: 12 | left: 13 | - text: Quickstart 14 | href: index.qmd 15 | - text: Installation 16 | href: docs/installation.qmd 17 | - text: Databases 18 | href: docs/databases.qmd 19 | - text: Parameters 20 | href: docs/parameters.qmd 21 | - text: Datasets 22 | href: docs/datasets.qmd 23 | - text: Usage 24 | href: docs/usage.qmd 25 | - text: Rate Limits 26 | href: docs/rate_limits.qmd 27 | - text: Demo 28 | href: docs/demo.qmd 29 | right: 30 | - icon: github 31 | href: https://github.com/Promptly-Technologies-LLC/imfp 32 | page-footer: 33 | left: "Copyright 2024, Promptly Technologies, LLC. MIT License." 34 | right: 35 | - icon: github 36 | href: https://github.com/Promptly-Technologies-LLC/imfp 37 | 38 | format: 39 | html: 40 | theme: cosmo 41 | toc: true -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | ## v1.2.1 (2025-06-30) 5 | 6 | ### Bug Fixes 7 | 8 | - Bump version for dependabot chores 9 | ([`cba9584`](https://github.com/Promptly-Technologies-LLC/imfp/commit/cba9584ff542ad1440b00f933453f50b0e46cfe0)) 10 | 11 | ### Chores 12 | 13 | - Make sure version-incremented lockfile gets committed during CI release 14 | ([`848c355`](https://github.com/Promptly-Technologies-LLC/imfp/commit/848c35583230b29c62ff32ea30bd20d5f0495a08)) 15 | 16 | - **deps**: Bump requests in the pip group across 1 directory 17 | ([`52ac3a3`](https://github.com/Promptly-Technologies-LLC/imfp/commit/52ac3a3187c5ceaf5ec97d8c7f15ca73cd5c4479)) 18 | 19 | Bumps the pip group with 1 update in the / directory: [requests](https://github.com/psf/requests). 20 | 21 | Updates `requests` from 2.32.3 to 2.32.4 - [Release notes](https://github.com/psf/requests/releases) 22 | - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - 23 | [Commits](https://github.com/psf/requests/compare/v2.32.3...v2.32.4) 24 | 25 | --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 26 | 27 | dependency-type: direct:production 28 | 29 | dependency-group: pip 30 | 31 | ... 32 | 33 | Signed-off-by: dependabot[bot] 34 | 35 | 36 | ## v1.2.0 (2025-02-08) 37 | 38 | ### Bug Fixes 39 | 40 | - Resolve mypy errors 41 | ([`5e0ac24`](https://github.com/Promptly-Technologies-LLC/imfp/commit/5e0ac24206746621a10242a5815f67ba4a67bc8c)) 42 | 43 | ### Chores 44 | 45 | - Gitignore DS_STORE 46 | ([`4878b90`](https://github.com/Promptly-Technologies-LLC/imfp/commit/4878b907171294ff8f81439dceb817b46a15a243)) 47 | 48 | - Update lockfile 49 | ([`a5a70ea`](https://github.com/Promptly-Technologies-LLC/imfp/commit/a5a70ea34774f670e8fdab4ca5b6b0dadcdea662)) 50 | 51 | ### Documentation 52 | 53 | - Point to a conventional commit hook that works on POSIX systems 54 | ([`89d5a11`](https://github.com/Promptly-Technologies-LLC/imfp/commit/89d5a11e274f7aab975d9902a9194edbadb95b3f)) 55 | 56 | - Remove leftover tail call from usage.qmd 57 | ([`a92f91d`](https://github.com/Promptly-Technologies-LLC/imfp/commit/a92f91da649da258949de94a19e14ea9c5c5132e)) 58 | 59 | ### Features 60 | 61 | - Resolved mypy errors and enhanced function argument type enforcement 62 | ([`dd2e41a`](https://github.com/Promptly-Technologies-LLC/imfp/commit/dd2e41aa96e8d320d52c50e60a7721941006b249)) 63 | 64 | 65 | ## v1.1.10 (2025-01-27) 66 | 67 | ### Bug Fixes 68 | 69 | - Add missing imports to usage examples 70 | ([`e5729c6`](https://github.com/Promptly-Technologies-LLC/imfp/commit/e5729c6a5bf8830a96b13a3d18ed6542b9b91177)) 71 | 72 | - Handle dev as dependency group, not an extra 73 | ([`baf6b98`](https://github.com/Promptly-Technologies-LLC/imfp/commit/baf6b9828804f0cdbb27973eeb058326140b5203)) 74 | 75 | - Resolve some documentation rendering errors 76 | ([`604e5e6`](https://github.com/Promptly-Technologies-LLC/imfp/commit/604e5e62e848e9b54ee0d70508037cd77bd87c97)) 77 | 78 | ### Code Style 79 | 80 | - Added mypy dev dependency 81 | ([`dd632a9`](https://github.com/Promptly-Technologies-LLC/imfp/commit/dd632a9bea26eca7da92122f49fca92142b37f52)) 82 | 83 | ### Documentation 84 | 85 | - Add search and code fold functionality to documentation 86 | ([`fbfec44`](https://github.com/Promptly-Technologies-LLC/imfp/commit/fbfec44d875e327530f3c7c1d24592fc3a449ebb)) 87 | 88 | - Added exchange rate conversion 89 | ([`ec1d705`](https://github.com/Promptly-Technologies-LLC/imfp/commit/ec1d705d08d2d93a351097d3beadb0093706cb13)) 90 | 91 | - Added llms.txt 92 | ([`8e97b33`](https://github.com/Promptly-Technologies-LLC/imfp/commit/8e97b331f0595c3bce19a38e0d1dc0f45133af88)) 93 | 94 | - Complete first draft of refactored documentation 95 | ([`653a4ee`](https://github.com/Promptly-Technologies-LLC/imfp/commit/653a4ee712f71cc30d635ed1c297080adedb732b)) 96 | 97 | - Fixed broken Github Actions test workflow badge 98 | ([`cbde373`](https://github.com/Promptly-Technologies-LLC/imfp/commit/cbde373fca9d9b1de9f421d3d9bba0f141d6bd32)) 99 | 100 | - Polished the usage page and added a rate limits page 101 | ([`3acf267`](https://github.com/Promptly-Technologies-LLC/imfp/commit/3acf2670ea68afdf52f972b6dcf4f078f5aeea13)) 102 | 103 | - Rewrote the quickstart guide 104 | ([`8684aff`](https://github.com/Promptly-Technologies-LLC/imfp/commit/8684aff05f5080b7670f0147c5356d843693c669)) 105 | 106 | - Some minor copyediting 107 | ([`7bdf61d`](https://github.com/Promptly-Technologies-LLC/imfp/commit/7bdf61dc4bf19dafa69a135342b7963e9c95627b)) 108 | 109 | - Updated documentation for parameters function 110 | ([`d3dc190`](https://github.com/Promptly-Technologies-LLC/imfp/commit/d3dc190797e1b9bc08744b8b8556b163fb43e40f)) 111 | 112 | - Worked out bugs in documentation examples 113 | ([`386fee3`](https://github.com/Promptly-Technologies-LLC/imfp/commit/386fee30abfa6343afd890271f00a862dcd30069)) 114 | 115 | 116 | ## v1.1.9 (2025-01-19) 117 | 118 | ### Bug Fixes 119 | 120 | - Commit changelog generated in ci back to repo 121 | ([`8e04da4`](https://github.com/Promptly-Technologies-LLC/imfp/commit/8e04da44b9aca422c82ceec4a5145ac1707f8669)) 122 | 123 | 124 | ## v1.1.8 (2025-01-19) 125 | 126 | 127 | ## v1.1.7 (2025-01-19) 128 | 129 | ### Bug Fixes 130 | 131 | - Authenticate to Github actions with app to permit version bump push 132 | ([`97d42c7`](https://github.com/Promptly-Technologies-LLC/imfp/commit/97d42c7b97530ec0443a2d4c2f223fa5c7c185e3)) 133 | 134 | - Skip ci workflow on version bump 135 | ([`666562b`](https://github.com/Promptly-Technologies-LLC/imfp/commit/666562bc26ddbe096f50b7f98cc214c4c9645a33)) 136 | 137 | - Version bump [skip ci] 138 | ([`bec937c`](https://github.com/Promptly-Technologies-LLC/imfp/commit/bec937cf741dbea14835c134122a22b4c7d4f2cf)) 139 | 140 | 141 | ## v1.1.6 (2025-01-18) 142 | 143 | ### Bug Fixes 144 | 145 | - Add uv to path as part of build command 146 | ([`f12fcac`](https://github.com/Promptly-Technologies-LLC/imfp/commit/f12fcac1b4a90b0d052c31772e3730db2f1bf627)) 147 | 148 | - Don't use the semantic-version action for build or commit steps 149 | ([`1102d90`](https://github.com/Promptly-Technologies-LLC/imfp/commit/1102d9043839c428654a38825b28f7181efcbdbc)) 150 | 151 | - Incorporate package build into semantic release version action 152 | ([`7a2251c`](https://github.com/Promptly-Technologies-LLC/imfp/commit/7a2251c4866bf344985e631aad13b41640ce746f)) 153 | 154 | - Install uv in semantic-release build command since it's containerized 155 | ([`8db02e2`](https://github.com/Promptly-Technologies-LLC/imfp/commit/8db02e25b92b7e186690081538cd0bc743a056f1)) 156 | 157 | - Simplify workaround 158 | ([`f99a512`](https://github.com/Promptly-Technologies-LLC/imfp/commit/f99a512e130e854244434bbd1a9f5f48199e3ec2)) 159 | 160 | - Work around bug that prevents uv from being found by Actions build command 161 | ([`cee17a3`](https://github.com/Promptly-Technologies-LLC/imfp/commit/cee17a3ed8d8887a53f0c988688162eaa96cebe2)) 162 | 163 | 164 | ## v1.1.0 (2025-01-18) 165 | 166 | ### Bug Fixes 167 | 168 | - Change supported Python and pandas versions to prevent numpy error 169 | ([`5650881`](https://github.com/Promptly-Technologies-LLC/imfp/commit/56508812a3fe58290dbe72c6022b3cec5e0c2116)) 170 | 171 | - Implement new automated publishing workflow with python-semantic-release 172 | ([`b616073`](https://github.com/Promptly-Technologies-LLC/imfp/commit/b6160736e1083b86837da53963b650df01f7a94d)) 173 | 174 | - Install dev dependencies with --extra flag in all docs/workflows 175 | ([`90e31b4`](https://github.com/Promptly-Technologies-LLC/imfp/commit/90e31b49148112acfd5e71c46966b89afa4eaf55)) 176 | 177 | - Non-incremented version throws a warning but not an error 178 | ([`1b9227f`](https://github.com/Promptly-Technologies-LLC/imfp/commit/1b9227fc59d906c48b47b01d6ca391567e08c03e)) 179 | 180 | - Repair malformed pyproject.toml 181 | ([`3ec2fd6`](https://github.com/Promptly-Technologies-LLC/imfp/commit/3ec2fd640848c28699ede5e087acbed82bf1715d)) 182 | 183 | - Repaired broken test workflow badge 184 | ([`0cb33fd`](https://github.com/Promptly-Technologies-LLC/imfp/commit/0cb33fd05ae8dc9491f7337e05d5d5663ce48034)) 185 | 186 | ### Continuous Integration 187 | 188 | - Give permissions to documentation workflow 189 | ([`04f8aba`](https://github.com/Promptly-Technologies-LLC/imfp/commit/04f8aba294340ea1a6274590f930e27f6f84fe83)) 190 | 191 | - Install dependencies before running black code formatter 192 | ([`ae6eabc`](https://github.com/Promptly-Technologies-LLC/imfp/commit/ae6eabc02ef9a7ee58e195e729517c55c900718a)) 193 | 194 | - Prevent error when version not incremented 195 | ([`c5a456e`](https://github.com/Promptly-Technologies-LLC/imfp/commit/c5a456e4cf08eaaec78f201bb7d20007fe9eb8f8)) 196 | 197 | 198 | ## v1.0.8 (2023-04-28) 199 | 200 | 201 | ## v1.0.7 (2023-04-28) 202 | 203 | 204 | ## v1.0.6 (2023-04-28) 205 | 206 | 207 | ## v1.0.5 (2023-04-03) 208 | 209 | 210 | ## v1.0.2 (2023-03-30) 211 | 212 | 213 | ## v1.0.0 (2023-03-29) 214 | -------------------------------------------------------------------------------- /docs/data/GENDER_EQUALITY.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Promptly-Technologies-LLC/imfp/93d9ba9c0c76868b494e22d7b8efa2387d8f1c33/docs/data/GENDER_EQUALITY.pickle -------------------------------------------------------------------------------- /docs/data/IFS.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Promptly-Technologies-LLC/imfp/93d9ba9c0c76868b494e22d7b8efa2387d8f1c33/docs/data/IFS.pickle -------------------------------------------------------------------------------- /docs/databases.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Working with Databases" 3 | --- 4 | 5 | ## Understanding IMF Databases 6 | 7 | The IMF serves many different databases through its API, and the API needs to know which of these many databases you're requesting data from. Before you can fetch any data, you'll need to: 8 | 9 | 1. Get a list of available databases 10 | 2. Find the database ID for the data you want 11 | 12 | Then you can use that database ID to fetch the data. 13 | 14 | ## Fetching the Database List 15 | 16 | ### Fetching an Index of Databases with the `imf_databases` Function 17 | 18 | To obtain the list of available databases and their corresponding IDs, use `imf_databases`: 19 | 20 | ``` {python} 21 | import imfp 22 | 23 | #Fetch the list of databases available through the IMF API 24 | databases = imfp.imf_databases() 25 | databases.head() 26 | ``` 27 | 28 | 29 | This function returns the IMF’s listing of 259 databases available through the API. (In reality, a few of the listed databases are defunct and not actually available. The databases FAS_2015, GFS01, FM202010, APDREO202010, AFRREO202010, WHDREO202010, BOPAGG_2020, and DOT_2020Q1 were unavailable as of last check.) 30 | 31 | ## Exploring the Database List 32 | 33 | To view and explore the database list, it’s possible to explore subsets of the data frame by row number with `databases.loc`: 34 | 35 | ``` {python} 36 | # View a subset consisting of rows 5 through 9 37 | databases.loc[5:9] 38 | ``` 39 | 40 | 41 | Or, if you already know which database you want, you can fetch the corresponding code by searching for a string match using `str.contains` and subsetting the data frame for matching rows. For instance, here’s how to search for commodities data: 42 | 43 | ``` {python} 44 | databases[databases['description'].str.contains("Commodity")] 45 | ``` 46 | 47 | See also [Working with Large Data Frames](usage.qmd#working-with-large-data-frames) for sample code showing how to view the full contents of the data frame in a browser window. 48 | 49 | ## Best Practices 50 | 51 | 1. **Cache the Database List**: The database list rarely changes. Consider saving it locally if you'll be making multiple queries. See [Caching Strategy](rate_limits.qmd#caching-strategy) for sample code. 52 | 53 | 2. **Search Strategically**: Use specific search terms to find relevant databases. For example: 54 | 55 | - "Price" for price indices 56 | - "Trade" for trade statistics 57 | - "Financial" for financial data 58 | 59 | 3. **Use a Browser Viewer**: See [Working with Large Data Frames](usage.qmd#working-with-large-data-frames) for sample code showing how to view the full contents of the data frame in a browser window. 60 | 61 | 4. **Note Database IDs**: Once you find a database you'll use frequently, note its database ID for future reference. 62 | 63 | ## Next Steps 64 | 65 | Once you've identified the database you want to use, you'll need to: 66 | 67 | 1. Get the list of parameters for that database (see [Parameters](parameters.qmd)) 68 | 2. Use those parameters to fetch your data (see [Datasets](datasets.qmd)) 69 | -------------------------------------------------------------------------------- /docs/datasets.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Requesting Datasets" 3 | --- 4 | 5 | ## Making a Request 6 | 7 | To retrieve data from an IMF database, you'll need the database ID and any relevant [filter parameters](parameters.qmd). Here's a basic example using the Primary Commodity Price System (PCPS) database: 8 | 9 | ``` {python} 10 | import imfp 11 | 12 | # Get parameters and their valid codes 13 | params = imfp.imf_parameters("PCPS") 14 | 15 | # Fetch annual coal price index data 16 | df = imfp.imf_dataset( 17 | database_id="PCPS", 18 | freq=["A"], # Annual frequency 19 | commodity=["PCOAL"], # Coal prices 20 | unit_measure=["IX"], # Index 21 | start_year=2000, 22 | end_year=2015 23 | ) 24 | ``` 25 | 26 | This example creates two objects we'll use in the following sections: 27 | 28 | - `params`: A dictionary of parameters and their valid codes 29 | - `df`: The retrieved data frame containing our requested data 30 | 31 | ## Decoding Returned Data 32 | 33 | When you retrieve data using `imf_dataset`, the returned data frame contains columns that correspond to the parameters you specified in your request. However, these columns use input codes (short identifiers) rather than human-readable descriptions. To make your data more interpretable, you can replace these codes with their corresponding text descriptions using the parameter information from `imf_parameters`, so that codes like "A" (Annual) or "W00" (World) become self-explanatory labels. 34 | 35 | For example, suppose we want to decode the `freq` (frequency), `ref_area` (geographical area), and `unit_measure` (unit) columns in our dataset. We'll merge the parameter descriptions into our data frame: 36 | 37 | ``` {python} 38 | # Decode frequency codes (e.g., "A" → "Annual") 39 | df = df.merge( 40 | # Select code-description pairs 41 | params['freq'][['input_code', 'description']], 42 | # Match codes in the data frame 43 | left_on='freq', 44 | # ...to codes in the parameter data 45 | right_on='input_code', 46 | # Keep all data rows 47 | how='left' 48 | ).drop(columns=['freq', 'input_code'] 49 | ).rename(columns={"description": "freq"}) 50 | 51 | # Decode geographic area codes (e.g., "W00" → "World") 52 | df = df.merge( 53 | params['ref_area'][['input_code', 'description']], 54 | left_on='ref_area', 55 | right_on='input_code', 56 | how='left' 57 | ).drop(columns=['ref_area', 'input_code'] 58 | ).rename(columns={"description":"ref_area"}) 59 | 60 | # Decode unit codes (e.g., "IX" → "Index") 61 | df = df.merge( 62 | params['unit_measure'][['input_code', 'description']], 63 | left_on='unit_measure', 64 | right_on='input_code', 65 | how='left' 66 | ).drop(columns=['unit_measure', 'input_code'] 67 | ).rename(columns={"description":"unit_measure"}) 68 | 69 | df.head() 70 | ``` 71 | 72 | After decoding, the data frame is much more human-interpretable. This transformation makes the data more accessible for analysis and presentation, while maintaining all the original information. 73 | 74 | ## Understanding the Data Frame 75 | 76 | Also note that the returned data frame has additional mysterious-looking codes as values in some columns. 77 | 78 | Codes in the `time_format` column are ISO 8601 duration codes. In this case, “P1Y” means “periods of 1 year.” See [Time Period Conversion](usage.qmd#time-period-conversion) for more information on reconciling time periods. 79 | 80 | The `unit_mult` column represents the number of zeroes you should add to the value column. For instance, if value is in millions, then the unit multiplier will be 6. If in billions, then the unit multiplier will be 9. See [Unit Multiplier Adjustment](usage.qmd#unit-multiplier-adjustment) for more information on reconciling units. 81 | -------------------------------------------------------------------------------- /docs/installation.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Installation" 3 | --- 4 | 5 | ## Prerequisites 6 | 7 | To install the latest version of `imfp`, you will need to have [Python 3.10 or later](https://www.python.org/downloads/) installed on your system. 8 | 9 | If you don't already have Python, we recommend installing [the `uv` package manager](https://astral.sh/setup-uv/) and installing Python with `uv python install`. 10 | 11 | ## Installation 12 | 13 | To install the latest stable `imfp` wheel from PyPi using pip: 14 | 15 | ``` bash 16 | pip install --upgrade imfp 17 | ``` 18 | 19 | Alternatively, to install from the source code on Github, you can use the following command: 20 | 21 | ``` bash 22 | pip install --upgrade git+https://github.com/Promptly-Technologies-LLC/imfp.git 23 | ``` 24 | 25 | You can then import the package in your Python script: 26 | 27 | ``` python 28 | import imfp 29 | ``` 30 | 31 | ## Suggested Dependencies for Data Analysis 32 | 33 | `imfp` outputs data in a `pandas` data frame, so you will want to use the `pandas` package (which is installed with `imfp`) for its functions for viewing and manipulating this object type. For data visualization, we recommend installing these additional packages: 34 | 35 | ``` bash 36 | pip install -q matplotlib seaborn 37 | ``` 38 | 39 | You can then import these packages in your Python script: 40 | 41 | ``` python 42 | import pandas as pd 43 | import matplotlib.pyplot as plt 44 | import seaborn as sns 45 | ``` 46 | 47 | ## Development Installation 48 | 49 | To get started with development of `imfp`, 50 | 51 | 1. Fork and clone the repository 52 | 2. Install [uv](https://astral.sh/setup-uv/) with `curl -LsSf https://astral.sh/uv/install.sh | sh` 53 | 3. Install the dependencies with `uv sync` 54 | 4. Install a git pre-commit hook to enforce conventional commits: 55 | ``` bash 56 | curl -o- https://raw.githubusercontent.com/tapsellorg/conventional-commits-git-hook/master/scripts/install.sh | sh 57 | ``` 58 | 59 | To edit and preview the documentation, you'll also want to install the [Quarto CLI tool](https://quarto.org/docs/download/). 60 | -------------------------------------------------------------------------------- /docs/parameters.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Working with Parameters" 3 | --- 4 | 5 | ## Filtering IMF Dataset Requests with Parameters 6 | 7 | Once you have a `database_id`, it’s possible to make a call to `imf_dataset` to fetch the entire database: 8 | 9 | ``` {python} 10 | #| eval: false 11 | import imfp 12 | import pandas as pd 13 | 14 | # Set float format to 2 decimal places for pandas display output 15 | pd.set_option('display.float_format', lambda x: '%.2f' % x) 16 | 17 | imfp.imf_dataset(database_id) 18 | ``` 19 | 20 | However, while this will succeed for a few small databases, it will fail for all of the larger ones. And even in the rare case when it succeeds, fetching an entire database can take a long time. You’re much better off supplying additional filter parameters to reduce the size of your request. 21 | 22 | Requests to databases available through the IMF API are complicated by the fact that each database uses a different set of parameters when making a request. (At last count, there were 43 unique parameters used in making API requests from the various databases!) You also have to have the list of valid input codes for each parameter. The `imf_parameters` function solves this problem. Use the function to obtain the full list of parameters and valid input codes for a given database. 23 | 24 | ## Understanding Filter Parameters 25 | 26 | Each database available through the IMF API has its own set of parameters that can be used to filter and specify the data you want to retrieve. 27 | 28 | Each parameter will be a column in the data. Each row in the data will contain a value for that parameter. The parameter will always be a categorical variable, meaning that it can take only a limited set of values. We refer to these values as "input codes," because you can input them in your API request to filter the data. 29 | 30 | What this means, though, is that before making an API request to retrieve data, you need to know what the available filtering parameters are for the database, and what codes you can use for filtering the data by each parameter. 31 | 32 | There are two main functions for working with parameters: 33 | 34 | - `imf_parameters()`: Get the full list of parameters and valid input codes for a database 35 | - `imf_parameter_defs()`: Get text descriptions of what each parameter represents 36 | 37 | ## Discovering Available Parameters 38 | 39 | To get started, you'll need to know what parameters are available for your chosen database. Use `imf_parameters()` to get this information: 40 | 41 | ``` {python} 42 | import imfp 43 | 44 | # Fetch list of valid parameters for the Primary Commodity Price System database 45 | params = imfp.imf_parameters("PCPS") 46 | 47 | # View the available parameter names 48 | params.keys() 49 | ``` 50 | 51 | The function returns a dictionary of data frames. 52 | 53 | Each key in the dictionary corresponds to a parameter used in making requests from the database. The value for each key is a data frame with the following columns: 54 | 55 | - `input_code`: The valid codes you can use for that parameter 56 | - `description`: A short text description of what each code represents 57 | 58 | For example, to see the valid codes for the `freq` (frequency) parameter: 59 | 60 | ``` {python} 61 | # View the data frame of valid input codes for the frequency parameter 62 | params['freq'] 63 | ``` 64 | 65 | ## Parameter Definitions 66 | 67 | If the parameter name is not self-explanatory, you can use the `imf_parameter_defs()` function to get a text description of what each parameter represents. 68 | 69 | ``` {python} 70 | # Get descriptions of what each parameter means 71 | params_defs = imfp.imf_parameter_defs("PCPS") 72 | 73 | params_defs 74 | ``` 75 | 76 | ## Supplying Parameters 77 | 78 | ### Basic Approach (Recommended for Most Users) 79 | 80 | To make a request to fetch data from the IMF API, just call `imf_dataset` with the database ID and keyword arguments for each parameter, where the keyword argument name is the parameter name and the value is the list of codes you want. 81 | 82 | For instance, on exploring the `freq` parameter of the Primary Commodity Price System database above, we found that the frequency can take one of three values: "A" for annual, "Q" for quarterly, and "M" for monthly. Thus, to request annual data, we can call `imf_dataset` with `freq = ["A"]`. 83 | 84 | Here's a complete example that fetches annual coal prices for the years 2000 through 2015: 85 | 86 | ``` {python} 87 | #| eval: false 88 | # Example: Get annual coal prices 89 | df = imfp.imf_dataset( 90 | database_id="PCPS", 91 | freq=["A"], # Annual frequency 92 | commodity=["PCOAL"], # Coal prices 93 | start_year=2000, 94 | end_year=2015 95 | ) 96 | ``` 97 | 98 | ### Advanced Approaches 99 | 100 | For more complex queries, there are two programmatic ways to supply parameters to `imf_dataset`. These approaches are particularly useful when you need to filter parameters based on their descriptions or when working with multiple parameter values. 101 | 102 | #### 1. List Arguments with Parameter Filtering 103 | 104 | This approach uses string matching to find the correct parameter codes before passing them to `imf_dataset`: 105 | 106 | ``` {python} 107 | # Fetch the input code column of the freq parameter... 108 | selected_freq = list( 109 | params['freq']['input_code'][ 110 | # ...where the description contains "Annual" 111 | params['freq']['description'].str.contains("Annual") 112 | ] 113 | ) 114 | 115 | # Fetch the input code column of the commodity parameter... 116 | selected_commodity = list( 117 | params['commodity']['input_code'][ 118 | # ...where the description contains "Coal" 119 | params['commodity']['description'].str.contains("Coal") 120 | ] 121 | ) 122 | 123 | # Fetch the input code column of the unit_measure parameter... 124 | selected_unit_measure = list( 125 | params['unit_measure']['input_code'][ 126 | # ...where the description contains "Index" 127 | params['unit_measure']['description'].str.contains("Index") 128 | ] 129 | ) 130 | 131 | # Request data from the API using the filtered parameter code lists 132 | df = imfp.imf_dataset( 133 | database_id="PCPS", 134 | freq=selected_freq, 135 | commodity=selected_commodity, 136 | unit_measure=selected_unit_measure, 137 | start_year=2000, 138 | end_year=2015 139 | ) 140 | 141 | df.head() 142 | ``` 143 | 144 | #### 2. Parameters Dictionary Approach 145 | 146 | This approach modifies the parameters dictionary directly and passes the entire filtered dictionary to `imf_dataset` as a single `parameters` keyword argument. This is more concise but requires understanding how the parameters dictionary works: 147 | 148 | ``` {python} 149 | # Copy the params dictionary 150 | modified_params = params.copy() 151 | 152 | # Overwrite the data frame for each parameter in the dictionary with filtered rows 153 | modified_params['freq'] = params['freq'][ 154 | # ...where the input code description for freq contains "Annual" 155 | params['freq']['description'].str.contains("Annual") 156 | ] 157 | modified_params['commodity'] = params['commodity'][ 158 | # ...where the input code description for commodity contains "Coal" 159 | params['commodity']['description'].str.contains("Coal") 160 | ] 161 | modified_params['unit_measure'] = params['unit_measure'][ 162 | # ...where the input code description for unit_measure contains "Index" 163 | params['unit_measure']['description'].str.contains("Index") 164 | ] 165 | 166 | # Pass the modified dictionary to imf_dataset 167 | df = imfp.imf_dataset( 168 | database_id="PCPS", 169 | parameters=modified_params, 170 | start_year=2000, 171 | end_year=2015 172 | ) 173 | 174 | df.head() 175 | ``` 176 | 177 | Note that when using the parameters dictionary approach, you cannot combine it with individual parameter arguments. If you supply a `parameters` argument, any other keyword arguments for individual parameters will be ignored. 178 | 179 | -------------------------------------------------------------------------------- /docs/rate_limits.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Rate Limits" 3 | --- 4 | 5 | ## API Rate Management 6 | 7 | The IMF API imposes very restrictive (and incompletely documented) rate limits, not only for individual users and applications, but also globally for all users of the API. Thus, at high-traffic times, you may find that your requests fail. It's highly recommended that you set up proactive error handling, wait times, retries, and request caching to avoid hitting the API's rate limits. The `imfp` library provides some tools to help you do this (with more planned for future releases). 8 | 9 | ### Setting Application Name 10 | 11 | The IMF API has an application-based rate limit of 50 requests per second. Each application is identified by the "user_agent" variable in the request header. By default, all `imfp` users share the same application name, which could lead to rate limit issues if many users are making requests simultaneously. 12 | 13 | This could prove problematic if the `imfp` library became too popular and too many users tried to make simultaneous API requests using the default app name. By setting a custom application name, users can avoid hitting this rate limit and being blocked by the API. To solve this problem, `imfp` supplies the `set_imf_app_name()` function to set a custom application name. 14 | 15 | `set_imf_app_name()` sets the application name by changing the `IMF_APP_NAME` variable in the environment. If this variable doesn't exist, `set_imf_app_name()` will create it. To set a custom application name, simply call the `set_imf_app_name()` function with your desired application name as an argument: 16 | 17 | ``` {python} 18 | import imfp 19 | 20 | # Set custom app name as an environment variable 21 | imfp.set_imf_app_name("my_custom_app_name") 22 | ``` 23 | 24 | The function will throw an error if the provided name is missing, NULL, NA, not a string, or longer than 255 characters. If the provided name is "imfp" (the default) or an empty string, the function will issue a warning recommending the use of a unique app name to avoid hitting rate limits. 25 | 26 | ### Managing Request Timing 27 | 28 | If making multiple requests in a short period of time, you may want to increase the wait time between requests to avoid hitting the API's rate limits. This is done with the `set_imf_wait_time()` function: 29 | 30 | ``` {python} 31 | #| eval: false 32 | # Increase wait time to 5 seconds 33 | imfp.set_imf_wait_time(5) 34 | ``` 35 | 36 | ### Retries 37 | 38 | `imfp` automatically handles rate limits with exponential backoff: 39 | 40 | 1. Waits for specified time 41 | 2. Retries the request 42 | 3. Increases wait time exponentially on subsequent failures 43 | 4. Stops after 3 attempts (default) 44 | 45 | You can modify retry behavior: 46 | 47 | ``` {python} 48 | #| eval: false 49 | # Retry 4 times rather than the default 3 50 | df = imfp.imf_dataset("IFS", "NGDP_D_SA_IX", times=4) 51 | ``` 52 | 53 | ### Caching Strategy 54 | 55 | To reduce API calls, you can cache frequently accessed data. For instance, in a Jupyter or Quarto notebook that you run multiple times, you can wrap each `imfp` function call in an `if` statement that checks if the returned data has already been saved to a file. If it has, it loads the data from the file. If it hasn't, it fetches the data from the API and saves it to a file. 56 | 57 | Note that to run this code, you will need to install the `pyarrow` library, which `pandas` uses as its engine for reading and writing parquet files (but which is not installed with `pandas` or `imfp` by default). Use `pip install pyarrow` to install it. 58 | 59 | ``` {python} 60 | #| eval: false 61 | import os 62 | import pandas as pd 63 | 64 | # Fetch imf databases from file if available, else from API 65 | cache_path = f"data/imf_databases.parquet" 66 | if os.path.exists(cache_path): 67 | databases = pd.read_parquet(cache_path) 68 | else: 69 | databases = imfp.imf_databases() 70 | os.makedirs("data", exist_ok=True) 71 | databases.to_parquet(cache_path) 72 | ``` 73 | 74 | You can also functionalize this logic to permit reuse several times in the same script or notebook. See Jenny Xu's excellent [demo notebook](demo.qmd#utility-functions) for example caching functions. 75 | 76 | ## Performance Tips 77 | 78 | 1. **Filter Early**: Use parameters to limit data at the API level 79 | 2. **Parallelize Carefully**: Avoid running parallel API requests, even from multiple clients 80 | 3. **Use Efficient Formats**: Store cached data in parquet or feather files 81 | 4. **Validate Data**: Check for errors and empty responses 82 | -------------------------------------------------------------------------------- /docs/static/Headshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Promptly-Technologies-LLC/imfp/93d9ba9c0c76868b494e22d7b8efa2387d8f1c33/docs/static/Headshot.jpg -------------------------------------------------------------------------------- /docs/usage.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Suggestions for Usage" 3 | --- 4 | 5 | ## Determining Data Availability 6 | 7 | Unfortunately, **many** of the indicators listed as available in the lists of input codes returned by `imf_parameters()` are not actually available. This is a deficiency of the API rather than the library; someone at the IMF presumably intended to provide these indicators at some point, but never got around to it. 8 | 9 | The only way to be certain whether an indicator is available is to make a request to the API and see if it succeeds. If not, you will receive an error message indicating that no data was found for your parameters. In general, if you see this message, you should try making a less restrictive version of your request. For instance, if your request returns no data for an indicator for a given country and time period, you can omit the country or time period parameter and try again. If you still get no data, that indicator is not actually available through the API. 10 | 11 | While it is not fully predictable which indicators will be available, as a general rule you can expect to get unadjusted series but not adjusted ones. For instance, real and per capita GDP are not available (although they are listed) through the API, but nominal GDP is. The API does, however, make available all the adjustment variables you would need to adjust the data yourself. See the [Common Data Transformations](#common-data-transformations) section below for examples of how to make adjustments. 12 | 13 | ## Working with Large Data Frames 14 | 15 | ### Inspecting Data 16 | 17 | `imfp` outputs data in `pandas` DataFrames, so you will want to use the `pandas` package for its functions for viewing and manipulating this object type. 18 | 19 | For large datasets, you can use the `pandas` library's `info()` method to get a quick summary of the data frame, including the number of rows and columns, the count of non-missing values, the column names, and the data types. 20 | 21 | ``` {python} 22 | import imfp 23 | import pandas as pd 24 | 25 | # Set float format to 2 decimal places for pandas display output 26 | pd.set_option('display.float_format', lambda x: '%.2f' % x) 27 | 28 | df: pd.DataFrame = imfp.imf_dataset( 29 | database_id="PCPS", 30 | commodity=["PCOAL"], 31 | unit_measure=["IX"], 32 | start_year=2000, end_year=2001 33 | ) 34 | 35 | # Quick summary of DataFrame 36 | df.info() 37 | ``` 38 | 39 | Alternatively, you can use the `head()` method to view the first 5 rows of the data frame. 40 | 41 | ``` {python} 42 | # View first 5 rows of DataFrame 43 | df.head() 44 | ``` 45 | 46 | ### Cleaning Data 47 | 48 | #### Numeric Conversion 49 | 50 | All data is returned from the IMF API as a text (object) data type, so you will want to cast numeric columns to numeric. 51 | 52 | ``` {python} 53 | # Numeric columns 54 | numeric_cols = ["unit_mult", "obs_value"] 55 | 56 | # Cast numeric columns 57 | df[numeric_cols] = df[numeric_cols].apply(pd.to_numeric) 58 | ``` 59 | 60 | #### Categorical Conversion 61 | 62 | You can also convert string columns to categorical types for better memory usage. 63 | 64 | ``` {python} 65 | # Convert categorical columns like ref_area and indicator to category type 66 | categorical_cols = [ 67 | "freq", 68 | "ref_area", 69 | "commodity", 70 | "unit_measure", 71 | "time_format" 72 | ] 73 | 74 | df[categorical_cols] = df[categorical_cols].astype("category") 75 | ``` 76 | 77 | #### NA Removal 78 | 79 | After conversion, you may want to drop any rows with missing values. 80 | 81 | ``` {python} 82 | # Drop rows with missing values 83 | df = df.dropna() 84 | ``` 85 | 86 | #### Time Period Conversion 87 | 88 | The `time_period` column can be more difficult to work with, because it may be differently formatted depending on the frequency of the data. 89 | 90 | Annual data will be formatted as a four-digit year, such as "2000", which can be trivially converted to numeric. 91 | 92 | However, quarterly data will be formatted as "2000-Q1", and monthly data will be formatted like "2000-01". 93 | 94 | You can use the `pandas` library's `to_datetime()` method with the `format="mixed"` argument to convert this column to a datetime object in a format-agnostic way: 95 | 96 | ``` {python} 97 | # Convert time_period to datetime 98 | df["datetime"] = pd.to_datetime(df["time_period"], format="mixed") 99 | df[["freq", "datetime"]].head() 100 | ``` 101 | 102 | Alternatively, you can split the `time_period` column into separate columns for year, quarter, and month, and then convert each to a numeric value: 103 | 104 | ``` {python} 105 | # Split time_period into separate columns 106 | df["year"] = df["time_period"].str.extract(r"(\d{4})")[0] 107 | df["quarter"] = df["time_period"].str.extract(r"Q(\d{1})")[0] 108 | df["month"] = df["time_period"].str.extract(r"-(\d{2})")[0] 109 | 110 | # Convert year, quarter, and month to numeric 111 | df["year"] = pd.to_numeric(df["year"]) 112 | df["quarter"] = pd.to_numeric(df["quarter"]) 113 | df["month"] = pd.to_numeric(df["month"]) 114 | 115 | df[["time_period", "year", "quarter", "month"]].head() 116 | ``` 117 | 118 | ### Summarizing Data 119 | 120 | After converting columns to numeric, you can use the `describe()` function to get a quick summary of the statistical properties of these, including the count of rows, the mean, the standard deviation, the minimum and maximum values, and the quartiles. 121 | 122 | ``` {python} 123 | # Statistical summary 124 | df.describe() 125 | ``` 126 | 127 | ### Viewing Data 128 | 129 | For large data frames, it can be useful to view the data in a browser window. To facilitate this, you can define a `View()` function as follows. This function will save the data frame to a temporary HTML file and open it in your default web browser. 130 | 131 | ``` {python} 132 | #| eval: false 133 | import tempfile 134 | import webbrowser 135 | 136 | # Define a simple function to view data frame in a browser window 137 | def View(df: pd.DataFrame): 138 | html = df.to_html() 139 | with tempfile.NamedTemporaryFile('w', 140 | delete=False, suffix='.html') as f: 141 | url = 'file://' + f.name 142 | f.write(html) 143 | webbrowser.open(url) 144 | 145 | # Call the function 146 | View(df) 147 | ``` 148 | 149 | ## Common Data Transformations 150 | 151 | The International Financial Statistics (IFS) database provides key macroeconomic aggregates that are frequently needed when working with other IMF datasets. Here, we'll demonstrate how to use three fundamental indicators—GDP, price deflators, and population statistics—to transform your data. 152 | 153 | These transformations are essential for: 154 | 155 | - Converting nominal to real dollar values 156 | - Calculating per capita metrics 157 | - Harmonizing data across different frequencies 158 | - Adjusting for different unit scales 159 | 160 | For a complete, end-to-end example of these transformations in a real analysis workflow, see Jenny Xu's superb [demo notebook](https://github.com/jennyxu/imfp-demo). 161 | 162 | ### Fetching IFS Adjusters 163 | 164 | First, let's retrieve the key adjustment variables from the IFS database: 165 | 166 | ``` {python} 167 | # Fetch GDP Deflator (Index, Annual) 168 | deflator = imfp.imf_dataset( 169 | database_id="IFS", 170 | indicator="NGDP_D_SA_IX", 171 | freq="Q", 172 | start_year=2010 173 | ) 174 | 175 | # Fetch Population Estimates (Annual) 176 | population = imfp.imf_dataset( 177 | database_id="IFS", 178 | indicator="LP_PE_NUM", 179 | freq="A", 180 | start_year=2010 181 | ) 182 | 183 | # Fetch Exchange Rate (Annual) 184 | exchange_rate = imfp.imf_dataset( 185 | database_id="IFS", 186 | indicator="ENDE_XDC_USD_RATE", 187 | freq="Q", 188 | # start_year=2010 currently breaks this query for some reason 189 | ) 190 | ``` 191 | 192 | We'll also retireve a nominal GDP series to be adjusted: 193 | 194 | ``` {python} 195 | # Fetch Nominal GDP (Domestic currency, annual) 196 | nominal_gdp = imfp.imf_dataset( 197 | database_id="IFS", 198 | indicator="NGDP_XDC", 199 | freq="A", 200 | start_year=2010 201 | ) 202 | ``` 203 | 204 | **Key IFS Indicators**: 205 | 206 | - `NGDP_D_SA_IX`: GDP deflator index (seasonally adjusted) 207 | - `LP_PE_NUM`: Population estimates 208 | - `ENDE_XDC_USD_RATE`: Exchange rate (domestic currency per USD) 209 | - `NGDP_XDC`: Nominal GDP in domestic currency 210 | 211 | ### Harmonizing Frequencies 212 | 213 | When working with data of different frequencies, you'll often need to harmonize them. For example, population and national GDP are available at an annual frequency, while the GDP deflator and exchange rates can only be obtained at a monthly or quarterly frequency. There are two common approaches: 214 | 215 | 1. Using Q4 values: This approach is often used for stock variables (measurements taken at a point in time) and when you want to align with end-of-year values: 216 | 217 | ```{python} 218 | # Keep only Q4 observations for annual comparisons 219 | deflator = deflator[deflator['time_period'].str.contains("Q4")] 220 | exchange_rate = exchange_rate[exchange_rate['time_period'].str.contains("Q4")] 221 | 222 | # Extract just the year from the time period for Q4 data 223 | deflator['time_period'] = deflator['time_period'].str[:4] 224 | exchange_rate['time_period'] = exchange_rate['time_period'].str[:4] 225 | ``` 226 | 227 | ``` {python} 228 | #| include: false 229 | #| echo: false 230 | # Hidden fixup to filter out exchange rate data before 2010 231 | # Remove this line when the start_year parameter is fixed for this query 232 | exchange_rate = exchange_rate[exchange_rate['time_period'].astype(int) > 2010] 233 | ``` 234 | 235 | 2. Calculating annual averages: This approach is more appropriate for flow variables (measurements over a period) and when you want to smooth out seasonal variations: 236 | 237 | ``` {python} 238 | #| eval: false 239 | # Alternative: Calculate annual averages 240 | deflator = deflator.groupby( 241 | ['ref_area', deflator['time_period']], 242 | as_index=False 243 | ).agg({ 244 | 'obs_value': 'mean' 245 | }) 246 | ``` 247 | 248 | Choose the appropriate method based on your specific analysis needs and the economic meaning of your variables. 249 | 250 | ### Unit Multiplier Adjustment 251 | 252 | IMF data often includes a `unit_mult` column that indicates the scale of the values (e.g., millions, billions). We can write a helper function to apply these scaling factors: 253 | 254 | ``` {python} 255 | def apply_unit_multiplier(df): 256 | """Convert to numeric, adjust values using IMF's scaling factors, and drop 257 | missing values""" 258 | df['obs_value'] = pd.to_numeric(df['obs_value']) 259 | df['unit_mult'] = pd.to_numeric(df['unit_mult']) 260 | df['adjusted_value'] = df['obs_value'] * 10 ** df['unit_mult'] 261 | df = df.dropna(subset=["obs_value"]) 262 | return df 263 | 264 | # Apply to each dataset 265 | deflator = apply_unit_multiplier(deflator) 266 | population = apply_unit_multiplier(population) 267 | exchange_rate = apply_unit_multiplier(exchange_rate) 268 | nominal_gdp = apply_unit_multiplier(nominal_gdp) 269 | ``` 270 | 271 | ### Merging Datasets 272 | 273 | After harmonizing unit scales, we can combine the datasets using `pd.DataFrame.merge()` with `ref_area` and `time_period` as keys: 274 | 275 | ``` {python} 276 | merged = ( 277 | nominal_gdp.merge( 278 | deflator, 279 | on=['ref_area', 'time_period'], 280 | suffixes=('_gdp', '_deflator') 281 | ) 282 | .merge( 283 | population, 284 | on=['ref_area', 'time_period'] 285 | ) 286 | .merge( 287 | exchange_rate, 288 | on=['ref_area', 'time_period'], 289 | suffixes=('_population', '_exchange_rate') 290 | ) 291 | ) 292 | ``` 293 | 294 | ### Calculating Real Values 295 | 296 | With the merged dataset, we can now calculate real GDP and per capita values: 297 | 298 | ``` {python} 299 | # Convert nominal to real GDP 300 | merged['real_gdp'] = ( 301 | (merged['adjusted_value_gdp'] / merged['adjusted_value_deflator']) * 100 302 | ) 303 | 304 | # Calculate per capita values (using population obs_value) 305 | merged['real_gdp_per_capita'] = merged['real_gdp'] / merged['adjusted_value_population'] 306 | 307 | # Display the first 5 rows of the transformed data 308 | merged[['time_period', 'real_gdp', 'real_gdp_per_capita']].head() 309 | ``` 310 | 311 | ### Exchange Rate Adjustment 312 | 313 | Note that this result is still in the domestic currency of the country. If you need to convert to a common currency, you can use the exchange rate data from the IFS database. 314 | 315 | ``` {python} 316 | # Because 'adjusted_value_exrate' is local-currency-per-USD, 317 | # dividing local-currency real GDP by it yields GDP in USD. 318 | merged["real_gdp_usd"] = ( 319 | merged["real_gdp"] / merged["adjusted_value_exchange_rate"] 320 | ) 321 | 322 | # (Optional) real GDP per capita in USD 323 | merged["real_gdp_usd_per_capita"] = ( 324 | merged["real_gdp_usd"] / merged["adjusted_value_population"] 325 | ) 326 | 327 | # Inspect results 328 | merged[["time_period","ref_area","real_gdp","real_gdp_usd","real_gdp_usd_per_capita"]].head() 329 | ``` 330 | -------------------------------------------------------------------------------- /experimental/download_databases.py: -------------------------------------------------------------------------------- 1 | # This script tries (and mostly fails) to download full databases in sequence. I don't 2 | # recommend trying this. 3 | 4 | import imfp 5 | from pandas import DataFrame 6 | 7 | # Set a custom wait time 8 | _imf_wait_time = 10 9 | 10 | # Attempt to download databases sequentially 11 | databases: DataFrame = imfp.imf_databases() 12 | datasets: dict[str, list[DataFrame | None]] = {"database_names": [], "dataframes": []} 13 | for database_id in databases["database_id"]: 14 | datasets["database_names"].append(database_id) 15 | try: 16 | datasets["dataframes"].append(imfp.imf_dataset(database_id)) 17 | except Exception as e: 18 | datasets["dataframes"].append(None) 19 | print("An error occurred when downloading", database_id, ": ", e) 20 | -------------------------------------------------------------------------------- /experimental/download_indicators.py: -------------------------------------------------------------------------------- 1 | # This script tries to download whole databases indicator by indicator 2 | 3 | import imfp 4 | from pandas import DataFrame 5 | 6 | # Examine database list 7 | databases = imfp.imf_databases() 8 | 9 | # Set a custom wait time and a database to query 10 | _imf_wait_time = 10 11 | database_to_download = "IFS" 12 | 13 | # Try to download the database indicator by indicator (Note that some databases don't 14 | # use the 'indicator' parameter, so this won't work with every database) 15 | indicators: DataFrame = imfp.imf_parameters("IFS")["indicator"] 16 | datasets: dict[str, list[DataFrame | None]] = {"indicator_names": [], "dataframes": []} 17 | for indicator in indicators["input_code"]: 18 | datasets["indicator_names"].append(indicator) 19 | try: 20 | datasets["dataframes"].append( 21 | imfp.imf_dataset(database_id=database_to_download, indicator=indicator) 22 | ) 23 | except Exception as e: 24 | datasets["dataframes"].append(None) 25 | print("An error occurred when downloading", indicator, ": ", e) 26 | -------------------------------------------------------------------------------- /imfp/__init__.py: -------------------------------------------------------------------------------- 1 | from .utils import ( 2 | _imf_get, 3 | _min_wait_time_limited, 4 | _download_parse, 5 | _imf_metadata, 6 | _imf_dimensions, 7 | ) 8 | from .data import imf_databases, imf_parameters, imf_parameter_defs, imf_dataset 9 | from .admin import set_imf_app_name, set_imf_wait_time 10 | 11 | __all__ = [ 12 | "_imf_get", 13 | "_min_wait_time_limited", 14 | "_imf_wait_time", 15 | "_download_parse", 16 | "_imf_metadata", 17 | "_imf_dimensions", 18 | "_imf_wait_time", 19 | "imf_databases", 20 | "imf_parameters", 21 | "imf_parameter_defs", 22 | "imf_dataset", 23 | "set_imf_app_name", 24 | "set_imf_wait_time", 25 | ] 26 | -------------------------------------------------------------------------------- /imfp/admin.py: -------------------------------------------------------------------------------- 1 | from os import environ 2 | from warnings import warn 3 | from typing import Union 4 | import type_enforced 5 | 6 | 7 | @type_enforced.Enforcer 8 | def set_imf_app_name(name: str = "imfp") -> None: 9 | """ 10 | Set the IMF Application Name. 11 | 12 | Set a unique application name to be used in requests to the IMF API as an 13 | environment variable. 14 | 15 | Args: 16 | name (str, optional): A string representing the application name. 17 | Default is "imfp". 18 | 19 | Returns: 20 | None 21 | 22 | Raises: 23 | ValueError: If the provided name is not a valid string or contains 24 | forbidden characters. 25 | 26 | Examples: 27 | imf_app_name("my_custom_app_name") 28 | """ 29 | 30 | if len(name) > 255: 31 | raise ValueError("Application name must be no longer than 255 characters.") 32 | 33 | if name == "imfp" or name == "": 34 | warn( 35 | "Best practice is to choose a unique app name. Use of a default " 36 | "or empty app name may result in hitting API rate limits and " 37 | "being blocked by the API.", 38 | UserWarning, 39 | ) 40 | 41 | forbidden_chars = set(range(32)) | {127} 42 | if any(ord(c) in forbidden_chars for c in name): 43 | raise ValueError( 44 | "The application name contains forbidden characters. " 45 | "Please remove control characters and non-printable " 46 | "ASCII characters." 47 | ) 48 | 49 | environ["IMF_APP_NAME"] = name 50 | 51 | return None 52 | 53 | 54 | @type_enforced.Enforcer 55 | def set_imf_wait_time(wait_time: Union[int, float] = 1.5) -> None: 56 | """ 57 | Set the IMF wait time as an environment variable. 58 | 59 | Args: 60 | wait_time (Union[int, float], optional): The wait time in seconds to be set as an environment variable. Defaults to 1.5. 61 | 62 | Raises: 63 | TypeError: If the provided wait_time is not a numeric value (int or float). 64 | ValueError: If the provided wait_time is not greater than 0. 65 | """ 66 | if wait_time >= 0: 67 | environ["IMF_WAIT_TIME"] = str(wait_time) 68 | else: 69 | raise ValueError("Rate limit wait time must be greater than or equal to 0.") 70 | -------------------------------------------------------------------------------- /imfp/utils.py: -------------------------------------------------------------------------------- 1 | from os import environ, path 2 | import hashlib 3 | from time import sleep, perf_counter 4 | from requests import get 5 | from json import loads, load, dump, JSONDecodeError 6 | from pandas import DataFrame 7 | import re 8 | import logging 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | def _min_wait_time_limited(default_wait_time=1.5): 14 | def decorator(func): 15 | last_called = [0.0] 16 | 17 | def wrapper(*args, **kwargs): 18 | min_wait_time = float(environ.get("IMF_WAIT_TIME", default_wait_time)) 19 | elapsed = perf_counter() - last_called[0] 20 | left_to_wait = min_wait_time - elapsed 21 | if left_to_wait > 0: 22 | sleep(left_to_wait) 23 | ret = func(*args, **kwargs) 24 | last_called[0] = perf_counter() 25 | return ret 26 | 27 | return wrapper 28 | 29 | return decorator 30 | 31 | 32 | @_min_wait_time_limited() 33 | def _imf_get(url, headers): 34 | """ 35 | A rate-limited wrapper around the requests.get method. 36 | 37 | Args: 38 | url (str): The URL to send a GET request to. 39 | headers (dict): The headers to use in the API request. 40 | 41 | Returns: 42 | requests.Response: The response object returned by requests.get. 43 | 44 | Usage: 45 | response = _imf_get( 46 | 'http://dataservices.imf.org/REST/SDMX_JSON.svc/Dataflow' 47 | ) 48 | print(response.text) 49 | """ 50 | logger.debug(f"Sending GET request to {url}") 51 | response = get(url, headers) 52 | return response 53 | 54 | 55 | _imf_use_cache = False 56 | _imf_save_response = False 57 | 58 | 59 | def _download_parse(URL, times=3): 60 | """ 61 | (Internal) Download and parse JSON content from a URL with rate limiting 62 | and retries. 63 | 64 | This function is rate-limited and will perform a specified number of 65 | retries in case of failure. 66 | 67 | Args: 68 | URL (str): The URL to download and parse the JSON content from. 69 | times (int, optional): The number of times to retry the request in case 70 | of failure. Defaults to 3. 71 | 72 | Returns: 73 | dict: The parsed JSON content as a Python dictionary. 74 | 75 | Raises: 76 | ValueError: If the content cannot be parsed as JSON after the specified 77 | number of retries. 78 | """ 79 | 80 | global _imf_use_cache, _imf_save_response 81 | use_cache = _imf_use_cache 82 | save_response = _imf_save_response 83 | 84 | app_name = environ.get("IMF_APP_NAME") 85 | if app_name: 86 | app_name = app_name[:255] 87 | else: 88 | app_name = "imfp" 89 | 90 | headers = {"Accept": "application/json", "User-Agent": app_name} 91 | for _ in range(times): 92 | if use_cache: 93 | cached_status, cached_content = _load_cached_response(URL) 94 | if cached_content is not None: 95 | content = cached_content 96 | status = cached_status 97 | else: 98 | response = _imf_get(URL, headers=headers) 99 | content = response.text 100 | status = response.status_code 101 | 102 | if save_response: 103 | file_name = hashlib.sha256(URL.encode()).hexdigest() 104 | file_path = f"tests/responses/{file_name}.json" 105 | print(f"Saving response to: {file_path}") 106 | with open(file_path, "w") as file: 107 | dump({"status_code": status, "content": content}, file) 108 | 109 | if status != 200 or ("<" in content and ">" in content): 110 | matches = re.search("<[^>]+>(.*?)<\\/[^>]+>", content) 111 | inner_text = matches.group(1) 112 | output_string = re.sub(" GKey\\s*=\\s*[a-f0-9-]+", "", inner_text) 113 | 114 | if "Rejected" in content or "Bandwidth" in content: 115 | err_message = ( 116 | f"API request failed. URL: '{URL}' " 117 | f"Status: '{status}', " 118 | f"Content: '{output_string}'\n\n" 119 | "API may be overwhelmed by too many " 120 | "requests. Take a break and try again." 121 | ) 122 | elif "Service" in content: 123 | err_message = ( 124 | f"API request failed. URL: '{URL}' " 125 | f"Status: '{status}', " 126 | f"Content: '{output_string}'\n\n" 127 | "Your requested dataset may be too large. " 128 | "Try narrowing your request and try again." 129 | ) 130 | elif status == 400: 131 | err_message = ( 132 | f"API request failed. URL: '{URL}' " 133 | f"Status: '{status}', " 134 | f"Content: '{output_string}'\n\n" 135 | "Too many parameters supplied. " 136 | "Please narrow the request and try again." 137 | ) 138 | elif status == 500 and "please check your query" in content.lower(): 139 | err_message = ( 140 | f"API request failed. URL: '{URL}' " 141 | f"Status: '{status}', " 142 | f"Content: '{output_string}'\n\n" 143 | "Your request may be missing one or more required " 144 | "parameters. Please adjust your query and try again." 145 | ) 146 | else: 147 | err_message = ( 148 | f"API request failed. URL: '{URL}' " 149 | f"Status: '{status}', " 150 | f"Content: '{output_string}'" 151 | ) 152 | 153 | if _ < times - 1: 154 | sleep(5 ** (_ + 1)) 155 | else: 156 | raise ValueError(err_message) 157 | else: 158 | try: 159 | json_parsed = loads(content) 160 | return json_parsed 161 | except JSONDecodeError: 162 | if _ < times - 1: 163 | sleep(5 ** (_ + 1)) 164 | else: 165 | raise ValueError( 166 | f"Content from API could not be parsed as JSON. URL: '{URL}' " 167 | f"Status: '{status}', Content: '{content}'" 168 | ) 169 | 170 | 171 | def _load_cached_response(URL): 172 | file_name = hashlib.sha256(URL.encode()).hexdigest() 173 | file_path = f"tests/responses/{file_name}.json" 174 | 175 | if path.exists(file_path): 176 | with open(file_path, "r") as file: 177 | data = load(file) 178 | return data.get("status_code"), data.get("content") 179 | return None, None 180 | 181 | 182 | def _imf_dimensions(database_id, times=3, inputs_only=True): 183 | """ 184 | (Internal) Retrieve the list of codes for dimensions of an individual IMF 185 | database. 186 | 187 | Args: 188 | database_id (str): The ID of the IMF database. 189 | times (int, optional): The number of times to retry the request in case 190 | of failure. Defaults to 3. 191 | inputs_only (bool, optional): If True, only include input parameters. 192 | Defaults to True. 193 | 194 | Returns: 195 | pandas.DataFrame: A DataFrame containing the parameter names and their 196 | corresponding codes and descriptions. 197 | """ 198 | URL = ( 199 | f"http://dataservices.imf.org/REST/SDMX_JSON.svc/DataStructure/" 200 | f"{database_id}" 201 | ) 202 | raw_dl = _download_parse(URL, times) 203 | 204 | code = [] 205 | for item in raw_dl["Structure"]["CodeLists"]["CodeList"]: 206 | code.append(item["@id"]) 207 | description = [] 208 | for item in raw_dl["Structure"]["CodeLists"]["CodeList"]: 209 | description.append(item["Name"]["#text"]) 210 | codelist_df = DataFrame({"code": code, "description": description}) 211 | 212 | params = [ 213 | dim["@conceptRef"].lower() 214 | for dim in ( 215 | raw_dl["Structure"]["KeyFamilies"]["KeyFamily"]["Components"]["Dimension"] 216 | ) 217 | ] 218 | codes = [ 219 | dim["@codelist"] 220 | for dim in ( 221 | raw_dl["Structure"]["KeyFamilies"]["KeyFamily"]["Components"]["Dimension"] 222 | ) 223 | ] 224 | param_code_df = DataFrame({"parameter": params, "code": codes}) 225 | 226 | if inputs_only: 227 | result_df = param_code_df.merge(codelist_df, on="code", how="left") 228 | else: 229 | result_df = param_code_df.merge(codelist_df, on="code", how="outer") 230 | 231 | return result_df 232 | 233 | 234 | def _imf_metadata(URL, times=3): 235 | """ 236 | (Internal) Access metadata for a dataset. 237 | 238 | Args: 239 | URL (str): The URL used to request metadata. 240 | times (int, optional): Maximum number of requests to attempt. Defaults 241 | to 3. 242 | 243 | Returns: 244 | dict: A dictionary containing the metadata information. 245 | 246 | Raises: 247 | ValueError: If the URL is not provided. 248 | 249 | Examples: 250 | # Find Primary Commodity Price System database metadata 251 | metadata = ( 252 | imf_metadata("http://dataservices.imf.org/REST/SDMX_JSON.svc/" 253 | "GenericMetadata/PCPS/A..?start_year=2020") 254 | ) 255 | """ 256 | 257 | if not URL: 258 | raise ValueError("Must supply URL.") 259 | 260 | URL = URL.replace("CompactData", "GenericMetadata") 261 | raw_dl = _download_parse(URL, times=times) 262 | 263 | output = { 264 | "XMLschema": raw_dl["GenericMetadata"]["@xmlns:xsd"], 265 | "message": raw_dl["GenericMetadata"]["@xsi:schemaLocation"], 266 | "language": ( 267 | raw_dl["GenericMetadata"]["Header"]["Sender"]["Name"]["@xml:lang"] 268 | ), 269 | "timestamp": raw_dl["GenericMetadata"]["Header"]["Prepared"], 270 | "custodian": (raw_dl["GenericMetadata"]["Header"]["Sender"]["Name"]["#text"]), 271 | "custodian_url": ( 272 | raw_dl["GenericMetadata"]["Header"]["Sender"]["Contact"]["URI"] 273 | ), 274 | "custodian_telephone": ( 275 | raw_dl["GenericMetadata"]["Header"]["Sender"]["Contact"]["Telephone"] 276 | ), 277 | } 278 | return output 279 | -------------------------------------------------------------------------------- /index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "imfp" 3 | --- 4 | 5 | 6 | # imfp 7 | 8 | [![Tests](https://github.com/Promptly-Technologies-LLC/imfp/actions/workflows/test.yml/badge.svg)](https://github.com/Promptly-Technologies-LLC/imfp/actions/workflows/test.yml) 9 | [![PyPI Version](https://img.shields.io/pypi/v/imfp.svg)](https://pypi.python.org/pypi/imfp) 10 | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) 11 | 12 | `imfp`, created and maintained by [Promptly Technologies](https://promptlytechnologies.com), is a Python package for downloading data from the [International Monetary Fund's](http://data.imf.org/) [RESTful JSON API](http://datahelp.imf.org/knowledgebase/articles/667681-using-json-restful-web-service). 13 | 14 | ## Installation 15 | 16 | To install the stable version of imfp from PyPi, use pip. 17 | 18 | ```bash 19 | pip install --upgrade imfp 20 | ``` 21 | 22 | To load the library, use `import`: 23 | 24 | ``` {python} 25 | import imfp 26 | ``` 27 | 28 | ## Workflow 29 | 30 | The `imfp` package introduces four core functions: `imf_databases`, `imf_parameters`, `imf_parameter_defs`, and `imf_dataset`. The function for downloading datasets is `imf_dataset`, but you will need the other functions to determine what arguments to supply to your `imf_dataset` function call. 31 | 32 | ### Fetching a List of Databases with `imf_databases` 33 | 34 | For instance, all calls to `imf_dataset` require a `database_id`. This is because the IMF serves many different databases through its API, and the API needs to know which of these many databases you're requesting data from. 35 | 36 | To fetch a list of available databases, use: 37 | 38 | ``` {python} 39 | # Fetch list of available databases 40 | databases = imfp.imf_databases() 41 | ``` 42 | 43 | See [Working with Databases](docs/databases.qmd) for more information. 44 | 45 | ### Fetching a List of Parameters and Input Codes with `imf_parameters` 46 | 47 | Requests to fetch data from IMF databases are complicated by the fact that each database uses a different set of parameters when making a request. (At last count, there were 43 unique parameters used in making API requests from the various databases!) You also have to have the list of valid input codes for each parameter. See [Working with Parameters](docs/parameters.qmd) for a more detailed explanation of parameters and input codes and how they work. 48 | 49 | To obtain the full list of parameters and valid input codes for a given database, use: 50 | 51 | ``` {python} 52 | # Fetch list of valid parameters and input codes for commodity price database 53 | params = imfp.imf_parameters("PCPS") 54 | ``` 55 | 56 | The `imf_parameters` function returns a dictionary of data frames. Each dictionary key name corresponds to a parameter used in making requests from the database: 57 | 58 | ``` {python} 59 | # Get key names from the params object 60 | params.keys() 61 | ``` 62 | 63 | Each named list item is a data frame containing the valid input codes (and their descriptions) that can be used with the named parameter. 64 | 65 | To access the data frame containing valid values for each parameter, subset the `params` dict by the parameter name: 66 | 67 | ``` {python} 68 | # View the data frame of valid input codes for the frequency parameter 69 | params['freq'] 70 | ``` 71 | 72 | ### Supplying Parameter Arguments to `imf_dataset` 73 | 74 | To make a request to fetch data from the IMF API, just call `imfp.imf_dataset` with the database ID and keyword arguments for each parameter, where the keyword argument name is the parameter name and the value is the list of codes you want. 75 | 76 | For instance, on exploring the `freq` parameter of the Primary Commodity Price System database above, we found that the frequency can take one of three values: "A" for annual, "Q" for quarterly, and "M" for monthly. Thus, to request annual data, we can call `imfp.imf_dataset` with `freq = ["A"]`. 77 | 78 | Similarly, we might search the dataframes of valid input codes for the `commodity` and `unit_measure` parameters to find the input codes for coal and index: 79 | 80 | ``` {python} 81 | # Find the 'commodity' input code for coal 82 | params['commodity'].loc[ 83 | params['commodity']['description'].str.contains("Coal") 84 | ] 85 | ``` 86 | 87 | ``` {python} 88 | # Find the 'unit_measure' input code for index 89 | params['unit_measure'].loc[ 90 | params['unit_measure']['description'].str.contains("Index") 91 | ] 92 | 93 | ``` 94 | 95 | Finally, we can use the information we've gathered to make the request to fetch the data: 96 | 97 | ``` {python} 98 | # Request data from the API 99 | df = imfp.imf_dataset(database_id = "PCPS", 100 | freq = ["A"], commodity = ["PCOAL", "PCOALAU", "PCOALSA"], 101 | unit_measure = ["IX"], 102 | start_year = 2000, end_year = 2015) 103 | 104 | # Display the first few entries in the retrieved data frame 105 | df.head() 106 | ``` 107 | 108 | The returned data frame has a `time_format` column that contains ISO 8601 duration codes. In this case, “P1Y” means “periods of 1 year.” The `unit_mult` column represents the power of 10 to which the value column should be raised. For instance, if value is in millions, then the unit multiplier will be 6 (meaning 10^6). If in billions, then the unit multiplier will be 9 (meaning 10^9). For more information on interpreting the returned data frame, see [Understanding the Data Frame](docs/usage.qmd#understanding-the-data-frame). 109 | 110 | ## Working with the Returned Data Frame 111 | 112 | Note that all columns in the returned data frame are string objects, and to plot the series we will need to convert to valid numeric or date formats: 113 | 114 | ``` {python} 115 | # Convert obs_value to numeric and time_period to integer year 116 | df = df.astype({"time_period" : int, "obs_value" : float}) 117 | ``` 118 | 119 | Then, using `seaborn` with `hue`, we can plot different indicators in different colors: 120 | 121 | ``` {python} 122 | import seaborn as sns 123 | 124 | # Plot prices of different commodities in different colors with seaborn 125 | sns.lineplot(data=df, x='time_period', y='obs_value', hue='commodity'); 126 | ``` 127 | 128 | ## Contributing 129 | 130 | We welcome contributions to improve `imfp`! Here's how you can help: 131 | 132 | 1. If you find a bug, please open [a Github issue](https://github.com/Promptly-Technologies-LLC/imfp/issues) 133 | 2. To fix a bug: 134 | - Fork and clone the repository and open a terminal in the repository directory 135 | - Install [uv](https://astral.sh/setup-uv/) with `curl -LsSf https://astral.sh/uv/install.sh | sh` 136 | - Install the dependencies with `uv sync` 137 | - Install a git hook to enforce conventional commits with `curl -o- https://raw.githubusercontent.com/tapsellorg/conventional-commits-git-hook/master/scripts/install.sh | sh` 138 | - Create a fix, commit it with an ["Angular-style Conventional Commit"](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) message, and push it to your fork 139 | - Open a pull request to our `main` branch 140 | 141 | Note that if you want to change and preview the documentation, you will need to install the [Quarto CLI tool](https://quarto.org/docs/download/). 142 | 143 | Version incrementing, package building, testing, changelog generation, documentation rendering, publishing to PyPI, and Github release creation is handled automatically by the GitHub Actions workflow based on the commit messages. 144 | 145 | ## Working with LLMs 146 | 147 | In line with the [llms.txt standard](https://llmstxt.org/), we have exposed the full Markdown-formatted project documentation as a [single text file](docs/static/llms.txt) to make it more usable by LLM agents. 148 | 149 | ``` {python} 150 | #| echo: false 151 | #| include: false 152 | import re 153 | from pathlib import Path 154 | 155 | def extract_file_paths(quarto_yml_path): 156 | """ 157 | Extract href paths from _quarto.yml file. 158 | Returns a list of .qmd file paths. 159 | """ 160 | with open(quarto_yml_path, 'r', encoding='utf-8') as f: 161 | content = f.read() 162 | 163 | # Find all href entries that point to .qmd files 164 | pattern = r'href:\s*(.*?\.qmd)' 165 | matches = re.findall(pattern, content, re.MULTILINE) 166 | return matches 167 | 168 | 169 | def process_qmd_content(file_path): 170 | """ 171 | Process a .qmd file by converting YAML frontmatter to markdown heading. 172 | Returns the processed content as a string. 173 | """ 174 | with open(file_path, 'r', encoding='utf-8') as f: 175 | content = f.read() 176 | 177 | # Replace YAML frontmatter with markdown heading 178 | pattern = r'^---\s*\ntitle:\s*"([^"]+)"\s*\n---' 179 | processed_content = re.sub(pattern, r'# \1', content) 180 | return processed_content 181 | 182 | 183 | # Get the current working directory 184 | base_dir = Path.cwd() 185 | quarto_yml_path = base_dir / '_quarto.yml' 186 | 187 | print(quarto_yml_path) 188 | 189 | # Extract file paths from _quarto.yml 190 | qmd_files = extract_file_paths(quarto_yml_path) 191 | print(qmd_files) 192 | 193 | # Process each .qmd file and collect contents 194 | processed_contents = [] 195 | for qmd_file in qmd_files: 196 | file_path = base_dir / qmd_file 197 | if file_path.exists(): 198 | processed_content = process_qmd_content(file_path) 199 | processed_contents.append(processed_content) 200 | 201 | # Concatenate all contents with double newline separator 202 | final_content = '\n\n'.join(processed_contents) 203 | 204 | # Ensure the output directory exists 205 | output_dir = base_dir / 'docs' / 'static' 206 | output_dir.mkdir(parents=True, exist_ok=True) 207 | 208 | # Write the concatenated content to the output file 209 | output_path = output_dir / 'llms.txt' 210 | with open(output_path, 'w', encoding='utf-8') as f: 211 | f.write(final_content) 212 | ``` 213 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | 3 | [mypy-type_enforced.*] 4 | ignore_missing_imports = True -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "imfp" 3 | version = "1.2.1" 4 | description = "Python package for downloading economic data from the International Monetary Fund JSON RESTful API endpoint." 5 | authors = [ 6 | {name = "Christopher C. Smith", email = "christopher.smith@promptlytechnologies.com"} 7 | ] 8 | license = {file = "LICENSE"} 9 | readme = "README.md" 10 | keywords = ["economics", "finance", "IMF", "API"] 11 | classifiers = [ 12 | "Intended Audience :: Financial and Insurance Industry", 13 | "Programming Language :: Python :: 3", 14 | "License :: OSI Approved :: MIT License", 15 | "Operating System :: OS Independent", 16 | ] 17 | requires-python = ">=3.10" 18 | dependencies = [ 19 | "numpy == 2.1.3", 20 | "pandas == 2.2.3", 21 | "python-semantic-release>=9.16.1", 22 | "requests == 2.32.4", 23 | "statsmodels == 0.14.4", 24 | "tabulate == 0.9.0", 25 | "type-enforced>=1.10.1", 26 | ] 27 | 28 | [project.urls] 29 | homepage = "https://promptlytechnologies.com/imfp" 30 | repository = "https://github.com/Promptly-Technologies-LLC/imfp" 31 | 32 | [build-system] 33 | requires = ["setuptools>=75"] 34 | build-backend = "setuptools.build_meta" 35 | 36 | [tool.setuptools] 37 | packages = ["imfp"] 38 | 39 | [tool.semantic_release] 40 | assets = [] 41 | build_command_env = [] 42 | commit_message = "{version}\n\nAutomatically generated by python-semantic-release" 43 | commit_parser = "angular" 44 | logging_use_named_masks = false 45 | major_on_zero = true 46 | allow_zero_version = true 47 | repo_dir = "." 48 | no_git_verify = false 49 | tag_format = "v{version}" 50 | version_toml = [ 51 | "pyproject.toml:project.version" 52 | ] 53 | 54 | [tool.semantic_release.branches.main] 55 | match = "(main|master)" 56 | prerelease_token = "rc" 57 | prerelease = false 58 | 59 | [tool.semantic_release.changelog] 60 | exclude_commit_patterns = [] 61 | mode = "init" 62 | insertion_flag = "" 63 | template_dir = "templates" 64 | 65 | [tool.semantic_release.changelog.default_templates] 66 | changelog_file = "changelog.md" 67 | output_format = "md" 68 | mask_initial_release = false 69 | 70 | [tool.semantic_release.changelog.environment] 71 | block_start_string = "{%" 72 | block_end_string = "%}" 73 | variable_start_string = "{{" 74 | variable_end_string = "}}" 75 | comment_start_string = "{#" 76 | comment_end_string = "#}" 77 | trim_blocks = false 78 | lstrip_blocks = false 79 | newline_sequence = "\n" 80 | keep_trailing_newline = false 81 | extensions = [] 82 | autoescape = false 83 | 84 | [tool.semantic_release.commit_author] 85 | env = "GIT_COMMIT_AUTHOR" 86 | default = "semantic-release " 87 | 88 | [tool.semantic_release.commit_parser_options] 89 | minor_tags = ["feat"] 90 | patch_tags = ["build", "chore", "fix", "perf", "refactor", "style"] 91 | other_allowed_tags = [ "ci", "docs", "test"] 92 | allowed_tags = ["feat", "fix", "perf", "build", "chore", "ci", "docs", "style", "refactor", "test"] 93 | default_bump_level = 0 94 | 95 | [tool.semantic_release.remote] 96 | name = "origin" 97 | type = "github" 98 | ignore_token_for_push = false 99 | insecure = false 100 | 101 | [tool.semantic_release.publish] 102 | dist_glob_patterns = ["dist/*"] 103 | upload_to_vcs_release = true 104 | 105 | [dependency-groups] 106 | dev = [ 107 | "pyarrow>=19.0.0", 108 | "responses == 0.23.3", 109 | "pytest == 7.4.4", 110 | "pytest-runner == 6.0.1", 111 | "black == 24.10.0", 112 | "pytest-mock == 3.14.0", 113 | "jupyter == 1.1.1", 114 | "seaborn == 0.13.2", 115 | "quarto == 0.1.0", 116 | "scikit-learn == 1.5.2", 117 | "mypy>=1.14.1", 118 | ] 119 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Promptly-Technologies-LLC/imfp/93d9ba9c0c76868b494e22d7b8efa2387d8f1c33/tests/__init__.py -------------------------------------------------------------------------------- /tests/responses/0492d2c673234c8b4351a965d177830557855c6504d064eff10276e374f733a2.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"968c7cba-c746-4b0a-bd1d-b62cc5a8a766\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:54\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_Country_FISCALDECENTRALIZATION\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Country\"},\"Code\":[{\"@value\":\"AF\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Afghanistan\"}},{\"@value\":\"AL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Albania\"}},{\"@value\":\"AM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Armenia\"}},{\"@value\":\"AU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Australia\"}},{\"@value\":\"AT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Austria\"}},{\"@value\":\"AZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Azerbaijan\"}},{\"@value\":\"BY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Belarus\"}},{\"@value\":\"BE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Belgium\"}},{\"@value\":\"BA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bosnia and Herzegovina\"}},{\"@value\":\"BR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Brazil\"}},{\"@value\":\"BG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bulgaria\"}},{\"@value\":\"CV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cabo Verde\"}},{\"@value\":\"KH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cambodia\"}},{\"@value\":\"CA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Canada\"}},{\"@value\":\"CL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Chile\"}},{\"@value\":\"CN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"China\"}},{\"@value\":\"CO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Colombia\"}},{\"@value\":\"CR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Costa Rica\"}},{\"@value\":\"HR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Croatia\"}},{\"@value\":\"CY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cyprus\"}},{\"@value\":\"CZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Czech Republic\"}},{\"@value\":\"DK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Denmark\"}},{\"@value\":\"SV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"El Salvador\"}},{\"@value\":\"EE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Estonia\"}},{\"@value\":\"FI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Finland\"}},{\"@value\":\"FR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"France\"}},{\"@value\":\"GE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Georgia\"}},{\"@value\":\"DE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Germany\"}},{\"@value\":\"GR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Greece\"}},{\"@value\":\"GT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Guatemala\"}},{\"@value\":\"HN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Honduras\"}},{\"@value\":\"HU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hungary\"}},{\"@value\":\"IS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Iceland\"}},{\"@value\":\"ID\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Indonesia\"}},{\"@value\":\"IR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Iran, Islamic Republic of\"}},{\"@value\":\"IE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ireland\"}},{\"@value\":\"IL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Israel\"}},{\"@value\":\"IT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Italy\"}},{\"@value\":\"JP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Japan\"}},{\"@value\":\"KZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kazakhstan\"}},{\"@value\":\"KE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kenya\"}},{\"@value\":\"KI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kiribati\"}},{\"@value\":\"KR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Korea, Republic of\"}},{\"@value\":\"KG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kyrgyzstan\"}},{\"@value\":\"LV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Latvia\"}},{\"@value\":\"LT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Lithuania\"}},{\"@value\":\"LU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Luxembourg\"}},{\"@value\":\"MT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Malta\"}},{\"@value\":\"MH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Marshall islands\"}},{\"@value\":\"MU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mauritius\"}},{\"@value\":\"MX\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mexico\"}},{\"@value\":\"MD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Moldova, Republic of\"}},{\"@value\":\"MN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mongolia\"}},{\"@value\":\"MM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Myanmar\"}},{\"@value\":\"NA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Namibia\"}},{\"@value\":\"NP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Nepal\"}},{\"@value\":\"NL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Netherlands\"}},{\"@value\":\"NZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"New Zealand\"}},{\"@value\":\"MK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"North Macedonia, Republic of\"}},{\"@value\":\"NO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Norway\"}},{\"@value\":\"PW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Palau\"}},{\"@value\":\"PY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Paraguay\"}},{\"@value\":\"PE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Peru\"}},{\"@value\":\"PL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Poland\"}},{\"@value\":\"PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Portugal\"}},{\"@value\":\"RO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Romania\"}},{\"@value\":\"RU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Russian Federation\"}},{\"@value\":\"RW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Rwanda\"}},{\"@value\":\"SN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Senegal\"}},{\"@value\":\"RS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Serbia\"}},{\"@value\":\"SK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Slovakia\"}},{\"@value\":\"SI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Slovenia\"}},{\"@value\":\"SO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Somalia\"}},{\"@value\":\"ZA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"South Africa\"}},{\"@value\":\"ES\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Spain\"}},{\"@value\":\"SE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sweden\"}},{\"@value\":\"CH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Switzerland\"}},{\"@value\":\"TH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Thailand\"}},{\"@value\":\"TN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tunisia\"}},{\"@value\":\"TR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Turkey\"}},{\"@value\":\"UG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Uganda\"}},{\"@value\":\"UA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ukraine\"}},{\"@value\":\"AE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"United Arab Emirates\"}},{\"@value\":\"GB\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"United Kingdom\"}},{\"@value\":\"US\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}},{\"@value\":\"UZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Uzbekistan\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/167923e1a4ca6c4b2d753ee87c4bf37c3f343b5145ccb2d9af37e73445b3014a.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"c31624ba-6ea7-4d05-b80f-434393bdfe0f\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:38\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_AREA_APDREO201904\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Geographical Areas\"},\"Code\":[{\"@value\":\"AU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Australia\"}},{\"@value\":\"BD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bangladesh\"}},{\"@value\":\"BT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bhutan\"}},{\"@value\":\"BN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Brunei Darussalam\"}},{\"@value\":\"KH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cambodia\"}},{\"@value\":\"HK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hong Kong\"}},{\"@value\":\"MO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Macao\"}},{\"@value\":\"CN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"China\"}},{\"@value\":\"FJ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiji\"}},{\"@value\":\"IN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"India\"}},{\"@value\":\"ID\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Indonesia\"}},{\"@value\":\"JP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Japan\"}},{\"@value\":\"KI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kiribati\"}},{\"@value\":\"KR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Korea, Republic of\"}},{\"@value\":\"LA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Lao People`s Democratic Republic\"}},{\"@value\":\"MY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Malaysia\"}},{\"@value\":\"MV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Maldives\"}},{\"@value\":\"MH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Marshall islands\"}},{\"@value\":\"FM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Micronesia, Federated States of\"}},{\"@value\":\"MN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mongolia\"}},{\"@value\":\"MM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Myanmar\"}},{\"@value\":\"NP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Nepal\"}},{\"@value\":\"NZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"New Zealand\"}},{\"@value\":\"PW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Palau\"}},{\"@value\":\"PG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Papua New Guinea\"}},{\"@value\":\"PH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Philippines\"}},{\"@value\":\"WS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Samoa\"}},{\"@value\":\"SG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Singapore\"}},{\"@value\":\"SB\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Solomon Islands\"}},{\"@value\":\"LK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sri Lanka\"}},{\"@value\":\"TW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taiwan, Province of China\"}},{\"@value\":\"TH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Thailand\"}},{\"@value\":\"TL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Timor-Leste\"}},{\"@value\":\"TO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tonga\"}},{\"@value\":\"TV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tuvalu\"}},{\"@value\":\"VU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Vanuatu\"}},{\"@value\":\"VN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Viet Nam\"}},{\"@value\":\"1C_ALLC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Countries\"}},{\"@value\":\"1C_ALLG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Country Groups\"}},{\"@value\":\"R4\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"ASEAN (Countries for the Association of South-East Asian Nations)\"}},{\"@value\":\"1C_229\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Asia\"}},{\"@value\":\"S2\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Eastern Asia\"}},{\"@value\":\"1C_Industrial_Asia\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Industrial Asia\"}},{\"@value\":\"1C_PICs_and_Small_States\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"PICs and Small States\"}},{\"@value\":\"1C_9502\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"South Asia\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/1a87bb86263c3393b6e9161caebb5413b96eff9d8bb7e799ed0ad544504b8a3e.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"69f852e5-4be0-47bc-9f1b-8dc0ed133eb2\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:57\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_Sector_FISCALDECENTRALIZATION\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Sector\"},\"Code\":[{\"@value\":\"1C_CG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Central Government\"}},{\"@value\":\"1C_LG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Local Government\"}},{\"@value\":\"1C_SG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"State Government\"}},{\"@value\":\"1C_SNG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Subnational Government\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/4421ce6d93ac13daa2466aee1db3c90be8091e9fdcec4591f312b2036afc4d0e.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/WHDREO201910 http://dataservices.imf.org/compact/WHDREO201910.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"7e0db753-1f76-4e4d-b557-1b616bbf725d\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T13:00:08\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"WHDREO201910\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/WHDREO201910\",\"Series\":[{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@INDICATOR\":\"PPPSH\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"16.3359977434372\"},{\"@TIME_PERIOD\":\"2012\",\"@OBS_VALUE\":\"16.1938273911054\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@INDICATOR\":\"NGDPD\",\"@UNIT_MULT\":\"9\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"15542.6\"},{\"@TIME_PERIOD\":\"2012\",\"@OBS_VALUE\":\"16197.05\"}]}]}}}"} -------------------------------------------------------------------------------- /tests/responses/54d693d531be56db0b2c65dcfcd1feeadf5ca875afafa8d4d81390a7a46c0269.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"92938c15-1852-488b-b2e0-a2499c63bb9d\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:39\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_INDICATOR_APDREO201904\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"},\"Code\":[{\"@value\":\"BCA_BP6_USD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments, Current Account, Total, Net, In billions of US Dollars\"}},{\"@value\":\"BCA_GDP_BP6_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments, Current Account, Total, Net, Percent of GDP\"}},{\"@value\":\"TX_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"External Trade, Exports of Goods and Services, Percent Change\"}},{\"@value\":\"TM_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"External Trade, Imports of Goods and Services, Percent Change\"}},{\"@value\":\"GGXWDG_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiscal, General Government, Gross debt position, 2001 Manual, Percent of FY GDP\"}},{\"@value\":\"GGXCNL_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiscal, General Government, Net lending/borrowing, 2001 Manual, Percent of FY GDP\"}},{\"@value\":\"NGDPD_USD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Gross Domestic Product in US Dollars, Constant Prices, in billions\"}},{\"@value\":\"NGDP_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Gross Domestic Product, Real, Constant Prices, Percent Change\"}},{\"@value\":\"NTDD_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Total Domestic Demand, Real, Constant Prices, Percent Change\"}},{\"@value\":\"PCPI_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Prices, Consumer Price Index, All items, CPI (p.a.), percent change\"}},{\"@value\":\"All_Indicators\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Indicators\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/70da50370c93a6db03ecb77506c0d8d99c1edebc4715b121f72817db77d2dec8.json: -------------------------------------------------------------------------------- 1 | {"status_code": 404, "content": "\ufeff\r\n\r\n\r\n \r\n Service\r\n \r\n \r\n \r\n
\r\n

Service

\r\n

Endpoint not found. Please see the service help page for constructing valid requests to the service.

\r\n
\r\n \r\n"} -------------------------------------------------------------------------------- /tests/responses/71ea273f717cde44a36f207915a2d4c125ce0db250075fdf67ff8c6278dcbf6a.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/GFSR2019 http://dataservices.imf.org/compact/GFSR2019.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"7fc35c27-62fb-491d-b8e5-fb6fbdc820f0\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:31\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"GFSR2019\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/GFSR2019\",\"Series\":[{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@REF_SECTOR\":\"S13\",\"@UNIT_MEASURE\":\"XDC\",\"@CLASSIFICATION\":\"W0_S1_G1412\",\"@UNIT_MULT\":\"9\",\"@GLOBAL_DSD_TIME_SERIES_CODE\":\"A|US|S13|W0|S1|G1412|_Z|_Z|_Z|XDC|_T|_X\",\"@INDICATOR_CODE\":\"GROPD_G14_XDC\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2001\",\"@OBS_VALUE\":\"28.511\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"},{\"@TIME_PERIOD\":\"2002\",\"@OBS_VALUE\":\"26.046\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@REF_SECTOR\":\"S13\",\"@UNIT_MEASURE\":\"XDC\",\"@CLASSIFICATION\":\"W0_S1_G1151\",\"@UNIT_MULT\":\"9\",\"@GLOBAL_DSD_TIME_SERIES_CODE\":\"A|US|S13|W0|S1|G1151|_Z|_Z|_Z|XDC|_T|_X\",\"@INDICATOR_CODE\":\"GRTTC_G14_XDC\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2001\",\"@OBS_VALUE\":\"20.636\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"},{\"@TIME_PERIOD\":\"2002\",\"@OBS_VALUE\":\"19.938\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@REF_SECTOR\":\"S13\",\"@UNIT_MEASURE\":\"XDC_R_B1GQ\",\"@CLASSIFICATION\":\"W0_S1_G1412\",\"@UNIT_MULT\":\"0\",\"@GLOBAL_DSD_TIME_SERIES_CODE\":\"A|US|S13|W0|S1|G1412|_Z|_Z|_Z|XDC_R_B1GQ|_T|_X\",\"@INDICATOR_CODE\":\"GROPD_G14_GDP_PT\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2001\",\"@OBS_VALUE\":\"0.269433675193079\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"},{\"@TIME_PERIOD\":\"2002\",\"@OBS_VALUE\":\"0.238157720284004\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@REF_SECTOR\":\"S13\",\"@UNIT_MEASURE\":\"XDC_R_B1GQ\",\"@CLASSIFICATION\":\"W0_S1_G1151\",\"@UNIT_MULT\":\"0\",\"@GLOBAL_DSD_TIME_SERIES_CODE\":\"A|US|S13|W0|S1|G1151|_Z|_Z|_Z|XDC_R_B1GQ|_T|_X\",\"@INDICATOR_CODE\":\"GRTTC_G14_GDP_PT\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2001\",\"@OBS_VALUE\":\"0.195013620051362\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"},{\"@TIME_PERIOD\":\"2002\",\"@OBS_VALUE\":\"0.182307787261863\",\"@BASES_OF_RECORDING_GROSSNET\":\"NP\",\"@VALUATION\":\"NP\",\"@NATURE_OF_DATA\":\"A\",\"@BASES_OF_RECORDING_CASH_NON_CASH\":\"AC\"}]}]}}}"} -------------------------------------------------------------------------------- /tests/responses/7a5eb96e0fb69d0163be56543efcc84681fa4aa714b346be3a324df709eea90e.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/WHDREO201910 http://dataservices.imf.org/compact/WHDREO201910.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"6723ad4f-e90a-4fa3-9730-0831f56cbc5e\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T13:00:01\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"WHDREO201910\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/WHDREO201910\",\"Series\":{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@INDICATOR\":\"NGDPD\",\"@UNIT_MULT\":\"9\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"15542.6\"},{\"@TIME_PERIOD\":\"2012\",\"@OBS_VALUE\":\"16197.05\"}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/7e89af364cdf5466341cee28b1e5ab022f102c9deb60975e51e9b6357a2cd0b6.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/AFRREO http://dataservices.imf.org/compact/AFRREO.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"ed59fc3b-3ab2-4293-b7d0-6c2b43de08da\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:41\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"AFRREO\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/AFRREO\",\"Series\":[{\"@FREQ\":\"A\",\"@REF_AREA\":\"7A\",\"@INDICATOR\":\"GGX_G01_GDP_PT\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2021\",\"@OBS_VALUE\":\"23.0051262608049\"},{\"@TIME_PERIOD\":\"2022\",\"@OBS_VALUE\":\"23.734926506081\"},{\"@TIME_PERIOD\":\"2023\",\"@OBS_VALUE\":\"23.1245422945703\"},{\"@TIME_PERIOD\":\"2024\",\"@OBS_VALUE\":\"22.6152110458504\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"7A\",\"@INDICATOR\":\"TTT_IX\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2021\",\"@OBS_VALUE\":\"131.453693601118\"},{\"@TIME_PERIOD\":\"2022\",\"@OBS_VALUE\":\"121.93842376361\"},{\"@TIME_PERIOD\":\"2023\",\"@OBS_VALUE\":\"127.833001013171\"},{\"@TIME_PERIOD\":\"2024\",\"@OBS_VALUE\":\"129.361036635382\"}]}]}}}"} -------------------------------------------------------------------------------- /tests/responses/853b070a5f371baa0266ac85dc18fef90f49d5b7f46634e365373b0396e6a825.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/WHDREO201910 http://dataservices.imf.org/compact/WHDREO201910.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"3335b0ed-97d0-4fce-838b-21c3f1a810cb\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:55\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"WHDREO201910\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/WHDREO201910\",\"Series\":[{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@INDICATOR\":\"PPPSH\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"16.3359977434372\"}},{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@INDICATOR\":\"NGDPD\",\"@UNIT_MULT\":\"9\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"15542.6\"}}]}}}"} -------------------------------------------------------------------------------- /tests/responses/9389b5b12ec2506f945561b5cd2677e344b7669f311d5889f4d492898b1b8c82.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/FISCALDECENTRALIZATION http://dataservices.imf.org/compact/FISCALDECENTRALIZATION.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"9c147896-e532-4ce1-a70e-a5f71ee659b3\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:59\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"FISCALDECENTRALIZATION\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/FISCALDECENTRALIZATION\",\"Series\":[{\"@FREQ\":\"A\",\"@REF_AREA\":\"AZ\",\"@INDICATOR\":\"edu\",\"@REF_SECTOR\":\"1C_CG\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2008\",\"@OBS_VALUE\":\"0.957205653190613\"},{\"@TIME_PERIOD\":\"2009\",\"@OBS_VALUE\":\"0.955707252025604\"},{\"@TIME_PERIOD\":\"2010\",\"@OBS_VALUE\":\"0.959064304828644\"},{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"0.955699563026428\"},{\"@TIME_PERIOD\":\"2012\",\"@OBS_VALUE\":\"0.959778070449829\"},{\"@TIME_PERIOD\":\"2013\",\"@OBS_VALUE\":\"0.960965156555176\"},{\"@TIME_PERIOD\":\"2014\",\"@OBS_VALUE\":\"0.960977137088776\"},{\"@TIME_PERIOD\":\"2015\",\"@OBS_VALUE\":\"0.960850059986115\"},{\"@TIME_PERIOD\":\"2016\",\"@OBS_VALUE\":\"0.954623222351074\"},{\"@TIME_PERIOD\":\"2017\",\"@OBS_VALUE\":\"0.955424070358276\"},{\"@TIME_PERIOD\":\"2018\",\"@OBS_VALUE\":\"0.963269174098969\"},{\"@TIME_PERIOD\":\"2019\",\"@OBS_VALUE\":\"0.963109195232391\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"BE\",\"@INDICATOR\":\"edu\",\"@REF_SECTOR\":\"1C_CG\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"1995\",\"@OBS_VALUE\":\"0.148475483059883\"},{\"@TIME_PERIOD\":\"1996\",\"@OBS_VALUE\":\"0.157209306955338\"},{\"@TIME_PERIOD\":\"1997\",\"@OBS_VALUE\":\"0.160545215010643\"},{\"@TIME_PERIOD\":\"1998\",\"@OBS_VALUE\":\"0.165051460266113\"},{\"@TIME_PERIOD\":\"1999\",\"@OBS_VALUE\":\"0.168574646115303\"},{\"@TIME_PERIOD\":\"2000\",\"@OBS_VALUE\":\"0.17657881975174\"},{\"@TIME_PERIOD\":\"2001\",\"@OBS_VALUE\":\"0.179207935929298\"},{\"@TIME_PERIOD\":\"2002\",\"@OBS_VALUE\":\"0.181529149413109\"},{\"@TIME_PERIOD\":\"2003\",\"@OBS_VALUE\":\"0.185218274593353\"},{\"@TIME_PERIOD\":\"2004\",\"@OBS_VALUE\":\"0.193123459815979\"},{\"@TIME_PERIOD\":\"2005\",\"@OBS_VALUE\":\"0.197988212108612\"},{\"@TIME_PERIOD\":\"2006\",\"@OBS_VALUE\":\"0.203635990619659\"},{\"@TIME_PERIOD\":\"2007\",\"@OBS_VALUE\":\"0.210155203938484\"},{\"@TIME_PERIOD\":\"2008\",\"@OBS_VALUE\":\"0.214128196239471\"},{\"@TIME_PERIOD\":\"2009\",\"@OBS_VALUE\":\"0.217726200819016\"},{\"@TIME_PERIOD\":\"2010\",\"@OBS_VALUE\":\"0.217949241399765\"},{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"0.219404950737953\"},{\"@TIME_PERIOD\":\"2012\",\"@OBS_VALUE\":\"0.224673196673393\"},{\"@TIME_PERIOD\":\"2013\",\"@OBS_VALUE\":\"0.230727463960648\"},{\"@TIME_PERIOD\":\"2014\",\"@OBS_VALUE\":\"0.234622806310654\"},{\"@TIME_PERIOD\":\"2015\",\"@OBS_VALUE\":\"0.235006958246231\"},{\"@TIME_PERIOD\":\"2016\",\"@OBS_VALUE\":\"0.00429508928209543\"},{\"@TIME_PERIOD\":\"2017\",\"@OBS_VALUE\":\"0.00423895288258791\"},{\"@TIME_PERIOD\":\"2018\",\"@OBS_VALUE\":\"2.10032558243256E-05\"},{\"@TIME_PERIOD\":\"2019\",\"@OBS_VALUE\":\"1.7043905245373E-05\"},{\"@TIME_PERIOD\":\"2020\",\"@OBS_VALUE\":\"1.32127888718969E-05\"}]},{\"@FREQ\":\"A\",\"@REF_AREA\":\"BY\",\"@INDICATOR\":\"edu\",\"@REF_SECTOR\":\"1C_CG\",\"@UNIT_MULT\":\"0\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2003\",\"@OBS_VALUE\":\"0.178740829229355\"},{\"@TIME_PERIOD\":\"2004\",\"@OBS_VALUE\":\"0.248583897948265\"},{\"@TIME_PERIOD\":\"2005\",\"@OBS_VALUE\":\"0.254320502281189\"},{\"@TIME_PERIOD\":\"2006\",\"@OBS_VALUE\":\"0.26431080698967\"},{\"@TIME_PERIOD\":\"2007\",\"@OBS_VALUE\":\"0.255804181098938\"},{\"@TIME_PERIOD\":\"2008\",\"@OBS_VALUE\":\"0.252243399620056\"},{\"@TIME_PERIOD\":\"2009\",\"@OBS_VALUE\":\"0.260102599859238\"},{\"@TIME_PERIOD\":\"2010\",\"@OBS_VALUE\":\"0.254148304462433\"},{\"@TIME_PERIOD\":\"2011\",\"@OBS_VALUE\":\"0.240457579493523\"},{\"@TIME_PERIOD\":\"2012\",\"@OBS_VALUE\":\"0.242539182305336\"},{\"@TIME_PERIOD\":\"2013\",\"@OBS_VALUE\":\"0.236265286803246\"},{\"@TIME_PERIOD\":\"2014\",\"@OBS_VALUE\":\"0.229930490255356\"},{\"@TIME_PERIOD\":\"2015\",\"@OBS_VALUE\":\"0.228821411728859\"},{\"@TIME_PERIOD\":\"2016\",\"@OBS_VALUE\":\"0.210943415760994\"},{\"@TIME_PERIOD\":\"2017\",\"@OBS_VALUE\":\"0.220428556203842\"},{\"@TIME_PERIOD\":\"2018\",\"@OBS_VALUE\":\"0.218940675258636\"},{\"@TIME_PERIOD\":\"2019\",\"@OBS_VALUE\":\"0.216243594884872\"},{\"@TIME_PERIOD\":\"2020\",\"@OBS_VALUE\":\"0.226735144853592\"}]}]}}}"} -------------------------------------------------------------------------------- /tests/responses/96418874c9efcc78c9c6f32b6b2db71b181b5b13cefa60a87500945e070ddf1c.json: -------------------------------------------------------------------------------- 1 | {"status_code": 400, "content": "\u00ef\u00bb\u00bf\r\n\r\n\r\n \r\n Request Error\r\n \r\n \r\n \r\n
\r\n

Request Error

\r\n

The server encountered an error processing the request. Please see the service help page for constructing valid requests to the service.

\r\n
\r\n \r\n"} -------------------------------------------------------------------------------- /tests/responses/9729441e62b866b218f2c3b2d46e130715880dcecf9601c785d435bb0a650187.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"c775eba0-0d78-4f91-bd81-9fb1dca70c17\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:29\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_INDICATOR_GFSR2019\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"},\"Code\":[{\"@value\":\"W0_S1_G1151\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Customs \\u0026 other import duties\"}},{\"@value\":\"W0_S1_G1412\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Dividend revenue\"}},{\"@value\":\"W0_S1_G1142\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Excise taxes\"}},{\"@value\":\"W0_S1_G1141\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General taxes on goods \\u0026 services\"}},{\"@value\":\"W0_S1_G1M13A\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants in cash\"}},{\"@value\":\"W0_S1_G1M13B\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants in kind\"}},{\"@value\":\"W0_S1_G13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue\"}},{\"@value\":\"W1_S13_G13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from foreign govts\"}},{\"@value\":\"W1_S13_G13K\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from foreign govts: capital\"}},{\"@value\":\"W1_S13_G13C\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from foreign govts: current\"}},{\"@value\":\"1A_S1_G13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from int orgs\"}},{\"@value\":\"1A_S1_G13K\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from int orgs: capital\"}},{\"@value\":\"1A_S1_G13C\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from int orgs: current\"}},{\"@value\":\"W2_S13_G13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from other gen govt\"}},{\"@value\":\"W2_S13_G13K\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from other gen govt: capital\"}},{\"@value\":\"W2_S13_G13C\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grants revenue from other gen govt: current\"}},{\"@value\":\"W0_S1_G1223\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Imputed social contributions revenue\"}},{\"@value\":\"W0_S1_G1411\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Interest revenue\"}},{\"@value\":\"W1_S1_G1411\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Interest revenue from nonresidents\"}},{\"@value\":\"W2_S13_G1411\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Interest revenue from other gen govt\"}},{\"@value\":\"W2_S1W_G1411\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Interest revenue from residents other than gen govt\"}},{\"@value\":\"W0_S1_G1136\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other recurrent taxes on property\"}},{\"@value\":\"W0_S1_G14\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other revenue\"}},{\"@value\":\"W0_S1_G122\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other social contributions revenue\"}},{\"@value\":\"W0_S1_G1221\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other social contributions revenue: employees\"}},{\"@value\":\"W0_S1_G1222\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other social contributions revenue: employers\"}},{\"@value\":\"W0_S1_G116\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other taxes n.e.c.\"}},{\"@value\":\"W0_S1_G1146\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other taxes on goods \\u0026 services\"}},{\"@value\":\"W0_S1_G1156\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other taxes on int trade \\u0026 transactions\"}},{\"@value\":\"W0_S1_G1414\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Property income from investment income disbursements\"}},{\"@value\":\"W0_S1_G141\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Property income revenue\"}},{\"@value\":\"W0_S1_G1131\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Recurrent taxes on immovable property\"}},{\"@value\":\"W0_S1_G1132\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Recurrent taxes on net wealth\"}},{\"@value\":\"W0_S1_G1416\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Reinvested earnings on FDI\"}},{\"@value\":\"W0_S1_G1415\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Rent revenue\"}},{\"@value\":\"W0_S1_G1\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue\"}},{\"@value\":\"W0_S1_G1452\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from NI \\u0026 SGS: capital claims\"}},{\"@value\":\"W0_S1_G14513\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from NI \\u0026 SGS: current claims\"}},{\"@value\":\"W0_S1_G14512\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from NI \\u0026 SGS: fees\"}},{\"@value\":\"W0_S1_G14511\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from NI \\u0026 SGS: premiums\"}},{\"@value\":\"W0_S1_G145\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from NI \\u0026 SGS: premiums, fees \\u0026 claims\"}},{\"@value\":\"W0_S1_G1451\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from NI \\u0026 SGS: premiums, fees \\u0026 current claims\"}},{\"@value\":\"W0_S1_G1422\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from administrative fees\"}},{\"@value\":\"W0_S1_G143\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from fines, penalties \\u0026 forfeits\"}},{\"@value\":\"W0_S1_G1424\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from imputed sales of goods \\u0026 services\"}},{\"@value\":\"W0_S1_G14412\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from other current transfers: not subsidies\"}},{\"@value\":\"W0_S1_G14411\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from other current transfers: subsidies\"}},{\"@value\":\"W0_S1_G144\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from other transfers\"}},{\"@value\":\"W00_S1W_G1442\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from other transfers: capital\"}},{\"@value\":\"W0_S1_G1441\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from other transfers: current\"}},{\"@value\":\"W0_S1_G142\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from sales of goods \\u0026 services\"}},{\"@value\":\"W0_S1_G1421\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from sales of market establishments\"}},{\"@value\":\"W0_S1_G1423\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue from sales of nonmarket establishments\"}},{\"@value\":\"W0_S1_G11412\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sales taxes\"}},{\"@value\":\"W0_S1_G1213\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Self/non-employed social contributions revenue\"}},{\"@value\":\"W0_S1_G12\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social contributions\"}},{\"@value\":\"W0_S1_G121\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social security contributions revenue\"}},{\"@value\":\"W0_S1_G1212\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social security contributions revenue: employers\"}},{\"@value\":\"W0_S1_G1211\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social security contributions: revenue employees\"}},{\"@value\":\"W0_S1_G11\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tax revenue\"}},{\"@value\":\"W0_S1_G1135\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes in the form of capital levies on property\"}},{\"@value\":\"W0_S1_G1143\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes in the form of profits of fiscal monopolies\"}},{\"@value\":\"W0_S1_G1133\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on estate, inheritance, \\u0026 gifts\"}},{\"@value\":\"W0_S1_G1154\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on exchange profits\"}},{\"@value\":\"W0_S1_G1152\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on exports\"}},{\"@value\":\"W0_S1_G11414\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on financial \\u0026 capital transactions\"}},{\"@value\":\"W0_S1_G1155\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on foreign exchange \"}},{\"@value\":\"W0_S1_G114\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on goods \\u0026 services\"}},{\"@value\":\"W0_S1_G111\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on income, profits, \\u0026 capital gains\"}},{\"@value\":\"W0_S1_G1112\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on income, profits, \\u0026 capital gains: corporations\"}},{\"@value\":\"W0_S1_G1111\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on income, profits, \\u0026 capital gains: individuals\"}},{\"@value\":\"W0_S1_G1113\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on income, profits, \\u0026 capital gains: other\"}},{\"@value\":\"W0_S1_G115\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on int trade \\u0026 transactions\"}},{\"@value\":\"W0_S1_G112\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on payroll \\u0026 workforce\"}},{\"@value\":\"W0_S1_G1153\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on profits of export/import monopolies\"}},{\"@value\":\"W0_S1_G113\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on property\"}},{\"@value\":\"W0_S1_G1144\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on specific services\"}},{\"@value\":\"W0_S1_G1145\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on use of/permission to use goods\"}},{\"@value\":\"W0_S1_G11452\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on use of/permission to use goods: other\"}},{\"@value\":\"W0_S1_G11451\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taxes on use of/permission to use goods: vehicles\"}},{\"@value\":\"W0_S1_G11413\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Turnover \\u0026 general taxes on goods \\u0026 services\"}},{\"@value\":\"W0_S1_G1214\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Unallocable social contributions revenue\"}},{\"@value\":\"W0_S1_G11411\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Value-added taxes\"}},{\"@value\":\"W0_S1_G1413\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Withdrawals of income from quasi-corporations\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/99011ca9d9c0254302eda9eae9a11cf84547b5da409f2b9f835e84d553c8f6de.json: -------------------------------------------------------------------------------- 1 | {"status_code": 500, "content": "There is an issue while retrieving the data, please check your query or contact an administrator. GKey = 1588cb4a-1c43-4829-85c0-5804af9f4fe6"} -------------------------------------------------------------------------------- /tests/responses/994ba19449a36d5309efc65d1897497c8b2276000346eb33ac4fb412a8ee107b.json: -------------------------------------------------------------------------------- 1 | {"status_code": 400, "content": "\u00ef\u00bb\u00bf\r\n\r\n\r\n \r\n Request Error\r\n \r\n \r\n \r\n
\r\n

Request Error

\r\n

The server encountered an error processing the request. Please see the service help page for constructing valid requests to the service.

\r\n
\r\n \r\n"} -------------------------------------------------------------------------------- /tests/responses/9c0f19b539fdf2fef0eaf7d13b710db9dfea34545a7b8c77207ab9a061b35bde.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/WHDREO201910 http://dataservices.imf.org/compact/WHDREO201910.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"c2f841ca-23b5-484d-b2ba-fd2a17fb3b2d\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:51\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"WHDREO201910\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/WHDREO201910\"}}}"} -------------------------------------------------------------------------------- /tests/responses/9d084971a2602e85454daed6f45c2e435f38a3226af0e255ef1e2512a63e427d.json: -------------------------------------------------------------------------------- 1 | {"status_code": 400, "content": "\r\nBad Request\r\n\r\n

Bad Request - Invalid URL

\r\n

HTTP Error 400. The request URL is invalid.

\r\n\r\n"} -------------------------------------------------------------------------------- /tests/responses/9efd32c5e4f2add3934730a10bb1f379e4b8335e55ee9a3fa79339e7e3f3c32b.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/BOP http://dataservices.imf.org/compact/BOP.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"d7d358a9-4c2e-45d1-895a-cf93257c6baa\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:45:48\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"BOP\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/BOP\",\"Series\":{\"@FREQ\":\"A\",\"@REF_AREA\":\"US\",\"@INDICATOR\":\"BXSTVPO_BP6_USD\",\"@UNIT_MULT\":\"6\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2020\",\"@OBS_VALUE\":\"21539\"},{\"@TIME_PERIOD\":\"2021\",\"@OBS_VALUE\":\"24238\"},{\"@TIME_PERIOD\":\"2022\",\"@OBS_VALUE\":\"70661\"}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/aa3ebaaaada203bc41db5f152079c52351ad29421c80502f2437dd163ff8cc75.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"CompactData\":{\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/APDREO201904 http://dataservices.imf.org/compact/APDREO201904.xsd\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"Header\":{\"ID\":\"77c60725-3789-4719-8fe2-f0cb4e4b7a08\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:41\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"APDREO201904\"},\"DataSet\":{\"@xmlns\":\"http://dataservices.imf.org/compact/APDREO201904\",\"Series\":{\"@FREQ\":\"A\",\"@REF_AREA\":\"AU\",\"@INDICATOR\":\"BCA_BP6_USD\",\"@UNIT_MULT\":\"9\",\"@TIME_FORMAT\":\"P1Y\",\"Obs\":[{\"@TIME_PERIOD\":\"2016\",\"@OBS_VALUE\":\"-41.4814740931077\"},{\"@TIME_PERIOD\":\"2017\",\"@OBS_VALUE\":\"-35.4118859620353\"},{\"@TIME_PERIOD\":\"2018\",\"@OBS_VALUE\":\"-30.4365992823552\"},{\"@TIME_PERIOD\":\"2019\",\"@OBS_VALUE\":\"-29.0856894821764\"},{\"@TIME_PERIOD\":\"2020\",\"@OBS_VALUE\":\"-31.599455277958\"},{\"@TIME_PERIOD\":\"2021\",\"@OBS_VALUE\":\"-32.3272506693359\"},{\"@TIME_PERIOD\":\"2022\",\"@OBS_VALUE\":\"-37.9893793176996\"},{\"@TIME_PERIOD\":\"2023\",\"@OBS_VALUE\":\"-40.9427825343936\"},{\"@TIME_PERIOD\":\"2024\",\"@OBS_VALUE\":\"-45.0398837962118\"}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/b9aa21417de4354522d04ac2d6fd6bdcfbc3ccaa161d5f35a888284d2c813240.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"20063527-0f87-40a8-91f1-376d9856969a\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T13:00:06\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_INDICATOR_WHDREO201910\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"},\"Code\":[{\"@value\":\"BCA_GDP_BP6\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments, Current Account, Total, Net(BPM6), percent of GDP in U.S. dollars\"}},{\"@value\":\"PCPIE_PCH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Consumer Prices, end of period, percent change\"}},{\"@value\":\"NGDP_FY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiscal year gross domestic product, current prices\"}},{\"@value\":\"GGEI_GDP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government expense, interest, percent of fiscal year GDP\"}},{\"@value\":\"GGXWDG_GDP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government gross debt, percent of Fiscal year GDP\"}},{\"@value\":\"GGXCNL_GDP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government net lending/borrowing, percent of fiscal year GDP\"}},{\"@value\":\"GGXONLB_GDP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government primary net lending/borrowing, percent of Fiscal year GDP\"}},{\"@value\":\"GGROPI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government revenue, other, interest income\"}},{\"@value\":\"GGR_GDP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government revenue, percent of fiscal year GDP\"}},{\"@value\":\"GGX_GDP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government total expenditure, percent of Fiscal year GDP\"}},{\"@value\":\"NGDPD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@value\":\"NGDP_RPCH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product, constant prices, National Currency, percent change\"}},{\"@value\":\"NGDP_GRM_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross Domestic Product, Nominal, Growth rate, Momentum, previous period, Percent\"}},{\"@value\":\"NGDP_R_PC_SCR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross Domestic Product, Real, Percent Change, Score\"}},{\"@value\":\"PPPSH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@value\":\"All_Indicators\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Indicators\"}},{\"@value\":\"All_Indicators_and_Indicator_Groups\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Indicators and Indicator Groups\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/be998e19a868fd4831a1a7d6c8bebfba443e40a028b8d75270ee9926fe930ca5.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"f22d7dd7-c33a-4af0-ac51-67ee9e28c7e9\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:38\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_AREA_AFRREO\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Geographical Areas\"},\"Code\":[{\"@value\":\"AO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Angola\"}},{\"@value\":\"BJ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Benin\"}},{\"@value\":\"BW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Botswana\"}},{\"@value\":\"BF\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Burkina Faso\"}},{\"@value\":\"BI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Burundi\"}},{\"@value\":\"CV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cape Verde\"}},{\"@value\":\"CM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cameroon\"}},{\"@value\":\"CF\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Central African Republic\"}},{\"@value\":\"TD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Chad\"}},{\"@value\":\"KM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Comoros\"}},{\"@value\":\"CD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Congo, the Democratic Republic of the\"}},{\"@value\":\"CG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Congo\"}},{\"@value\":\"CI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cote d`Ivoire\"}},{\"@value\":\"GQ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Equatorial Guinea\"}},{\"@value\":\"ER\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Eritrea\"}},{\"@value\":\"SZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Eswatini\"}},{\"@value\":\"ET\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ethiopia\"}},{\"@value\":\"GA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gabon\"}},{\"@value\":\"GM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gambia\"}},{\"@value\":\"GH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ghana\"}},{\"@value\":\"GN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Guinea\"}},{\"@value\":\"GW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Guinea-Bissau\"}},{\"@value\":\"KE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kenya\"}},{\"@value\":\"LS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Lesotho\"}},{\"@value\":\"LR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Liberia\"}},{\"@value\":\"MG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Madagascar\"}},{\"@value\":\"MW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Malawi\"}},{\"@value\":\"ML\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mali\"}},{\"@value\":\"MU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mauritius\"}},{\"@value\":\"MZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mozambique\"}},{\"@value\":\"NA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Namibia\"}},{\"@value\":\"NE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Niger\"}},{\"@value\":\"NG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Nigeria\"}},{\"@value\":\"RW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Rwanda\"}},{\"@value\":\"ST\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sao Tome and Principe\"}},{\"@value\":\"SN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Senegal\"}},{\"@value\":\"SC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Seychelles\"}},{\"@value\":\"SL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sierra Leone\"}},{\"@value\":\"ZA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"South Africa\"}},{\"@value\":\"SS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"South Sudan\"}},{\"@value\":\"TZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tanzania, United Republic of\"}},{\"@value\":\"TG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Togo\"}},{\"@value\":\"UG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Uganda\"}},{\"@value\":\"ZM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Zambia\"}},{\"@value\":\"ZW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Zimbabwe\"}},{\"@value\":\"1C_ALLC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Countries\"}},{\"@value\":\"1C_ALL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Countries and Country Groups\"}},{\"@value\":\"1C_ALLG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Country Groups\"}},{\"@value\":\"5X\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"CEMAC\"}},{\"@value\":\"1C_609\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"CFA franc zone\"}},{\"@value\":\"1C_762\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Common Market of Eastern and Southern Africa (COMESA)\"}},{\"@value\":\"R19\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"EAC (East African Community) deprecated\"}},{\"@value\":\"1C_776\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Economic Community of West African States (ECOWAS)\"}},{\"@value\":\"1C_757\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Southern African Customs Union (SACU)\"}},{\"@value\":\"R18\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SADC (South African Development Community)\"}},{\"@value\":\"1C_733\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA countries in fragile situations\"}},{\"@value\":\"1C_729\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA low-income countries\"}},{\"@value\":\"1C_651\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA low-income countries excluding countries in fragile situations\"}},{\"@value\":\"1C_720\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA middle-income countries\"}},{\"@value\":\"1C_703\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA middle-income countries excluding South Africa and Nigeria\"}},{\"@value\":\"1C_706\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA oil-exporting countries\"}},{\"@value\":\"1C_700\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA oil-exporting countries excluding Nigeria\"}},{\"@value\":\"1C_697\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA oil-importing countries\"}},{\"@value\":\"1C_650\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"SSA oil-importing countries excluding South Africa\"}},{\"@value\":\"F6\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sub-Saharan Africa\"}},{\"@value\":\"1C_604\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sub-Saharan Africa excluding Nigeria and South Africa\"}},{\"@value\":\"7A\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"WAEMU (West African Economic and Monetary Union)\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/bf90c1b9d850a6a425a5bb73a91aea4bb6c40b88ce898a90ccbc6f73829a729c.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"ca154c59-2560-434c-99d8-a992bff880d4\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:26\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_SECTOR_GFSR2019\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Sector\"},\"Code\":[{\"@value\":\"S1311B\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Budgetary central government\"}},{\"@value\":\"S1311\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Central government (excl. social security funds)\"}},{\"@value\":\"S1321\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Central government (incl. social security funds)\"}},{\"@value\":\"S13112\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Extrabudgetary central government\"}},{\"@value\":\"S13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General government\"}},{\"@value\":\"S1313\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Local governments\"}},{\"@value\":\"S1314\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social security funds\"}},{\"@value\":\"S1312\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"State governments\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/c1e6b5a48b9c67f127af854207ff7c147b8a19faa5b1aec08e88b5a57bdded96.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"1be30e69-b6b8-4926-9e84-f1a7f3c94dbf\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:36\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":[{\"@id\":\"CL_UNIT_MULT\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Scale\"},\"Code\":[{\"@value\":\"0\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Units\"}},{\"@value\":\"2\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundreds\"}},{\"@value\":\"3\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Thousands\"}},{\"@value\":\"6\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Millions\"}},{\"@value\":\"9\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Billions\"}},{\"@value\":\"12\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Trillions\"}},{\"@value\":\"N15\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Quadrillionths\"}},{\"@value\":\"N14\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Trillionths\"}},{\"@value\":\"N13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Trillionths\"}},{\"@value\":\"N12\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Trillionths\"}},{\"@value\":\"N11\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Billionths\"}},{\"@value\":\"N10\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Billionths\"}},{\"@value\":\"N9\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Billionths\"}},{\"@value\":\"N8\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Millionths\"}},{\"@value\":\"N7\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Millionths\"}},{\"@value\":\"N6\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Millionths\"}},{\"@value\":\"N5\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Thousandths\"}},{\"@value\":\"N4\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Thousandths\"}},{\"@value\":\"N3\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Thousandths\"}},{\"@value\":\"N2\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundredths\"}},{\"@value\":\"N1\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tenths\"}},{\"@value\":\"1\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tens\"}},{\"@value\":\"4\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Thousands\"}},{\"@value\":\"5\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Thousands\"}},{\"@value\":\"7\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Millions\"}},{\"@value\":\"8\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Millions\"}},{\"@value\":\"10\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Billions\"}},{\"@value\":\"11\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Billions\"}},{\"@value\":\"13\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ten Trillions\"}},{\"@value\":\"14\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hundred Trillions\"}},{\"@value\":\"15\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Quadrillions\"}}]},{\"@id\":\"CL_FREQ\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Frequency\"},\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Frequency\"},\"Code\":[{\"@value\":\"A\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Annual\"}},{\"@value\":\"B\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bi-annual\"}},{\"@value\":\"Q\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Quarterly\"}},{\"@value\":\"M\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Monthly\"}},{\"@value\":\"D\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Daily\"}},{\"@value\":\"W\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Weekly\"}}]},{\"@id\":\"CL_AREA_APDREO201904\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Geographical Areas\"},\"Code\":[{\"@value\":\"AU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Australia\"}},{\"@value\":\"BD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bangladesh\"}},{\"@value\":\"BT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bhutan\"}},{\"@value\":\"BN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Brunei Darussalam\"}},{\"@value\":\"KH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Cambodia\"}},{\"@value\":\"HK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Hong Kong\"}},{\"@value\":\"MO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Macao\"}},{\"@value\":\"CN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"China\"}},{\"@value\":\"FJ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiji\"}},{\"@value\":\"IN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"India\"}},{\"@value\":\"ID\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Indonesia\"}},{\"@value\":\"JP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Japan\"}},{\"@value\":\"KI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Kiribati\"}},{\"@value\":\"KR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Korea, Republic of\"}},{\"@value\":\"LA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Lao People`s Democratic Republic\"}},{\"@value\":\"MY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Malaysia\"}},{\"@value\":\"MV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Maldives\"}},{\"@value\":\"MH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Marshall islands\"}},{\"@value\":\"FM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Micronesia, Federated States of\"}},{\"@value\":\"MN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mongolia\"}},{\"@value\":\"MM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Myanmar\"}},{\"@value\":\"NP\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Nepal\"}},{\"@value\":\"NZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"New Zealand\"}},{\"@value\":\"PW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Palau\"}},{\"@value\":\"PG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Papua New Guinea\"}},{\"@value\":\"PH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Philippines\"}},{\"@value\":\"WS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Samoa\"}},{\"@value\":\"SG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Singapore\"}},{\"@value\":\"SB\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Solomon Islands\"}},{\"@value\":\"LK\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Sri Lanka\"}},{\"@value\":\"TW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Taiwan, Province of China\"}},{\"@value\":\"TH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Thailand\"}},{\"@value\":\"TL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Timor-Leste\"}},{\"@value\":\"TO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tonga\"}},{\"@value\":\"TV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tuvalu\"}},{\"@value\":\"VU\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Vanuatu\"}},{\"@value\":\"VN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Viet Nam\"}},{\"@value\":\"1C_ALLC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Countries\"}},{\"@value\":\"1C_ALLG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Country Groups\"}},{\"@value\":\"R4\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"ASEAN (Countries for the Association of South-East Asian Nations)\"}},{\"@value\":\"1C_229\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Asia\"}},{\"@value\":\"S2\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Eastern Asia\"}},{\"@value\":\"1C_Industrial_Asia\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Industrial Asia\"}},{\"@value\":\"1C_PICs_and_Small_States\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"PICs and Small States\"}},{\"@value\":\"1C_9502\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"South Asia\"}}]},{\"@id\":\"CL_INDICATOR_APDREO201904\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"},\"Code\":[{\"@value\":\"BCA_BP6_USD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments, Current Account, Total, Net, In billions of US Dollars\"}},{\"@value\":\"BCA_GDP_BP6_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments, Current Account, Total, Net, Percent of GDP\"}},{\"@value\":\"TX_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"External Trade, Exports of Goods and Services, Percent Change\"}},{\"@value\":\"TM_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"External Trade, Imports of Goods and Services, Percent Change\"}},{\"@value\":\"GGXWDG_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiscal, General Government, Gross debt position, 2001 Manual, Percent of FY GDP\"}},{\"@value\":\"GGXCNL_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Fiscal, General Government, Net lending/borrowing, 2001 Manual, Percent of FY GDP\"}},{\"@value\":\"NGDPD_USD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Gross Domestic Product in US Dollars, Constant Prices, in billions\"}},{\"@value\":\"NGDP_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Gross Domestic Product, Real, Constant Prices, Percent Change\"}},{\"@value\":\"NTDD_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Total Domestic Demand, Real, Constant Prices, Percent Change\"}},{\"@value\":\"PCPI_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Prices, Consumer Price Index, All items, CPI (p.a.), percent change\"}},{\"@value\":\"All_Indicators\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Indicators\"}}]},{\"@id\":\"CL_TIME_FORMAT\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Time format\"},\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Time formats based on ISO 8601.\"},\"Code\":[{\"@value\":\"P1Y\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Annual\"}},{\"@value\":\"P6M\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bi-annual\"}},{\"@value\":\"P3M\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Quarterly\"}},{\"@value\":\"P1M\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Monthly\"}},{\"@value\":\"P7D\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Weekly\"}},{\"@value\":\"P1D\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Daily\"}}]}]},\"Concepts\":{\"ConceptScheme\":{\"@id\":\"APDREO201904\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Asia and Pacific Regional Economic Outlook (APDREO) April 2019\"},\"Concept\":[{\"@id\":\"OBS_VALUE\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Value\"},\"TextFormat\":{\"@textType\":\"Double\"}},{\"@id\":\"UNIT_MULT\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Scale\"}},{\"@id\":\"TIME_FORMAT\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Time format\"},\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Time formats based on ISO 8601.\"}},{\"@id\":\"FREQ\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Frequency\"}},{\"@id\":\"REF_AREA\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Reference Area\"}},{\"@id\":\"INDICATOR\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"}},{\"@id\":\"BASE_YEAR\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Base Year\"},\"TextFormat\":{\"@textType\":\"String\"}},{\"@id\":\"TIME_PERIOD\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Date\"},\"TextFormat\":{\"@textType\":\"DateTime\"}},{\"@id\":\"OBS_STATUS\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Observation Status (incl. Confidentiality)\"},\"TextFormat\":{\"@textType\":\"String\"}}]}},\"KeyFamilies\":{\"KeyFamily\":{\"@id\":\"APDREO201904\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Asia and Pacific Regional Economic Outlook (APDREO) April 2019\"},\"Components\":{\"Dimension\":[{\"@conceptRef\":\"FREQ\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@codelist\":\"CL_FREQ\",\"@codelistVersion\":\"1.0\",\"@codelistAgency\":\"IMF\",\"@isFrequencyDimension\":\"true\"},{\"@conceptRef\":\"REF_AREA\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@codelist\":\"CL_AREA_APDREO201904\",\"@codelistVersion\":\"1.0\",\"@codelistAgency\":\"IMF\"},{\"@conceptRef\":\"INDICATOR\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@codelist\":\"CL_INDICATOR_APDREO201904\",\"@codelistVersion\":\"1.0\",\"@codelistAgency\":\"IMF\"}],\"TimeDimension\":{\"@conceptRef\":\"TIME_PERIOD\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\"},\"PrimaryMeasure\":{\"@conceptRef\":\"OBS_VALUE\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"TextFormat\":{\"@textType\":\"Double\"}},\"Attribute\":[{\"@conceptRef\":\"UNIT_MULT\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@codelist\":\"CL_UNIT_MULT\",\"@codelistVersion\":\"1.0\",\"@codelistAgency\":\"IMF\",\"@attachmentLevel\":\"Series\",\"@assignmentStatus\":\"Mandatory\"},{\"@conceptRef\":\"BASE_YEAR\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@attachmentLevel\":\"Series\",\"@assignmentStatus\":\"Conditional\",\"TextFormat\":{\"@textType\":\"String\"}},{\"@conceptRef\":\"OBS_STATUS\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@attachmentLevel\":\"Observation\",\"@assignmentStatus\":\"Conditional\",\"TextFormat\":{\"@textType\":\"String\"}},{\"@conceptRef\":\"TIME_FORMAT\",\"@conceptVersion\":\"1.0\",\"@conceptSchemeRef\":\"APDREO201904\",\"@conceptSchemeAgency\":\"IMF\",\"@codelist\":\"CL_TIME_FORMAT\",\"@codelistVersion\":\"1.0\",\"@codelistAgency\":\"IMF\",\"@attachmentLevel\":\"Series\",\"@assignmentStatus\":\"Mandatory\",\"@isTimeFormat\":\"true\"}]},\"Annotations\":{\"Annotation\":[{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Latest Update Date\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"10/22/2019\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Name\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"Asia and Pacific Regional Economic Outlook (APDREO) April 2019\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Temporal Coverage\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"Annual data starting in year of publication - 3 and projections up to the year of publication + 5.\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Geographic Coverage\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"ASEAN; Australia; Bangladesh; Bhutan; Brunei Darussalam; Cambodia; China, P.R.: Hong Kong; China, P.R.: Mainland; East Asia; Emerging Asia; Fiji; India; Indonesia; Industrial Asia; Japan; Kiribati; Korea, Republic of; Lao People\\u0027s Democratic Republic; Malaysia; Maldives; Marshall Islands, Republic of; Micronesia, Federated States of; Mongolia; Myanmar; Nepal; New Zealand; Palau; Papua New Guinea; Philippines; PICs and Small States; Samoa; Singapore; Solomon Islands; South Asia; Sri Lanka; Taiwan Province of China; Thailand; Timor-Leste, Dem. Rep. of; Tonga; Tuvalu; Vanuatu; Vietnam.\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Methodology\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"APD REO follows WEO methodology.\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Sectoral Coverage\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"National Accounts, Prices, Balance of Payments, External Trade, Fiscal\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Definition\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"APD Regional Economic Outlook (REO) provides information on recent economic developments and prospects for countries in Asia and Pacific. Data for the REO for Asia and Pacific is prepared in conjunction with the semi-annual World Economic Outlook (WEO) exercises, spring and fall. Data are consistent with the projections underlying the WEO. REO aggregate data may differ from WEO aggregates due to differences in group membership. Composite data for country groups are weighted averages of data for individual countries. Arithmetic weighted averages are used for all concepts except for inflation and broad money, for which geometric averages are used. PPP GDP weights from the WEO database are used for the aggregation of real GDP growth, real non-oil GDP growth, real per capita GDP growth, investment, national savings, broad money, claims on the nonfinancial private sector, and real and nominal effective exchange rates. Aggregates for other concepts are weighted by GDP in U.S. dollars at market exchange rates.\"}},{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common\",\"AnnotationTitle\":\"Code\",\"AnnotationText\":{\"@xml:lang\":\"en\",\"#text\":\"APDREO201904\"}}]}}}}}"} -------------------------------------------------------------------------------- /tests/responses/d6bd4b36396414f070a68802fe9e509fdc82928d88a6dc3821a48f4e40542ce7.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"GenericMetadata\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"0222e1cb-c674-497c-90df-7ee82cb98cb5\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:46:25\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"BOP\"},\"MetadataSet\":{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/genericmetadata\",\"MetadataStructureRef\":\"MDSD_BOP\",\"MetadataStructureAgencyRef\":\"IMF\",\"ReportRef\":\"OBSERVATION_REPORT\",\"AttributeValueSet\":[{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"BOP\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"FREQ\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"1\"}}},{\"@conceptID\":\"FREQ\",\"ReportedAttribute\":[{\"@conceptID\":\"FREQ_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Annual\"}},{\"@conceptID\":\"FREQ_ID\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"YEAR\"}},{\"@conceptID\":\"FREQ_MNEMO\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"A\"}}]}]},{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"BOP\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"REF_AREA\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US\"}}},{\"@conceptID\":\"REF_AREA\",\"ReportedAttribute\":[{\"@conceptID\":\"REF_AREA_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}},{\"@conceptID\":\"REF_AREA_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"111\"}},{\"@conceptID\":\"REF_AREA_SHORT_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}},{\"@conceptID\":\"REF_AREA_FULL_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}},{\"@conceptID\":\"REF_AREA_ISO__CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US\"}},{\"@conceptID\":\"REF_AREA_ISO__CODE_1\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"USA\"}},{\"@conceptID\":\"REF_AREA_SDMX_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US\"}},{\"@conceptID\":\"REF_AREA_SDMX_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}}]}]},{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"BOP\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"INDICATOR\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"BXSTVPO_BP6_USD\"}}},{\"@conceptID\":\"INDICATOR\",\"ReportedAttribute\":[{\"@conceptID\":\"INDICATOR_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Current Account, Goods and Services, Services, Travel, Personal, Other, Credit, US Dollars\"}},{\"@conceptID\":\"INDICATOR_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"BXSTVPO_BP6_USD\"}},{\"@conceptID\":\"INDICATOR_SHORT_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Current Account, Goods and Services, Services, Travel, Personal, Other, Credit, US Dollars\"}},{\"@conceptID\":\"INDICATOR_FULL_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments, Current Account, Goods and Services, Services, Travel, Personal, Other, Credit [BPM6], US Dollar\"}},{\"@conceptID\":\"INDICATOR_CTS_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"BXSTVPO_BP6_USD\"}},{\"@conceptID\":\"INDICATOR_METHODOLOGY\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Balance of Payments Manual, 6th Edition\"}},{\"@conceptID\":\"INDICATOR_UNIT\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US Dollars\"}},{\"@conceptID\":\"INDICATOR_TOPIC\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"External Sector\"}},{\"@conceptID\":\"INDICATOR_KEY_INDICATOR\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Other Indicator\"}},{\"@conceptID\":\"INDICATOR_SDMX_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"BXSTVPO_BP6_USD\"}},{\"@conceptID\":\"INDICATOR_SDMX_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Current Account, Goods and Services, Services, Travel, Personal, Other, Credit, US Dollars\"}},{\"@conceptID\":\"INDICATOR_ALTERNATE_PUBLICATION_CODES\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\".1BD133.C.X.N.1\"}}]}]}]}}}"} -------------------------------------------------------------------------------- /tests/responses/d6d401840c0745c103a251d427313a183f5a2ce869c3a0886bc8de1e3641cafd.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"GenericMetadata\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"ff4c30b9-756a-47cb-a91f-90c5d6037bcf\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T13:00:10\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"},\"DataSetID\":\"WHDREO201910\"},\"MetadataSet\":{\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/genericmetadata\",\"MetadataStructureRef\":\"MDSD_WHDREO201910\",\"MetadataStructureAgencyRef\":\"IMF\",\"ReportRef\":\"OBSERVATION_REPORT\",\"AttributeValueSet\":[{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"WHDREO201910\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"FREQ\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"1\"}}},{\"@conceptID\":\"FREQ\",\"ReportedAttribute\":[{\"@conceptID\":\"FREQ_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Annual\"}},{\"@conceptID\":\"FREQ_ID\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"YEAR\"}},{\"@conceptID\":\"FREQ_MNEMO\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"A\"}}]}]},{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"WHDREO201910\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"REF_AREA\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US\"}}},{\"@conceptID\":\"REF_AREA\",\"ReportedAttribute\":[{\"@conceptID\":\"REF_AREA_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}},{\"@conceptID\":\"REF_AREA_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"111\"}},{\"@conceptID\":\"REF_AREA_ISO__CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US\"}},{\"@conceptID\":\"REF_AREA_ISO__CODE_1\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"USA\"}},{\"@conceptID\":\"REF_AREA_SOURCE_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"111\"}},{\"@conceptID\":\"REF_AREA_SDMX_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US\"}},{\"@conceptID\":\"REF_AREA_SDMX_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}}]}]},{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"WHDREO201910\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"INDICATOR\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"NGDPD\"}}},{\"@conceptID\":\"INDICATOR\",\"ReportedAttribute\":[{\"@conceptID\":\"INDICATOR_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"NGDPD\"}},{\"@conceptID\":\"INDICATOR_SHORT_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_FULL_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_UINT\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"US Dollars\"}},{\"@conceptID\":\"INDICATOR_TOPIC\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Real Sector\"}},{\"@conceptID\":\"INDICATOR_CTS_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"NGDPD\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"NGDPD\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE__COLLECTION\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE__DISSEMINATION\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE__EDD\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_SDMX_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Gross domestic product in U.S. dollars\"}},{\"@conceptID\":\"INDICATOR_SDMX_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"NGDPD\"}}]}]},{\"TargetRef\":\"DATA_STRUCTURE_DEFINITION\",\"TargetValues\":{\"ComponentValue\":{\"@object\":\"KeyFamily\",\"@component\":\"DSD\",\"#text\":\"WHDREO201910\"}},\"ReportedAttribute\":[{\"@conceptID\":\"OBS_IFS_KEY\",\"ReportedAttribute\":{\"@conceptID\":\"INDICATOR\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"PPPSH\"}}},{\"@conceptID\":\"INDICATOR\",\"ReportedAttribute\":[{\"@conceptID\":\"INDICATOR_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"PPPSH\"}},{\"@conceptID\":\"INDICATOR_SHORT_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_FULL_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_UINT\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Percent\"}},{\"@conceptID\":\"INDICATOR_TOPIC\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Real Sector\"}},{\"@conceptID\":\"INDICATOR_CTS_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"PPPSH\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"PPPSH\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE__COLLECTION\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE__DISSEMINATION\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_SOURCE_CODE__EDD\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_SDMX_NAME\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"Purchasing Power Parity, share of World\"}},{\"@conceptID\":\"INDICATOR_SDMX_CODE\",\"Value\":{\"@xml:lang\":\"en\",\"#text\":\"PPPSH\"}}]}]}]}}}"} -------------------------------------------------------------------------------- /tests/responses/dee06a4674a0979ad4a97e21dc84d886a4d25d2756e2cffff61f6082cfaabee4.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"e4ba7fc2-1895-4ce6-b04c-cda35d188296\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:58:56\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_Indicator_FISCALDECENTRALIZATION\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"},\"Code\":[{\"@value\":\"cs\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Capital spending, share of general government\"}},{\"@value\":\"comp\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Compensation of employees, share of general government\"}},{\"@value\":\"cfc\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Consumption of fixed capital, share of general government\"}},{\"@value\":\"debt\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Debt, share of own revenue\"}},{\"@value\":\"defense\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Defense, share of general government\"}},{\"@value\":\"deficit\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Deficit, share of own spending\"}},{\"@value\":\"ea\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Economic affairs, share of general government\"}},{\"@value\":\"edu\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Education, share of general government\"}},{\"@value\":\"ep\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Environmental protection, share of general government\"}},{\"@value\":\"exc\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Excise, share of general government\"}},{\"@value\":\"sd\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Expenditure decentralization (ratio of own spending to general government spending)\"}},{\"@value\":\"gps\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"General public services, share of general government\"}},{\"@value\":\"gs\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Goods and Services, share of general government\"}},{\"@value\":\"health\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Health, share of general government\"}},{\"@value\":\"hca\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Housing \\u0026 community ammenities, share of general government\"}},{\"@value\":\"ipcg\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Income, Profits, Capital Gains, share of general government\"}},{\"@value\":\"interest\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Interest, share of general government\"}},{\"@value\":\"it\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"International Trade, share of general government\"}},{\"@value\":\"oe\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other expenses, share of general government\"}},{\"@value\":\"or\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other revenue, share of general government\"}},{\"@value\":\"ot\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Other Taxes, share of general government\"}},{\"@value\":\"payroll\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Payroll, share of general government\"}},{\"@value\":\"property\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Property, share of general government\"}},{\"@value\":\"pos\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Public order \\u0026 safety, share of general government\"}},{\"@value\":\"recreation\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Recreation, share of general government\"}},{\"@value\":\"rd\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue decentralization (ratio of own revenues to general government revenues)\"}},{\"@value\":\"sb\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social benefits, share of general government\"}},{\"@value\":\"sc\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social contributions, share of general government\"}},{\"@value\":\"sp\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Social protection, share of general government\"}},{\"@value\":\"subs\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Subsidies, share of general government\"}},{\"@value\":\"taxd\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Tax revenue decentralization (share of general government)\"}},{\"@value\":\"transferDep1\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Transfer dependency method 1, ratio of net transfers to own spending\"}},{\"@value\":\"transferDep2\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Transfer dependency method 2, ratio of net transfers to own revenue\"}},{\"@value\":\"ugs\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Use of goods \\u0026 services, share of general government\"}},{\"@value\":\"vat\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"VAT, share of general government\"}},{\"@value\":\"vfi\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Vertical Fiscal Imbalance (1- ratio of own revenue to own spending)\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/e10427a320166a298902487c055d4ee2acd79f2eee51d76f63eea44f40a80c06.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"ed2a7e55-880f-4e47-ad86-3cab3fbb03b0\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T13:00:05\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_AREA_WHDREO201910\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Geographical Areas\"},\"Code\":[{\"@value\":\"AI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Anguilla\"}},{\"@value\":\"AG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Antigua and Barbuda\"}},{\"@value\":\"AR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Argentina\"}},{\"@value\":\"AW\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Aruba\"}},{\"@value\":\"BS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bahamas\"}},{\"@value\":\"BB\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Barbados\"}},{\"@value\":\"BZ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Belize\"}},{\"@value\":\"BO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Bolivia\"}},{\"@value\":\"BR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Brazil\"}},{\"@value\":\"CA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Canada\"}},{\"@value\":\"CL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Chile\"}},{\"@value\":\"CO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Colombia\"}},{\"@value\":\"CR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Costa Rica\"}},{\"@value\":\"DM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Dominica\"}},{\"@value\":\"DO\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Dominican Republic\"}},{\"@value\":\"5Y\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Eastern Caribbean Currency Union\"}},{\"@value\":\"EC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Ecuador\"}},{\"@value\":\"SV\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"El Salvador\"}},{\"@value\":\"GD\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Grenada\"}},{\"@value\":\"GT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Guatemala\"}},{\"@value\":\"GY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Guyana\"}},{\"@value\":\"HT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Haiti\"}},{\"@value\":\"HN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Honduras\"}},{\"@value\":\"JM\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Jamaica\"}},{\"@value\":\"MX\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Mexico\"}},{\"@value\":\"MS\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Montserrat\"}},{\"@value\":\"NI\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Nicaragua\"}},{\"@value\":\"PA\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Panama\"}},{\"@value\":\"PY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Paraguay\"}},{\"@value\":\"PE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Peru\"}},{\"@value\":\"PR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Puerto Rico\"}},{\"@value\":\"KN\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Saint Kitts and Nevis\"}},{\"@value\":\"LC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Saint Lucia\"}},{\"@value\":\"VC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Saint Vincent and the Grenadines\"}},{\"@value\":\"SR\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Suriname\"}},{\"@value\":\"TT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Trinidad and Tobago\"}},{\"@value\":\"US\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"United States\"}},{\"@value\":\"UY\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Uruguay\"}},{\"@value\":\"VE\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Venezuela, Bolivarian Republic\"}},{\"@value\":\"1C_ALLC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Countries\"}},{\"@value\":\"1C_ALL\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Countries and Country Groups\"}},{\"@value\":\"1C_ALLG\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Country Groups\"}},{\"@value\":\"1C_1218\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Caribbean\"}},{\"@value\":\"1C_1212\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Central America\"}},{\"@value\":\"A10\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Western Hemisphere\"}},{\"@value\":\"1C_1205\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Latin America and the Caribbean: Excluding Argentina\"}},{\"@value\":\"A2\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"North American countries\"}},{\"@value\":\"A7\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"South American countries\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/ef2557079983e2791002a31aad1f884431fa0c82965370dcedae49a27f780635.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"4614cf27-e2cf-47b2-95ff-7484267cc991\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:39\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_INDICATOR_AFRREO\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Indicator\"},\"Code\":[{\"@value\":\"FMB_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Broad Money, Percent change, Previous period, Percent\"}},{\"@value\":\"FMB_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Broad Money, Percent of GDP, Percent\"}},{\"@value\":\"FDSAOP_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Claims on Private Sector, Percent change, Previous period, Percent\"}},{\"@value\":\"FDSAOP_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Claims on Private Sector, Percent of GDP, Percent\"}},{\"@value\":\"PCPI_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Consumer Prices, All items, Percent change, Previous period, Percent\"}},{\"@value\":\"PCPI_EOP_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Consumer Prices, End of Period, Percent change, Previous period, Percent\"}},{\"@value\":\"BCA_BP6_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Current Account, Total, Net, Percent of GDP, Percent\"}},{\"@value\":\"ENEER_IX\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Exchange Rates, Nominal Effective Exchange Rate , based on Consumer Price Index, Index\"}},{\"@value\":\"EREER_IX\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Exchange Rates, Real Effective Exchange Rate , based on Consumer Price Index, Index\"}},{\"@value\":\"NGDPRPC_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"GDP per Capita, Real, Percent change, Previous period, Percent\"}},{\"@value\":\"BXGS_BP6_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Goods and Services, Credit, Percent of GDP, Percent\"}},{\"@value\":\"BMGS_BP6_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Goods and Services, Debit, Percent of GDP, Percent\"}},{\"@value\":\"NI_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross Capital Formation, Nominal, Percent of GDP, Percent\"}},{\"@value\":\"GGXWDG_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross debt position (Gen. Govt.), Percent of GDP, Percent\"}},{\"@value\":\"NGDP_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross Domestic Product, Real, Percent change, Previous period, Percent\"}},{\"@value\":\"NGS_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Gross National Saving, Nominal, Percent of GDP, Percent\"}},{\"@value\":\"BFD_BP6_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Net lending (+) / net borrowing (-) (balance from financial account), Direct investment, Percent of GDP, Percent\"}},{\"@value\":\"GGXCNL_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Net lending/borrowing (Gen. Govt.), Percent of GDP, Percent\"}},{\"@value\":\"GGXCNLXG_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Net lending/borrowing excluding Grants (Gen. Govt.), Percent of GDP, Percent\"}},{\"@value\":\"NGDPXO_R_PC_PP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Non-Oil GDP, Real, Percent change, Previous period, Percent\"}},{\"@value\":\"D_G_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Official Debt, Debtor, Percent of GDP, Percent\"}},{\"@value\":\"GGR_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Revenue (Gen. Govt.), Percent of GDP, Percent\"}},{\"@value\":\"TTT_IX\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Terms of Trade for Goods, Index\"}},{\"@value\":\"GGX_G01_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Total Expenditure (Gen. Govt.), Percent of GDP, Percent\"}},{\"@value\":\"All_Indicators\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"All Indicators\"}},{\"@value\":\"BG_BP6_GDP_PT\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Goods and Services, Goods, Net, Percent of GDP, Percent\"}},{\"@value\":\"IAR_BP6_MI_MH\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Reserves, Net, Months of imported goods and services, Months\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/f47414735adbb906b7aa69135a9df5f59b72fe4800de3c9e36adf0d1308dd804.json: -------------------------------------------------------------------------------- 1 | {"status_code": 200, "content": "{\"Structure\":{\"@xmlns:xsd\":\"http://www.w3.org/2001/XMLSchema\",\"@xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\",\"@xsi:schemaLocation\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure https://registry.sdmx.org/schemas/v2_0/SDMXStructure.xsd http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd\",\"Header\":{\"ID\":\"13a308e5-f908-4706-b036-56f53190938d\",\"Test\":\"false\",\"Prepared\":\"2023-04-29T12:59:28\",\"Sender\":{\"@id\":\"1C0\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"IMF\"},\"Contact\":{\"URI\":\"http://www.imf.org\",\"Telephone\":\"+ 1 (202) 623-6220\"}},\"Receiver\":{\"@id\":\"ZZZ\"}},\"CodeLists\":{\"CodeList\":{\"@id\":\"CL_UNIT_GFSR2019\",\"@agencyID\":\"IMF\",\"@version\":\"1.0\",\"@isFinal\":\"true\",\"@xmlns\":\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure\",\"Name\":{\"@xml:lang\":\"en\",\"#text\":\"Unit\"},\"Code\":[{\"@value\":\"XDC\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Domestic currency\"}},{\"@value\":\"XDC_R_B1GQ\",\"Description\":{\"@xml:lang\":\"en\",\"#text\":\"Percent of GDP\"}}]}}}}"} -------------------------------------------------------------------------------- /tests/responses/fddfa660fef62f5f457f207de95739738f207c8bc128ac29fb99203f8d3b84bb.json: -------------------------------------------------------------------------------- 1 | {"status_code": 500, "content": "There is an issue while retrieving the data, please check your query or contact an administrator. GKey = 7ff1a363-0dfe-4d57-887a-6e36e517a0ff"} -------------------------------------------------------------------------------- /tests/test_admin.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pytest 3 | from imfp import set_imf_app_name, set_imf_wait_time 4 | import os 5 | 6 | logger = logging.getLogger(__name__) 7 | logger.setLevel(logging.DEBUG) 8 | 9 | 10 | def test_set_imf_app_name(): 11 | with pytest.warns(UserWarning): 12 | set_imf_app_name("") 13 | with pytest.warns(UserWarning): 14 | set_imf_app_name("imfp") 15 | 16 | with pytest.raises(TypeError): 17 | set_imf_app_name(None) 18 | with pytest.raises(TypeError): 19 | set_imf_app_name(float("nan")) 20 | with pytest.raises(TypeError): 21 | set_imf_app_name(["z", "z"]) 22 | 23 | with pytest.raises(ValueError): 24 | set_imf_app_name("z" * 256) 25 | 26 | set_imf_app_name("imfr_admin_functions_tester") 27 | assert os.getenv("IMF_APP_NAME") == "imfr_admin_functions_tester" 28 | 29 | 30 | @pytest.fixture 31 | def env_setup_teardown(): 32 | # Store the original value of the environment variable 33 | original_value = os.environ.get("IMF_WAIT_TIME", None) 34 | 35 | # Perform the test 36 | yield 37 | 38 | # Restore the original value of the environment variable after the test 39 | if original_value is not None: 40 | os.environ["IMF_WAIT_TIME"] = original_value 41 | else: 42 | os.environ.pop("IMF_WAIT_TIME", None) 43 | 44 | 45 | def test_set_imf_wait_time(env_setup_teardown): 46 | # Test with valid input (int) 47 | set_imf_wait_time(5) 48 | assert os.environ["IMF_WAIT_TIME"] == "5" 49 | 50 | # Test with valid input (float) 51 | set_imf_wait_time(2.5) 52 | assert os.environ["IMF_WAIT_TIME"] == "2.5" 53 | 54 | # Test with invalid input (string) 55 | with pytest.raises(TypeError): 56 | set_imf_wait_time("some_string") 57 | 58 | # Test with invalid input (negative value) 59 | with pytest.raises(ValueError): 60 | set_imf_wait_time(-1) 61 | -------------------------------------------------------------------------------- /tests/test_data.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pytest 3 | import os 4 | import pandas as pd 5 | from imfp import ( 6 | imf_databases, 7 | imf_parameters, 8 | imf_parameter_defs, 9 | imf_dataset, 10 | set_imf_wait_time, 11 | ) 12 | from imfp.utils import _imf_save_response, _imf_use_cache 13 | 14 | logger = logging.getLogger(__name__) 15 | logger.setLevel(logging.DEBUG) 16 | 17 | 18 | # Set test configuration options 19 | create_cache = False 20 | use_cache = True 21 | wait_time = 0 22 | 23 | 24 | @pytest.fixture 25 | def set_options(monkeypatch): 26 | # Create the responses directory if it doesn't exist 27 | os.makedirs("tests/responses", exist_ok=True) 28 | 29 | # Store the original values of the options 30 | original_save_response = _imf_save_response 31 | original_use_cache = _imf_use_cache 32 | original_wait_time = os.environ.get("IMF_WAIT_TIME", None) 33 | 34 | # Set caching options for response mocking 35 | monkeypatch.setattr("imfp.utils._imf_save_response", create_cache) 36 | monkeypatch.setattr("imfp.utils._imf_use_cache", use_cache) 37 | set_imf_wait_time(wait_time) 38 | 39 | # Perform the test 40 | yield float(os.environ.get("IMF_WAIT_TIME")) 41 | 42 | # Restore the original values of the options during teardown 43 | monkeypatch.setattr("imfp.utils._imf_save_response", original_save_response) 44 | monkeypatch.setattr("imfp.utils._imf_use_cache", original_use_cache) 45 | if original_wait_time is not None: 46 | os.environ["IMF_WAIT_TIME"] = original_wait_time 47 | else: 48 | os.environ.pop("IMF_WAIT_TIME", None) 49 | 50 | 51 | def test_imf_databases(set_options): 52 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 53 | 54 | result = imf_databases() 55 | assert isinstance(result, pd.DataFrame), "Result should be a pandas DataFrame" 56 | expected_column_names = ["database_id", "description"] 57 | assert ( 58 | list(result.columns) == expected_column_names 59 | ), "Result should have the expected column names" 60 | assert result.isna().sum().sum() == 0, "Result should not contain any NAs" 61 | assert len(result["database_id"]) == len( 62 | result["description"] 63 | ), "Both columns should have the same length" 64 | 65 | 66 | def test_imf_parameter_defs(set_options): 67 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 68 | 69 | result = imf_parameter_defs("BOP_2017M08") 70 | assert isinstance(result, pd.DataFrame), "Result should be a pandas DataFrame" 71 | assert result.shape[0] == 3, "Result should have 3 rows" 72 | assert result.shape[1] == 2, "Result should have 2 columns" 73 | expected_column_names = ["parameter", "description"] 74 | assert ( 75 | list(result.columns) == expected_column_names 76 | ), "Result should have the expected column names" 77 | 78 | result = imf_parameter_defs("BOP_2017M08", inputs_only=False) 79 | assert isinstance(result, pd.DataFrame), "Result should be a pandas DataFrame" 80 | assert result.shape[0] == 5, "Result should have 5 rows" 81 | assert result.shape[1] == 2, "Result should have 2 columns" 82 | expected_column_names = ["parameter", "description"] 83 | assert ( 84 | list(result.columns) == expected_column_names 85 | ), "Result should have the expected column names" 86 | 87 | with pytest.raises(Exception): 88 | imf_parameter_defs(times=1) 89 | with pytest.raises(Exception): 90 | imf_parameters("not_a_real_database", times=1) 91 | 92 | 93 | def test_imf_parameters(set_options): 94 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 95 | 96 | params = imf_parameters("BOP") 97 | assert all(params["freq"]["input_code"] == ["A", "M", "Q"]) 98 | with pytest.raises(Exception): 99 | imf_parameters(times=1) 100 | with pytest.raises(Exception): 101 | imf_parameters(database_id="not_a_real_database", times=1) 102 | 103 | 104 | def test_imf_dataset_error_handling(set_options): 105 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 106 | 107 | params = imf_parameters("FISCALDECENTRALIZATION") 108 | params["freq"] = params["freq"][0:1] 109 | params["ref_area"] = params["ref_area"][5:10] 110 | params["indicator"] = params["indicator"][ 111 | params["indicator"]["input_code"].str.contains("edu") 112 | ] 113 | params["ref_sector"] = params["ref_sector"][0:1] 114 | with pytest.raises(Exception): 115 | imf_dataset( 116 | database_id="APDREO201904", 117 | counterpart_area="X", 118 | counterpart_sector="X", 119 | times=1, 120 | ) 121 | with pytest.warns(Warning): 122 | imf_dataset( 123 | database_id="APDREO201904", ref_area="AU", indicator=["BCA_BP6_USD", "XYZ"] 124 | ) 125 | with pytest.raises(Exception): 126 | imf_dataset(times=1) 127 | with pytest.raises(Exception): 128 | imf_dataset(database_id=2, times=1) 129 | with pytest.raises(Exception): 130 | imf_dataset(database_id=[], times=1) 131 | with pytest.raises(Exception): 132 | imf_dataset(database_id=["a", "b"], times=1) 133 | with pytest.raises(Exception): 134 | imf_dataset(database_id="not_a_real_database", times=1) 135 | with pytest.raises(Exception): 136 | imf_dataset(database_id="PCPS", start_year=1, times=1) 137 | with pytest.raises(Exception): 138 | imf_dataset(database_id="PCPS", end_year="a", times=1) 139 | with pytest.raises(Exception): 140 | imf_dataset(database_id="PCPS", end_year=[1999, 2004], times=1) 141 | with pytest.raises(Exception): 142 | imf_dataset( 143 | database_id="WHDREO201910", 144 | freq="M", 145 | ref_area="US", 146 | indicator=["PPPSH", "NGDPD"], 147 | start_year=2010, 148 | end_year=2011, 149 | ) 150 | with pytest.warns(Warning): 151 | imf_dataset( 152 | database_id="FISCALDECENTRALIZATION", 153 | parameters=params, 154 | ref_sector=["1C_CG", "1C_LG"], 155 | ) 156 | with pytest.raises(Exception, match=".*outside the dataset's range.*"): 157 | imf_dataset( 158 | database_id="BOP_2017M06", 159 | freq="A", 160 | ref_area="AF", 161 | start_year=2016, 162 | end_year=2018, 163 | ) 164 | 165 | 166 | def test_imf_dataset_params_list_request(set_options): 167 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 168 | 169 | params = imf_parameters("GFSR2019") 170 | params["freq"] = params["freq"][params["freq"]["input_code"].str.contains("A")] 171 | params["ref_area"] = params["ref_area"][ 172 | params["ref_area"]["input_code"].str.contains("US") 173 | ] 174 | params["classification"] = params["classification"][ 175 | params["classification"]["input_code"].isin(["W0_S1_G1151", "W0_S1_G1412"]) 176 | ] 177 | params["ref_sector"] = params["ref_sector"][ 178 | params["ref_sector"]["input_code"].isin(["S13"]) 179 | ] 180 | df = imf_dataset( 181 | database_id="GFSR2019", parameters=params, start_year=2001, end_year=2002 182 | ) 183 | assert len(df) > 1 184 | assert all(int(date) >= 2001 and int(date) <= 2002 for date in df["time_period"]) 185 | assert all(ref_sector == "S13" for ref_sector in df["ref_sector"]) 186 | 187 | 188 | def test_imf_dataset_vector_parameters_request(set_options): 189 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 190 | 191 | df = imf_dataset( 192 | database_id="AFRREO", 193 | indicator=["TTT_IX", "GGX_G01_GDP_PT"], 194 | ref_area="7A", 195 | start_year=2021, 196 | ) 197 | assert len(df) > 1 198 | assert all(int(date) >= 2021 for date in df["time_period"]) 199 | assert all( 200 | indicator in ["TTT_IX", "GGX_G01_GDP_PT"] for indicator in df["indicator"] 201 | ) 202 | 203 | 204 | def test_imf_dataset_data_frame_prep(set_options): 205 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 206 | 207 | case_1 = imf_dataset( 208 | database_id="WHDREO201910", 209 | freq="A", 210 | ref_area="US", 211 | indicator=["PPPSH", "NGDPD"], 212 | start_year=2010, 213 | end_year=2012, 214 | ) 215 | case_2 = imf_dataset( 216 | database_id="WHDREO201910", 217 | freq="A", 218 | ref_area="US", 219 | indicator=["PPPSH", "NGDPD"], 220 | start_year=2010, 221 | end_year=2011, 222 | ) 223 | case_3 = imf_dataset( 224 | database_id="WHDREO201910", 225 | freq="A", 226 | ref_area="US", 227 | indicator=["NGDPD"], 228 | start_year=2011, 229 | end_year=2012, 230 | ) 231 | 232 | desired_names = [ 233 | "time_period", 234 | "obs_value", 235 | "freq", 236 | "ref_area", 237 | "indicator", 238 | "unit_mult", 239 | "time_format", 240 | ] 241 | 242 | assert len(case_1) == 4 and len(case_2) == 2 and len(case_3) == 2 243 | assert ( 244 | len(case_1.columns) == 7 245 | and len(case_2.columns) == 7 246 | and len(case_3.columns) == 7 247 | ) 248 | assert ( 249 | all(col in desired_names for col in case_1.columns) 250 | and all(col in desired_names for col in case_2.columns) 251 | and all(col in desired_names for col in case_3.columns) 252 | ) 253 | 254 | 255 | def test_imf_dataset_include_metadata(set_options): 256 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 257 | 258 | output = imf_dataset( 259 | database_id="WHDREO201910", 260 | freq="A", 261 | ref_area="US", 262 | indicator=["PPPSH", "NGDPD"], 263 | start_year=2010, 264 | end_year=2012, 265 | include_metadata=True, 266 | ) 267 | assert isinstance(output, tuple) 268 | assert len(output) == 2 269 | assert isinstance(output[0], dict) 270 | assert isinstance(output[1], pd.core.frame.DataFrame) 271 | assert all([not pd.isna(value) for value in output[0].values()]) 272 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pytest 3 | import responses 4 | import time 5 | import pandas as pd 6 | import os 7 | from imfp import ( 8 | _imf_get, 9 | _download_parse, 10 | _imf_metadata, 11 | _imf_dimensions, 12 | set_imf_wait_time, 13 | ) 14 | from imfp.utils import _imf_save_response, _imf_use_cache 15 | from typing import List 16 | 17 | logger = logging.getLogger(__name__) 18 | logger.setLevel(logging.DEBUG) 19 | 20 | 21 | # Set test configuration options 22 | create_cache = False 23 | use_cache = True 24 | wait_time = 0 25 | 26 | 27 | @pytest.fixture 28 | def set_options(monkeypatch): 29 | # Create the responses directory if it doesn't exist 30 | os.makedirs("tests/responses", exist_ok=True) 31 | 32 | # Store the original values of the options 33 | original_save_response = _imf_save_response 34 | original_use_cache = _imf_use_cache 35 | original_wait_time = os.environ.get("IMF_WAIT_TIME", None) 36 | 37 | # Set caching options for response mocking 38 | monkeypatch.setattr("imfp.utils._imf_save_response", create_cache) 39 | monkeypatch.setattr("imfp.utils._imf_use_cache", use_cache) 40 | set_imf_wait_time(wait_time) 41 | 42 | # Perform the test 43 | yield float(os.environ.get("IMF_WAIT_TIME")) 44 | 45 | # Restore the original values of the options during teardown 46 | monkeypatch.setattr("imfp.utils._imf_save_response", original_save_response) 47 | monkeypatch.setattr("imfp.utils._imf_use_cache", original_use_cache) 48 | if original_wait_time is not None: 49 | os.environ["IMF_WAIT_TIME"] = original_wait_time 50 | else: 51 | os.environ.pop("IMF_WAIT_TIME", None) 52 | 53 | 54 | @pytest.fixture 55 | def env_setup_teardown(): 56 | # Store the original value of the environment variable 57 | original_value = os.environ.get("IMF_WAIT_TIME", None) 58 | 59 | # Set the environment variable for the test 60 | os.environ["IMF_WAIT_TIME"] = "2.5" 61 | 62 | # Perform the test 63 | yield original_value 64 | 65 | # Restore the original value of the environment variable after the test 66 | if original_value is not None: 67 | os.environ["IMF_WAIT_TIME"] = original_value 68 | else: 69 | os.environ.pop("IMF_WAIT_TIME", None) 70 | 71 | 72 | @responses.activate 73 | def test_imf_get(env_setup_teardown): 74 | # Check if the new value is larger than the default value (1.5) or the original value if it exists 75 | original_value = env_setup_teardown 76 | if original_value: 77 | assert float(original_value) <= float(os.environ["IMF_WAIT_TIME"]) 78 | else: 79 | assert 1.5 <= float(os.environ["IMF_WAIT_TIME"]) 80 | 81 | # Define a mock URL and response 82 | mock_url = "https://example.com/" 83 | mock_response_text = "Example Domain" 84 | mock_header = {"Accept": "application/json", "User-Agent": "imfp"} 85 | 86 | # Add the mock response to the responses library 87 | responses.add(responses.GET, mock_url, body=mock_response_text, status=200) 88 | 89 | # Call the _imf_get function and assert that the response text 90 | # matches the mock response 91 | response = _imf_get(mock_url, mock_header) 92 | assert response.text == mock_response_text 93 | 94 | # Test the rate-limiting functionality by checking the elapsed time 95 | # between two requests 96 | start_time = time.perf_counter() 97 | _imf_get(mock_url, mock_header) 98 | _imf_get(mock_url, mock_header) 99 | end_time = time.perf_counter() 100 | elapsed_time = end_time - start_time 101 | 102 | # The elapsed time should be at least the minimum set in the environ variable 103 | assert elapsed_time >= float(os.environ["IMF_WAIT_TIME"]) 104 | 105 | 106 | def test_download_parse(set_options): 107 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 108 | 109 | # Test with a valid URL 110 | valid_url = ( 111 | "http://dataservices.imf.org/REST/SDMX_JSON.svc/" 112 | "CompactData/BOP/A.US.BXSTVPO_BP6_USD?startPeriod=2020" 113 | ) 114 | valid_result = _download_parse(valid_url) 115 | assert isinstance(valid_result, dict) 116 | assert len(valid_result) == 1 117 | assert "CompactData" in valid_result 118 | assert len(valid_result["CompactData"]) == 6 119 | 120 | # Test with an invalid URL 121 | invalid_url = ( 122 | "http://dataservices.imf.org/REST/SDMX_JSON.svc/" 123 | "CompactData/not_a_real_database/" 124 | ) 125 | with pytest.raises(ValueError): 126 | _download_parse(invalid_url) 127 | 128 | 129 | def test_imf_metadata_valid_url(set_options): 130 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 131 | 132 | URL = ( 133 | "http://dataservices.imf.org/REST/SDMX_JSON.svc/" 134 | "CompactData/BOP/A.US.BXSTVPO_BP6_USD?startPeriod=2020" 135 | ) 136 | metadata = _imf_metadata(URL) 137 | 138 | assert isinstance(metadata, dict) 139 | assert len(metadata) == 7 140 | assert all(value != "NA" for value in metadata.values()) 141 | 142 | 143 | def test_imf_metadata_invalid_url(set_options): 144 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 145 | 146 | URL = ( 147 | "http://dataservices.imf.org/REST/" 148 | "SDMX_JSON.svc/CompactData/not_a_real_database/" 149 | ) 150 | 151 | with pytest.raises(Exception): 152 | _imf_metadata(URL) 153 | 154 | 155 | def test_imf_metadata_empty_url(set_options): 156 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 157 | 158 | URL = "" 159 | 160 | with pytest.raises(ValueError): 161 | _imf_metadata(URL) 162 | 163 | 164 | def test_imf_dimensions_valid_database_id(set_options): 165 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 166 | 167 | database_id = "PCPS" 168 | dimensions = _imf_dimensions(database_id) 169 | 170 | assert isinstance(dimensions, pd.DataFrame) 171 | assert dimensions.shape == (4, 3) 172 | assert dimensions.isna().sum().sum() == 0 173 | 174 | 175 | def test_imf_dimensions_invalid_database_id(set_options): 176 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 177 | 178 | database_id = "not_a_real_database_id" 179 | 180 | with pytest.raises(Exception): 181 | _imf_dimensions(database_id) 182 | 183 | 184 | def test_imf_dimensions_times_param(set_options): 185 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 186 | 187 | database_id = "PCPS" 188 | dimensions = _imf_dimensions(database_id, times=2) 189 | 190 | assert isinstance(dimensions, pd.DataFrame) 191 | assert dimensions.shape == (4, 3) 192 | assert dimensions.isna().sum().sum() == 0 193 | 194 | 195 | def test_imf_dimensions_inputs_only_param(set_options): 196 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 197 | 198 | database_id = "PCPS" 199 | dimensions_1 = _imf_dimensions(database_id, inputs_only=True) 200 | dimensions_2 = _imf_dimensions(database_id, inputs_only=False) 201 | 202 | assert isinstance(dimensions_1, pd.DataFrame) 203 | assert isinstance(dimensions_2, pd.DataFrame) 204 | assert dimensions_1.shape == (4, 3) 205 | assert dimensions_2.shape == (6, 3) 206 | assert dimensions_1.isna().sum().sum() == 0 207 | assert dimensions_2.isna().sum().sum() == 2 208 | 209 | 210 | def test_bad_request(set_options): 211 | assert (wait_time - 0.1) < set_options < (wait_time + 0.1) 212 | 213 | URL = "http://dataservices.imf.org/REST/SDMX_JSON.svc/CompactData/BOP_2017M06/A+M+Q.AF+AL+DZ+AO+AI+AG+AR+AM+AW+AU+AT+AZ+BS+BH+BD+BB+BY+BE+R1+BZ+BJ+BM+BT+BO+BA+BW+BR+BN+BG+BF+BI+KH+CM+CA+CV+CF+TD+CL+HK+MO+CN+CO+KM+CD+CG+CR+CI+HR+CW+1C_355+CY+CZ+CSH+DK+DJ+DM+DO+5Y+EC+EG+SV+GQ+ER+EE+ET+U2+FO+FJ+FI+FR+PF+NC+GA+GM+GE+DE+GH+GR+GD+GT+GN+GW+GY+HT+HN+HU+IS+IN+ID+IR+IQ+IE+IL+IT+JM+JP+JO+KZ+KE+KI+KR+XK+KW+KG+LA+LV+LB+LS+LR+LY+LT+LU+MK+MG+MW+MY+MV+ML+MT+MH+MR+MU+MX+FM+MD+MN+ME+MS+MA+MZ+MM+NA+NP+NL+AN+NZ+NI+NE+NG+NO+OM+PK+PW+PA+PG+PY+PE+PH+PL+PT+QA+RO+RU+RW+WS+ST+SA+SN+RS+SC+SL+SG+SX+SK+SI+SB+SO+ZA+SS+ES+LK+KN+LC+VC+SD+SR+SZ+SE+CH+SY+TW+TJ+TZ+TH+TL+TG+TO+TT+TN+TR+TM+TV+UG+UA+GB+US+UY+VU+VE+VN+PS+1C_473+1C_459+YE+YUC+ZM+ZW+BOP_Reporters+All_Countries+IIP_Reporters.IADDF_BP6_EUR" 214 | 215 | with pytest.raises(ValueError) as excinfo: 216 | _download_parse(URL) 217 | 218 | assert "Too many parameters supplied" in str(excinfo.value) 219 | 220 | URL = "http://dataservices.imf.org/REST/SDMX_JSON.svc/CompactData/BOP_2017M06/.." 221 | 222 | with pytest.raises(ValueError) as excinfo: 223 | _download_parse(URL) 224 | 225 | assert "too large" in str(excinfo.value) 226 | --------------------------------------------------------------------------------