bib_optimizer 0.5.1__py3-none-any.whl

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.
@@ -0,0 +1,2 @@
1
+ # Version
2
+ __version__ = "0.5.1"
@@ -0,0 +1,23 @@
1
+ """Version:
2
+ --------
3
+
4
+ - bib_optimizer v0.5.1
5
+ """
6
+ import sys
7
+ from bib_optimizer import helpers
8
+
9
+ def main():
10
+ if len(sys.argv[1:]) != 3:
11
+ raise Exception("Sorry, please input three files: your tex filename, bib filename, and the desired new bib filename")
12
+ tex = sys.argv[1:][0]
13
+ old_bib = sys.argv[1:][1]
14
+ new_bib = sys.argv[1:][2]
15
+
16
+ helpers.bib_opt(tex, old_bib, new_bib)
17
+
18
+
19
+
20
+ if __name__ == '__main__':
21
+ main()
22
+
23
+
@@ -0,0 +1,74 @@
1
+ import bibtexparser
2
+ import re
3
+ from bibtexparser.bwriter import BibTexWriter
4
+
5
+ def _augment_func(filecontent, all_keys, temp_citations):
6
+ for e in re.findall(r'\\cite[tp]?\{([^}]+)\}', filecontent):
7
+ for c in e.split(','):
8
+ c = c.strip()
9
+ if c not in temp_citations:
10
+ all_keys.append(c)
11
+ temp_citations.add(c)
12
+
13
+ return all_keys, temp_citations
14
+
15
+ def bib_opt(filename, input_bib, output_bib):
16
+ with open(filename, 'r', encoding='utf-8') as file:
17
+ lines = file.readlines()
18
+ filtered_lines = [line for line in lines if not line.lstrip().startswith('%')]
19
+ filecontent = ''.join(filtered_lines)
20
+
21
+ with open(input_bib, 'r', encoding='utf-8') as bibfile:
22
+ bib_database = bibtexparser.load(bibfile)
23
+
24
+ allowed_keys = []
25
+ all_keys = []
26
+ temp_citations = set()
27
+
28
+ split_pattern = r'(.*?)(\\(?:input|include)[^\n]*\n)(.*?)((?=\\(?:input|include))|\Z)'
29
+ matches = re.findall(split_pattern, filecontent, flags=re.DOTALL)
30
+ split_results = [(before, after.strip()) for before, input_line, after, _ in matches]
31
+
32
+ input_pattern_extended = r'\\(?:input|include)\s*(?:{([^}]+)}|([^\s\n]+))'
33
+ matches = re.findall(input_pattern_extended, filecontent)
34
+ input_files_extended = [m[0] if m[0] else m[1] for m in matches]
35
+
36
+ if not split_results:
37
+ all_keys, temp_citations = _augment_func(filecontent, all_keys, temp_citations)
38
+ else:
39
+ for split_result, input_file_extended in zip(split_results, input_files_extended):
40
+ all_keys, temp_citations = _augment_func(split_result[0], all_keys, temp_citations)
41
+
42
+ if ".tex" not in input_file_extended:
43
+ input_file_extended += ".tex"
44
+
45
+ try:
46
+ with open(input_file_extended, 'r', encoding='utf-8') as file:
47
+ _lines = file.readlines()
48
+
49
+ _filtered_lines = [line for line in _lines if not line.lstrip().startswith('%')]
50
+ _filecontent = ''.join(_filtered_lines)
51
+
52
+ all_keys, temp_citations = _augment_func(_filecontent, all_keys, temp_citations)
53
+ except Exception as e:
54
+ print(f'{e}, skipped.')
55
+
56
+ all_keys, temp_citations = _augment_func(split_result[1], all_keys, temp_citations)
57
+
58
+ for k in all_keys:
59
+ allowed_keys.append(k)
60
+
61
+ entry_dict = {entry.get('ID'): entry for entry in bib_database.entries}
62
+ filtered_entries = [entry_dict[key] for key in allowed_keys if key in entry_dict]
63
+
64
+ writer = BibTexWriter()
65
+ writer.indent = ' '
66
+ writer.order_entries_by = None
67
+
68
+ new_bib_database = bibtexparser.bibdatabase.BibDatabase()
69
+ new_bib_database.entries = filtered_entries
70
+
71
+ with open(output_bib, 'w', encoding='utf-8') as bibfile:
72
+ bibfile.write(writer.write(new_bib_database))
73
+
74
+ print(f'successfully created {output_bib}')
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: bib_optimizer
3
+ Version: 0.5.1
4
+ Summary: Clean and optimize bib file.
5
+ Author-email: Ka Wa Yip <yipkawa@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Ka Wa Yip
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/kwyip/bib_optimizer
29
+ Project-URL: Issues, https://github.com/kwyip/bib_optimizer/issues
30
+ Keywords: latex,bib,bibliography
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Programming Language :: Python
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Programming Language :: Python :: 3.8
35
+ Classifier: Programming Language :: Python :: 3.9
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: Programming Language :: Python :: 3.14
41
+ Requires-Python: >=3.8
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: bibtexparser<2,>=1.4.3
45
+ Provides-Extra: build
46
+ Requires-Dist: build; extra == "build"
47
+ Requires-Dist: twine; extra == "build"
48
+ Provides-Extra: dev
49
+ Requires-Dist: black; extra == "dev"
50
+ Requires-Dist: bumpver; extra == "dev"
51
+ Requires-Dist: isort; extra == "dev"
52
+ Requires-Dist: mypy; extra == "dev"
53
+ Requires-Dist: pytest; extra == "dev"
54
+ Dynamic: license-file
55
+
56
+ <figure>
57
+ <img src="https://github.com/kwyip/bib_optimizer/blob/main/logo.png?raw=True" alt="logo" height="143" />
58
+ <!-- <figcaption>An elephant at sunset</figcaption> -->
59
+ </figure>
60
+
61
+ [![](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/kwyip/bib_optimizer/blob/main/LICENSE)
62
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/bib_optimizer)](https://pypi.org/project/bib-optimizer/)
63
+ [![Static Badge](https://img.shields.io/badge/CalVer-2025.0416-ff5733)](https://pypi.org/project/bib-optimizer)
64
+ [![Static Badge](https://img.shields.io/badge/PyPI-wheels-d8d805)](https://pypi.org/project/bib-optimizer/#files)
65
+ [![](https://pepy.tech/badge/bib_optimizer/month)](https://pepy.tech/project/bib_optimizer)
66
+
67
+ [bib-optimizer](https://bibopt.github.io/)
68
+ ==========================================
69
+
70
+ Oh, sure, because who doesn't love manually cleaning up messy `.bib` files? `bib_optimizer.py` heroically steps in to remove those lazy, _unused_ citations and _reorder_ the survivors exactly as they appear in the `.tex` file—because, clearly, chaos is the default setting for bibliographies.
71
+
72
+ In layman's terms, it automates bibliography management by:
73
+
74
+ 1. removing unused citations,
75
+ 2. reordering the remaining ones to match their order of appearance in the `.tex` file.
76
+
77
+ **Input Files:**
78
+
79
+ * `main.tex` – The LaTeX source file.
80
+ * `ref.bib` – The original bibliography file.
81
+
82
+ These input files will **remain unchanged**.
83
+
84
+ **Output File:**
85
+
86
+ * `ref_opt.bib` – A placeholder filename for the newly generated, cleaned, and ordered bibliography file.
87
+
88
+ * * *
89
+
90
+ Installation
91
+ ------------
92
+
93
+ ### Install from PyPI with pip
94
+
95
+ Create and activate a virtual environment, then install the latest release from PyPI:
96
+
97
+ ```bash
98
+ python -m venv .venv
99
+
100
+ # Linux/macOS
101
+ source .venv/bin/activate
102
+
103
+ # Windows
104
+ .venv\Scripts\activate
105
+
106
+ python -m pip install --upgrade bib_optimizer
107
+ ```
108
+
109
+ Alternatively, install the command in an isolated environment with [uv](https://docs.astral.sh/uv/):
110
+
111
+ ```bash
112
+ uv tool install bib_optimizer
113
+ ```
114
+
115
+ After either installation method, the `bibopt` command is available in your terminal.
116
+
117
+ ### Install from source for development
118
+
119
+ This repository uses uv for project and dependency management.
120
+
121
+ 1. **Clone the repository**
122
+
123
+ ```bash
124
+ git clone https://github.com/kwyip/bib_optimizer.git
125
+ cd bib_optimizer
126
+ ```
127
+
128
+ 2. **Install environment**
129
+
130
+ ```bash
131
+ # This creates the virtual environment and installs all dependencies
132
+ uv sync
133
+ ```
134
+
135
+ 3. **Activate environment**
136
+
137
+ ```bash
138
+ # Linux/MacOS
139
+ source .venv/bin/activate
140
+
141
+ # Windows
142
+ .venv\Scripts\activate
143
+ ```
144
+
145
+ _🐍 This requires Python 3.8 or newer versions_
146
+
147
+ * * *
148
+
149
+ ### Steps to Clean Your Bibliography
150
+
151
+ 1. **Prepare the input files (e.g., by downloading them from Overleaf)**.
152
+ 2. **Run the command to generate a new `.bib` file (for example, you may name it `ref_opt.bib`)**:
153
+
154
+
155
+        `bibopt main.tex ref.bib ref_opt.bib`
156
+
157
+
158
+
159
+ 3. **Use the Cleaned Bibliography**
160
+ Replace `ref.bib` with `ref_opt.bib` in your LaTeX project.
161
+
162
+ * * *
163
+
164
+ ### Test
165
+
166
+ You may test the installation using the sample input files (`sample_main.tex` and `sample_ref.bib`) located in the test folder.
167
+
168
+ <img src="https://github.com/kwyip/bib_optimizer/blob/main/sample_main_shot.png?raw=True" alt="sample_main_shot" width="34.83%"/>&nbsp;&nbsp;<img src="https://github.com/kwyip/bib_optimizer/blob/main/sample_ref_shot.png?raw=True" alt="sample_ref_shot" width="43%" />
169
+
170
+ `sample_main.tex` _and_ `sample_ref.bib`
171
+
172
+ <img src="https://github.com/kwyip/bib_optimizer/blob/main/sample_ref_opt_shot.png?raw=True" alt="sample_ref_opt_shot" width="43%" />
173
+
174
+ _A sample_ `ref_opt.bib` _created after running_ `bibopt sample_main.tex sample_ref.bib ref_opt.bib`
175
+
176
+ * * *
177
+
178
+ ## Code-free use with an AI agent
179
+
180
+ [**Download `SKILL.md`**](./SKILL.md), then upload these files to your AI agent:
181
+
182
+ - `SKILL.md`,
183
+ - the root `.tex` file,
184
+ - the source `.bib` file, and if any:
185
+ - every `.tex` file referenced through `\input` or `\include`.
186
+
187
+ > [!TIP]
188
+ > Use this prompt:
189
+ >
190
+ > ```text
191
+ > Use the attached `SKILL.md` to optimize the attached LaTeX and BibTeX files.
192
+ > Return only the optimized `.bib` file.
193
+ > ```
194
+
195
+
196
+ https://github.com/user-attachments/assets/2b4e3224-2aee-44c1-974c-812dead72e2f
197
+
198
+
199
+ * * *
200
+
201
+ #### New feature (version 0.4.0)
202
+
203
+ If the `main.tex` calls inputs from other `.tex` (e.g., with `\input{...}`), the newly generated `ref_opt.bib` will preserve the order of appearances in the `main.tex` with each inputted `.tex` as well. \
204
+ (The dependent `.tex` files need to be placed in the same directory as `main.tex`.)
205
+
206
+ ---
207
+ #### New feature (version 0.4.1)
208
+
209
+ On top of version 0.4, skip any `\input` `.tex` file if not found.
210
+
211
+ ---
212
+ #### New feature/Fix (version 0.4.2)
213
+
214
+ Added support for the `\include{...}` command in addition to `\input{...}`, fixing missing citations when a LaTeX project uses `\include` to split its content across files.
215
+
216
+ ---
217
+ #### New feature/Fix (version 0.4.3)
218
+
219
+ Added Python 3.14 support and constrained `bibtexparser` to the compatible 1.x release series, fixing `ModuleNotFoundError: No module named 'bibtexparser.bwriter'` during fresh installations.
220
+
221
+ ---
222
+ #### New feature/Fix (version 0.5.0)
223
+
224
+ Add code-free SKILL.md
225
+
226
+ ♥ Lastly executed on Python `3.14` on 2026-09-29.
@@ -0,0 +1,9 @@
1
+ bib_optimizer/__init__.py,sha256=wtNuHruEXNf66l6yJfYsYwiI1zbxaXAilx4ETNB75lw,32
2
+ bib_optimizer/__main__.py,sha256=acTU0Czt3QFrYU-JuyyJiZEtcMAIxKEd0WEAR4dtAh0,434
3
+ bib_optimizer/helpers.py,sha256=ml0MjhFj51T_Bjk6322Bx21KobsAI34p64fEPPOLhbo,2957
4
+ bib_optimizer-0.5.1.dist-info/licenses/LICENSE,sha256=IzsoHjUTsM_-99MnVs-R6ndlOzyOUAMKUsPWymFOE9A,1066
5
+ bib_optimizer-0.5.1.dist-info/METADATA,sha256=2XsLNeiuO5a5L5Louz6R9TVR9j46zh_cxgYuctoXPaU,7805
6
+ bib_optimizer-0.5.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
7
+ bib_optimizer-0.5.1.dist-info/entry_points.txt,sha256=Dm0EpcwsJZNNfhnn9LYI43WLzVlgEtNFVIFL4oCSPlc,55
8
+ bib_optimizer-0.5.1.dist-info/top_level.txt,sha256=j4x4ncmbt2X7sqnKYX_CbakLJt7NZgWLBIP1PzY8Qog,14
9
+ bib_optimizer-0.5.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ bibopt = bib_optimizer.__main__:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ka Wa Yip
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.
@@ -0,0 +1 @@
1
+ bib_optimizer