data-manipulation 0.53__tar.gz → 0.55__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.
Files changed (86) hide show
  1. {data_manipulation-0.53 → data_manipulation-0.55}/.github/ISSUE_TEMPLATE/bug_report.md +10 -7
  2. data_manipulation-0.55/.gitignore +229 -0
  3. {data_manipulation-0.53 → data_manipulation-0.55}/CHANGELOG.md +28 -17
  4. {data_manipulation-0.53 → data_manipulation-0.55}/CODE_OF_CONDUCT.md +9 -6
  5. {data_manipulation-0.53 → data_manipulation-0.55}/PKG-INFO +9 -9
  6. {data_manipulation-0.53 → data_manipulation-0.55}/README.md +1 -1
  7. {data_manipulation-0.53 → data_manipulation-0.55}/RELEASE.md +38 -4
  8. data_manipulation-0.55/conftest.py +24 -0
  9. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/__init__.py +1 -2
  10. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/_version.py +3 -3
  11. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/base.py +29 -90
  12. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/beautifulsoup_.py +18 -17
  13. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/boto3_.py +18 -18
  14. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/cryptography_.py +12 -17
  15. data_manipulation-0.55/data_manipulation/iceberg/__init__.py +49 -0
  16. data_manipulation-0.55/data_manipulation/iceberg/catalog.py +454 -0
  17. data_manipulation-0.55/data_manipulation/iceberg/ingest.py +398 -0
  18. data_manipulation-0.55/data_manipulation/iceberg/ledger.py +876 -0
  19. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/kerberos_.py +4 -7
  20. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/mysql_connector_python_.py +28 -26
  21. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/openldap_.py +6 -10
  22. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/pandas_.py +71 -228
  23. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/postgres_.py +16 -48
  24. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/pyspark_.py +27 -95
  25. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/smtplib_.py +14 -11
  26. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/sqlalchemy_.py +21 -36
  27. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation.egg-info/PKG-INFO +9 -9
  28. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation.egg-info/SOURCES.txt +33 -13
  29. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation.egg-info/requires.txt +6 -2
  30. data_manipulation-0.55/data_manipulation.egg-info/scm_file_list.json +64 -0
  31. data_manipulation-0.55/data_manipulation.egg-info/scm_version.json +8 -0
  32. data_manipulation-0.55/docs/api/base.md +3 -0
  33. data_manipulation-0.55/docs/api/beautifulsoup_.md +3 -0
  34. data_manipulation-0.55/docs/api/boto3_.md +3 -0
  35. data_manipulation-0.55/docs/api/cryptography_.md +3 -0
  36. data_manipulation-0.55/docs/api/kerberos_.md +3 -0
  37. data_manipulation-0.55/docs/api/mysql_connector_python_.md +3 -0
  38. data_manipulation-0.55/docs/api/pandas_.md +3 -0
  39. data_manipulation-0.55/docs/api/polars_.md +3 -0
  40. data_manipulation-0.55/docs/api/postgres_.md +3 -0
  41. data_manipulation-0.55/docs/api/pyspark_.md +3 -0
  42. data_manipulation-0.55/docs/api/smtplib_.md +3 -0
  43. data_manipulation-0.55/docs/api/sqlalchemy_.md +3 -0
  44. {data_manipulation-0.53 → data_manipulation-0.55}/docs/changelog.md +28 -17
  45. {data_manipulation-0.53 → data_manipulation-0.55}/docs/index.md +1 -2
  46. data_manipulation-0.55/mkdocs.yml +36 -0
  47. data_manipulation-0.55/pyproject.toml +97 -0
  48. data_manipulation-0.55/tests/conftest.py +36 -0
  49. data_manipulation-0.55/tests/test_base.py +124 -0
  50. data_manipulation-0.55/tests/test_beautifulsoup.py +40 -0
  51. data_manipulation-0.55/tests/test_boto3.py +22 -0
  52. data_manipulation-0.55/tests/test_cryptography.py +43 -0
  53. data_manipulation-0.55/tests/test_iceberg.py +45 -0
  54. data_manipulation-0.55/tests/test_kerberos.py +26 -0
  55. data_manipulation-0.55/tests/test_mysql.py +27 -0
  56. data_manipulation-0.55/tests/test_openldap.py +29 -0
  57. data_manipulation-0.55/tests/test_pandas.py +128 -0
  58. data_manipulation-0.55/tests/test_postgres.py +32 -0
  59. data_manipulation-0.55/tests/test_pyspark.py +64 -0
  60. data_manipulation-0.55/tests/test_smtplib.py +35 -0
  61. data_manipulation-0.55/tests/test_sqlalchemy.py +43 -0
  62. data_manipulation-0.53/.gitignore +0 -100
  63. data_manipulation-0.53/Makefile +0 -144
  64. data_manipulation-0.53/data_manipulation/django_.py +0 -169
  65. data_manipulation-0.53/data_manipulation/geopandas_.py +0 -84
  66. data_manipulation-0.53/docs/api.md +0 -59
  67. data_manipulation-0.53/docs/commands.md +0 -10
  68. data_manipulation-0.53/mkdocs.yml +0 -25
  69. data_manipulation-0.53/models/.gitkeep +0 -0
  70. data_manipulation-0.53/notebooks/.gitkeep +0 -0
  71. data_manipulation-0.53/pyproject.toml +0 -55
  72. data_manipulation-0.53/references/.gitkeep +0 -0
  73. data_manipulation-0.53/reports/.gitkeep +0 -0
  74. data_manipulation-0.53/reports/figures/.gitkeep +0 -0
  75. data_manipulation-0.53/setup.sh +0 -37
  76. data_manipulation-0.53/test_environment.py +0 -26
  77. data_manipulation-0.53/tox.ini +0 -3
  78. {data_manipulation-0.53 → data_manipulation-0.55}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  79. {data_manipulation-0.53 → data_manipulation-0.55}/CONTRIBUTING.md +0 -0
  80. {data_manipulation-0.53 → data_manipulation-0.55}/LICENSE +0 -0
  81. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation/polars_.py +0 -0
  82. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation.egg-info/dependency_links.txt +0 -0
  83. {data_manipulation-0.53 → data_manipulation-0.55}/data_manipulation.egg-info/top_level.txt +0 -0
  84. {data_manipulation-0.53 → data_manipulation-0.55}/docs/getting-started.md +0 -0
  85. {data_manipulation-0.53 → data_manipulation-0.55}/docs/hooks.py +0 -0
  86. {data_manipulation-0.53 → data_manipulation-0.55}/setup.cfg +0 -0
@@ -12,6 +12,7 @@ A clear and concise description of what the bug is.
12
12
 
13
13
  **To Reproduce**
14
14
  Steps to reproduce the behavior:
15
+
15
16
  1. Go to '...'
16
17
  2. Click on '....'
17
18
  3. Scroll down to '....'
@@ -24,15 +25,17 @@ A clear and concise description of what you expected to happen.
24
25
  If applicable, add screenshots to help explain your problem.
25
26
 
26
27
  **Desktop (please complete the following information):**
27
- - OS: [e.g. iOS]
28
- - Browser [e.g. chrome, safari]
29
- - Version [e.g. 22]
28
+
29
+ - OS: [e.g. iOS]
30
+ - Browser [e.g. chrome, safari]
31
+ - Version [e.g. 22]
30
32
 
31
33
  **Smartphone (please complete the following information):**
32
- - Device: [e.g. iPhone6]
33
- - OS: [e.g. iOS8.1]
34
- - Browser [e.g. stock browser, safari]
35
- - Version [e.g. 22]
34
+
35
+ - Device: [e.g. iPhone6]
36
+ - OS: [e.g. iOS8.1]
37
+ - Browser [e.g. stock browser, safari]
38
+ - Version [e.g. 22]
36
39
 
37
40
  **Additional context**
38
41
  Add any other context about the problem here.
@@ -0,0 +1,229 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ *.lcov
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ # Pipfile.lock
97
+
98
+ # UV
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ # uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ # poetry.lock
110
+ # poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ # pdm.lock
117
+ # pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ # pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi/*
127
+ !.pixi/config.toml
128
+
129
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130
+ __pypackages__/
131
+
132
+ # Celery stuff
133
+ celerybeat-schedule*
134
+ celerybeat.pid
135
+
136
+ # Redis
137
+ *.rdb
138
+ *.aof
139
+ *.pid
140
+
141
+ # RabbitMQ
142
+ mnesia/
143
+ rabbitmq/
144
+ rabbitmq-data/
145
+
146
+ # ActiveMQ
147
+ activemq-data/
148
+
149
+ # SageMath parsed files
150
+ *.sage.py
151
+
152
+ # Environments
153
+ .env
154
+ .envrc
155
+ .venv
156
+ env/
157
+ venv/
158
+ ENV/
159
+ env.bak/
160
+ venv.bak/
161
+
162
+ # Spyder project settings
163
+ .spyderproject
164
+ .spyproject
165
+
166
+ # Rope project settings
167
+ .ropeproject
168
+
169
+ # mkdocs documentation
170
+ /site
171
+
172
+ # mypy
173
+ .mypy_cache/
174
+ .dmypy.json
175
+ dmypy.json
176
+
177
+ # Pyre type checker
178
+ .pyre/
179
+
180
+ # pytype static type analyzer
181
+ .pytype/
182
+
183
+ # Cython debug symbols
184
+ cython_debug/
185
+
186
+ # PyCharm
187
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
188
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
189
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
190
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
191
+ # .idea/
192
+
193
+ # Abstra
194
+ # Abstra is an AI-powered process automation framework.
195
+ # Ignore directories containing user credentials, local state, and settings.
196
+ # Learn more at https://abstra.io/docs
197
+ .abstra/
198
+
199
+ # Visual Studio Code
200
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
201
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
202
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
203
+ # you could uncomment the following to ignore the entire vscode folder
204
+ # .vscode/
205
+ # Temporary file for partial code execution
206
+ tempCodeRunnerFile.py
207
+
208
+ # Ruff stuff:
209
+ .ruff_cache/
210
+
211
+ # PyPI configuration file
212
+ .pypirc
213
+
214
+ # Marimo
215
+ marimo/_static/
216
+ marimo/_lsp/
217
+ __marimo__/
218
+
219
+ # Streamlit
220
+ .streamlit/secrets.toml
221
+
222
+ # custom
223
+ .claude
224
+ .opencode
225
+ .specstory
226
+ .vscode
227
+ AGENTS.md
228
+ CLAUDE.md
229
+ data_manipulation/_version.py
@@ -4,29 +4,40 @@
4
4
 
5
5
  ### Removed
6
6
 
7
- - **`pandas_.clean_none()`** function has been removed.
7
+ - **`django_` module** - removed entirely (breaking change). The Django helpers
8
+ (`init_django`, `get_django_countries_dict`, `django_validate_email`,
9
+ `django_validate_url`, `django_validate_phone`) now live in the
10
+ [`django-util`](https://github.com/shawnngtq/django-util) package:
11
+ `django_util.utility` (`init_django`, `get_django_countries_dict`) and
12
+ `django_util.validators` (the `django_validate_*` functions). `data_manipulation`
13
+ no longer depends on Django. This warrants a major version bump on release.
14
+
15
+ - **`pandas_.clean_none()`** - function has been removed.
8
16
  Migrate to pandas built-ins:
17
+
9
18
  ```python
10
19
  df = df.replace(r"^\s*$", np.nan, regex=True)
11
20
  df = df.where(pd.notnull(df), None)
12
21
  ```
13
22
 
14
- - **`pandas_.config_pandas_display()`** function has been removed.
23
+ - **`pandas_.config_pandas_display()`** - function has been removed.
15
24
  Set display options directly:
25
+
16
26
  ```python
17
27
  pd.set_option("display.max_columns", 500)
18
28
  pd.set_option("display.max_colwidth", 500)
19
29
  pd.set_option("display.expand_frame_repr", True)
20
30
  ```
21
31
 
22
- - **`prometheus_` module** was an empty placeholder; removed from
32
+ - **`prometheus_` module** - was an empty placeholder; removed from
23
33
  the public API and from `__init__` imports.
24
34
 
25
35
  ### Changed
26
36
 
27
- - **`base.get_none_variation()`** now returns a `frozenset` of 7
37
+ - **`base.get_none_variation()`** - now returns a `frozenset` of 7
28
38
  lowercase canonical strings instead of a 72-item list of case
29
39
  permutations. Use `.casefold()` for membership checks:
40
+
30
41
  ```python
31
42
  # before
32
43
  if value in get_none_variation():
@@ -36,46 +47,46 @@
36
47
  ...
37
48
  ```
38
49
 
39
- - **`pyspark_.group_count()`** the `percent` column is now computed
50
+ - **`pyspark_.group_count()`** - the `percent` column is now computed
40
51
  as a native Spark column expression instead of a Python UDF.
41
52
  Behaviour is identical; performance improves on large datasets.
42
53
 
43
- - **`pyspark_.column_into_list()`** raises `ValueError` (with the
54
+ - **`pyspark_.column_into_list()`** - raises `ValueError` (with the
44
55
  list of available columns) when the requested column does not exist.
45
56
  Previously returned `None` silently.
46
57
 
47
- - **`pandas_.print_dataframe_overview()`** now returns a
58
+ - **`pandas_.print_dataframe_overview()`** - now returns a
48
59
  `Dict[str, Dict[str, Any]]` of per-column stats (`unique`,
49
60
  `null_count`, `value_counts`). Still prints to stdout as before;
50
61
  existing call sites are unaffected.
51
62
 
52
- - **`pandas_.compare_dataframes()`** now returns a comparison
63
+ - **`pandas_.compare_dataframes()`** - now returns a comparison
53
64
  summary dict (`same_length`, `df1_length`, `df2_length`, `columns`).
54
65
  Still prints to stdout as before; existing call sites are unaffected.
55
66
 
56
- - **`pyspark_` module** all `print()` calls replaced with
67
+ - **`pyspark_` module** - all `print()` calls replaced with
57
68
  `logger.info()` / `logger.debug()`. Output is now routed through
58
69
  the standard logging pipeline and can be silenced or redirected.
59
70
 
60
- - **`sqlalchemy_.create_sqlalchemy_engine()`** duplicate
71
+ - **`sqlalchemy_.create_sqlalchemy_engine()`** - duplicate
61
72
  `if/elif` timeout branches (both setting the same value) consolidated
62
73
  into a single condition.
63
74
 
64
- - **`django_.django_validate_phone()`** now has an explicit
75
+ - **`django_.django_validate_phone()`** - now has an explicit
65
76
  `return None` on failure instead of a bare `return`.
66
77
 
67
- ### Fixed (previous pass reference)
78
+ ### Fixed (previous pass - reference)
68
79
 
69
- - `pyspark_.columns_statistics()` always-true condition in empty-column
80
+ - `pyspark_.columns_statistics()` - always-true condition in empty-column
70
81
  detection (third clause was truthy for any non-empty string).
71
- - `pandas_.dtypes_dictionary()` `.iteritems()` removed in pandas 2.0;
82
+ - `pandas_.dtypes_dictionary()` - `.iteritems()` removed in pandas 2.0;
72
83
  replaced with `.items()`.
73
84
  - Bare `except:` replaced with `except Exception:` in `pandas_` and
74
85
  `django_`.
75
- - `base.string_boolean_to_int()` removed (used `distutils`, dropped
86
+ - `base.string_boolean_to_int()` - removed (used `distutils`, dropped
76
87
  in Python 3.12).
77
- - `flask_.py` deleted (was entirely commented-out dead code).
78
- - `beautifulsoup_.preprocess()` fixed mixed tabs/spaces and invalid
88
+ - `flask_.py` - deleted (was entirely commented-out dead code).
89
+ - `beautifulsoup_.preprocess()` - fixed mixed tabs/spaces and invalid
79
90
  `\s` escape sequences.
80
91
  - All modules now guard third-party imports with `try/except`; the
81
92
  package imports cleanly even when optional dependencies are missing.
@@ -23,13 +23,16 @@ include:
23
23
  Examples of unacceptable behavior by participants include:
24
24
 
25
25
  * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
26
+
27
+ advances
27
28
  * Trolling, insulting/derogatory comments, and personal or political attacks
28
29
  * Public or private harassment
29
30
  * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
+
32
+ address, without explicit permission
31
33
  * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
34
+
35
+ professional setting
33
36
 
34
37
  ## Our Responsibilities
35
38
 
@@ -55,7 +58,7 @@ further defined and clarified by project maintainers.
55
58
  ## Enforcement
56
59
 
57
60
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at Shawn.coding.acc@gmail.com. All
61
+ reported by contacting the project team at <Shawn.coding.acc@gmail.com>. All
59
62
  complaints will be reviewed and investigated and will result in a response that
60
63
  is deemed necessary and appropriate to the circumstances. The project team is
61
64
  obligated to maintain confidentiality with regard to the reporter of an incident.
@@ -68,9 +71,9 @@ members of the project's leadership.
68
71
  ## Attribution
69
72
 
70
73
  This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
74
+ available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
72
75
 
73
76
  [homepage]: https://www.contributor-covenant.org
74
77
 
75
78
  For answers to common questions about this code of conduct, see
76
- https://www.contributor-covenant.org/faq
79
+ <https://www.contributor-covenant.org/faq>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data_manipulation
3
- Version: 0.53
3
+ Version: 0.55
4
4
  Summary: Powerful data manipulation
5
5
  Author-email: Shawn Ng <shawn.coding.acc@gmail.com>
6
6
  License-Expression: BSD-3-Clause
@@ -10,30 +10,30 @@ Classifier: Environment :: Console
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Intended Audience :: Science/Research
12
12
  Classifier: Programming Language :: Python
13
- Classifier: Programming Language :: Python :: 3.9
14
- Classifier: Programming Language :: Python :: 3.10
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.14
17
14
  Classifier: Programming Language :: Cython
18
15
  Classifier: Topic :: Scientific/Engineering
19
- Requires-Python: >=3.9
16
+ Requires-Python: >=3.14
20
17
  Description-Content-Type: text/markdown
21
18
  License-File: LICENSE
22
19
  Requires-Dist: beautifulsoup4
23
20
  Requires-Dist: boto3
24
21
  Requires-Dist: cryptography
25
- Requires-Dist: django
26
22
  Requires-Dist: flask
27
- Requires-Dist: geopandas
28
23
  Requires-Dist: ipython
29
24
  Requires-Dist: loguru
30
25
  Requires-Dist: mysql-connector-python
31
26
  Requires-Dist: numpy
32
27
  Requires-Dist: pandas
28
+ Requires-Dist: polars
33
29
  Requires-Dist: psycopg
30
+ Requires-Dist: pyiceberg
34
31
  Requires-Dist: pyspark
35
32
  Requires-Dist: python-dotenv
36
33
  Requires-Dist: sqlalchemy
34
+ Provides-Extra: test
35
+ Requires-Dist: pytest; extra == "test"
36
+ Requires-Dist: pytest-mock; extra == "test"
37
37
  Dynamic: license-file
38
38
 
39
39
  # Data Manipulation
@@ -56,7 +56,7 @@ Data Manipulation is a Python package providing powerful utility functions. It c
56
56
 
57
57
  ## Where to get it
58
58
 
59
- The source code is currently hosted on GitHub at: https://github.com/shawnngtq/data-manipulation
59
+ The source code is currently hosted on GitHub at: <https://github.com/shawnngtq/data-manipulation>
60
60
 
61
61
  ```bash
62
62
  pip install data-manipulation
@@ -18,7 +18,7 @@ Data Manipulation is a Python package providing powerful utility functions. It c
18
18
 
19
19
  ## Where to get it
20
20
 
21
- The source code is currently hosted on GitHub at: https://github.com/shawnngtq/data-manipulation
21
+ The source code is currently hosted on GitHub at: <https://github.com/shawnngtq/data-manipulation>
22
22
 
23
23
  ```bash
24
24
  pip install data-manipulation
@@ -20,6 +20,16 @@ git status
20
20
 
21
21
  `git status` should report no changes before continuing.
22
22
 
23
+ ## Local Development Build
24
+
25
+ Contributors do not need PyPI credentials or this release flow. To work on the package
26
+ locally, install it editable and build with the standard tooling:
27
+
28
+ ```bash
29
+ pip install -e .
30
+ python -m build # or: uv build
31
+ ```
32
+
23
33
  ## Tag The Release
24
34
 
25
35
  Use the next release version, for example `0.50`:
@@ -34,13 +44,17 @@ The tag must point at the exact commit being released.
34
44
 
35
45
  ## Publish Documentation
36
46
 
37
- Build the MkDocs documentation:
47
+ Both commands require an environment that provides `mkdocs`, `mkdocs-material`, and
48
+ `mkdocstrings-python` (for example a virtualenv, conda env, or pixi shell). Activate that
49
+ environment before running them.
50
+
51
+ Build the MkDocs documentation (local preview only):
38
52
 
39
53
  ```bash
40
54
  mkdocs build
41
55
  ```
42
56
 
43
- Publish the generated HTML to GitHub Pages:
57
+ Deploy to GitHub Pages:
44
58
 
45
59
  ```bash
46
60
  mkdocs gh-deploy
@@ -48,18 +62,38 @@ mkdocs gh-deploy
48
62
 
49
63
  This publishes the contents of `site/` to the `gh-pages` branch.
50
64
 
65
+ **Note - documentation and PyPI releases are independent.**
66
+
67
+ - **Tags are only for PyPI releases.** `setuptools-scm` derives the package
68
+ version from git tags. Create a tag only when the shipped `data_manipulation/`
69
+ package changes; tooling- or docs-only changes need no tag.
70
+ - **Docs deploy without a tag.** `deploy_docs` publishes current `master` to the
71
+ separate `gh-pages` branch, independent of any tag or PyPI release.
72
+ - **Commit and push doc/source changes to `master` before building.** The site
73
+ renders the working tree, and `create_update_docs` writes only to the
74
+ gitignored `site/` directory - no tracked files change.
75
+ - **When cutting a release, build docs after tagging** so the published site
76
+ matches the released commit.
77
+
51
78
  ## Publish To PyPI
52
79
 
80
+ Build from a **clean checkout of the tagged commit** so the artifacts carry the tag
81
+ version. `setuptools-scm` derives the version from git, so any uncommitted tracked change
82
+ makes it emit the *next* version as `<next>.devN+d<date>` instead of the tag - confirm
83
+ `git status` is clean before building.
84
+
53
85
  Build and validate the distribution artifacts:
54
86
 
55
87
  ```bash
56
- ./setup.sh cleanup
88
+ rm -rf build dist ./*.egg-info
89
+ python -m build
90
+ python -m twine check --strict dist/*
57
91
  ```
58
92
 
59
93
  Upload the artifacts:
60
94
 
61
95
  ```bash
62
- ./setup.sh upload
96
+ python -m twine upload dist/*
63
97
  ```
64
98
 
65
99
  When prompted by `twine`, enter the PyPI API token. The token should start with
@@ -0,0 +1,24 @@
1
+ """Repo-root pytest configuration.
2
+
3
+ ``--doctest-modules`` (see ``[tool.pytest.ini_options]``) collects doctests from
4
+ every ``data_manipulation/*.py``. We only want to *execute* examples that are
5
+ robustly runnable, so ignore the rest here. Their ``Examples:`` blocks still
6
+ render in the mkdocs API reference — they are just not auto-verified.
7
+
8
+ Auto-verified modules (not ignored): base.py, beautifulsoup_.py, sqlalchemy_.py.
9
+ """
10
+
11
+ collect_ignore = [
12
+ "data_manipulation/__init__.py",
13
+ "data_manipulation/_version.py",
14
+ "data_manipulation/pandas_.py",
15
+ "data_manipulation/pyspark_.py",
16
+ "data_manipulation/boto3_.py",
17
+ "data_manipulation/kerberos_.py",
18
+ "data_manipulation/openldap_.py",
19
+ "data_manipulation/cryptography_.py",
20
+ "data_manipulation/mysql_connector_python_.py",
21
+ "data_manipulation/postgres_.py",
22
+ "data_manipulation/smtplib_.py",
23
+ "data_manipulation/polars_.py",
24
+ ]
@@ -3,8 +3,7 @@ from data_manipulation import (
3
3
  beautifulsoup_,
4
4
  boto3_,
5
5
  cryptography_,
6
- django_,
7
- geopandas_,
6
+ iceberg,
8
7
  kerberos_,
9
8
  mysql_connector_python_,
10
9
  openldap_,
@@ -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.53'
22
- __version_tuple__ = version_tuple = (0, 53)
21
+ __version__ = version = '0.55'
22
+ __version_tuple__ = version_tuple = (0, 55)
23
23
 
24
- __commit_id__ = commit_id = 'g2446c213a'
24
+ __commit_id__ = commit_id = 'gb82db140a'