data-manipulation 0.50__tar.gz → 0.53__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.
- {data_manipulation-0.50 → data_manipulation-0.53}/.gitignore +6 -5
- data_manipulation-0.53/CHANGELOG.md +81 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/PKG-INFO +6 -1
- {data_manipulation-0.50 → data_manipulation-0.53}/README.md +5 -0
- data_manipulation-0.53/RELEASE.md +84 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/__init__.py +0 -2
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/_version.py +3 -3
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/base.py +33 -45
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/beautifulsoup_.py +8 -8
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/boto3_.py +5 -1
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/cryptography_.py +11 -2
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/django_.py +7 -3
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/geopandas_.py +11 -5
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/kerberos_.py +5 -1
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/mysql_connector_python_.py +5 -1
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/pandas_.py +80 -67
- data_manipulation-0.53/data_manipulation/polars_.py +87 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/postgres_.py +14 -2
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/pyspark_.py +44 -30
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/smtplib_.py +5 -1
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/sqlalchemy_.py +18 -8
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation.egg-info/PKG-INFO +6 -1
- data_manipulation-0.53/data_manipulation.egg-info/SOURCES.txt +48 -0
- data_manipulation-0.53/docs/api.md +59 -0
- data_manipulation-0.53/docs/changelog.md +81 -0
- data_manipulation-0.53/docs/commands.md +10 -0
- data_manipulation-0.50/docs/_build/html/_sources/getting-started.rst.txt → data_manipulation-0.53/docs/getting-started.md +1 -2
- data_manipulation-0.53/docs/hooks.py +10 -0
- data_manipulation-0.53/docs/index.md +13 -0
- data_manipulation-0.53/mkdocs.yml +25 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/setup.sh +13 -10
- data_manipulation-0.50/data_manipulation/flask_.py +0 -31
- data_manipulation-0.50/data_manipulation/prometheus_.py +0 -0
- data_manipulation-0.50/data_manipulation.egg-info/SOURCES.txt +0 -98
- data_manipulation-0.50/docs/.nojekyll +0 -0
- data_manipulation-0.50/docs/Makefile +0 -153
- data_manipulation-0.50/docs/_build/doctrees/commands.doctree +0 -0
- data_manipulation-0.50/docs/_build/doctrees/data_manipulation.doctree +0 -0
- data_manipulation-0.50/docs/_build/doctrees/environment.pickle +0 -0
- data_manipulation-0.50/docs/_build/doctrees/getting-started.doctree +0 -0
- data_manipulation-0.50/docs/_build/doctrees/index.doctree +0 -0
- data_manipulation-0.50/docs/_build/doctrees/modules.doctree +0 -0
- data_manipulation-0.50/docs/_build/html/.buildinfo +0 -4
- data_manipulation-0.50/docs/_build/html/.nojekyll +0 -0
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/base.html +0 -576
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/beautifulsoup_.html +0 -184
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/boto3_.html +0 -268
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/cryptography_.html +0 -225
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/django_.html +0 -258
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/geopandas_.html +0 -159
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/kerberos_.html +0 -170
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/mysql_connector_python_.html +0 -310
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/openldap_.html +0 -172
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/pandas_.html +0 -867
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/pyspark_.html +0 -551
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/smtplib_.html +0 -163
- data_manipulation-0.50/docs/_build/html/_modules/data_manipulation/sqlalchemy_.html +0 -274
- data_manipulation-0.50/docs/_build/html/_modules/index.html +0 -89
- data_manipulation-0.50/docs/_build/html/_sources/commands.rst.txt +0 -10
- data_manipulation-0.50/docs/_build/html/_sources/data_manipulation.rst.txt +0 -141
- data_manipulation-0.50/docs/_build/html/_sources/index.rst.txt +0 -28
- data_manipulation-0.50/docs/_build/html/_sources/modules.rst.txt +0 -7
- data_manipulation-0.50/docs/_build/html/_static/basic.css +0 -906
- data_manipulation-0.50/docs/_build/html/_static/doctools.js +0 -149
- data_manipulation-0.50/docs/_build/html/_static/documentation_options.js +0 -13
- data_manipulation-0.50/docs/_build/html/_static/file.png +0 -0
- data_manipulation-0.50/docs/_build/html/_static/language_data.js +0 -192
- data_manipulation-0.50/docs/_build/html/_static/minus.png +0 -0
- data_manipulation-0.50/docs/_build/html/_static/nature.css +0 -245
- data_manipulation-0.50/docs/_build/html/_static/plus.png +0 -0
- data_manipulation-0.50/docs/_build/html/_static/pygments.css +0 -75
- data_manipulation-0.50/docs/_build/html/_static/searchtools.js +0 -635
- data_manipulation-0.50/docs/_build/html/_static/sphinx_highlight.js +0 -154
- data_manipulation-0.50/docs/_build/html/commands.html +0 -128
- data_manipulation-0.50/docs/_build/html/data_manipulation.html +0 -2299
- data_manipulation-0.50/docs/_build/html/genindex.html +0 -509
- data_manipulation-0.50/docs/_build/html/getting-started.html +0 -113
- data_manipulation-0.50/docs/_build/html/index.html +0 -155
- data_manipulation-0.50/docs/_build/html/modules.html +0 -206
- data_manipulation-0.50/docs/_build/html/objects.inv +0 -0
- data_manipulation-0.50/docs/_build/html/py-modindex.html +0 -171
- data_manipulation-0.50/docs/_build/html/search.html +0 -98
- data_manipulation-0.50/docs/_build/html/searchindex.js +0 -1
- data_manipulation-0.50/docs/commands.rst +0 -10
- data_manipulation-0.50/docs/conf.py +0 -273
- data_manipulation-0.50/docs/data_manipulation.rst +0 -141
- data_manipulation-0.50/docs/getting-started.rst +0 -6
- data_manipulation-0.50/docs/index.html +0 -1
- data_manipulation-0.50/docs/index.rst +0 -28
- data_manipulation-0.50/docs/make.bat +0 -190
- data_manipulation-0.50/docs/modules.rst +0 -7
- {data_manipulation-0.50 → data_manipulation-0.53}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/CODE_OF_CONDUCT.md +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/CONTRIBUTING.md +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/LICENSE +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/Makefile +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/openldap_.py +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation.egg-info/dependency_links.txt +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation.egg-info/requires.txt +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation.egg-info/top_level.txt +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/models/.gitkeep +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/notebooks/.gitkeep +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/pyproject.toml +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/references/.gitkeep +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/reports/.gitkeep +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/reports/figures/.gitkeep +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/setup.cfg +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/test_environment.py +0 -0
- {data_manipulation-0.50 → data_manipulation-0.53}/tox.ini +0 -0
|
@@ -51,15 +51,15 @@ coverage.xml
|
|
|
51
51
|
# Django stuff:
|
|
52
52
|
*.log
|
|
53
53
|
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
!docs/build
|
|
54
|
+
# MkDocs documentation
|
|
55
|
+
/site/
|
|
57
56
|
|
|
58
57
|
# PyBuilder
|
|
59
58
|
target/
|
|
60
59
|
|
|
61
60
|
# DotEnv configuration
|
|
62
61
|
.env
|
|
62
|
+
.pypirc
|
|
63
63
|
|
|
64
64
|
# Database
|
|
65
65
|
*.db
|
|
@@ -93,7 +93,8 @@ target/
|
|
|
93
93
|
.mypy_cache/
|
|
94
94
|
|
|
95
95
|
# custom
|
|
96
|
+
.opencode
|
|
97
|
+
.specstory
|
|
96
98
|
build.sh
|
|
97
|
-
install_packages.sh
|
|
98
99
|
docs/README*
|
|
99
|
-
.
|
|
100
|
+
install_packages.sh
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
### Removed
|
|
6
|
+
|
|
7
|
+
- **`pandas_.clean_none()`** — function has been removed.
|
|
8
|
+
Migrate to pandas built-ins:
|
|
9
|
+
```python
|
|
10
|
+
df = df.replace(r"^\s*$", np.nan, regex=True)
|
|
11
|
+
df = df.where(pd.notnull(df), None)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- **`pandas_.config_pandas_display()`** — function has been removed.
|
|
15
|
+
Set display options directly:
|
|
16
|
+
```python
|
|
17
|
+
pd.set_option("display.max_columns", 500)
|
|
18
|
+
pd.set_option("display.max_colwidth", 500)
|
|
19
|
+
pd.set_option("display.expand_frame_repr", True)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- **`prometheus_` module** — was an empty placeholder; removed from
|
|
23
|
+
the public API and from `__init__` imports.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **`base.get_none_variation()`** — now returns a `frozenset` of 7
|
|
28
|
+
lowercase canonical strings instead of a 72-item list of case
|
|
29
|
+
permutations. Use `.casefold()` for membership checks:
|
|
30
|
+
```python
|
|
31
|
+
# before
|
|
32
|
+
if value in get_none_variation():
|
|
33
|
+
...
|
|
34
|
+
# after
|
|
35
|
+
if isinstance(value, str) and value.casefold() in get_none_variation():
|
|
36
|
+
...
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- **`pyspark_.group_count()`** — the `percent` column is now computed
|
|
40
|
+
as a native Spark column expression instead of a Python UDF.
|
|
41
|
+
Behaviour is identical; performance improves on large datasets.
|
|
42
|
+
|
|
43
|
+
- **`pyspark_.column_into_list()`** — raises `ValueError` (with the
|
|
44
|
+
list of available columns) when the requested column does not exist.
|
|
45
|
+
Previously returned `None` silently.
|
|
46
|
+
|
|
47
|
+
- **`pandas_.print_dataframe_overview()`** — now returns a
|
|
48
|
+
`Dict[str, Dict[str, Any]]` of per-column stats (`unique`,
|
|
49
|
+
`null_count`, `value_counts`). Still prints to stdout as before;
|
|
50
|
+
existing call sites are unaffected.
|
|
51
|
+
|
|
52
|
+
- **`pandas_.compare_dataframes()`** — now returns a comparison
|
|
53
|
+
summary dict (`same_length`, `df1_length`, `df2_length`, `columns`).
|
|
54
|
+
Still prints to stdout as before; existing call sites are unaffected.
|
|
55
|
+
|
|
56
|
+
- **`pyspark_` module** — all `print()` calls replaced with
|
|
57
|
+
`logger.info()` / `logger.debug()`. Output is now routed through
|
|
58
|
+
the standard logging pipeline and can be silenced or redirected.
|
|
59
|
+
|
|
60
|
+
- **`sqlalchemy_.create_sqlalchemy_engine()`** — duplicate
|
|
61
|
+
`if/elif` timeout branches (both setting the same value) consolidated
|
|
62
|
+
into a single condition.
|
|
63
|
+
|
|
64
|
+
- **`django_.django_validate_phone()`** — now has an explicit
|
|
65
|
+
`return None` on failure instead of a bare `return`.
|
|
66
|
+
|
|
67
|
+
### Fixed (previous pass — reference)
|
|
68
|
+
|
|
69
|
+
- `pyspark_.columns_statistics()` — always-true condition in empty-column
|
|
70
|
+
detection (third clause was truthy for any non-empty string).
|
|
71
|
+
- `pandas_.dtypes_dictionary()` — `.iteritems()` removed in pandas 2.0;
|
|
72
|
+
replaced with `.items()`.
|
|
73
|
+
- Bare `except:` replaced with `except Exception:` in `pandas_` and
|
|
74
|
+
`django_`.
|
|
75
|
+
- `base.string_boolean_to_int()` — removed (used `distutils`, dropped
|
|
76
|
+
in Python 3.12).
|
|
77
|
+
- `flask_.py` — deleted (was entirely commented-out dead code).
|
|
78
|
+
- `beautifulsoup_.preprocess()` — fixed mixed tabs/spaces and invalid
|
|
79
|
+
`\s` escape sequences.
|
|
80
|
+
- All modules now guard third-party imports with `try/except`; the
|
|
81
|
+
package imports cleanly even when optional dependencies are missing.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data_manipulation
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.53
|
|
4
4
|
Summary: Powerful data manipulation
|
|
5
5
|
Author-email: Shawn Ng <shawn.coding.acc@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -43,6 +43,7 @@ Dynamic: license-file
|
|
|
43
43
|
- [Where to get it](#where-to-get-it)
|
|
44
44
|
- [Dependencies](#dependencies)
|
|
45
45
|
- [License](#license)
|
|
46
|
+
- [Maintainer Release](#maintainer-release)
|
|
46
47
|
- [Getting Help](#getting-help)
|
|
47
48
|
- [Discussion and Development](#discussion-and-development)
|
|
48
49
|
- [Contributing to data manipulation](#contributing-to-data-manipulation)
|
|
@@ -69,6 +70,10 @@ The dependencies will be installed automatically along with this package, using
|
|
|
69
70
|
|
|
70
71
|
[BSD 3](LICENSE)
|
|
71
72
|
|
|
73
|
+
## Maintainer Release
|
|
74
|
+
|
|
75
|
+
Release and deployment steps are documented in [RELEASE.md](RELEASE.md).
|
|
76
|
+
|
|
72
77
|
## Getting Help
|
|
73
78
|
|
|
74
79
|
For usage questions, the best place to go to is StackOverflow.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- [Where to get it](#where-to-get-it)
|
|
6
6
|
- [Dependencies](#dependencies)
|
|
7
7
|
- [License](#license)
|
|
8
|
+
- [Maintainer Release](#maintainer-release)
|
|
8
9
|
- [Getting Help](#getting-help)
|
|
9
10
|
- [Discussion and Development](#discussion-and-development)
|
|
10
11
|
- [Contributing to data manipulation](#contributing-to-data-manipulation)
|
|
@@ -31,6 +32,10 @@ The dependencies will be installed automatically along with this package, using
|
|
|
31
32
|
|
|
32
33
|
[BSD 3](LICENSE)
|
|
33
34
|
|
|
35
|
+
## Maintainer Release
|
|
36
|
+
|
|
37
|
+
Release and deployment steps are documented in [RELEASE.md](RELEASE.md).
|
|
38
|
+
|
|
34
39
|
## Getting Help
|
|
35
40
|
|
|
36
41
|
For usage questions, the best place to go to is StackOverflow.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Release Guide
|
|
2
|
+
|
|
3
|
+
This guide is for maintainers publishing documentation to GitHub Pages and
|
|
4
|
+
package artifacts to PyPI.
|
|
5
|
+
|
|
6
|
+
## Preconditions
|
|
7
|
+
|
|
8
|
+
- Work from a clean `master` branch.
|
|
9
|
+
- Release versions are derived from git tags by `setuptools-scm`.
|
|
10
|
+
- Never build or upload release artifacts from a dirty worktree.
|
|
11
|
+
- Keep PyPI credentials out of git.
|
|
12
|
+
|
|
13
|
+
Check the release state:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git checkout master
|
|
17
|
+
git pull --ff-only origin master
|
|
18
|
+
git status
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`git status` should report no changes before continuing.
|
|
22
|
+
|
|
23
|
+
## Tag The Release
|
|
24
|
+
|
|
25
|
+
Use the next release version, for example `0.50`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git tag -a 0.50 -m "Release 0.50"
|
|
29
|
+
git push origin master
|
|
30
|
+
git push origin 0.50
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The tag must point at the exact commit being released.
|
|
34
|
+
|
|
35
|
+
## Publish Documentation
|
|
36
|
+
|
|
37
|
+
Build the MkDocs documentation:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
mkdocs build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Publish the generated HTML to GitHub Pages:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
mkdocs gh-deploy
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This publishes the contents of `site/` to the `gh-pages` branch.
|
|
50
|
+
|
|
51
|
+
## Publish To PyPI
|
|
52
|
+
|
|
53
|
+
Build and validate the distribution artifacts:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
./setup.sh cleanup
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Upload the artifacts:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
./setup.sh upload
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
When prompted by `twine`, enter the PyPI API token. The token should start with
|
|
66
|
+
`pypi-`. It will not be displayed while typing or pasting.
|
|
67
|
+
|
|
68
|
+
## Verify The Release
|
|
69
|
+
|
|
70
|
+
Install the published package in a fresh environment and confirm the version:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python3 -m pip install --upgrade data-manipulation
|
|
74
|
+
python3 -c "import data_manipulation; print(data_manipulation.__version__)"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Security Notes
|
|
78
|
+
|
|
79
|
+
- Do not commit PyPI API tokens, passwords, or `.pypirc` files with credentials.
|
|
80
|
+
- Do not add tokens to shell history as command-line arguments.
|
|
81
|
+
- Prefer entering the PyPI token at the `twine` prompt or using a local secret
|
|
82
|
+
store.
|
|
83
|
+
- If a token is accidentally committed or exposed, revoke it in PyPI immediately
|
|
84
|
+
and create a new one.
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.53'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 53)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g2446c213a'
|
|
@@ -7,7 +7,11 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
8
8
|
from urllib.parse import urlencode, urlparse, urlunparse
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
try:
|
|
11
|
+
from loguru import logger
|
|
12
|
+
except ImportError:
|
|
13
|
+
import logging
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
def deprecated(func):
|
|
@@ -82,27 +86,24 @@ def get_string_case_combination(str_: str) -> List[str]:
|
|
|
82
86
|
return list(map("".join, itertools.product(*zip(str_.upper(), str_.lower()))))
|
|
83
87
|
|
|
84
88
|
|
|
85
|
-
def get_none_variation() ->
|
|
86
|
-
"""Returns a
|
|
89
|
+
def get_none_variation() -> frozenset:
|
|
90
|
+
"""Returns a frozenset of lowercase None/null string representations.
|
|
91
|
+
|
|
92
|
+
Use with .casefold() for case-insensitive membership tests:
|
|
93
|
+
item.casefold() in get_none_variation()
|
|
87
94
|
|
|
88
95
|
Returns:
|
|
89
|
-
|
|
96
|
+
frozenset: Frozenset of lowercase null string representations.
|
|
90
97
|
|
|
91
98
|
Examples:
|
|
92
|
-
>>> get_none_variation()
|
|
93
|
-
|
|
99
|
+
>>> "none" in get_none_variation()
|
|
100
|
+
True
|
|
101
|
+
>>> "NONE".casefold() in get_none_variation()
|
|
102
|
+
True
|
|
103
|
+
>>> "valid".casefold() in get_none_variation()
|
|
104
|
+
False
|
|
94
105
|
"""
|
|
95
|
-
|
|
96
|
-
[None]
|
|
97
|
-
+ get_string_case_combination("none")
|
|
98
|
-
+ get_string_case_combination("null")
|
|
99
|
-
+ get_string_case_combination("na")
|
|
100
|
-
+ get_string_case_combination("n.a")
|
|
101
|
-
+ get_string_case_combination("n.a.")
|
|
102
|
-
+ get_string_case_combination("nan")
|
|
103
|
-
+ get_string_case_combination("nil")
|
|
104
|
-
)
|
|
105
|
-
return variations
|
|
106
|
+
return frozenset({"none", "null", "na", "n.a", "n.a.", "nan", "nil"})
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
def get_country_name_variation() -> dict:
|
|
@@ -172,35 +173,17 @@ def list_tuple_without_none(list_tuple: Union[List, Tuple]) -> Union[List, Tuple
|
|
|
172
173
|
|
|
173
174
|
none_variations = get_none_variation()
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def string_boolean_to_int(boolean_str_rep: str) -> int:
|
|
182
|
-
"""Converts string boolean representations to integers.
|
|
183
|
-
|
|
184
|
-
Args:
|
|
185
|
-
boolean_str_rep (str): String representation of boolean value.
|
|
176
|
+
def _keep(item: Any) -> bool:
|
|
177
|
+
if not item:
|
|
178
|
+
return False
|
|
179
|
+
if isinstance(item, str):
|
|
180
|
+
return item.casefold() not in none_variations
|
|
181
|
+
return True
|
|
186
182
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
Examples:
|
|
191
|
-
>>> string_boolean_to_int("true")
|
|
192
|
-
1
|
|
193
|
-
>>> string_boolean_to_int("True")
|
|
194
|
-
1
|
|
195
|
-
"""
|
|
196
|
-
try:
|
|
197
|
-
from distutils.util import strtobool
|
|
183
|
+
if isinstance(list_tuple, list):
|
|
184
|
+
return [item for item in list_tuple if _keep(item)]
|
|
185
|
+
return tuple(item for item in list_tuple if _keep(item))
|
|
198
186
|
|
|
199
|
-
return strtobool(string_str_to_str(boolean_str_rep))
|
|
200
|
-
except ValueError as e:
|
|
201
|
-
raise ValueError(
|
|
202
|
-
f"Invalid boolean string representation: {boolean_str_rep}"
|
|
203
|
-
) from e
|
|
204
187
|
|
|
205
188
|
|
|
206
189
|
def string_dlt_to_dlt(dlt_str_rep: str) -> Union[Dict, List, Tuple]:
|
|
@@ -417,9 +400,14 @@ def parse_ps_aux(ps_aux_commands: str) -> List[List[str]]:
|
|
|
417
400
|
check=True,
|
|
418
401
|
)
|
|
419
402
|
lines = output.stdout.strip().split("\n")
|
|
420
|
-
if not lines:
|
|
403
|
+
if not lines or not lines[0]:
|
|
421
404
|
return []
|
|
422
405
|
|
|
406
|
+
if "PID" not in lines[0] and "USER" not in lines[0]:
|
|
407
|
+
logger.warning(
|
|
408
|
+
"ps output header looks unexpected; "
|
|
409
|
+
"column split may be incorrect"
|
|
410
|
+
)
|
|
423
411
|
n_columns = len(lines[0].split()) - 1
|
|
424
412
|
return [line.split(None, n_columns) for line in lines if line]
|
|
425
413
|
except subprocess.SubprocessError as e:
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from typing import TYPE_CHECKING, Optional
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
try:
|
|
5
|
+
from loguru import logger
|
|
6
|
+
except ImportError:
|
|
7
|
+
import logging
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
5
9
|
|
|
6
10
|
if TYPE_CHECKING:
|
|
7
11
|
from bs4 import BeautifulSoup
|
|
@@ -31,15 +35,11 @@ def preprocess(html: str) -> Optional[str]:
|
|
|
31
35
|
Reference: https://stackoverflow.com/questions/23241641
|
|
32
36
|
"""
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
pattern = re.compile("(^[\s]+)|([\s]+$)", re.MULTILINE)
|
|
38
|
+
pattern = re.compile(r"(^[\s]+)|([\s]+$)", re.MULTILINE)
|
|
36
39
|
html = re.sub(pattern, "", html)
|
|
37
|
-
# convert newlines to spaces, this preserves newline delimiters
|
|
38
40
|
html = re.sub("\n", " ", html)
|
|
39
|
-
|
|
40
|
-
html = re.sub("[\s]
|
|
41
|
-
# remove whitespaces after closing tags
|
|
42
|
-
html = re.sub(">[\s]+", ">", html)
|
|
41
|
+
html = re.sub(r"[\s]+<", "<", html)
|
|
42
|
+
html = re.sub(r">[\s]+", ">", html)
|
|
43
43
|
return html
|
|
44
44
|
|
|
45
45
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Dict, List, Optional, Union
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
try:
|
|
5
|
+
from loguru import logger
|
|
6
|
+
except ImportError:
|
|
7
|
+
import logging
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
5
9
|
|
|
6
10
|
# Constants - now serving as defaults
|
|
7
11
|
DEFAULT_MAX_ATTACHMENT_SIZE = 10 * 1024 * 1024 # 10MB
|
|
@@ -2,8 +2,17 @@ import os
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Union
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
from
|
|
5
|
+
try:
|
|
6
|
+
from cryptography.fernet import Fernet, InvalidToken
|
|
7
|
+
HAS_CRYPTOGRAPHY = True
|
|
8
|
+
except ImportError:
|
|
9
|
+
HAS_CRYPTOGRAPHY = False
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from loguru import logger
|
|
13
|
+
except ImportError:
|
|
14
|
+
import logging
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
7
16
|
|
|
8
17
|
|
|
9
18
|
def generate_fernet_key(
|
|
@@ -2,7 +2,11 @@ import os
|
|
|
2
2
|
import sys
|
|
3
3
|
from typing import Dict, List, Optional, Tuple
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
try:
|
|
6
|
+
from loguru import logger
|
|
7
|
+
except ImportError:
|
|
8
|
+
import logging
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
def init_django(
|
|
@@ -151,12 +155,12 @@ def django_validate_phone(
|
|
|
151
155
|
|
|
152
156
|
try:
|
|
153
157
|
return PhoneNumber.from_string(phone).as_e164
|
|
154
|
-
except:
|
|
158
|
+
except Exception:
|
|
155
159
|
try:
|
|
156
160
|
return PhoneNumber.from_string(phone, region=region).as_e164
|
|
157
161
|
except Exception as e:
|
|
158
162
|
logger.error(e)
|
|
159
|
-
return
|
|
163
|
+
return None
|
|
160
164
|
|
|
161
165
|
|
|
162
166
|
if __name__ == "__main__":
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
from numpy.typing import NDArray
|
|
3
|
+
from typing import TypeVar
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
try:
|
|
6
|
+
import numpy as np
|
|
7
|
+
from numpy.typing import NDArray
|
|
8
|
+
HAS_NUMPY = True
|
|
9
|
+
NumericType = TypeVar("NumericType", float, NDArray[np.float64])
|
|
10
|
+
except ImportError:
|
|
11
|
+
np = None
|
|
12
|
+
HAS_NUMPY = False
|
|
13
|
+
NumericType = TypeVar("NumericType", float, float)
|
|
8
14
|
|
|
9
15
|
# Earth's radius in kilometers
|
|
10
16
|
EARTH_RADIUS_KM = 6371.0
|
{data_manipulation-0.50 → data_manipulation-0.53}/data_manipulation/mysql_connector_python_.py
RENAMED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from contextlib import contextmanager
|
|
2
2
|
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Union
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
try:
|
|
5
|
+
from loguru import logger
|
|
6
|
+
except ImportError:
|
|
7
|
+
import logging
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
5
9
|
|
|
6
10
|
if TYPE_CHECKING:
|
|
7
11
|
from mysql.connector.connection import MySQLConnection
|