Skip to content

middlewares

FieldNormalizationMiddleware

FieldNormalizationMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Normalize field names (journaltitle -> journal, etc.)

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

transform_entry

transform_entry(entry: Entry, *args, **kwargs) -> Entry

Transform entry fields.

Source code in ures/literature/citation/middlewares.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def transform_entry(self, entry: Entry, *args, **kwargs) -> Entry:
    """Transform entry fields."""
    for field in entry.fields:
        # Handle special cases
        key = field.key
        value = field.value
        if key == "pages":
            # Normalize page ranges
            field.value = self._normalize_pages(value)
        else:
            field.value = value
        # Apply field mapping
        rules = self.rule_register.get_rule(entry.entry_type)
        field_mappings = copy.deepcopy(
            self.rule_register.get_default_field_mapping()
        )
        field_mappings.update(rules.field_mappings)
        new_key = field_mappings.get(field.key, field.key)
        field.key = new_key
    return entry

LanguageAsciiNormalizationMiddleware

LanguageAsciiNormalizationMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

normalize_language

normalize_language(language_str: str) -> Any

Normalize language string to ISO 639-1 code.

Source code in ures/literature/citation/middlewares.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
def normalize_language(self, language_str: str) -> Any:
    """Normalize language string to ISO 639-1 code."""
    special_cases = {
        "pinyin": "zh",
    }
    if language_str in special_cases:
        return special_cases[language_str]
    if not isinstance(language_str, str):
        logger.warning(f"Failed to normalize language '{language_str}'")
        return language_str
    language_str = language_str.strip().lower()
    try:
        lang = pycountry.languages.get(name=language_str)
        if lang and hasattr(lang, "alpha_2"):
            return lang.alpha_2
        # Try searching by common name
        for lang in pycountry.languages:
            if language_str in str(lang.name).lower():
                if hasattr(lang, "alpha_2"):
                    return lang.alpha_2
    except:
        logger.warning(f"Failed to normalize language '{language_str}'")
        return language_str
    return language_str

ProceedingsNormalizationMiddleware

ProceedingsNormalizationMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

normailize_proceedings

normailize_proceedings(proceedings_str: str) -> str

Normalize proceedings string to standard format.

Source code in ures/literature/citation/middlewares.py
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
def normailize_proceedings(self, proceedings_str: str) -> str:
    """Normalize proceedings string to standard format."""
    patterns = [
        r"\bIn\s+Proceedings\s+of\s+the\s+",
        r"\bIn\s+Proceedings\s+of\s+",
        r"\bIn\s+Proc\.\s+of\s+the\s+",
        r"\bIn\s+Proc\.\s+of\s+",
        r"\bProceedings\s+of\s+the\s+",
        r"\bProceedings\s+of\s+",
        r"\bProc\.\s+of\s+the\s+",
        r"\bProc\.\s+of\s+",
        r"\bIn\s+(?=\d|\w+\s+(International|Annual|ACM|IEEE))",
        r"\bProc\.\s+",
    ]
    proceedings_str = self._shorten_venue_year(proceedings_str.strip())
    for pattern in patterns:
        if re.search(pattern, proceedings_str, re.IGNORECASE):
            proceedings_str = re.sub(
                pattern, "", proceedings_str, flags=re.IGNORECASE
            )
            proceedings_str = re.sub(r"\s+", " ", proceedings_str).strip()
            break
    prefix_map = {
        "remove": "",
        "full": "In Proceedings of the ",
        "short": "In Proc. of the ",
        "proceedings": "Proceedings of the ",
        "minimal": "In ",
        "proc": "Proc. ",
    }

    style = self.rule_register.get_rule(
        "inproceedings"
    ).formatting.proceedings_style
    prefix = prefix_map.get(style, "full")
    return f"{prefix}{proceedings_str}".strip()

AcmConferenceVenueMiddleware

AcmConferenceVenueMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Put the conference city on the field ACM actually prints.

ACM-Reference-Format appends location or city to the booktitle and prints address after the publisher. Zotero's BibTeX export has only address for Place, and that Place is the venue city. BibLaTeX venue is the event location. For ACM and the default style, move the venue city onto location when location and city are empty. A publisher address is left in place when venue already holds the city. Books and IEEE entries are unchanged.

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

TypeNormalizationMiddleware

TypeNormalizationMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Normalize entry types (conference -> inproceedings, etc.)

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

RuleBasedValidationMiddleware

RuleBasedValidationMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Validate entries against predefined rules.

Source code in ures/literature/citation/middlewares.py
264
265
266
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

transform_entry

transform_entry(entry: Entry, *args, **kwargs)

Validate entry using dataclass rules.

Source code in ures/literature/citation/middlewares.py
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
def transform_entry(self, entry: Entry, *args, **kwargs):
    """Validate entry using dataclass rules."""
    is_valid = True
    rule = self.rule_register.get_rule(entry.entry_type)
    missing_required = []
    for req_field in rule.required_fields:
        if not field_group_present(entry, req_field):
            missing_required.append(req_field)

    if len(missing_required) > 0:
        is_valid = False

    suggested_fields = getattr(rule, "suggested_fields", [])
    if not isinstance(suggested_fields, list):
        suggested_fields = []
    missing_suggested = []
    for spec in suggested_fields:
        if not field_group_present(entry, spec):
            missing_suggested.append(spec)

    is_valid_field = Field(key="is_valid", value=is_valid)
    missing_fields = Field(key="missing_fields", value=missing_required)
    missing_suggested_field = Field(
        key="missing_suggested", value=missing_suggested
    )
    entry.set_field(is_valid_field)
    entry.set_field(missing_fields)
    entry.set_field(missing_suggested_field)

    return entry

OutputCleanupNoneResultMiddleware

OutputCleanupNoneResultMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Cleanup entries that are invalid or have missing required fields.

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

OutputDropForbiddenFieldsMiddleware

OutputDropForbiddenFieldsMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Drop fields the style overlay explicitly removed.

Source code in ures/literature/citation/middlewares.py
30
31
32
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

OutputOnlyDesiredFieldsMiddleware

OutputOnlyDesiredFieldsMiddleware(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Keep only desired fields in the output.

Source code in ures/literature/citation/middlewares.py
329
330
331
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()

OutputLimitMaxAuthors

OutputLimitMaxAuthors(rule_register: Optional[BibRuleRegister] = None)

Bases: CitationMiddleware

Keep only desired fields in the output.

Source code in ures/literature/citation/middlewares.py
362
363
364
def __init__(self, rule_register: Optional[BibRuleRegister] = None):
    super().__init__()
    self.rule_register = rule_register or BibRuleRegister()