hdx-python-utilities 4.0.8__tar.gz → 4.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/.pre-commit-config.yaml +1 -1
- hdx_python_utilities-4.1.0/CLAUDE.md +81 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/PKG-INFO +4 -5
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/README.md +0 -1
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/documentation/index.md +3 -91
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/pyproject.toml +3 -3
- hdx_python_utilities-4.1.0/src/hdx/utilities/_version.py +24 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/base_downloader.py +0 -4
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/downloader.py +0 -54
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/path.py +10 -23
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/retriever.py +1 -7
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/saver.py +0 -139
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_downloader.py +0 -12
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_retriever.py +0 -16
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_saver.py +1 -151
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_text.py +1 -1
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/uv.lock +132 -98
- hdx_python_utilities-4.0.8/src/hdx/utilities/_version.py +0 -34
- hdx_python_utilities-4.0.8/tests/fixtures/config/json_csv.yaml +0 -108
- hdx_python_utilities-4.0.8/tests/fixtures/retriever/test_hxl.csv +0 -4
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/.github/workflows/publish-test.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/.github/workflows/publish.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/.github/workflows/run-python-tests.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/.gitignore +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/LICENSE +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/documentation/.readthedocs.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/documentation/mkdocs.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/__init__.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/compare.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/dateparse.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/dictandlist.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/easy_logging.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/email.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/encoding.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/error_handler.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/errors_onexit.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/file_hashing.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/frictionless_wrapper.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/html.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/loader.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/matching.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/session.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/state.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/text.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/url.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/useragent.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/uuid.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/zip_crc.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/compare/test_csv_processing.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/compare/test_csv_processing2.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/empty.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/hdx_config.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/hdx_config.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/hdx_email_configuration.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/hdx_email_configuration.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/logging_config.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/logging_config.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/project_configuration.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/project_configuration.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/smtp_config.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/smtp_config.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/user_agent_config.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/user_agent_config2.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/user_agent_config3.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/config/user_agent_config_wrong.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/basicauth.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/bearertoken.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/extra_params.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/extra_params.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/extra_params_tree.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_csv_processing.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_csv_processing_blanks.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_data.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_data.xlsx +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_data1.csv/empty.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_data2.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_json_processing.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_xls_processing.xls +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/downloader/test_xlsx_processing.xlsx +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/file_hashing/bad_header.zip +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/file_hashing/bad_index.xlsx +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/file_hashing/empty.zip +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/file_hashing/test.xlsx +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/file_hashing/test_shapefile.zip +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/file_hashing/valid_sig_invalid_body.zip +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/html/response.html +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/loader/empty.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/loader/empty.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/loader/empty_list.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/fallbacks/test.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/fallbacks/test.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/fallbacks/test.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/fallbacks/test.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/retriever-test.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/test.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/test.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/test.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/retriever/test.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out2.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out2.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out5.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out6.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out7.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out8.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/out8.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-false_sortkeys-false.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-false_sortkeys-false.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-false_sortkeys-true.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-false_sortkeys-true.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-true_sortkeys-false.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-true_sortkeys-false.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-true_sortkeys-true.json +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/saver/pretty-true_sortkeys-true.yaml +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/state/analysis_dates.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/state/last_build_date.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/test_data.csv +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/text/text1.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/fixtures/text/text2.txt +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/conftest.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_compare.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_dateparse.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_dictandlist.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_easy_logging.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_email.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_encoding.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_error_handler.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_file_hashing.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_html.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_loader.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_matching.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_path.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_state.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_url.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_useragent.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_uuid.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/test_zip_crc.py +0 -0
- {hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/tests/hdx/utilities/utils.py +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**hdx-python-utilities** is a general-purpose Python utility library (not HDX-specific) providing helpers for: downloading files, retrieving tabular data (CSV/JSON/XLSX), date parsing, JSON/YAML I/O, dict/list manipulation, HTML parsing, file hashing, text processing, error handling, and more.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
uv sync
|
|
14
|
+
|
|
15
|
+
# Run all tests with coverage
|
|
16
|
+
uv run pytest
|
|
17
|
+
|
|
18
|
+
# Run a single test file
|
|
19
|
+
uv run pytest tests/hdx/utilities/test_downloader.py
|
|
20
|
+
|
|
21
|
+
# Run a single test by name
|
|
22
|
+
uv run pytest tests/hdx/utilities/test_downloader.py -k "test_download_file"
|
|
23
|
+
|
|
24
|
+
# Lint and format
|
|
25
|
+
uv run ruff check
|
|
26
|
+
pre-commit run --all-files
|
|
27
|
+
|
|
28
|
+
# Build
|
|
29
|
+
uv build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Coverage is written to `coverage.lcov` and JUnit XML to `test-results.xml`.
|
|
33
|
+
|
|
34
|
+
## Source Layout
|
|
35
|
+
|
|
36
|
+
All source lives under `src/hdx/utilities/`. Tests mirror the layout under `tests/hdx/utilities/` with fixtures in `tests/fixtures/`.
|
|
37
|
+
|
|
38
|
+
Key modules:
|
|
39
|
+
- `base_downloader.py` — `BaseDownload` ABC defining the interface (`download_file`, `download_tabular_rows`, etc.) and `DownloadError`
|
|
40
|
+
- `downloader.py` — `Download(BaseDownload)`: HTTP downloading via `requests` + `frictionless` for tabular parsing; supports auth (basic, bearer, extra params), rate limiting, retries, and streaming rows
|
|
41
|
+
- `retriever.py` — `Retrieve(BaseDownload)`: wraps a `Download`, adding save/load-from-disk and static fallback directories; registered instances in `Retrieve.retrievers` dict
|
|
42
|
+
- `session.py` — `get_session()` builds a `requests.Session` with retry logic and auth headers
|
|
43
|
+
- `frictionless_wrapper.py` — thin wrapper around `frictionless.TableResource` for tabular reads
|
|
44
|
+
- `loader.py` / `saver.py` — JSON and YAML I/O (YAML uses `ruamel.yaml` to preserve order/comments)
|
|
45
|
+
- `dateparse.py` — date/time parsing and timezone utilities
|
|
46
|
+
- `dictandlist.py` — dict/list helpers (merge, flatten, key renaming, etc.)
|
|
47
|
+
- `path.py` — `script_dir()`, temp dir helpers, `NotFoundError`
|
|
48
|
+
- `error_handler.py` / `errors_onexit.py` — structured error accumulation and on-exit reporting
|
|
49
|
+
- `text.py` — text processing including `smart_split`
|
|
50
|
+
- `matching.py` — fuzzy/phonetic matching utilities
|
|
51
|
+
- `state.py` — lightweight on-disk state persistence
|
|
52
|
+
- `useragent.py` — user-agent string construction (reads `~/.useragent.yaml` by default)
|
|
53
|
+
|
|
54
|
+
## Key Patterns
|
|
55
|
+
|
|
56
|
+
**Download / Retrieve layering** — `Download` handles raw HTTP; `Retrieve` adds a save/use_saved/fallback layer on top. Callers typically use `Retrieve` rather than `Download` directly. Both implement `BaseDownload` so they're interchangeable.
|
|
57
|
+
|
|
58
|
+
**Tabular row iteration** — `download_tabular_rows()` (on both `Download` and `Retrieve`) yields dicts via `frictionless.TableResource`. The `frictionless_wrapper.py` module handles the `FrictionlessException` boundary. Supports CSV, JSON, XLSX, and XLS.
|
|
59
|
+
|
|
60
|
+
**User-agent requirement** — `Download` requires a user agent. Either set a global user agent via `UserAgent.set_global(...)` or pass `user_agent=` directly. Missing user agent raises at construction time.
|
|
61
|
+
|
|
62
|
+
**Context manager usage** — `Download` and `Retrieve` are designed as context managers (`with Download(...) as downloader:`). `__exit__` closes the session.
|
|
63
|
+
|
|
64
|
+
**Auth precedence** — environment variables `EXTRA_PARAMS`, `BASIC_AUTH`, `BEARER_TOKEN` override constructor arguments. Among constructor args: `auth` > `basic_auth`/`basic_auth_file` > `bearer_token`/`bearer_token_file` > `extra_params_dict` > `extra_params_json`/`extra_params_yaml`.
|
|
65
|
+
|
|
66
|
+
## Code Style
|
|
67
|
+
|
|
68
|
+
- Python ≥ 3.10; type hints throughout using `X | Y` union syntax (PEP 604)
|
|
69
|
+
- Google-style docstrings with `Args:` and `Returns:` sections
|
|
70
|
+
- Formatted and linted with `ruff` (rules: E, F, I, UP; E501 ignored)
|
|
71
|
+
- No inline comments unless the *why* is non-obvious
|
|
72
|
+
|
|
73
|
+
## Collaboration Style
|
|
74
|
+
|
|
75
|
+
- Be objective, not agreeable. Push back when you disagree, flag tradeoffs honestly.
|
|
76
|
+
- Keep explanations brief and to the point.
|
|
77
|
+
- Don't rely on recalled knowledge for facts that could be stale. Read the actual source first.
|
|
78
|
+
|
|
79
|
+
## Scope of Changes
|
|
80
|
+
|
|
81
|
+
When fixing a bug or addressing PR feedback, change only what is necessary to resolve the specific issue. Do not refactor surrounding code, rename variables, adjust formatting, or make improvements in the same commit unless they are directly required by the fix.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hdx-python-utilities
|
|
3
|
-
Version: 4.0
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: HDX Python Utilities for streaming tabular data, date and time handling and other helpful functions
|
|
5
5
|
Project-URL: Homepage, https://github.com/OCHA-DAP/hdx-python-utilities
|
|
6
6
|
Author-email: Michael Rans <rans@email.com>
|
|
@@ -25,8 +25,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.14
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Requires-Python: >=3.10
|
|
28
|
-
Requires-Dist: frictionless>=5.
|
|
29
|
-
Requires-Dist: ijson>=3.
|
|
28
|
+
Requires-Dist: frictionless>=5.19.0
|
|
29
|
+
Requires-Dist: ijson>=3.5.0
|
|
30
30
|
Requires-Dist: jsonlines>=4.0.0
|
|
31
31
|
Requires-Dist: loguru
|
|
32
32
|
Requires-Dist: openpyxl>=3.1.2
|
|
@@ -38,7 +38,7 @@ Requires-Dist: ruamel-yaml
|
|
|
38
38
|
Requires-Dist: tableschema-to-template>=0.0.13
|
|
39
39
|
Requires-Dist: typing-extensions
|
|
40
40
|
Requires-Dist: xlrd>=2.0.1
|
|
41
|
-
Requires-Dist: xlsx2csv
|
|
41
|
+
Requires-Dist: xlsx2csv==0.8.4
|
|
42
42
|
Requires-Dist: xlwt>=1.3.0
|
|
43
43
|
Provides-Extra: diff
|
|
44
44
|
Requires-Dist: cydifflib; extra == 'diff'
|
|
@@ -63,7 +63,6 @@ Note that these are not specific to HDX.
|
|
|
63
63
|
1. Retrieval of data from url with saving to file or from data previously saved
|
|
64
64
|
1. Date utilities
|
|
65
65
|
1. Loading and saving JSON and YAML (maintaining order)
|
|
66
|
-
1. Loading and saving HXLated csv and/or JSON
|
|
67
66
|
1. Dictionary and list utilities
|
|
68
67
|
1. HTML utilities (inc. BeautifulSoup helper)
|
|
69
68
|
1. Compare files (eg. for testing)
|
|
@@ -10,7 +10,6 @@ Note that these are not specific to HDX.
|
|
|
10
10
|
1. Retrieval of data from url with saving to file or from data previously saved
|
|
11
11
|
1. Date utilities
|
|
12
12
|
1. Loading and saving JSON and YAML (maintaining order)
|
|
13
|
-
1. Loading and saving HXLated csv and/or JSON
|
|
14
13
|
1. Dictionary and list utilities
|
|
15
14
|
1. HTML utilities (inc. BeautifulSoup helper)
|
|
16
15
|
1. Compare files (eg. for testing)
|
|
@@ -9,7 +9,6 @@ Python developers. Note that these are not specific to HDX.
|
|
|
9
9
|
1. [Retrieval of data from url with saving to file or from data previously saved](#retrieving-files)
|
|
10
10
|
1. [Date utilities](#date-utilities)
|
|
11
11
|
1. [Loading and saving JSON and YAML (maintaining order)](#loading-and-saving-json-and-yaml)
|
|
12
|
-
1. [Loading and saving HXLated csv and/or JSON](#loading-and-saving-hxlated-csv-andor-json)
|
|
13
12
|
1. [Dictionary and list utilities](#dictionary-and-list-utilities)
|
|
14
13
|
1. [HTML utilities (inc. BeautifulSoup helper)](#html-utilities)
|
|
15
14
|
1. [Compare files (eg. for testing)](#comparing-files)
|
|
@@ -34,6 +33,9 @@ The code for the library is [here](https://github.com/OCHA-DAP/hdx-python-utilit
|
|
|
34
33
|
The library has detailed API documentation which can be found in the menu at the top.
|
|
35
34
|
|
|
36
35
|
## Breaking Changes
|
|
36
|
+
From 4.1.0, save_hxlated_output and Download.hxl_row removed. Parameter use_hxl removed
|
|
37
|
+
from all calls in Download and Retrieve.
|
|
38
|
+
|
|
37
39
|
From 4.0.4, get_filename_from_url, get_filename_extension_from_url, get_path_for_url,
|
|
38
40
|
get_url_for_get, get_url_params_for_post moved to module url
|
|
39
41
|
|
|
@@ -185,9 +187,6 @@ Other useful functions:
|
|
|
185
187
|
headers, iterator = downloader.get_tabular_rows_as_list(url)
|
|
186
188
|
for row in iterator:
|
|
187
189
|
...
|
|
188
|
-
# Get hxl row
|
|
189
|
-
assert Download.hxl_row(["a", "b", "c"], {"b": "#b", "c": "#c"}, dict_form=True)
|
|
190
|
-
# == {"a": "", "b": "#b", "c": "#c"}
|
|
191
190
|
# Build get url from url and dictionary of parameters
|
|
192
191
|
Download.get_url_for_get("http://www.lala.com/hdfa?a=3&b=4",
|
|
193
192
|
OrderedDict([("c", "e"), ("d", "f")]))
|
|
@@ -461,93 +460,6 @@ as a csv or Excel.
|
|
|
461
460
|
|
|
462
461
|
save_iterable(xlfilepath, list_of_lists, headers=["h1", "h2", "h3", "h4"], format="xlsx")
|
|
463
462
|
|
|
464
|
-
## Loading and saving HXLated csv and/or JSON
|
|
465
|
-
|
|
466
|
-
`save_hxlated_output` is a utility to save HXLated output (currently JSON and/or csv are
|
|
467
|
-
supported) based on a given configuration. Here is an example YAML configuration:
|
|
468
|
-
|
|
469
|
-
input:
|
|
470
|
-
headers:
|
|
471
|
-
- "Col1"
|
|
472
|
-
- "Col2"
|
|
473
|
-
- "Col3"
|
|
474
|
-
hxltags:
|
|
475
|
-
- "#tag1"
|
|
476
|
-
- "#tag2"
|
|
477
|
-
- "#tag3"
|
|
478
|
-
process:
|
|
479
|
-
- header: "tag4"
|
|
480
|
-
hxltag: "#tag4"
|
|
481
|
-
expression: "#tag1 * 10"
|
|
482
|
-
output:
|
|
483
|
-
csv:
|
|
484
|
-
filename: "out.csv"
|
|
485
|
-
hxltags:
|
|
486
|
-
- "#tag2"
|
|
487
|
-
- "#tag3"
|
|
488
|
-
json:
|
|
489
|
-
filename: "out.json"
|
|
490
|
-
data: "results"
|
|
491
|
-
metadata:
|
|
492
|
-
"#date": "{{today}}"
|
|
493
|
-
"#mytag": 123
|
|
494
|
-
hxltags:
|
|
495
|
-
- "#tag1"
|
|
496
|
-
- "#tag2"
|
|
497
|
-
|
|
498
|
-
The `input` section is needed if the rows of data that are passed in are missing either
|
|
499
|
-
headers or HXL hashtags. The `output` section defines what files will be created. If
|
|
500
|
-
`hxltags` are specified, then only those columns are output. CSV output would look like
|
|
501
|
-
this:
|
|
502
|
-
|
|
503
|
-
Col2,Col3,tag4
|
|
504
|
-
#tag2,#tag3,#tag4
|
|
505
|
-
2,3,10
|
|
506
|
-
5,6,40
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
For JSON output, if no `metadata` or `data` is specified, the output will look like
|
|
510
|
-
this:
|
|
511
|
-
|
|
512
|
-
[
|
|
513
|
-
{"#tag1":1,"#tag2":"2","#tag4":10},
|
|
514
|
-
{"#tag1":4,"#tag2":"5","#tag4":40}
|
|
515
|
-
]
|
|
516
|
-
|
|
517
|
-
If only `metadata` was specified, not `data`, then output is like this:
|
|
518
|
-
|
|
519
|
-
{"metadata":{"#date":"today!","#mytag":123},"data":[
|
|
520
|
-
{"#tag1":1,"#tag2":"2","#tag4":10},
|
|
521
|
-
{"#tag1":4,"#tag2":"5","#tag4":40}
|
|
522
|
-
]}
|
|
523
|
-
|
|
524
|
-
Otherwise, the result is like this:
|
|
525
|
-
|
|
526
|
-
{"metadata":{"#date":"today!","#mytag":123},"results":[
|
|
527
|
-
{"#tag1":1,"#tag2":"2","#tag4":10},
|
|
528
|
-
{"#tag1":4,"#tag2":"5","#tag4":40}
|
|
529
|
-
]}
|
|
530
|
-
|
|
531
|
-
The utility is called as follows:
|
|
532
|
-
|
|
533
|
-
save_hxlated_output(
|
|
534
|
-
configuration,
|
|
535
|
-
rows,
|
|
536
|
-
includes_header=True,
|
|
537
|
-
includes_hxltags=True,
|
|
538
|
-
output_dir=output_dir,
|
|
539
|
-
today="today!",
|
|
540
|
-
)
|
|
541
|
-
|
|
542
|
-
The first parameter is the configuration which can come from a YAML file for example.
|
|
543
|
-
The second parameter, `rows` is the data. That data can be a list of lists, tuples or
|
|
544
|
-
dictionaries. If `includes_header` is `True`, headers are taken from `rows`, otherwise
|
|
545
|
-
they must be given by the configuration. If `includes_hxltags` is `True`, HXL hashtags
|
|
546
|
-
are taken from `rows`, otherwise they must be given by the configuration. `output_dir`
|
|
547
|
-
specifies where the output should go and defaults to "". Any other parameters (such as
|
|
548
|
-
`today` in the example above) are used to populate template variables given in the
|
|
549
|
-
configuration for the metadata.
|
|
550
|
-
|
|
551
463
|
## Dictionary and list utilities
|
|
552
464
|
|
|
553
465
|
Examples:
|
|
@@ -39,14 +39,14 @@ requires-python = ">=3.10"
|
|
|
39
39
|
# Extras for frictionless[excel,json] added explicitly
|
|
40
40
|
# for conda-forge compatibility
|
|
41
41
|
dependencies = [
|
|
42
|
-
"frictionless>=5.
|
|
42
|
+
"frictionless>=5.19.0",
|
|
43
43
|
# frictionless[excel]
|
|
44
44
|
"openpyxl>=3.1.2",
|
|
45
45
|
"tableschema-to-template>=0.0.13",
|
|
46
46
|
"xlrd>=2.0.1",
|
|
47
47
|
"xlwt>=1.3.0",
|
|
48
48
|
# frictionless[json]
|
|
49
|
-
"ijson>=3.
|
|
49
|
+
"ijson>=3.5.0",
|
|
50
50
|
"jsonlines>=4.0.0",
|
|
51
51
|
# /end frictionless extras
|
|
52
52
|
"typing_extensions",
|
|
@@ -56,7 +56,7 @@ dependencies = [
|
|
|
56
56
|
"ratelimit",
|
|
57
57
|
"requests-file",
|
|
58
58
|
"ruamel.yaml",
|
|
59
|
-
"xlsx2csv",
|
|
59
|
+
"xlsx2csv==0.8.4",
|
|
60
60
|
]
|
|
61
61
|
|
|
62
62
|
[project.optional-dependencies]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '4.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (4, 1, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
{hdx_python_utilities-4.0.8 → hdx_python_utilities-4.1.0}/src/hdx/utilities/base_downloader.py
RENAMED
|
@@ -90,7 +90,6 @@ class BaseDownload(ABC):
|
|
|
90
90
|
def get_tabular_rows(
|
|
91
91
|
self,
|
|
92
92
|
url: Path | str | Sequence[str],
|
|
93
|
-
has_hxl: bool = False,
|
|
94
93
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
95
94
|
dict_form: bool = False,
|
|
96
95
|
*args: Any,
|
|
@@ -100,8 +99,6 @@ class BaseDownload(ABC):
|
|
|
100
99
|
where each row is returned as a list or dictionary depending on the
|
|
101
100
|
dict_rows argument.
|
|
102
101
|
|
|
103
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
104
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
105
102
|
The headers argument is either a row number or list of row numbers (in case of
|
|
106
103
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
107
104
|
the actual headers defined as a list of strings. It defaults to 1.
|
|
@@ -110,7 +107,6 @@ class BaseDownload(ABC):
|
|
|
110
107
|
|
|
111
108
|
Args:
|
|
112
109
|
url: A single or list of URLs or paths to read from
|
|
113
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
114
110
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
115
111
|
dict_form: Return dict or list for each row. Defaults to False (list)
|
|
116
112
|
*args (Any): Positional arguments
|
|
@@ -142,28 +142,6 @@ class Download(BaseDownload):
|
|
|
142
142
|
preparedrequest = self.session.prepare_request(request)
|
|
143
143
|
return preparedrequest.url
|
|
144
144
|
|
|
145
|
-
@staticmethod
|
|
146
|
-
def hxl_row(
|
|
147
|
-
headers: Sequence[str],
|
|
148
|
-
hxltags: dict[str, str],
|
|
149
|
-
dict_form: bool = False,
|
|
150
|
-
) -> list[str] | dict[str, str]:
|
|
151
|
-
"""Return HXL tag row for header row given list of headers and
|
|
152
|
-
dictionary with header to HXL hashtag mappings. Return list or
|
|
153
|
-
dictionary depending upon the dict_form argument.
|
|
154
|
-
|
|
155
|
-
Args:
|
|
156
|
-
headers: Headers for which to get HXL hashtags
|
|
157
|
-
hxltags: Header to HXL hashtag mapping
|
|
158
|
-
dict_form: Return dict or list. Defaults to False (list)
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
Return either a list or dictionary conating HXL hashtags
|
|
162
|
-
"""
|
|
163
|
-
if dict_form:
|
|
164
|
-
return {header: hxltags.get(header, "") for header in headers}
|
|
165
|
-
return [hxltags.get(header, "") for header in headers]
|
|
166
|
-
|
|
167
145
|
def normal_setup(
|
|
168
146
|
self,
|
|
169
147
|
url: Path | str,
|
|
@@ -674,7 +652,6 @@ class Download(BaseDownload):
|
|
|
674
652
|
def get_tabular_rows(
|
|
675
653
|
self,
|
|
676
654
|
url: Path | str | Sequence[str],
|
|
677
|
-
has_hxl: bool = False,
|
|
678
655
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
679
656
|
dict_form: bool = False,
|
|
680
657
|
include_headers: bool = False,
|
|
@@ -688,8 +665,6 @@ class Download(BaseDownload):
|
|
|
688
665
|
where each row is returned as a list or dictionary depending on the
|
|
689
666
|
dict_rows argument.
|
|
690
667
|
|
|
691
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
692
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
693
668
|
The headers argument is either a row number or list of row numbers (in case of
|
|
694
669
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
695
670
|
the actual headers defined as a list of strings. It defaults to 1. The dict_form
|
|
@@ -705,7 +680,6 @@ class Download(BaseDownload):
|
|
|
705
680
|
|
|
706
681
|
Args:
|
|
707
682
|
url: A single or list of URLs or paths to read from
|
|
708
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
709
683
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
710
684
|
dict_form: Return dict or list for each row. Defaults to False (list)
|
|
711
685
|
include_headers: Whether to include headers in iterator. Defaults to False.
|
|
@@ -772,8 +746,6 @@ class Download(BaseDownload):
|
|
|
772
746
|
row_function,
|
|
773
747
|
**temp_kwargs,
|
|
774
748
|
)
|
|
775
|
-
if has_hxl:
|
|
776
|
-
next(iterator)
|
|
777
749
|
yield from iterator
|
|
778
750
|
|
|
779
751
|
return outheaders, make_iterator()
|
|
@@ -781,7 +753,6 @@ class Download(BaseDownload):
|
|
|
781
753
|
def get_tabular_rows_as_list(
|
|
782
754
|
self,
|
|
783
755
|
url: Path | str | Sequence[str],
|
|
784
|
-
has_hxl: bool = False,
|
|
785
756
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
786
757
|
include_headers: bool = True,
|
|
787
758
|
ignore_blank_rows: bool = True,
|
|
@@ -793,8 +764,6 @@ class Download(BaseDownload):
|
|
|
793
764
|
"""Returns headers and an iterator where each row is returned as a
|
|
794
765
|
list.
|
|
795
766
|
|
|
796
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
797
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
798
767
|
The headers argument is either a row number or list of row numbers (in case of
|
|
799
768
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
800
769
|
the actual headers defined as a list of strings. It defaults to 1 and cannot be
|
|
@@ -809,7 +778,6 @@ class Download(BaseDownload):
|
|
|
809
778
|
|
|
810
779
|
Args:
|
|
811
780
|
url: A single or list of URLs or paths to read from
|
|
812
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
813
781
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
814
782
|
include_headers: Whether to include headers in iterator. Defaults to True.
|
|
815
783
|
ignore_blank_rows: Whether to ignore blank rows. Defaults to True.
|
|
@@ -842,7 +810,6 @@ class Download(BaseDownload):
|
|
|
842
810
|
|
|
843
811
|
headers, iterator = self.get_tabular_rows(
|
|
844
812
|
url,
|
|
845
|
-
has_hxl,
|
|
846
813
|
headers,
|
|
847
814
|
False,
|
|
848
815
|
include_headers,
|
|
@@ -857,7 +824,6 @@ class Download(BaseDownload):
|
|
|
857
824
|
def get_tabular_rows_as_dict(
|
|
858
825
|
self,
|
|
859
826
|
url: Path | str | Sequence[str],
|
|
860
|
-
has_hxl: bool = False,
|
|
861
827
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
862
828
|
ignore_blank_rows: bool = True,
|
|
863
829
|
infer_types: bool = False,
|
|
@@ -868,8 +834,6 @@ class Download(BaseDownload):
|
|
|
868
834
|
"""Returns headers and an iterator where each row is returned as a
|
|
869
835
|
dictionary.
|
|
870
836
|
|
|
871
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
872
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
873
837
|
The headers argument is either a row number or list of row numbers (in case of
|
|
874
838
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
875
839
|
the actual headers defined as a list of strings. It defaults to 1 and cannot be
|
|
@@ -884,7 +848,6 @@ class Download(BaseDownload):
|
|
|
884
848
|
|
|
885
849
|
Args:
|
|
886
850
|
url: A single or list of URLs or paths to read from
|
|
887
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
888
851
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
889
852
|
ignore_blank_rows: Whether to ignore blank rows. Defaults to True.
|
|
890
853
|
infer_types: Whether to infer types. Defaults to False (strings).
|
|
@@ -916,7 +879,6 @@ class Download(BaseDownload):
|
|
|
916
879
|
|
|
917
880
|
headers, iterator = self.get_tabular_rows(
|
|
918
881
|
url,
|
|
919
|
-
has_hxl,
|
|
920
882
|
headers,
|
|
921
883
|
True,
|
|
922
884
|
False,
|
|
@@ -931,7 +893,6 @@ class Download(BaseDownload):
|
|
|
931
893
|
def download_tabular_key_value(
|
|
932
894
|
self,
|
|
933
895
|
url: Path | str | Sequence[str],
|
|
934
|
-
has_hxl: bool = False,
|
|
935
896
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
936
897
|
include_headers: bool = True,
|
|
937
898
|
ignore_blank_rows: bool = True,
|
|
@@ -943,8 +904,6 @@ class Download(BaseDownload):
|
|
|
943
904
|
"""Download 2 column csv from url and return a dictionary of keys
|
|
944
905
|
(first column) and values (second column).
|
|
945
906
|
|
|
946
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
947
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
948
907
|
The headers argument is either a row number or list of row numbers (in case of
|
|
949
908
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
950
909
|
the actual headers defined as a list of strings. It defaults to 1 and cannot be
|
|
@@ -957,10 +916,8 @@ class Download(BaseDownload):
|
|
|
957
916
|
and row (which will be in dict or list form depending upon the dict_rows
|
|
958
917
|
argument) and outputs a modified row or None to ignore the row.
|
|
959
918
|
|
|
960
|
-
|
|
961
919
|
Args:
|
|
962
920
|
url: A single or list of URLs or paths to read from
|
|
963
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
964
921
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
965
922
|
include_headers: Whether to include headers in iterator. Defaults to True.
|
|
966
923
|
ignore_blank_rows: Whether to ignore blank rows. Defaults to True.
|
|
@@ -993,7 +950,6 @@ class Download(BaseDownload):
|
|
|
993
950
|
output_dict = {}
|
|
994
951
|
_, rows = self.get_tabular_rows_as_list(
|
|
995
952
|
url,
|
|
996
|
-
has_hxl,
|
|
997
953
|
headers,
|
|
998
954
|
include_headers,
|
|
999
955
|
ignore_blank_rows,
|
|
@@ -1011,7 +967,6 @@ class Download(BaseDownload):
|
|
|
1011
967
|
def download_tabular_rows_as_dicts(
|
|
1012
968
|
self,
|
|
1013
969
|
url: Path | str | Sequence[str],
|
|
1014
|
-
has_hxl: bool = False,
|
|
1015
970
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
1016
971
|
keycolumn: int = 1,
|
|
1017
972
|
ignore_blank_rows: bool = True,
|
|
@@ -1024,8 +979,6 @@ class Download(BaseDownload):
|
|
|
1024
979
|
are first column and values are dictionaries with keys from column
|
|
1025
980
|
headers and values from columns beneath.
|
|
1026
981
|
|
|
1027
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
1028
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
1029
982
|
The headers argument is either a row number or list of row numbers (in case of
|
|
1030
983
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
1031
984
|
the actual headers defined as a list of strings. It defaults to 1 and cannot be
|
|
@@ -1040,7 +993,6 @@ class Download(BaseDownload):
|
|
|
1040
993
|
|
|
1041
994
|
Args:
|
|
1042
995
|
url: A single or list of URLs or paths to read from
|
|
1043
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
1044
996
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
1045
997
|
keycolumn: Number of column to be used for key. Defaults to 1.
|
|
1046
998
|
ignore_blank_rows: Whether to ignore blank rows. Defaults to True.
|
|
@@ -1073,7 +1025,6 @@ class Download(BaseDownload):
|
|
|
1073
1025
|
"""
|
|
1074
1026
|
headers, iterator = self.get_tabular_rows_as_dict(
|
|
1075
1027
|
url,
|
|
1076
|
-
has_hxl,
|
|
1077
1028
|
headers,
|
|
1078
1029
|
ignore_blank_rows,
|
|
1079
1030
|
infer_types,
|
|
@@ -1095,7 +1046,6 @@ class Download(BaseDownload):
|
|
|
1095
1046
|
def download_tabular_cols_as_dicts(
|
|
1096
1047
|
self,
|
|
1097
1048
|
url: Path | str | Sequence[str],
|
|
1098
|
-
has_hxl: bool = False,
|
|
1099
1049
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
1100
1050
|
keycolumn: int = 1,
|
|
1101
1051
|
ignore_blank_rows: bool = True,
|
|
@@ -1108,8 +1058,6 @@ class Download(BaseDownload):
|
|
|
1108
1058
|
are header names and values are dictionaries with keys from first
|
|
1109
1059
|
column and values from other columns.
|
|
1110
1060
|
|
|
1111
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
1112
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
1113
1061
|
The headers argument is either a row number or list of row numbers (in case of
|
|
1114
1062
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
1115
1063
|
the actual headers defined as a list of strings. It defaults to 1 and cannot be
|
|
@@ -1124,7 +1072,6 @@ class Download(BaseDownload):
|
|
|
1124
1072
|
|
|
1125
1073
|
Args:
|
|
1126
1074
|
url: A single or list of URLs or paths to read from
|
|
1127
|
-
has_hxl: Whether files have HXL hashtags. Ignored for single url. Defaults to False.
|
|
1128
1075
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
1129
1076
|
keycolumn: Number of column to be used for key. Defaults to 1.
|
|
1130
1077
|
ignore_blank_rows: Whether to ignore blank rows. Defaults to True.
|
|
@@ -1157,7 +1104,6 @@ class Download(BaseDownload):
|
|
|
1157
1104
|
"""
|
|
1158
1105
|
headers, iterator = self.get_tabular_rows_as_dict(
|
|
1159
1106
|
url,
|
|
1160
|
-
has_hxl,
|
|
1161
1107
|
headers,
|
|
1162
1108
|
ignore_blank_rows,
|
|
1163
1109
|
infer_types,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Directory Path Utilities."""
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
|
-
import inspect
|
|
5
4
|
import logging
|
|
6
5
|
import sys
|
|
7
6
|
from collections.abc import Iterable, Iterator, Sequence
|
|
@@ -12,7 +11,6 @@ from os.path import (
|
|
|
12
11
|
from pathlib import Path
|
|
13
12
|
from shutil import rmtree
|
|
14
13
|
from tempfile import gettempdir
|
|
15
|
-
from typing import Any
|
|
16
14
|
|
|
17
15
|
from hdx.utilities.loader import load_text
|
|
18
16
|
from hdx.utilities.saver import save_text
|
|
@@ -25,45 +23,34 @@ class NotFoundError(Exception):
|
|
|
25
23
|
pass
|
|
26
24
|
|
|
27
25
|
|
|
28
|
-
def script_dir(
|
|
26
|
+
def script_dir(*args, **kwargs) -> Path:
|
|
29
27
|
"""Get current script's directory.
|
|
30
28
|
|
|
31
|
-
Args:
|
|
32
|
-
pyobject: Any Python object in the script
|
|
33
|
-
follow_symlinks: Follow symlinks or not. Defaults to True.
|
|
34
|
-
|
|
35
29
|
Returns:
|
|
36
30
|
Current script's directory
|
|
37
31
|
"""
|
|
38
32
|
if getattr(sys, "frozen", False):
|
|
39
|
-
#
|
|
40
|
-
|
|
33
|
+
# PyInstaller bundle
|
|
34
|
+
app_path = Path(sys.executable)
|
|
41
35
|
else:
|
|
42
|
-
# Standard
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# Resolve symlinks if requested, otherwise just make absolute
|
|
46
|
-
path = path.resolve() if follow_symlinks else path.absolute()
|
|
36
|
+
# Standard Python script
|
|
37
|
+
app_path = Path(__file__)
|
|
47
38
|
|
|
48
|
-
|
|
39
|
+
# .resolve() ensures we follow symlinks to the real folder,
|
|
40
|
+
# and makes the path absolute so CWD doesn't matter.
|
|
41
|
+
return app_path.resolve().parent
|
|
49
42
|
|
|
50
43
|
|
|
51
|
-
def script_dir_plus_file(
|
|
52
|
-
filename: str, pyobject: Any, follow_symlinks: bool = True
|
|
53
|
-
) -> Path:
|
|
44
|
+
def script_dir_plus_file(filename: str, *args, **kwargs) -> Path:
|
|
54
45
|
"""Get current script's directory and then append a filename.
|
|
55
46
|
|
|
56
47
|
Args:
|
|
57
48
|
filename: Filename to append to directory path
|
|
58
|
-
pyobject: Any Python object in the script
|
|
59
|
-
return_path: Whether to return a Path object. Defaults to returning str.
|
|
60
|
-
|
|
61
|
-
follow_symlinks: Follow symlinks or not. Defaults to True.
|
|
62
49
|
|
|
63
50
|
Returns:
|
|
64
51
|
Current script's directory and with filename appended
|
|
65
52
|
"""
|
|
66
|
-
return script_dir(
|
|
53
|
+
return script_dir() / filename
|
|
67
54
|
|
|
68
55
|
|
|
69
56
|
def get_temp_dir(
|
|
@@ -385,7 +385,6 @@ class Retrieve(BaseDownload):
|
|
|
385
385
|
def get_tabular_rows(
|
|
386
386
|
self,
|
|
387
387
|
url: Path | str | Sequence[str],
|
|
388
|
-
has_hxl: bool = False,
|
|
389
388
|
headers: int | Sequence[int] | Sequence[str] = 1,
|
|
390
389
|
dict_form: bool = False,
|
|
391
390
|
filename: str | None = None,
|
|
@@ -397,8 +396,6 @@ class Retrieve(BaseDownload):
|
|
|
397
396
|
where each row is returned as a list or dictionary depending on the
|
|
398
397
|
dict_rows argument.
|
|
399
398
|
|
|
400
|
-
When a list of urls is supplied (in url), then the has_hxl flag indicates if the
|
|
401
|
-
files are HXLated so that the HXL row is only included from the first file.
|
|
402
399
|
The headers argument is either a row number or list of row numbers (in case of
|
|
403
400
|
multi-line headers) to be considered as headers (rows start counting at 1), or
|
|
404
401
|
the actual headers defined as a list of strings. It defaults to 1.
|
|
@@ -407,7 +404,6 @@ class Retrieve(BaseDownload):
|
|
|
407
404
|
|
|
408
405
|
Args:
|
|
409
406
|
url: A single or list of URLs or paths to read from
|
|
410
|
-
has_hxl: Whether files have HXL hashtags. Defaults to False.
|
|
411
407
|
headers: Number of row(s) containing headers or list of headers. Defaults to 1.
|
|
412
408
|
dict_form: Return dict or list for each row. Defaults to False (list)
|
|
413
409
|
filename: Filename of saved file. Defaults to getting from url.
|
|
@@ -434,9 +430,7 @@ class Retrieve(BaseDownload):
|
|
|
434
430
|
path.append(pth)
|
|
435
431
|
|
|
436
432
|
kwargs.pop("file_prefix", None)
|
|
437
|
-
return self.downloader.get_tabular_rows(
|
|
438
|
-
path, has_hxl, headers, dict_form, **kwargs
|
|
439
|
-
)
|
|
433
|
+
return self.downloader.get_tabular_rows(path, headers, dict_form, **kwargs)
|
|
440
434
|
|
|
441
435
|
@classmethod
|
|
442
436
|
def generate_retrievers(
|