Releases: goerz/bibdeskparser
Releases · goerz/bibdeskparser
Release list
v0.3.0
- Added: a
createCLI command, creating a new, empty.bibfile that contains only the standard BibDesk header comment (bibdeskparser create new.bib, orbibdeskparser createto bootstrap the configureddefault_bib_file). It is the one command whoseBIBFILEmust not already exist -- an existing file is never overwritten; every other command still requires an existing file, and the "bibfile not found" error now suggestscreate. [[#24]] - Changed: the first
save()of a from-scratchLibrary(constructed without a path) now always synthesizes the standard BibDesk header, even if the library was never modified; previously an unmodified from-scratch library saved as an empty file. It also now raisesFileExistsErrorif the destination path already exists (a from-scratch library has no baseline timestamp for theStaleFileErrorcheck, so it would previously overwrite silently); to adapt, passforce=Truetosave()to deliberately overwrite an existing file with a from-scratch library. [[#24]] - Fixed:
@stringmacro names are now case-insensitive throughout, matching BibDesk's macro table. Names are normalized to their canonical lowercase form when a file is parsed (both@stringdefinitions and bare macro-reference field values, e.g. from a hand-edited@string{JAN = ...}/month = JAN), lookups inLibrary.strings(reading,in, deleting) match case-insensitively, andLibrary.rename_stringlooks up the old name case-insensitively, normalizes the new name to lowercase instead of rejecting a name containing uppercase letters, and treats a rename onto the same macro (a new name differing at most in case) as a no-op (therename_stringCLI command behaves the same). A hand-edited mixed-case@stringmonth definition now overrides the built-in month macro (and, like any month-macro override, can be deleted while still referenced), and a mixed-case bare reference resolves inLibrary.render,Library.search, and format specifiers. Note that saving a modified library rewrites hand-edited mixed-case macro names in lowercase (BibDesk preserves the case as written while matching case-insensitively). [[#22], [#23]] - Added: the twelve standard BibTeX month macros (
jan...dec) are now always defined, expanding to the full English month names ("January" ... "December"), matching BibDesk's built-in standard macros. A baremonth = janfield resolves inLibrary.render,Library.search, and format specifiers, and no longer counts as an undefined macro when saving, editing, or importing. The built-in macros do not appear inLibrary.stringsand are never written to the.bibfile; a@stringdefinition of the same name overrides them (and, unlike other in-use macros, can be deleted while still referenced, since references then fall back to the built-in month name). [[#21]] - Changed:
Library.keysnow returns atupleof citation keys (instead of the generic set-like view inherited fromcollections.abc.MutableMapping, which did not even display the keys in the REPL) and accepts optionaltypes,has,missing, andemptyfilter arguments, matching the--type/--has/--missing/--emptyoptions of thekeysCLI command (which now delegates to it). To adapt: code that relied on the set operations of the previous view should wrap the result inset(); code that relied on a live view reflecting later mutations should callkeys()again after mutating. [[#16]] - Added: every boolean CLI option that toggles behavior now has an explicit negative form, so that a default can later change without breaking existing invocations:
--fix-uppercase/--no-fix-uppercase(import,add),--keep-keys/--no-keep-keys(import),--skip-missing/--no-skip-missing(show),--remove/--no-remove(replace_file,unlink_file),--check-exists/--no-check-exists(add_file,replace_file), and--auto-file/--no-auto-file(add_file) (subsuming the previous--no-check-existsand--no-auto-fileflags, which keep working; the new--auto-filepositive form forces auto-filing even withoutfile_automatically = truein the configuration). [[#17]] - Added:
Entry.add_abstract, aLibrary.add_abstractthat delegates to it after locating the entry's first attached PDF (paths inEntry.filesare library-relative, so the PDF source is only available through theLibrarymethod), and a correspondingadd_abstractCLI command, fetching the abstract of an existing entry from the best available source -- Crossref (via the entry'sdoi), the text of the entry's first attached PDF (extracted with poppler'spdftotext, when installed), the arXiv API (viaeprint), or Semantic Scholar as a last resort -- cleaning it to plain-unicode prose (LaTeX/JATS math markup converted to unicode, ligature/hyphenation repair, publisher copyright trailers stripped), and validating it with heuristic garble checks. Each result carries its source and a confidence level (high/medium/low/none); only abstracts at or abovemin_confidence/--min-confidence(defaulthigh) are stored, and the CLI reports unstored candidates in full for manual review. Entries that already have a non-empty abstract are skipped unlessoverwrite/--overwriteis given;mark_empty/--mark-emptystores an emptyabstractfield as an "audited, nothing found" marker. New dependency:pylatexenc. - Added: an
add_abstracttable inbibdeskparser.toml, configuring the defaults for themin_confidenceandmark_emptykeyword arguments ofLibrary.add_abstract(and the like-named options of theadd_abstractCLI command); exposed asLibrary.config.add_abstract. An explicit argument or command-line flag always overrides the configured default. [[#18]] - Added:
Entry.add_preprint, a purely delegatingLibrary.add_preprint(likeLibrary.add_url), and a correspondingadd_preprintCLI command, recording the arXiv preprint of an existing entry in itseprintfield (witharchiveprefix = arXiv) -- either an explicitly given identifier (--eprint, no network access), or one found by searching the arXiv API by title and first author. A search result is stored only on a confident match (the entry's DOI, a near-exact title, or a good title corroborated by the first author), and a title-based match postdating the entry's publication year is rejected unless its journal reference corroborates the year. Theeprintfield encodes the audit state: absent = unknown (keys --missing eprint), empty = searched with no preprint found (keys --empty eprint, written bymark_empty/--mark-empty), non-empty = known (mark_emptyalso clears a stalearchiveprefix = arXivalongside the emptiedeprint). Entries with a non-emptyeprintare skipped unlessoverwrite/--overwriteis given; a failed search never modifies the entry. arXiv is the only supported preprint server for now. [[#19]] - Added: an
add_preprinttable inbibdeskparser.toml, configuring the default for themark_emptykeyword argument ofLibrary.add_preprint(and the like-named option of theadd_preprintCLI command); exposed asLibrary.config.add_preprint. An explicit argument or command-line flag always overrides the configured default. [[#19]] - Added: an
add_abstractflag onLibrary.add(--add-abstract/--no-add-abstracton theaddCLI command; default off) that stores the abstract returned alongside the fetched metadata (the publisher's Crossref deposit, or the arXiv summary) in the new entry'sabstractfield, cleaned and validated the same way. [[#20]] - Added: an
add_preprintflag onLibrary.add(--add-preprint/--no-add-preprinton theaddCLI command; default off) that searches arXiv for a preprint matching the newly added entry, exactly asLibrary.add_preprintdoes (skipped when the entry already has aneprint). [[#20]] - Added: an
addtable inbibdeskparser.toml, configuring the defaults for thefix_uppercase,add_abstract, andadd_preprintkeyword arguments ofLibrary.add(and the like-named options of theaddCLI command); exposed asLibrary.config.add. An explicit argument or command-line flag always overrides the configured default. [[#20]]
v0.2.1
- Added:
Library.import_bibtexand a correspondingimportCLI command (reading from a file,--stdin, or--url), importing the entries of a BibTeX snippet -- anything from a single publisher-provided entry to a complete.bibfile -- after thorough sanitization: journals are stored as@stringmacro references (resolved against the library's macros and the newjournal_macrosconfiguration table, or newly created from the journal's lowercased initials, honoring theinitials.journalexceptions; literalarXiv:...pseudo-journals stay literal and deriveeprint/archiveprefix), proper nouns in sentence-case titles and all configuredprotected_wordsare brace-protected, DOIs are normalized to their bare lowercase form, article page ranges collapse to the first page, non-essential article fields (month,publisher,numpages,issn, aurlshadowed by the DOI, ...) are dropped, and citation keys are regenerated (keep_keys/--keep-keysto opt out) from the configuredauto_keyformat or built-in defaults (e.g.GoerzPRA2014, orGoerz2205.15044for arXiv preprints). An entry whose DOI or eprint is already in the library is rejected; any validation problem rejects the whole import (reporting all problems at once) and leaves the library untouched. [[#14]] - Added:
Library.addand a correspondingaddCLI command, fetching bibliographic data by DOI, arXiv identifier, URL, or free-text search -- from Crossref (with DOI content negotiation as the fallback for work types with no BibTeX equivalent) or the arXiv API (respecting its rate limits) -- and adding it as a new entry via the same sanitization asimport_bibtex. The CLI command accepts--dry-run(print the entry instead of saving) and--fix-uppercase(repair all-uppercase publisher metadata, also available onimport). This subsumes the functionality of the getbibtex script. New dependencies:habanero,arxiv, andhttpx. [[#14]] - Added: a
journal_macrostable inbibdeskparser.toml, mapping@stringmacro names to the journal name(s) they stand for (a list value declares publisher-spelling aliases of the same journal), and aprotected_wordslist of words that import always brace-protects inside titles; exposed asLibrary.config.journal_macrosandLibrary.config.protected_words. [[#14]] - Added: CLI commands for working with the fields of a single entry:
fields KEYlists the defined field names,get_field KEY FIELDNAMEprints one field value,set_field KEY FIELDNAME VALUEsets a field (with--literal/--macroto force the value to be stored as literal text or as a bare@stringmacro reference), anddelete_field KEY FIELDNAMEremoves a field. These correspond to thedictinterface ofEntry(iteration, indexing, assignment, anddel). [[#13]] - Added: an
author KEYand aneditor KEYCLI command, printing an entry's authors/editors as structured names (last-name-first; with--json, as objects withfirst/von/last/jrname parts), corresponding to theEntry.authorandEntry.editorproperties. [[#13]] - Added: a
set_type KEY TYPECLI command, changing an entry's type (corresponding to assigningEntry.entry_type). [[#13]] - Added: the
groupsandkeywordsCLI commands accept an optional entryKEY, listing the groups/keywords of that single entry (corresponding to theEntry.groupsandEntry.keywordsproperties) instead of the library-wide mapping. [[#13]] - Added: filter options on the
keysCLI command:--type TYPEkeeps only entries of the given type(s), and--has FIELD/--missing FIELD/--empty FIELDkeep only entries whereFIELDis defined with a non-empty value, not defined at all, or defined but empty, respectively (all repeatable). [[#13]] - Fixed: assigning a
MacroString(e.g. viaset_field --macro) now normalizes the macro name to BibDesk's canonical lowercase form, matching how@stringdefinitions are stored; previously a non-canonical name such asPRAwas stored verbatim and then read back as a literalValueStringinstead of aMacroString. [[#13]] - Fixed: the CLI's top-level
--helpnow shows a complete, un-truncated one-line summary for every subcommand (previously long summaries were cut off with...). [[#11]] - Fixed:
Library.render(and therenderCLI command) now expands@stringmacros in the rendered citation, so a field likejournal = prashows its defined value (e.g.Phys. Rev. A) rather than the bare macro name. [[#12]] - Changed: bump the PyPI
Development Statusclassifier from2 - Pre-Alphato3 - Alpha.
v0.2.0
- Added: automatic filing of file attachments, mirroring BibDesk's AutoFile feature.
Library.rename_filewithout anew_filenamemoves an attachment into the configured auto-file location and renames it according to a file-name format in BibDesk's format-specifier language (the recommended format is%f{Cite Key}%u0%e, naming each file after its entry's citation key while keeping the real extension);Library.add_filefiles newly attached files the same way when auto-filing is in effect (file_automatically = truein the configuration, or explicitformat_spec/auto_file_locationarguments, withauto_file_location=""forcing a plain attach). A file whose name already matches the format is left in place (re-filing is idempotent), and the format's required%u/%U/%nspecifier disambiguates against existing files on disk. Therename_fileandadd_fileCLI commands gain the corresponding options. [[#10]] - Added: an
auto_filetable inbibdeskparser.toml, withformat_spec(a single format or a per-type table),location(the directory files are moved into, relative to the.bibfile or absolute),lowercase,clean, andfile_automaticallykeys, exposed asLibrary.config.auto_file. [[#10]] - Added: the file-name context of the format-specifier language: the
%l/%L/%e/%Eoriginal-file-name specifiers,/as a directory separator, and file-name oriented sanitization (only:is invalid; spaces and non-ASCII text survive). [[#10]] - Changed:
Library.eval_format_specalso evaluates file-name formats, via a newfilenamekeyword argument that selects the file-name dialect (any non-Nonevalue, including"", does so) and supplies the original-name specifiers%l/%L/%e/%E. Thefilenameneed not exist or be one of the entry's attachments; the format is evaluated purely, without touching the filesystem. Iffilenameis an attachment's current path that already matches the format, it evaluates to itself. Theeval_format_specCLI command gains a matching--filenameoption. [[#10]] - Changed:
Library.add_fileandLibrary.rename_filenow return the stored library-relative path of the attachment (previouslyNone),rename_file'snew_filenameargument is optional (omitting it triggers auto-filing), missing parent directories of a rename target are now created automatically, and a rename may move a file across filesystems. To adapt: existing code needs no changes unless it relied onrename_filefailing for a target in a nonexistent directory; the return values can be ignored. [[#10]] - Added: automatic citation-key generation. Calling
Library.rekeywithout anew_keygenerates the key from an auto-key format in BibDesk's format-specifier language (e.g.%a1%c{journal}0%Y%u0), taken from the newauto_keytable ofbibdeskparser.tomlor from the newformat_speckeyword argument. A key that already matches the format is kept unchanged, and a%u/%U/%nspecifier in the format disambiguates collisions, like in BibDesk. TherekeyCLI command correspondingly makesNEW_KEYoptional, adds a--format-spec PATTERNoption, and prints the generated key. [[#9]] - Added:
Library.eval_format_specand a matching read-onlyeval_format_specCLI command, evaluating an auto-key format for an entry and returning the key it yields, without renaming anything. A key that already matches the format evaluates to itself, so this identifies the entries whose citation key does not follow a given format. [[#9]] - Added: per-type auto-key formats. The
auto_keytable'sformat_specmay be a table mapping each entry type to its own format (with""as the fallback for unlisted types), so a mixed-type library can namejournalfor articles,booktitlefor conference papers, and so on. Theauto_keysettings are also available and settable asLibrary.config.auto_key(withformat_spec,lowercase, andcleanattributes). [[#9]] - Added: an
initialstable inbibdeskparser.toml, defining per-field exceptions (e.g. journal or conference-proceedings initials) to the acronym that the%cformat specifier builds from a field value. [[#9]] - Added: a "Format Specifiers" reference page documenting the format-specifier language. [[#9]]
- Changed:
Library.rekeynow returns the resulting citation key (previouslyNone). [[#9]] - Added: a "How to give an AI coding agent access to your library" how-to guide, describing the lightweight path for letting a shell-capable agent (such as Claude Code) drive the
bibdeskparserCLI, and expanded the top-level--helptext to orient such callers (read-only vs. mutating commands,--json, exit codes). [[#8]] - Added:
Library.editandLibrary.edit_stringsaccept a function foreditor, as an alternative to an editor command string. The function receives the path of the temporary file and must edit it in place; validation problems then raise aValueErrorinstead of prompting interactively. [[#8]] - Added: a
--stdinoption on theeditandedit_stringsCLI commands, reading the full edited text from standard input instead of opening an editor, and a--biboption onstrings, printing the@stringdefinitions as re-parseable@string{name = {value}}lines. Together withexport, these allow non-interactive (e.g., scripted or AI-agent) editing via pipes:export KEY... | ... | edit KEY... --stdinandstrings --bib | ... | edit_strings --stdin. [[#8]] - Changed: the
editandedit_stringsCLI commands now fail immediately with a usage error when invoked without a terminal on standard input and without--stdinor an explicit--editor, instead of blocking on$EDITOR. Non-interactive callers must pass--stdin(piping in the edited text) or--editorwith a command that needs no terminal. [[#8]] - Fixed: newly added entries, new
@stringmacros, and a newly synthesized static-groups@commentblock were appended at the very end of the.bibfile, after BibDesk's group@commentblocks. They are now written at their canonical position: macros in the alphabetically sorted@stringrun before the first entry, entries before the group@commentblocks, and the static-groups block before the smart-groups block, matching the layout BibDesk itself writes. - Added:
Library.searchand a correspondingsearchCLI subcommand: find entries matching a query, ranked best match first. Matching runs against the stored field values (bare@stringmacro names intact), the decoded Unicode values, and macro expansions, with accent-insensitive, word-overlap, fuzzy, and regex match levels, optionally limited to specific fields. [[#5]] - Added: a
bibdeskparsercommand-line tool that exposes the publicLibraryAPI as subcommands (keys,show,render,export,add_to_group,set_string,edit, ...). Data-output commands accept--json; the.bibfile argument may be omitted whendefault_bib_fileis configured. [[#4]] - Added: a
default_bib_fileoption inbibdeskparser.toml, naming the.bibfile the command-line tool operates on when none is given. [[#4]] - Added: the
BIBDESKPARSER_CONFIGenvironment variable, naming the user-levelbibdeskparser.tomlin place of the XDG location. Setting it to an empty value disables the user-level configuration entirely. [[#7]] - Added:
MacroString, mirroringValueString, to force a field value to be stored as a bare@stringmacro reference. Both are subtypes ofstr. - Added:
Entry.add_url,Entry.replace_url,Entry.remove_urland the correspondingLibrary.add_url,Library.replace_url,Library.remove_urlmethods for managing an entry's linked URLs. - Added: validation and normalization of
Entrytypes: constructing or assigning an entry type now lowercases it and rejects unrecognized types with aValueError. Loading a.bibfile still never validates. - Added: validation of the
author/editorfields: assigning an unparseable value raisesValueError. - Added: a
UserWarningwhen assigning a field that is not appropriate for the entry type. - Added: a "Bib Entry Types" reference page documenting the supported entry types and fields.
- Added: support for a
bibdeskparser.tomlconfiguration file (searched for next to the.bibfile and in the XDG config location), withverify_typesandverify_fieldsflags to disable entry-type validation and field-appropriateness warnings, andtypes/fieldstables to define custom entry types and fields or extend the built-in ones. The active configuration is exposed as theLibrary.configclass attribute (equally readable from a library instance asbib.config), whose attributes --verify_types,verify_fields,config_file,auto_key, and others -- can be assigned for in-process overrides that never write back to the configuration file. - Added: a "Configuration" reference page documenting the
bibdeskparser.tomlfile. - Changed:
Valuehas been renamed toValueString(breaking: renameValuetoValueStringin your code). Values returned by theEntrydict interface are nowValueString(for literal/braced values) orMacroString(for bare@stringmacro references) instances; both arestrsubclasses and compare as plain strings. - Changed:
Entry.urlsis now a read-only tuple (breaking: replace assignment toentry.urlswith the newadd_url/replace_url/remove_urlmethods). - Changed: the
keywordsfield is now readable through theEntrydict interface (indexing an entry bykeywordsreturns the comma-joined string). It is still not writable that way, and theEntry.keywordsproperty remains read-only; keywords are edited only through the owningLibrary. - Removed: the public
Entry.dirtyproperty (breaking: there is no public replacement; it was an internal detail).