textdirectory 0.3.2__tar.gz → 0.4.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.
Files changed (91) hide show
  1. textdirectory-0.4.0/.gitignore +106 -0
  2. textdirectory-0.4.0/AUTHORS.md +9 -0
  3. textdirectory-0.4.0/CHANGELOG.md +127 -0
  4. textdirectory-0.4.0/CONTRIBUTING.md +53 -0
  5. {textdirectory-0.3.2 → textdirectory-0.4.0}/LICENSE +22 -22
  6. textdirectory-0.4.0/PKG-INFO +262 -0
  7. textdirectory-0.4.0/README.md +229 -0
  8. textdirectory-0.4.0/docs/api.rst +36 -0
  9. textdirectory-0.4.0/docs/changelog.md +5 -0
  10. textdirectory-0.4.0/docs/conf.py +27 -0
  11. textdirectory-0.4.0/docs/contributing.md +5 -0
  12. textdirectory-0.4.0/docs/index.md +25 -0
  13. textdirectory-0.4.0/docs/installation.md +39 -0
  14. textdirectory-0.4.0/docs/releasing.md +103 -0
  15. textdirectory-0.4.0/docs/requirements.txt +4 -0
  16. textdirectory-0.4.0/docs/usage.md +92 -0
  17. textdirectory-0.4.0/examples/complex_transformation.py +17 -0
  18. textdirectory-0.4.0/examples/filter_and_transform.py +16 -0
  19. textdirectory-0.4.0/examples/repeating_transformation.py +14 -0
  20. textdirectory-0.4.0/examples/saved_states.py +16 -0
  21. textdirectory-0.4.0/examples/transform_to_leetspeak.py +13 -0
  22. textdirectory-0.4.0/pyproject.toml +126 -0
  23. textdirectory-0.4.0/src/textdirectory/__init__.py +11 -0
  24. textdirectory-0.4.0/src/textdirectory/__main__.py +6 -0
  25. textdirectory-0.4.0/src/textdirectory/cli.py +99 -0
  26. {textdirectory-0.3.2 → textdirectory-0.4.0/src}/textdirectory/crudespellchecker.py +179 -167
  27. {textdirectory-0.3.2 → textdirectory-0.4.0/src}/textdirectory/data/stopwords/stopwords_en.txt +96 -96
  28. textdirectory-0.4.0/src/textdirectory/helpers.py +273 -0
  29. textdirectory-0.4.0/src/textdirectory/py.typed +0 -0
  30. {textdirectory-0.3.2 → textdirectory-0.4.0/src}/textdirectory/textdirectory.py +607 -487
  31. textdirectory-0.4.0/src/textdirectory/transformations.py +440 -0
  32. textdirectory-0.4.0/tests/conftest.py +36 -0
  33. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/Text_A.txt +9 -9
  34. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/Text_B.txt +4 -4
  35. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/Text_C.txt +1 -1
  36. textdirectory-0.4.0/tests/data/testdata/Text_E.txt +2 -0
  37. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/level_2/Text_2_A.txt +1 -1
  38. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/level_2/Text_2_B.txt +1 -1
  39. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/level_2/Text_2_C.txt +6 -6
  40. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/level_2/Text_2_D.txt +1 -1
  41. textdirectory-0.4.0/tests/test_aggregation.py +25 -0
  42. textdirectory-0.4.0/tests/test_cli.py +117 -0
  43. textdirectory-0.4.0/tests/test_crudespellchecker.py +71 -0
  44. textdirectory-0.4.0/tests/test_filters.py +119 -0
  45. textdirectory-0.4.0/tests/test_general.py +23 -0
  46. textdirectory-0.4.0/tests/test_helpers.py +129 -0
  47. textdirectory-0.4.0/tests/test_states.py +42 -0
  48. textdirectory-0.4.0/tests/test_textdirectory_api.py +106 -0
  49. textdirectory-0.4.0/tests/test_transformation.py +86 -0
  50. textdirectory-0.4.0/tests/test_transformations.py +249 -0
  51. textdirectory-0.3.2/AUTHORS.rst +0 -13
  52. textdirectory-0.3.2/CONTRIBUTING.rst +0 -128
  53. textdirectory-0.3.2/HISTORY.rst +0 -81
  54. textdirectory-0.3.2/MANIFEST.in +0 -15
  55. textdirectory-0.3.2/PKG-INFO +0 -257
  56. textdirectory-0.3.2/README.rst +0 -158
  57. textdirectory-0.3.2/docs/Makefile +0 -20
  58. textdirectory-0.3.2/docs/_build/html/_static/file.png +0 -0
  59. textdirectory-0.3.2/docs/_build/html/_static/minus.png +0 -0
  60. textdirectory-0.3.2/docs/_build/html/_static/plus.png +0 -0
  61. textdirectory-0.3.2/docs/authors.rst +0 -1
  62. textdirectory-0.3.2/docs/conf.py +0 -163
  63. textdirectory-0.3.2/docs/contributing.rst +0 -1
  64. textdirectory-0.3.2/docs/history.rst +0 -1
  65. textdirectory-0.3.2/docs/index.rst +0 -20
  66. textdirectory-0.3.2/docs/installation.rst +0 -51
  67. textdirectory-0.3.2/docs/make.bat +0 -36
  68. textdirectory-0.3.2/docs/modules.rst +0 -7
  69. textdirectory-0.3.2/docs/readme.rst +0 -1
  70. textdirectory-0.3.2/docs/textdirectory.rst +0 -54
  71. textdirectory-0.3.2/docs/usage.rst +0 -7
  72. textdirectory-0.3.2/setup.cfg +0 -29
  73. textdirectory-0.3.2/setup.py +0 -53
  74. textdirectory-0.3.2/tests/test_textdirectory.py +0 -191
  75. textdirectory-0.3.2/textdirectory/__init__.py +0 -10
  76. textdirectory-0.3.2/textdirectory/cli.py +0 -64
  77. textdirectory-0.3.2/textdirectory/data/testdata/text_E.txt +0 -2
  78. textdirectory-0.3.2/textdirectory/helpers.py +0 -182
  79. textdirectory-0.3.2/textdirectory/transformations.py +0 -302
  80. textdirectory-0.3.2/textdirectory.egg-info/PKG-INFO +0 -257
  81. textdirectory-0.3.2/textdirectory.egg-info/SOURCES.txt +0 -51
  82. textdirectory-0.3.2/textdirectory.egg-info/dependency_links.txt +0 -1
  83. textdirectory-0.3.2/textdirectory.egg-info/entry_points.txt +0 -3
  84. textdirectory-0.3.2/textdirectory.egg-info/not-zip-safe +0 -1
  85. textdirectory-0.3.2/textdirectory.egg-info/requires.txt +0 -8
  86. textdirectory-0.3.2/textdirectory.egg-info/top_level.txt +0 -1
  87. {textdirectory-0.3.2 → textdirectory-0.4.0/src}/textdirectory/data/language_models/crudesc_lm_ame.gz.lm +0 -0
  88. {textdirectory-0.3.2 → textdirectory-0.4.0/src}/textdirectory/data/language_models/crudesc_lm_amehistorical.gz.lm +0 -0
  89. {textdirectory-0.3.2 → textdirectory-0.4.0/src}/textdirectory/data/language_models/crudesc_lm_en.gz.lm +0 -0
  90. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/Text_D.txt +0 -0
  91. {textdirectory-0.3.2/textdirectory → textdirectory-0.4.0/tests}/data/testdata/level_2/Text_2_E.txt +0 -0
@@ -0,0 +1,106 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ env/
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+
28
+ # PyInstaller
29
+ # Usually these files are written by a python script from a template
30
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
31
+ *.manifest
32
+ *.spec
33
+
34
+ # Installer logs
35
+ pip-log.txt
36
+ pip-delete-this-directory.txt
37
+
38
+ # Unit test / coverage reports
39
+ htmlcov/
40
+ .tox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+
50
+ # Translations
51
+ *.mo
52
+ *.pot
53
+
54
+ # Django stuff:
55
+ *.log
56
+ local_settings.py
57
+
58
+ # Flask stuff:
59
+ instance/
60
+ .webassets-cache
61
+
62
+ # Scrapy stuff:
63
+ .scrapy
64
+
65
+ # Sphinx documentation
66
+ docs/_build/
67
+
68
+ # PyBuilder
69
+ target/
70
+
71
+ # Jupyter Notebook
72
+ .ipynb_checkpoints
73
+
74
+ # pyenv
75
+ .python-version
76
+
77
+ # celery beat schedule file
78
+ celerybeat-schedule
79
+
80
+ # SageMath parsed files
81
+ *.sage.py
82
+
83
+ # dotenv
84
+ .env
85
+
86
+ # virtualenv
87
+ .venv
88
+ venv/
89
+ ENV/
90
+
91
+ # Spyder project settings
92
+ .spyderproject
93
+ .spyproject
94
+
95
+ # Rope project settings
96
+ .ropeproject
97
+
98
+ # mkdocs documentation
99
+ /site
100
+
101
+ # mypy
102
+ .mypy_cache/
103
+
104
+ # PyCharm
105
+ .idea/
106
+ test.txt
@@ -0,0 +1,9 @@
1
+ # Credits
2
+
3
+ ## Development Lead
4
+
5
+ * Ingo Kleiber <ingo@kleiber.me>
6
+
7
+ ## Contributors
8
+
9
+ * Lyuba Dimitrova <dimitrova@cl.uni-heidelberg.de>
@@ -0,0 +1,127 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0 (2026-07-26)
4
+
5
+ * modernized the packaging: pyproject.toml + hatchling, src/ layout, uv-based development workflow
6
+ * supported Python versions are now 3.10–3.13
7
+ * made spaCy and psutil optional dependencies (`pip install 'textdirectory[nlp]'` plus `python -m spacy download en_core_web_sm`)
8
+ * dropped the numpy dependency (replaced by the standard library random and statistics modules)
9
+ * spaCy models are now loaded once and cached instead of being reloaded per file and transformation
10
+ * added type hints throughout the package (py.typed)
11
+ * added `--version` and `python -m textdirectory` support to the CLI
12
+ * CLI filter arguments are now coerced to the expected types (filesize, TTR, and similarity filters previously failed from the CLI)
13
+ * CLI errors now exit with a non-zero exit code
14
+ * replaced Travis CI with GitHub Actions; replaced the legacy Read the Docs configuration; rewrote the documentation in Markdown
15
+ * the test corpus is no longer shipped inside the wheel (moved to tests/data/testdata/)
16
+ * fixed destage_transformation, which could never destage anything
17
+ * fixed the CrudeSpellChecker correction cache (wrong cache key) and a crash on tokens without word characters
18
+ * fixed transformation_usas_en_semtag: HTTPS, request timeout, and raising on HTTP errors
19
+ * stage_transformation and run_filters now validate names against the actual registries
20
+ * fixed filter_by_random_sampling turning the aggregation into a numpy array; note that the random sequence differs from previous versions
21
+ * transformation_remove_stopwords now raises for an unknown source or missing stopwords file instead of returning False
22
+ * tabulate_flat_list_of_dicts returns '' for an empty list; type_token_ratio returns 0.0 for empty text
23
+ * aggregate_to_file no longer silently drops unencodable characters when writing
24
+
25
+ ## 0.3.4 (2022-09-25)
26
+
27
+ * added transformation_replace_string
28
+ * added filter_by_type_token_ratio
29
+ * added tests for running transformations
30
+ * added contractions fix to transformation_lemmatize
31
+ * added the --disable_tqdm option to the CLI
32
+ * added the ability to output aggregations to the console when using the CLI
33
+ * added (static) coverage badge to the README
34
+ * unified some core approaches (e.g., how filters and transformations are applied; tokenizaton)
35
+ * improved test structure
36
+ * improved documentation
37
+ * fixed transformation_usas_en_semtag
38
+
39
+ ## 0.3.3 (2022-09-25)
40
+
41
+ * added filter_by_filenames
42
+ * added filter_by_filename_not_contains
43
+ * added transform_to_files
44
+ * added transformation_eebop4_to_plaintext
45
+ * added transformation_replace_digits
46
+ * added transformation_ftfy
47
+ * added fast and skip_checkpoint options to load_files
48
+ * added __repr__ method to TextDirectory
49
+ * added examples
50
+ * upgraded to spaCy 3
51
+ * improved the test suite
52
+ * fixed some minor bugs
53
+
54
+ ## 0.3.2 (2021-01-10)
55
+
56
+ * added transformation_expand_english_contractions
57
+ * fixed some minor bugs
58
+ * added __str__ method to TextDirectory
59
+ * added filename to __str__ output
60
+ * added `get_text` method
61
+
62
+ ## 0.3.1 (2020-01-20)
63
+
64
+ * added long_description_content_type to setup.py
65
+
66
+ ## 0.3.0 (2020-01-19)
67
+
68
+ * added transformation_remove_weird_tokens
69
+ * added transformation_lemmatizer
70
+ * fixed some minor bugs
71
+ * added a function to revert applied filters
72
+ * added a function that prints the current pipeline
73
+ * added a function that clears all transformations
74
+ * added helper functions to list available filters and transformations
75
+ * fixed a bug in which `tabulate_flat_list_of_dicts` would fail if the dictionary was empty
76
+ * `self.aggregation` does not hold a copy of the files anymore but references to `self.files`
77
+ * transformations relying on spaCy are now estimating a max_length based on available memory
78
+ * TextDirectory objects are now iterable
79
+
80
+ ## 0.2.2 (2019-06-13)
81
+
82
+ * changed the data packaging
83
+
84
+ ## 0.2.1 (2019-06-13)
85
+
86
+ * added transformation_remove_stopwords
87
+ * added transformation_remove_htmltags
88
+ * fixed some minor bugs
89
+
90
+ ## 0.2.0 (2018-05-13)
91
+
92
+ * added transform_to_memory() function
93
+ * added transformation_to_leetspeak() function
94
+ * added transformation_crude_spellchecker
95
+ * added filter_by_max_filesize
96
+ * added filter_by_min_filesize
97
+ * fixed a bug where load_files() would fail if there were no files
98
+
99
+ ## 0.1.4 (2018-05-02)
100
+
101
+ * fixed an object mutation problem in the tabulate function
102
+
103
+ ## 0.1.3 (2018-04-30)
104
+
105
+ * filter_by_random_sampling now has a "replacement" option
106
+ * changed from tabulate to an embedded function
107
+ * added transformation_remove_non_ascii
108
+ * added transformation_remove_non_alphanumerical
109
+ * added filter_by_similar_documents
110
+
111
+ ## 0.1.2 (2018-04-29)
112
+
113
+ * added transformation_postag
114
+ * added transformation_usas_en_semtag
115
+ * added transformation_uppercase
116
+ * added filter_by_filename_contains
117
+ * added parameter support for transformations
118
+
119
+ ## 0.1.1 (2018-04-27)
120
+
121
+ * added filter_by_chars_outliers
122
+ * added transformation_remove_nl
123
+
124
+ ## 0.1.0 (2018-04-26)
125
+
126
+ * Initial release
127
+ * First release on PyPI.
@@ -0,0 +1,53 @@
1
+ # Contributing
2
+
3
+ Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
4
+
5
+ ## Ways to Contribute
6
+
7
+ * **Report bugs** at <https://github.com/IngoKl/textdirectory/issues> — please include your operating system,
8
+ Python version, and detailed steps to reproduce.
9
+ * **Fix bugs** or **implement features**: anything tagged `bug` or `enhancement` in the issue tracker is open to
10
+ whoever wants to work on it.
11
+ * **Write documentation**: docstrings, the docs at <https://textdirectory.readthedocs.io>, or blog posts and
12
+ articles elsewhere.
13
+ * **Submit feedback**: the easiest way is to file an issue at <https://github.com/IngoKl/textdirectory/issues>.
14
+
15
+ ## Development Setup
16
+
17
+ The project uses [uv](https://docs.astral.sh/uv/) for environments and dependency management.
18
+
19
+ ```bash
20
+ git clone https://github.com/<your-fork>/textdirectory.git
21
+ cd textdirectory
22
+
23
+ # Create the environment with dev tools and the optional NLP dependencies
24
+ uv sync --group dev --extra nlp
25
+ uv pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
26
+ ```
27
+
28
+ Note: if you keep the repository inside a synced folder (e.g. Dropbox), exclude `.venv/` from syncing.
29
+
30
+ ## Running Checks
31
+
32
+ ```bash
33
+ uv run pytest # test suite (tests hitting live services are excluded by default)
34
+ uv run pytest -m network # live-service tests (UCREL USAS)
35
+ uv run ruff check src tests
36
+ uv run ruff format --check src tests
37
+ uv run mypy
38
+ ```
39
+
40
+ Tests that need spaCy and the `en_core_web_sm` model are skipped automatically when they are not installed.
41
+
42
+ ## Pull Request Guidelines
43
+
44
+ 1. Create a branch for your change and add tests for any new functionality or fixed bug.
45
+ 2. Make sure the full check suite above passes locally.
46
+ 3. Update the documentation if you add or change functionality (docstrings, README, and the docs pages).
47
+ 4. Add an entry to `CHANGELOG.md` under the unreleased version.
48
+ 5. The CI runs the tests on Python 3.10–3.13 on Linux and Windows; your change should pass on all of them.
49
+
50
+ ## Releasing
51
+
52
+ See the [releasing documentation](https://textdirectory.readthedocs.io/en/latest/releasing.html) for how versions
53
+ are bumped, built, and published to PyPI.
@@ -1,22 +1,22 @@
1
- MIT License
2
-
3
- Copyright (c) 2021, Ingo Kleiber
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
22
-
1
+ MIT License
2
+
3
+ Copyright (c) 2022, Ingo Kleiber
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,262 @@
1
+ Metadata-Version: 2.4
2
+ Name: textdirectory
3
+ Version: 0.4.0
4
+ Summary: Aggregate multiple text files into one, with filters and transformations.
5
+ Project-URL: Homepage, https://github.com/IngoKl/textdirectory
6
+ Project-URL: Documentation, https://textdirectory.readthedocs.io
7
+ Project-URL: Repository, https://github.com/IngoKl/textdirectory
8
+ Project-URL: Issues, https://github.com/IngoKl/textdirectory/issues
9
+ Author-email: Ingo Kleiber <ingo@kleiber.me>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: aggregation,corpus,nlp,text,textdirectory
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: beautifulsoup4>=4.11
24
+ Requires-Dist: click>=8.1
25
+ Requires-Dist: ftfy>=6.1
26
+ Requires-Dist: lxml>=4.9
27
+ Requires-Dist: requests>=2.28
28
+ Requires-Dist: tqdm>=4.64
29
+ Provides-Extra: nlp
30
+ Requires-Dist: psutil>=5.9; extra == 'nlp'
31
+ Requires-Dist: spacy<4,>=3.8; extra == 'nlp'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # TextDirectory
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/textdirectory.svg)](https://pypi.org/project/textdirectory/)
37
+ [![CI](https://github.com/IngoKl/textdirectory/actions/workflows/ci.yml/badge.svg)](https://github.com/IngoKl/textdirectory/actions/workflows/ci.yml)
38
+ [![Documentation Status](https://readthedocs.org/projects/textdirectory/badge/?version=latest)](https://textdirectory.readthedocs.io/en/latest/?badge=latest)
39
+ [![Python Versions](https://img.shields.io/pypi/pyversions/textdirectory.svg)](https://pypi.org/project/textdirectory/)
40
+
41
+ ![TextDirectory](https://user-images.githubusercontent.com/16179317/39367680-cd409a00-4a37-11e8-8d42-0bed5a4e814b.png)
42
+
43
+ *TextDirectory* allows you to combine multiple text files into one aggregated file. TextDirectory also supports matching
44
+ files for certain criteria and applying transformations to the aggregated text.
45
+
46
+ *TextDirectory* can be used as a mere tool (via the CLI) and as a Python library.
47
+
48
+ Of course, everything *TextDirectory* does could be achieved in bash or PowerShell. However, there are certain
49
+ use cases (e.g., when used as a library) in which it might be useful.
50
+
51
+ * Free software: MIT license
52
+ * Documentation: <https://textdirectory.readthedocs.io>
53
+
54
+ ## Features
55
+
56
+ * Aggregating multiple text files
57
+ * Filtering documents/texts based on various parameters such as length, content, and random sampling
58
+ * Filtering and transforming text files
59
+ * Transforming the aggregated text (e.g., transforming the text to lowercase)
60
+
61
+ | Version | Filters | Transformations |
62
+ |---------|---------|-----------------|
63
+ | 0.1.0 | filter_by_max_chars(n int); filter_by_min_chars(n int); filter_by_max_tokens(n int); filter_by_min_tokens(n int); filter_by_contains(str); filter_by_not_contains(str); filter_by_random_sampling(n int; replace=False) | transformation_lowercase |
64
+ | 0.1.1 | filter_by_chars_outliers(n sigmas int) | transformation_remove_nl |
65
+ | 0.1.2 | filter_by_filename_contains(contains str) | transformation_usas_en_semtag; transformation_uppercase; transformation_postag(spacy_model str) |
66
+ | 0.1.3 | filter_by_similar_documents(reference_file str; threshold float) | transformation_remove_non_ascii; transformation_remove_non_alphanumerical |
67
+ | 0.2.0 | filter_by_max_filesize(max_kb int); filter_by_min_filesize(min_kb int) | transformation_to_leetspeak; transformation_crude_spellchecker(language model str) |
68
+ | 0.2.1 | None | transformation_remove_stopwords(stopwords_source str; stopwords str [en]; spacy_model str; custom_stopwords str); transformation_remove_htmltags |
69
+ | 0.3.0 | None | transformation_remove_weird_tokens(spaCy model; remove_double_space=False); transformation_lemmatize(spaCy model) |
70
+ | 0.3.2 | None | transformation_expand_english_contractions |
71
+ | 0.3.3 | filter_by_filenames(filenames list); filter_by_filename_not_contains(not_contains str) | transformation_eebop4_to_plaintext; transformation_replace_digits(replacement_character str); transformation_ftfy |
72
+ | 0.3.4 | filter_by_type_token_ratio(min_ttr float; max_ttr float) | transformation_replace_string(replace str; replace_with str) |
73
+ | 0.4.0 | None (modernization release) | None (modernization release) |
74
+
75
+ ## Installation
76
+
77
+ Install *TextDirectory* via pip:
78
+
79
+ ```bash
80
+ pip install textdirectory
81
+ ```
82
+
83
+ The spaCy-based transformations (`transformation_postag`, `transformation_lemmatize`,
84
+ `transformation_remove_stopwords`, `transformation_remove_weird_tokens`) are optional. To use them, install the
85
+ `nlp` extra and download a spaCy model:
86
+
87
+ ```bash
88
+ pip install 'textdirectory[nlp]'
89
+ python -m spacy download en_core_web_sm
90
+ ```
91
+
92
+ ## Quickstart
93
+
94
+ *TextDirectory*, as exemplified below, works with a two-stage model. After loading in your data (directory) you can,
95
+ by applying *filters*, iteratively select the files you want to process.
96
+ In a second step you can perform transformations on the text before finally aggregating it to either a file or memory.
97
+
98
+ ![TextDirectory](https://user-images.githubusercontent.com/16179317/39367589-7f774116-4a37-11e8-9a09-5cbdf5f3311b.png)
99
+
100
+ ### As a Command-Line Tool
101
+
102
+ *TextDirectory* comes equipped with a CLI (`textdirectory`, also available as `python -m textdirectory`).
103
+
104
+ The syntax for both the *filters* and *transformations* works similarly. They are chained by adding slashes (/) and
105
+ parameters are passed via commas (,): `filter_by_min_tokens,5/filter_by_random_sampling,2`.
106
+
107
+ **Example 1: A Very Simple Aggregation**
108
+
109
+ ```bash
110
+ textdirectory --directory testdata --output_file aggregated.txt
111
+ ```
112
+
113
+ This will take all files (.txt) in *testdata* and then aggregates the files into a file called *aggregated.txt*.
114
+
115
+ You could also use '*' as a wildcard for filetype if you need to include all files and not just .txt:
116
+
117
+ ```bash
118
+ textdirectory --directory testdata --output_file aggregated.txt --filetype *
119
+ ```
120
+
121
+ **Example 2: Applying Filters and Transformations**
122
+
123
+ In this example, we want to filter the files based on their token count, perform a random sampling and finally
124
+ transform all text to lowercase:
125
+
126
+ ```bash
127
+ textdirectory --directory testdata --output_file aggregated.txt --filters filter_by_min_tokens,5/filter_by_random_sampling,2 --transformations transformation_lowercase
128
+ ```
129
+
130
+ After passing two filters (*filter_by_min_tokens* and *filter_by_random_sampling*) we've applied the
131
+ *transformation_lowercase* transformation.
132
+
133
+ The resulting file will contain the content of two files that each have at least five tokens.
134
+
135
+ The same transformation can also be staged multiple times. For example, we could stage two simple string replacements
136
+ like this:
137
+
138
+ ```bash
139
+ textdirectory --directory testdata --output_file aggregated.txt --transformations transformation_replace_string,lorem,x/transformation_replace_string,ipsum,y
140
+ ```
141
+
142
+ If the `--output_file` is missing, the CLI will output the aggregated text to the console. In this scenario, there is
143
+ no progress bar visible (can be controlled using `--disable_tqdm True/False`).
144
+
145
+ ### As a Python Library
146
+
147
+ In order to demonstrate *TextDirectory* as a Python library, we'll recreate the second example from above:
148
+
149
+ ```python
150
+ import textdirectory
151
+
152
+ td = textdirectory.TextDirectory(directory='testdata')
153
+ td.load_files(recursive=False, filetype='txt', sort=True)
154
+ td.filter_by_min_tokens(5)
155
+ td.filter_by_random_sampling(2)
156
+ td.stage_transformation(['transformation_lowercase'])
157
+ td.aggregate_to_file('aggregated.txt')
158
+ ```
159
+
160
+ If we don't have special requirements, we can also call
161
+ `td = textdirectory.TextDirectory(directory='testdata', autoload=True)` to skip manually calling `load_files`.
162
+ If we wanted to keep working with the actual aggregated text, we could have called `text = td.aggregate_to_memory()`
163
+ instead of `aggregate_to_file`.
164
+
165
+ ```python
166
+ import textdirectory
167
+
168
+ td = textdirectory.TextDirectory(directory='testdata', autoload=True)
169
+ td.get_text(0)
170
+ ```
171
+
172
+ Sometimes we might want to get the actual text of a given file. This can be achieved as seen above. The `get_text`
173
+ method will return the transformed text if it is available. Otherwise, it will simply read the file and return the
174
+ text.
175
+
176
+ Every applied filter will create a *state* (i.e., a checkpoint). If we want to go back to a previous state, we can
177
+ print all states by calling `td.print_saved_states()`. Previous states can then be loaded by calling
178
+ `td.load_aggregation_state(state=0)`.
179
+
180
+ It's also possible to pass arguments to the individual transformations. In order to do this (at the moment) you have
181
+ to adhere to the correct order of arguments:
182
+
183
+ ```python
184
+ # def transformation_remove_stopwords(text, stopwords_source='internal', stopwords='en', spacy_model='en_core_web_sm', custom_stopwords=None, *args)
185
+ td.stage_transformation(['transformation_remove_stopwords', 'internal', 'en', 'en_core_web_sm', 'dolor'])
186
+ ```
187
+
188
+ In the above example, we are adding additional custom stopwords to the transformer.
189
+
190
+ You also might not always want to aggregate texts into one file in many cases but filter and transform them:
191
+
192
+ ```python
193
+ import textdirectory
194
+
195
+ td = textdirectory.TextDirectory(directory='input')
196
+ td.load_files()
197
+
198
+ td.filter_by_max_chars(480)
199
+ td.stage_transformation(['transformation_to_leetspeak'])
200
+
201
+ td.transform_to_files('output')
202
+ ```
203
+
204
+ In the example above, we are loading all files in `input`. After filtering and transforming, the modified files will
205
+ be written to `output`.
206
+
207
+ In addition, there are a few [simple examples](https://github.com/IngoKl/textdirectory/tree/master/examples) in the
208
+ repository for you to look at.
209
+
210
+ ## Special Transformations
211
+
212
+ ### transformation_crude_spellchecker
213
+
214
+ This is a very crude spellchecker implemented following Peter Norvig's excellent
215
+ [tutorial](http://norvig.com/spell-correct.html). It's really more of an experiment and not production ready in any
216
+ sense of the word.
217
+
218
+ ### transformation_eebop4_to_plaintext
219
+
220
+ This is a highly specific transformation that will extract the plain text from an EEBO-TCP P4 corpus file.
221
+ Both the header as well as all XML tags will be removed during this transformation.
222
+
223
+ ### transformation_ftfy
224
+
225
+ This transformation simply applies `ftfy.fix_text` to the text.
226
+ It is highly recommended to use [ftfy](https://pypi.org/project/ftfy/) as a first transformation if you are working
227
+ with messy Unicode text.
228
+
229
+ ## Notes for Developers
230
+
231
+ The project uses [uv](https://docs.astral.sh/uv/) for development:
232
+
233
+ ```bash
234
+ uv sync --group dev --extra nlp
235
+ uv pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl
236
+
237
+ uv run pytest # run the test suite (network tests excluded by default)
238
+ uv run pytest -m network # run the tests that hit live external services
239
+ uv run ruff check src tests
240
+ uv run mypy
241
+ ```
242
+
243
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development guide and
244
+ [the releasing documentation](https://textdirectory.readthedocs.io/en/latest/releasing.html) for how releases are
245
+ built and published.
246
+
247
+ ## Behavior
248
+
249
+ We are not holding the actual texts in memory. This leads to much more disk read activity (and time inefficiency),
250
+ but saves memory. Of course, this is not the case when using `aggregate_to_memory`.
251
+
252
+ `transformation_usas_en_semtag` relies on the web version of
253
+ [Paul Rayson's USAS Tagger](http://ucrel.lancs.ac.uk/usas/). Don't use this transformation for large amounts of text,
254
+ give credit, and consider using their commercial product [Wmatrix](http://ucrel.lancs.ac.uk/wmatrix/).
255
+
256
+ If you are working with a lot of files, it might be wise to use `load_files(fast=True, skip_checkpoint=True)`.
257
+ This will load files much quicker but skip collecting metadata. This will limit the filters that you can use.
258
+
259
+ ## Credits
260
+
261
+ This package was originally based on the
262
+ [audreyr/cookiecutter-pypackage](https://github.com/audreyr/cookiecutter-pypackage) cookiecutter template.