• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iplweb / bpp / da7dd963-c5b3-44a5-91d8-08db9f55e4f1

11 Aug 2025 09:44AM UTC coverage: 46.068% (-0.6%) from 46.671%
da7dd963-c5b3-44a5-91d8-08db9f55e4f1

push

circleci

mpasternak
Merge branch 'release/v202508.1184'

164 of 864 new or added lines in 29 files covered. (18.98%)

3127 existing lines in 197 files now uncovered.

17450 of 37879 relevant lines covered (46.07%)

1.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.93
src/bpp/bibtex_export.py
1
"""
2
BibTeX export functionality for BPP publication models.
3

4
This module provides utilities to export Wydawnictwo_Ciagle and Wydawnictwo_Zwarte
5
models to BibTeX format.
6
"""
7
import re
3✔
8

9

10
def sanitize_bibtex_string(text: str) -> str:
3✔
11
    """
12
    Sanitize a string for use in BibTeX format.
13

14
    Args:
15
        text: Input string to sanitize
16

17
    Returns:
18
        Sanitized string safe for BibTeX
19
    """
NEW
20
    if not text:
×
NEW
21
        return ""
×
22

23
    # Remove or replace problematic characters
NEW
24
    text = str(text)
×
NEW
25
    text = text.replace("{", "\\{")
×
NEW
26
    text = text.replace("}", "\\}")
×
NEW
27
    text = text.replace("&", "\\&")
×
NEW
28
    text = text.replace("%", "\\%")
×
NEW
29
    text = text.replace("$", "\\$")
×
NEW
30
    text = text.replace("#", "\\#")
×
NEW
31
    text = text.replace("_", "\\_")
×
NEW
32
    text = text.replace("^", "\\^")
×
NEW
33
    text = text.replace("~", "\\~")
×
34

NEW
35
    return text.strip()
×
36

37

38
def format_authors_bibtex(wydawnictwo) -> str:
3✔
39
    """
40
    Format authors for BibTeX export.
41

42
    Args:
43
        wydawnictwo: Wydawnictwo_Ciagle or Wydawnictwo_Zwarte instance
44

45
    Returns:
46
        Formatted author string for BibTeX
47
    """
NEW
48
    authors = []
×
NEW
49
    try:
×
NEW
50
        for autor_obj in wydawnictwo.autorzy_dla_opisu():
×
NEW
51
            if hasattr(autor_obj, "zapisany_jako") and autor_obj.zapisany_jako:
×
NEW
52
                authors.append(autor_obj.zapisany_jako)
×
NEW
53
            elif hasattr(autor_obj, "autor"):
×
NEW
54
                full_name = f"{autor_obj.autor.nazwisko}, {autor_obj.autor.imiona}"
×
NEW
55
                authors.append(full_name)
×
NEW
56
    except Exception:
×
57
        # Fallback to cached authors if available
NEW
58
        if (
×
59
            hasattr(wydawnictwo, "opis_bibliograficzny_autorzy_cache")
60
            and wydawnictwo.opis_bibliograficzny_autorzy_cache
61
        ):
NEW
62
            authors = [
×
63
                f"{author.split()[-1]}, {' '.join(author.split()[:-1])}"
64
                for author in wydawnictwo.opis_bibliograficzny_autorzy_cache
65
            ]
66

NEW
67
    return " and ".join(authors)
×
68

69

70
def generate_bibtex_key(wydawnictwo) -> str:
3✔
71
    """
72
    Generate a unique BibTeX citation key.
73

74
    Args:
75
        wydawnictwo: Wydawnictwo_Ciagle or Wydawnictwo_Zwarte instance
76

77
    Returns:
78
        Generated BibTeX key
79
    """
80
    # Use first author's surname if available
NEW
81
    key_parts = []
×
82

NEW
83
    try:
×
NEW
84
        first_author = wydawnictwo.autorzy_dla_opisu().first()
×
NEW
85
        if first_author and hasattr(first_author, "autor"):
×
NEW
86
            surname = first_author.autor.nazwisko
×
87
            # Clean surname for key
NEW
88
            surname = re.sub(r"[^a-zA-Z0-9]", "", surname)
×
NEW
89
            key_parts.append(surname)
×
NEW
90
    except Exception:
×
NEW
91
        pass
×
92

93
    # Add year
NEW
94
    if hasattr(wydawnictwo, "rok") and wydawnictwo.rok:
×
NEW
95
        key_parts.append(str(wydawnictwo.rok))
×
96

97
    # Add ID as fallback or uniqueness
NEW
98
    key_parts.append(f"id{wydawnictwo.pk}")
×
99

NEW
100
    return "_".join(key_parts)
×
101

102

103
def wydawnictwo_ciagle_to_bibtex(wydawnictwo_ciagle) -> str:
3✔
104
    """
105
    Convert Wydawnictwo_Ciagle instance to BibTeX format.
106

107
    Args:
108
        wydawnictwo_ciagle: Wydawnictwo_Ciagle model instance
109

110
    Returns:
111
        BibTeX formatted string
112
    """
NEW
113
    key = generate_bibtex_key(wydawnictwo_ciagle)
×
NEW
114
    authors = format_authors_bibtex(wydawnictwo_ciagle)
×
115

NEW
116
    bibtex_entry = f"@article{{{key},\n"
×
117

118
    # Title
NEW
119
    if wydawnictwo_ciagle.tytul_oryginalny:
×
NEW
120
        title = sanitize_bibtex_string(wydawnictwo_ciagle.tytul_oryginalny)
×
NEW
121
        bibtex_entry += f"  title = {{{title}}},\n"
×
122

123
    # Authors
NEW
124
    if authors:
×
NEW
125
        bibtex_entry += f"  author = {{{sanitize_bibtex_string(authors)}}},\n"
×
126

127
    # Journal
NEW
128
    if hasattr(wydawnictwo_ciagle, "zrodlo") and wydawnictwo_ciagle.zrodlo:
×
NEW
129
        journal = sanitize_bibtex_string(wydawnictwo_ciagle.zrodlo.nazwa)
×
NEW
130
        bibtex_entry += f"  journal = {{{journal}}},\n"
×
131

132
    # Year
NEW
133
    if wydawnictwo_ciagle.rok:
×
NEW
134
        bibtex_entry += f"  year = {{{wydawnictwo_ciagle.rok}}},\n"
×
135

136
    # Volume (tom)
NEW
137
    if hasattr(wydawnictwo_ciagle, "numer_tomu") and wydawnictwo_ciagle.numer_tomu():
×
NEW
138
        volume = sanitize_bibtex_string(str(wydawnictwo_ciagle.numer_tomu()))
×
NEW
139
        bibtex_entry += f"  volume = {{{volume}}},\n"
×
140

141
    # Number (numer wydania/zeszytu)
NEW
142
    if (
×
143
        hasattr(wydawnictwo_ciagle, "numer_wydania")
144
        and wydawnictwo_ciagle.numer_wydania()
145
    ):
NEW
146
        number = sanitize_bibtex_string(str(wydawnictwo_ciagle.numer_wydania()))
×
NEW
147
        bibtex_entry += f"  number = {{{number}}},\n"
×
148

149
    # Pages
NEW
150
    if (
×
151
        hasattr(wydawnictwo_ciagle, "zakres_stron")
152
        and wydawnictwo_ciagle.zakres_stron()
153
    ):
NEW
154
        pages = sanitize_bibtex_string(str(wydawnictwo_ciagle.zakres_stron()))
×
NEW
155
        bibtex_entry += f"  pages = {{{pages}}},\n"
×
156

157
    # DOI
NEW
158
    if hasattr(wydawnictwo_ciagle, "doi") and wydawnictwo_ciagle.doi:
×
NEW
159
        doi = sanitize_bibtex_string(wydawnictwo_ciagle.doi)
×
NEW
160
        bibtex_entry += f"  doi = {{{doi}}},\n"
×
161

162
    # ISSN
NEW
163
    if hasattr(wydawnictwo_ciagle, "issn") and wydawnictwo_ciagle.issn:
×
NEW
164
        issn = sanitize_bibtex_string(wydawnictwo_ciagle.issn)
×
NEW
165
        bibtex_entry += f"  issn = {{{issn}}},\n"
×
166

167
    # URL
NEW
168
    if hasattr(wydawnictwo_ciagle, "www") and wydawnictwo_ciagle.www:
×
NEW
169
        url = sanitize_bibtex_string(wydawnictwo_ciagle.www)
×
NEW
170
        bibtex_entry += f"  url = {{{url}}},\n"
×
171

172
    # Remove trailing comma and newline, add closing brace
NEW
173
    bibtex_entry = bibtex_entry.rstrip(",\n") + "\n}\n"
×
174

NEW
175
    return bibtex_entry
×
176

177

178
def wydawnictwo_zwarte_to_bibtex(wydawnictwo_zwarte) -> str:
3✔
179
    """
180
    Convert Wydawnictwo_Zwarte instance to BibTeX format.
181

182
    Args:
183
        wydawnictwo_zwarte: Wydawnictwo_Zwarte model instance
184

185
    Returns:
186
        BibTeX formatted string
187
    """
NEW
188
    key = generate_bibtex_key(wydawnictwo_zwarte)
×
NEW
189
    authors = format_authors_bibtex(wydawnictwo_zwarte)
×
190

191
    # Determine entry type based on characteristics
NEW
192
    entry_type = "book"
×
NEW
193
    if (
×
194
        hasattr(wydawnictwo_zwarte, "wydawnictwo_nadrzedne")
195
        and wydawnictwo_zwarte.wydawnictwo_nadrzedne
196
    ):
NEW
197
        entry_type = "incollection"  # Chapter in book
×
NEW
198
    elif (
×
199
        hasattr(wydawnictwo_zwarte, "charakter_formalny")
200
        and wydawnictwo_zwarte.charakter_formalny
201
    ):
NEW
202
        charakter = wydawnictwo_zwarte.charakter_formalny.nazwa.lower()
×
NEW
203
        if "rozdziaƂ" in charakter or "chapter" in charakter:
×
NEW
204
            entry_type = "incollection"
×
NEW
205
        elif "konferencja" in charakter or "conference" in charakter:
×
NEW
206
            entry_type = "inproceedings"
×
207

NEW
208
    bibtex_entry = f"@{entry_type}{{{key},\n"
×
209

210
    # Title
NEW
211
    if wydawnictwo_zwarte.tytul_oryginalny:
×
NEW
212
        title = sanitize_bibtex_string(wydawnictwo_zwarte.tytul_oryginalny)
×
NEW
213
        bibtex_entry += f"  title = {{{title}}},\n"
×
214

215
    # Authors
NEW
216
    if authors:
×
NEW
217
        bibtex_entry += f"  author = {{{sanitize_bibtex_string(authors)}}},\n"
×
218

219
    # Publisher
NEW
220
    if (
×
221
        hasattr(wydawnictwo_zwarte, "get_wydawnictwo")
222
        and wydawnictwo_zwarte.get_wydawnictwo()
223
    ):
NEW
224
        publisher = sanitize_bibtex_string(wydawnictwo_zwarte.get_wydawnictwo())
×
NEW
225
        bibtex_entry += f"  publisher = {{{publisher}}},\n"
×
226

227
    # Year and address from miejsce_i_rok
NEW
228
    if (
×
229
        hasattr(wydawnictwo_zwarte, "miejsce_i_rok")
230
        and wydawnictwo_zwarte.miejsce_i_rok
231
    ):
NEW
232
        miejsce_i_rok = wydawnictwo_zwarte.miejsce_i_rok.strip()
×
233
        # Try to extract address and year
NEW
234
        parts = miejsce_i_rok.split()
×
NEW
235
        if parts:
×
236
            # Last part might be year if it's 4 digits
NEW
237
            if len(parts) > 1 and re.match(r"\d{4}", parts[-1]):
×
238
                # year_from_field = parts[-1]
NEW
239
                address = " ".join(parts[:-1])
×
NEW
240
                if address:
×
NEW
241
                    bibtex_entry += (
×
242
                        f"  address = {{{sanitize_bibtex_string(address)}}},\n"
243
                    )
244
            else:
245
                # Whole field as address
NEW
246
                bibtex_entry += (
×
247
                    f"  address = {{{sanitize_bibtex_string(miejsce_i_rok)}}},\n"
248
                )
249

250
    # Year
NEW
251
    if wydawnictwo_zwarte.rok:
×
NEW
252
        bibtex_entry += f"  year = {{{wydawnictwo_zwarte.rok}}},\n"
×
253

254
    # Pages
NEW
255
    if hasattr(wydawnictwo_zwarte, "strony") and wydawnictwo_zwarte.strony:
×
NEW
256
        pages = sanitize_bibtex_string(wydawnictwo_zwarte.strony)
×
NEW
257
        bibtex_entry += f"  pages = {{{pages}}},\n"
×
258

259
    # For chapters, add booktitle (parent publication)
NEW
260
    if (
×
261
        entry_type == "incollection"
262
        and hasattr(wydawnictwo_zwarte, "wydawnictwo_nadrzedne")
263
        and wydawnictwo_zwarte.wydawnictwo_nadrzedne
264
    ):
NEW
265
        if wydawnictwo_zwarte.wydawnictwo_nadrzedne.tytul_oryginalny:
×
NEW
266
            booktitle = sanitize_bibtex_string(
×
267
                wydawnictwo_zwarte.wydawnictwo_nadrzedne.tytul_oryginalny
268
            )
NEW
269
            bibtex_entry += f"  booktitle = {{{booktitle}}},\n"
×
270

271
    # DOI
NEW
272
    if hasattr(wydawnictwo_zwarte, "doi") and wydawnictwo_zwarte.doi:
×
NEW
273
        doi = sanitize_bibtex_string(wydawnictwo_zwarte.doi)
×
NEW
274
        bibtex_entry += f"  doi = {{{doi}}},\n"
×
275

276
    # ISBN
NEW
277
    if hasattr(wydawnictwo_zwarte, "isbn") and wydawnictwo_zwarte.isbn:
×
NEW
278
        isbn = sanitize_bibtex_string(wydawnictwo_zwarte.isbn)
×
NEW
279
        bibtex_entry += f"  isbn = {{{isbn}}},\n"
×
280

281
    # URL
NEW
282
    if hasattr(wydawnictwo_zwarte, "www") and wydawnictwo_zwarte.www:
×
NEW
283
        url = sanitize_bibtex_string(wydawnictwo_zwarte.www)
×
NEW
284
        bibtex_entry += f"  url = {{{url}}},\n"
×
285

286
    # Edition
NEW
287
    if (
×
288
        hasattr(wydawnictwo_zwarte, "oznaczenie_wydania")
289
        and wydawnictwo_zwarte.oznaczenie_wydania
290
    ):
NEW
291
        edition = sanitize_bibtex_string(wydawnictwo_zwarte.oznaczenie_wydania)
×
NEW
292
        bibtex_entry += f"  edition = {{{edition}}},\n"
×
293

294
    # Series
NEW
295
    if (
×
296
        hasattr(wydawnictwo_zwarte, "seria_wydawnicza")
297
        and wydawnictwo_zwarte.seria_wydawnicza
298
    ):
NEW
299
        series = sanitize_bibtex_string(wydawnictwo_zwarte.seria_wydawnicza.nazwa)
×
NEW
300
        bibtex_entry += f"  series = {{{series}}},\n"
×
301

302
    # Remove trailing comma and newline, add closing brace
NEW
303
    bibtex_entry = bibtex_entry.rstrip(",\n") + "\n}\n"
×
304

NEW
305
    return bibtex_entry
×
306

307

308
def export_to_bibtex(publications) -> str:
3✔
309
    """
310
    Export multiple publications to BibTeX format.
311

312
    Args:
313
        publications: Queryset or list of Wydawnictwo_Ciagle/Wydawnictwo_Zwarte instances
314

315
    Returns:
316
        Complete BibTeX file content as string
317
    """
NEW
318
    bibtex_entries = []
×
319

NEW
320
    for pub in publications:
×
NEW
321
        if hasattr(pub, "_meta"):
×
NEW
322
            model_name = pub._meta.model_name
×
NEW
323
            if model_name == "wydawnictwo_ciagle":
×
NEW
324
                bibtex_entries.append(wydawnictwo_ciagle_to_bibtex(pub))
×
NEW
325
            elif model_name == "wydawnictwo_zwarte":
×
NEW
326
                bibtex_entries.append(wydawnictwo_zwarte_to_bibtex(pub))
×
327

NEW
328
    return "\n".join(bibtex_entries)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc