pynakes 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.
- pynakes/__init__.py +8 -0
- pynakes/__main__.py +6 -0
- pynakes/_calendar.py +58 -0
- pynakes/_engine_groups.py +88 -0
- pynakes/_engine_helpers.py +741 -0
- pynakes/_engine_keys.py +92 -0
- pynakes/_engine_ops.py +564 -0
- pynakes/_identifiers.py +69 -0
- pynakes/_text_utils.py +163 -0
- pynakes/authors.py +270 -0
- pynakes/batch.py +165 -0
- pynakes/bibtex_parser.py +386 -0
- pynakes/bibtex_writer.py +182 -0
- pynakes/canonical.py +431 -0
- pynakes/capabilities.py +345 -0
- pynakes/cli.py +217 -0
- pynakes/cli_commands/__init__.py +1 -0
- pynakes/cli_commands/_fetch_report.py +39 -0
- pynakes/cli_commands/_reference.py +129 -0
- pynakes/cli_commands/add.py +150 -0
- pynakes/cli_commands/batch.py +87 -0
- pynakes/cli_commands/capabilities.py +34 -0
- pynakes/cli_commands/convert.py +185 -0
- pynakes/cli_commands/dedupe.py +116 -0
- pynakes/cli_commands/edit.py +105 -0
- pynakes/cli_commands/fetch.py +221 -0
- pynakes/cli_commands/fields.py +206 -0
- pynakes/cli_commands/files.py +110 -0
- pynakes/cli_commands/format.py +217 -0
- pynakes/cli_commands/groups.py +355 -0
- pynakes/cli_commands/import_ref.py +176 -0
- pynakes/cli_commands/init.py +302 -0
- pynakes/cli_commands/inspect.py +115 -0
- pynakes/cli_commands/integrity.py +173 -0
- pynakes/cli_commands/keys.py +457 -0
- pynakes/cli_commands/lint.py +68 -0
- pynakes/cli_commands/metadata.py +257 -0
- pynakes/cli_commands/normalize.py +206 -0
- pynakes/cli_commands/remove.py +86 -0
- pynakes/cli_commands/search.py +86 -0
- pynakes/cli_commands/setops.py +360 -0
- pynakes/cli_commands/show.py +48 -0
- pynakes/cli_commands/tex.py +277 -0
- pynakes/cli_commands/used.py +142 -0
- pynakes/cli_common.py +543 -0
- pynakes/cli_discovery.py +326 -0
- pynakes/convert.py +270 -0
- pynakes/dedupe.py +449 -0
- pynakes/diff.py +32 -0
- pynakes/editing.py +421 -0
- pynakes/engine.py +449 -0
- pynakes/fetch.py +695 -0
- pynakes/fetch_progress.py +35 -0
- pynakes/fields.py +280 -0
- pynakes/files.py +222 -0
- pynakes/filestore.py +913 -0
- pynakes/formatters/__init__.py +91 -0
- pynakes/formatters/_case.py +254 -0
- pynakes/formatters/_date.py +91 -0
- pynakes/formatters/_extra.py +130 -0
- pynakes/formatters/_latex.py +494 -0
- pynakes/formatters/_latex_tables.py +154 -0
- pynakes/formatters/_pages.py +32 -0
- pynakes/formatters/_registry.py +87 -0
- pynakes/formatters/_units.py +53 -0
- pynakes/group_tree.py +624 -0
- pynakes/groups.py +73 -0
- pynakes/importer.py +469 -0
- pynakes/inheritance.py +155 -0
- pynakes/initialize.py +264 -0
- pynakes/integrity.py +679 -0
- pynakes/interchange/__init__.py +75 -0
- pynakes/interchange/_shared.py +262 -0
- pynakes/interchange/csl.py +170 -0
- pynakes/interchange/csv.py +72 -0
- pynakes/interchange/endnote.py +171 -0
- pynakes/interchange/mods.py +328 -0
- pynakes/interchange/ris.py +152 -0
- pynakes/io.py +187 -0
- pynakes/journals.py +517 -0
- pynakes/keys.py +363 -0
- pynakes/lint.py +673 -0
- pynakes/metadata/__init__.py +196 -0
- pynakes/metadata/core.py +588 -0
- pynakes/metadata/jabref.py +888 -0
- pynakes/metadata/schema.py +190 -0
- pynakes/model.py +578 -0
- pynakes/normalize.py +540 -0
- pynakes/providers/__init__.py +1 -0
- pynakes/providers/_http.py +255 -0
- pynakes/providers/arxiv.py +133 -0
- pynakes/providers/crossref.py +78 -0
- pynakes/providers/doi.py +31 -0
- pynakes/providers/identity.py +48 -0
- pynakes/providers/openalex.py +122 -0
- pynakes/providers/pdf_overrides.json +106 -0
- pynakes/providers/pdf_overrides.py +61 -0
- pynakes/providers/publisher.py +111 -0
- pynakes/providers/semantic_scholar.py +45 -0
- pynakes/py.typed +0 -0
- pynakes/search.py +222 -0
- pynakes/setops.py +212 -0
- pynakes/usage.py +378 -0
- pynakes-0.5.1.dist-info/METADATA +242 -0
- pynakes-0.5.1.dist-info/RECORD +109 -0
- pynakes-0.5.1.dist-info/WHEEL +5 -0
- pynakes-0.5.1.dist-info/entry_points.txt +2 -0
- pynakes-0.5.1.dist-info/licenses/LICENSE +21 -0
- pynakes-0.5.1.dist-info/top_level.txt +1 -0
pynakes/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""pynakes: Agent-friendly BibTeX library management."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("pynakes")
|
|
7
|
+
except PackageNotFoundError: # running from a source tree that isn't installed
|
|
8
|
+
__version__ = "0.0.0+unknown"
|
pynakes/__main__.py
ADDED
pynakes/_calendar.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Canonical month name/number tables shared across pynakes.
|
|
2
|
+
|
|
3
|
+
Consolidates month-related data that was previously defined independently in
|
|
4
|
+
:mod:`pynakes.model`, :mod:`pynakes.interchange._shared`, and
|
|
5
|
+
:mod:`pynakes.formatters._date`. All three now import from this module,
|
|
6
|
+
guaranteeing a single source of truth.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# Three-letter BibTeX month macros (lowercase) mapped to full month names.
|
|
10
|
+
# This is the same dict historically exposed as ``COMMON_STRINGS`` in model.py.
|
|
11
|
+
MONTH_ABBR_TO_NAME: dict[str, str] = {
|
|
12
|
+
"jan": "January",
|
|
13
|
+
"feb": "February",
|
|
14
|
+
"mar": "March",
|
|
15
|
+
"apr": "April",
|
|
16
|
+
"may": "May",
|
|
17
|
+
"jun": "June",
|
|
18
|
+
"jul": "July",
|
|
19
|
+
"aug": "August",
|
|
20
|
+
"sep": "September",
|
|
21
|
+
"oct": "October",
|
|
22
|
+
"nov": "November",
|
|
23
|
+
"dec": "December",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
MONTH_ABBRS: list[str] = list(MONTH_ABBR_TO_NAME)
|
|
27
|
+
|
|
28
|
+
MONTH_NAMES: list[str] = [name.lower() for name in MONTH_ABBR_TO_NAME.values()]
|
|
29
|
+
|
|
30
|
+
# Three-letter macro → month number string (1-12, BibTeX-compatible).
|
|
31
|
+
# This is the same dict historically exposed as ``MONTH_NUMBERS`` in
|
|
32
|
+
# :mod:`pynakes.interchange._shared`.
|
|
33
|
+
MONTH_ABBR_TO_NUM: dict[str, str] = {
|
|
34
|
+
"jan": "1",
|
|
35
|
+
"feb": "2",
|
|
36
|
+
"mar": "3",
|
|
37
|
+
"apr": "4",
|
|
38
|
+
"may": "5",
|
|
39
|
+
"jun": "6",
|
|
40
|
+
"jul": "7",
|
|
41
|
+
"aug": "8",
|
|
42
|
+
"sep": "9",
|
|
43
|
+
"oct": "10",
|
|
44
|
+
"nov": "11",
|
|
45
|
+
"dec": "12",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Any month name (three-letter abbreviation or full lowercase) → 1-based int.
|
|
49
|
+
_MONTH_TO_NUM: dict[str, int] = {name: i + 1 for i, name in enumerate(MONTH_ABBRS)}
|
|
50
|
+
_MONTH_TO_NUM.update({name: i + 1 for i, name in enumerate(MONTH_NAMES)})
|
|
51
|
+
|
|
52
|
+
# Two-digit month number string → three-letter abbreviation.
|
|
53
|
+
MONTH_NUM_TO_ABBR: dict[str, str] = {f"{i + 1:02d}": abbr for i, abbr in enumerate(MONTH_ABBRS)}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def month_name_to_int(token: str) -> int | None:
|
|
57
|
+
"""Return 1-12 for a month name/abbreviation, or ``None``."""
|
|
58
|
+
return _MONTH_TO_NUM.get(token.strip().lower().rstrip("."))
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Group-operation mixin for :class:`~pynakes.engine.Bibliography`.
|
|
2
|
+
|
|
3
|
+
All methods here delegate to :mod:`pynakes.groups` / :mod:`pynakes.group_tree`;
|
|
4
|
+
the engine derives staged state from their model mutations. Do not import this
|
|
5
|
+
module directly; use ``pynakes.engine``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pynakes import group_tree as group_tree_ops
|
|
11
|
+
from pynakes import groups as group_ops
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BibliographyGroups:
|
|
15
|
+
"""Mixin providing group-tree operations for :class:`~pynakes.engine.Bibliography`.
|
|
16
|
+
|
|
17
|
+
Consumers must not instantiate this class directly.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def list_groups(self) -> list[str]:
|
|
21
|
+
"""Return all group names in first-seen order."""
|
|
22
|
+
return group_ops.list_groups(self.lib)
|
|
23
|
+
|
|
24
|
+
def list_entries_in_group(self, group: str) -> list[str]:
|
|
25
|
+
"""Return entry keys that belong to ``group``."""
|
|
26
|
+
return group_ops.list_entries_in_group(self.lib, group)
|
|
27
|
+
|
|
28
|
+
def add_to_group(self, key: str, group: str) -> int:
|
|
29
|
+
"""Add every entry with ``key`` to ``group``.
|
|
30
|
+
|
|
31
|
+
When the library has a group-tree, the group is also registered as a node
|
|
32
|
+
so the new membership is visible to ``groups tree``/``groups list`` and to
|
|
33
|
+
JabRef: an entry ``groups={X}`` with no ``X`` in the tree is an orphan
|
|
34
|
+
membership, invisible everywhere the tree drives the view. Flat, tree-less
|
|
35
|
+
libraries keep entry-field-only groups (surfaced by ``groups list``).
|
|
36
|
+
"""
|
|
37
|
+
count = group_ops.add_to_group(self.lib, key, group)
|
|
38
|
+
if count and group_tree_ops.list_tree(self.lib) is not None:
|
|
39
|
+
group_tree_ops.add_node(self.lib, group) # no-op if already a node
|
|
40
|
+
return count
|
|
41
|
+
|
|
42
|
+
def remove_from_group(self, key: str, group: str) -> int:
|
|
43
|
+
"""Remove every entry with ``key`` from ``group``."""
|
|
44
|
+
count = group_ops.remove_from_group(self.lib, key, group)
|
|
45
|
+
return count
|
|
46
|
+
|
|
47
|
+
def list_tree(self) -> list[group_tree_ops.GroupNode] | None:
|
|
48
|
+
"""Return the group hierarchy tree, or ``None`` if none defined."""
|
|
49
|
+
return group_tree_ops.list_tree(self.lib)
|
|
50
|
+
|
|
51
|
+
def add_group_node(
|
|
52
|
+
self,
|
|
53
|
+
name: str,
|
|
54
|
+
*,
|
|
55
|
+
parent: str = "",
|
|
56
|
+
context: int = 2,
|
|
57
|
+
color: str = "",
|
|
58
|
+
expanded: bool = True,
|
|
59
|
+
) -> bool:
|
|
60
|
+
"""Add a group node to the tree."""
|
|
61
|
+
ok = group_tree_ops.add_node(
|
|
62
|
+
self.lib, name, parent=parent, context=context, color=color, expanded=expanded
|
|
63
|
+
)
|
|
64
|
+
return ok
|
|
65
|
+
|
|
66
|
+
def remove_group_node(self, name: str) -> int:
|
|
67
|
+
"""Remove a group node and its descendants from the tree."""
|
|
68
|
+
count = group_tree_ops.remove_node(self.lib, name)
|
|
69
|
+
return count
|
|
70
|
+
|
|
71
|
+
def rename_group_node(self, old_name: str, new_name: str) -> bool:
|
|
72
|
+
"""Rename a group node, updating parent references in children."""
|
|
73
|
+
ok = group_tree_ops.rename_node(self.lib, old_name, new_name)
|
|
74
|
+
return ok
|
|
75
|
+
|
|
76
|
+
def move_group_node(self, name: str, new_parent: str) -> bool:
|
|
77
|
+
"""Move a group node to a new parent."""
|
|
78
|
+
ok = group_tree_ops.move_node(self.lib, name, new_parent)
|
|
79
|
+
return ok
|
|
80
|
+
|
|
81
|
+
def update_group_node(self, name: str, **kwargs) -> bool:
|
|
82
|
+
"""Update properties of a group node."""
|
|
83
|
+
ok = group_tree_ops.update_node(self.lib, name, **kwargs)
|
|
84
|
+
return ok
|
|
85
|
+
|
|
86
|
+
def list_entries_in_group_tree(self, group: str, *, strict: bool = False) -> list[str]:
|
|
87
|
+
"""Return entry keys in *group*, including descendants unless *strict*."""
|
|
88
|
+
return group_tree_ops.list_entries_in_group_tree(self.lib, group, strict=strict)
|