refkit 0.1.1__cp310-abi3-win_amd64.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.
refkit/__init__.py ADDED
@@ -0,0 +1,138 @@
1
+ """Citation parsing, rendering, and BibTeX editing."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.metadata import version as _metadata_version
6
+ from os import PathLike
7
+
8
+ from . import _native as _core
9
+ from . import types as types
10
+
11
+ __version__ = _metadata_version("refkit")
12
+
13
+
14
+ def _ensure_native_version() -> None:
15
+ if _core.__version__ == __version__:
16
+ return
17
+ raise SystemError(
18
+ f"The installed refkit extension version ({_core.__version__}) is incompatible "
19
+ f"with refkit {__version__}. Reinstall refkit from one release."
20
+ )
21
+
22
+
23
+ _ensure_native_version()
24
+
25
+ BibDocument = _core.BibDocument
26
+ BibEntry = _core.BibEntry
27
+ BibEntryMap = _core.BibEntryMap
28
+ BibField = _core.BibField
29
+ BibFieldMap = _core.BibFieldMap
30
+ Citation = _core.Citation
31
+ CitationGroup = _core.CitationGroup
32
+ Cite = _core.Cite
33
+ Document = _core.Document
34
+ Entry = _core.Entry
35
+ Library = _core.Library
36
+ Locale = _core.Locale
37
+ MissingReferenceError = _core.MissingReferenceError
38
+ RefkitError = _core.RefkitError
39
+ ParseError = _core.ParseError
40
+ Rendered = _core.Rendered
41
+ RenderedDocument = _core.RenderedDocument
42
+ Style = _core.Style
43
+ TidyError = _core.TidyError
44
+ TidyOptions = _core.TidyOptions
45
+ TidyResult = _core.TidyResult
46
+ TidySyntaxError = _core.TidySyntaxError
47
+ TidyWarning = _core.TidyWarning
48
+ build_info = _core.build_info
49
+ build_mode = _core.build_mode
50
+
51
+ __all__ = [
52
+ "BibDocument",
53
+ "BibEntry",
54
+ "BibEntryMap",
55
+ "BibField",
56
+ "BibFieldMap",
57
+ "Citation",
58
+ "Cite",
59
+ "CitationGroup",
60
+ "RefkitError",
61
+ "ParseError",
62
+ "Document",
63
+ "Entry",
64
+ "Library",
65
+ "Locale",
66
+ "MissingReferenceError",
67
+ "Rendered",
68
+ "RenderedDocument",
69
+ "Style",
70
+ "TidyError",
71
+ "TidyOptions",
72
+ "TidyResult",
73
+ "TidySyntaxError",
74
+ "TidyWarning",
75
+ "build_info",
76
+ "build_mode",
77
+ "cite",
78
+ "full_bibliography",
79
+ "tidy_bibtex",
80
+ "tidy_file",
81
+ "__version__",
82
+ "types",
83
+ ]
84
+
85
+
86
+ def tidy_bibtex(
87
+ source: str,
88
+ *,
89
+ options: TidyOptions | None = None,
90
+ ) -> TidyResult:
91
+ """Format BibTeX text and return the formatted source plus warnings."""
92
+
93
+ return _core.tidy_bibtex(source, options=options)
94
+
95
+
96
+ def tidy_file(
97
+ path: str | PathLike[str],
98
+ *,
99
+ output: str | PathLike[str] | None = None,
100
+ options: TidyOptions | None = None,
101
+ ) -> TidyResult:
102
+ """Read a BibTeX file, format it, and write the result when `output` is set."""
103
+
104
+ result = BibDocument.read(path).tidy(options=options)
105
+ if output is not None:
106
+ _core._write_bibtex(output, result.bibtex)
107
+ return result
108
+
109
+
110
+ def cite(
111
+ source: str | PathLike[str],
112
+ citation: str | Cite | CitationGroup,
113
+ *,
114
+ style: str | Style = "apa",
115
+ locale: str | Locale | None = "en-US",
116
+ ) -> Rendered:
117
+ """Read `source` and render one citation."""
118
+
119
+ library = Library.read(source)
120
+ loaded_style = Style.load(style) if isinstance(style, str) else style
121
+ rendered = Document(library, loaded_style, locale=locale).render(
122
+ [Citation("citation", citation)]
123
+ )
124
+ return rendered["citation"]
125
+
126
+
127
+ def full_bibliography(
128
+ source: str | PathLike[str],
129
+ *,
130
+ style: str | Style = "apa",
131
+ locale: str | Locale | None = "en-US",
132
+ ) -> Rendered:
133
+ """Read `source` and render every entry as a bibliography."""
134
+
135
+ library = Library.read(source)
136
+ loaded_style = Style.load(style) if isinstance(style, str) else style
137
+ document = Document(library, loaded_style, locale=locale)
138
+ return document.full_bibliography()
refkit/__init__.pyi ADDED
@@ -0,0 +1,91 @@
1
+ from os import PathLike
2
+
3
+ from . import types as types
4
+ from ._native import (
5
+ BibDocument,
6
+ BibEntry,
7
+ BibEntryMap,
8
+ BibField,
9
+ BibFieldMap,
10
+ Citation,
11
+ CitationGroup,
12
+ Cite,
13
+ Document,
14
+ Entry,
15
+ Library,
16
+ Locale,
17
+ MissingReferenceError,
18
+ ParseError,
19
+ RefkitError,
20
+ Rendered,
21
+ RenderedDocument,
22
+ Style,
23
+ TidyError,
24
+ TidyOptions,
25
+ TidyResult,
26
+ TidySyntaxError,
27
+ TidyWarning,
28
+ build_info,
29
+ build_mode,
30
+ )
31
+
32
+ __all__ = [
33
+ "BibDocument",
34
+ "BibEntry",
35
+ "BibEntryMap",
36
+ "BibField",
37
+ "BibFieldMap",
38
+ "Citation",
39
+ "Cite",
40
+ "CitationGroup",
41
+ "RefkitError",
42
+ "ParseError",
43
+ "Document",
44
+ "Entry",
45
+ "Library",
46
+ "Locale",
47
+ "MissingReferenceError",
48
+ "Rendered",
49
+ "RenderedDocument",
50
+ "Style",
51
+ "TidyError",
52
+ "TidyOptions",
53
+ "TidyResult",
54
+ "TidySyntaxError",
55
+ "TidyWarning",
56
+ "build_info",
57
+ "build_mode",
58
+ "cite",
59
+ "full_bibliography",
60
+ "tidy_bibtex",
61
+ "tidy_file",
62
+ "__version__",
63
+ "types",
64
+ ]
65
+
66
+ __version__: str
67
+
68
+ def tidy_bibtex(
69
+ source: str,
70
+ *,
71
+ options: TidyOptions | None = None,
72
+ ) -> TidyResult: ...
73
+ def tidy_file(
74
+ path: str | PathLike[str],
75
+ *,
76
+ output: str | PathLike[str] | None = None,
77
+ options: TidyOptions | None = None,
78
+ ) -> TidyResult: ...
79
+ def cite(
80
+ source: str | PathLike[str],
81
+ citation: str | Cite | CitationGroup,
82
+ *,
83
+ style: str | Style = "apa",
84
+ locale: str | Locale | None = "en-US",
85
+ ) -> Rendered: ...
86
+ def full_bibliography(
87
+ source: str | PathLike[str],
88
+ *,
89
+ style: str | Style = "apa",
90
+ locale: str | Locale | None = "en-US",
91
+ ) -> Rendered: ...
refkit/_native.pyd ADDED
Binary file
refkit/_native.pyi ADDED
@@ -0,0 +1,272 @@
1
+ from collections.abc import Iterable
2
+ from os import PathLike
3
+ from typing import Literal, TypeAlias
4
+
5
+ from .types import (
6
+ BibliographyLayout,
7
+ Diagnostic,
8
+ ProjectionRow,
9
+ RawBlock,
10
+ RawFailedBlock,
11
+ RenderedTree,
12
+ TidyRename,
13
+ )
14
+
15
+ __version__: str
16
+ build_info: str
17
+ build_mode: Literal["debug", "release"]
18
+ _RecoveryPolicy: TypeAlias = Literal["error", "report"]
19
+ _DuplicateRule: TypeAlias = Literal["doi", "key", "abstract", "citation"]
20
+ _MergeStrategy: TypeAlias = Literal["first", "last", "combine", "overwrite"]
21
+
22
+ class RefkitError(Exception): ...
23
+
24
+ class ParseError(RefkitError):
25
+ diagnostics: list[Diagnostic]
26
+
27
+ class MissingReferenceError(RefkitError): ...
28
+ class TidyError(RefkitError): ...
29
+
30
+ class TidySyntaxError(TidyError):
31
+ line: int
32
+ column: int
33
+ byte: int
34
+ character: str | None
35
+ message: str
36
+
37
+ class TidyOptions:
38
+ def __init__(
39
+ self,
40
+ *,
41
+ omit: Iterable[str] | None = None,
42
+ curly: bool = False,
43
+ numeric: bool = False,
44
+ months: bool = False,
45
+ space: int = 2,
46
+ tab: bool = False,
47
+ align: bool | int | None = 14,
48
+ blank_lines: bool = False,
49
+ sort: bool | Iterable[str] | None = None,
50
+ duplicates: Iterable[_DuplicateRule] | None = None,
51
+ merge: _MergeStrategy | None = None,
52
+ strip_enclosing_braces: bool = False,
53
+ drop_all_caps: bool = False,
54
+ escape: bool = True,
55
+ sort_fields: bool | Iterable[str] | None = None,
56
+ strip_comments: bool = False,
57
+ trailing_commas: bool = False,
58
+ encode_urls: bool = False,
59
+ tidy_comments: bool = True,
60
+ remove_empty_fields: bool = False,
61
+ remove_duplicate_fields: bool = True,
62
+ generate_keys: bool | str | None = None,
63
+ max_authors: int | None = None,
64
+ lowercase: bool = True,
65
+ enclosing_braces: bool | Iterable[str] | None = None,
66
+ remove_braces: bool | Iterable[str] | None = None,
67
+ wrap: bool | int | None = None,
68
+ ) -> None: ...
69
+
70
+ class TidyWarning:
71
+ @property
72
+ def code(self) -> Literal["missing_key", "duplicate_entry"]: ...
73
+ @property
74
+ def rule(self) -> _DuplicateRule | None: ...
75
+ @property
76
+ def message(self) -> str: ...
77
+
78
+ class TidyResult:
79
+ @property
80
+ def bibtex(self) -> str: ...
81
+ @property
82
+ def warnings(self) -> list[TidyWarning]: ...
83
+ @property
84
+ def renames(self) -> list[TidyRename]: ...
85
+ @property
86
+ def count(self) -> int: ...
87
+
88
+ def tidy_bibtex(source: str, *, options: TidyOptions | None = None) -> TidyResult: ...
89
+ def _write_bibtex(path: str | PathLike[str], source: str) -> None: ...
90
+
91
+ class Entry:
92
+ @property
93
+ def key(self) -> str: ...
94
+ @property
95
+ def entry_type(self) -> str: ...
96
+ @property
97
+ def title(self) -> str | None: ...
98
+ @property
99
+ def date(self) -> str | None: ...
100
+ @property
101
+ def parents(self) -> list[Entry]: ...
102
+ @property
103
+ def volume(self) -> str | None: ...
104
+ @property
105
+ def doi(self) -> str | None: ...
106
+
107
+ class Library:
108
+ @staticmethod
109
+ def read(path: str | PathLike[str], *, recovery: _RecoveryPolicy = "error") -> Library: ...
110
+ @staticmethod
111
+ def parse_bibtex(
112
+ source: str,
113
+ *,
114
+ recovery: _RecoveryPolicy = "error",
115
+ ) -> Library: ...
116
+ @staticmethod
117
+ def parse_yaml(source: str) -> Library: ...
118
+ @property
119
+ def diagnostics(self) -> list[Diagnostic]: ...
120
+ def keys(self) -> list[str]: ...
121
+ def get_many(self, keys: Iterable[str]) -> list[Entry]: ...
122
+ def values(self) -> list[Entry]: ...
123
+ def get(self, key: str) -> Entry | None: ...
124
+ def is_empty(self) -> bool: ...
125
+ def select(self, selector: str) -> list[Entry]: ...
126
+ def project(
127
+ self, fields: Iterable[str] | None = None, *, keys: Iterable[str] | None = None
128
+ ) -> list[ProjectionRow]: ...
129
+ def __len__(self) -> int: ...
130
+ def __bool__(self) -> bool: ...
131
+ def __contains__(self, key: str) -> bool: ...
132
+ def __getitem__(self, key: str) -> Entry: ...
133
+
134
+ class Style:
135
+ @staticmethod
136
+ def load(name: str) -> Style: ...
137
+ @staticmethod
138
+ def from_xml(xml: str) -> Style: ...
139
+ @staticmethod
140
+ def from_path(path: str | PathLike[str]) -> Style: ...
141
+ @property
142
+ def id(self) -> str: ...
143
+ @property
144
+ def title(self) -> str: ...
145
+
146
+ class Locale:
147
+ @staticmethod
148
+ def load(code: str) -> Locale: ...
149
+ @property
150
+ def code(self) -> str: ...
151
+
152
+ class Cite:
153
+ def __init__(
154
+ self, key: str, *, locator: str | None = None, label: str | None = None
155
+ ) -> None: ...
156
+ @property
157
+ def key(self) -> str: ...
158
+ @property
159
+ def locator(self) -> str | None: ...
160
+ @property
161
+ def label(self) -> str | None: ...
162
+
163
+ class CitationGroup:
164
+ def __init__(self, items: Iterable[str | Cite]) -> None: ...
165
+ @property
166
+ def items(self) -> list[Cite]: ...
167
+ def __len__(self) -> int: ...
168
+
169
+ class Citation:
170
+ def __init__(
171
+ self, id: str, citation: str | Cite | CitationGroup, *, note_number: int | None = None
172
+ ) -> None: ...
173
+ @property
174
+ def note_number(self) -> int | None: ...
175
+ @property
176
+ def id(self) -> str: ...
177
+ @property
178
+ def group(self) -> CitationGroup: ...
179
+
180
+ class Rendered:
181
+ @property
182
+ def layout(self) -> BibliographyLayout | None: ...
183
+ @property
184
+ def text(self) -> str: ...
185
+ @property
186
+ def html(self) -> str: ...
187
+ @property
188
+ def tree(self) -> RenderedTree: ...
189
+
190
+ class RenderedDocument:
191
+ @property
192
+ def citation_order(self) -> list[str]: ...
193
+ @property
194
+ def citations(self) -> dict[str, Rendered]: ...
195
+ @property
196
+ def bibliography(self) -> Rendered: ...
197
+ def __getitem__(self, id: str) -> Rendered: ...
198
+
199
+ class Document:
200
+ def __init__(
201
+ self, library: Library, style: Style, *, locale: str | Locale | None = None
202
+ ) -> None: ...
203
+ def render(self, citations: Iterable[Citation]) -> RenderedDocument: ...
204
+ def cited_bibliography(self, citations: Iterable[Citation]) -> Rendered: ...
205
+ def full_bibliography(self) -> Rendered: ...
206
+
207
+ class BibField:
208
+ @property
209
+ def name(self) -> str: ...
210
+ @property
211
+ def value(self) -> str: ...
212
+ @value.setter
213
+ def value(self, value: str) -> None: ...
214
+ @property
215
+ def span(self) -> tuple[int, int]: ...
216
+
217
+ class BibFieldMap:
218
+ def unique_keys(self) -> list[str]: ...
219
+ def occurrence_keys(self) -> list[str]: ...
220
+ def occurrences(self) -> list[BibField]: ...
221
+ def get_all(self, key: str) -> list[BibField]: ...
222
+ def is_empty(self) -> bool: ...
223
+ def get_unique(self, key: str) -> BibField | None: ...
224
+ def __len__(self) -> int: ...
225
+ def __bool__(self) -> bool: ...
226
+ def __contains__(self, key: str) -> bool: ...
227
+ def __getitem__(self, key: str) -> BibField: ...
228
+
229
+ class BibEntry:
230
+ @property
231
+ def key(self) -> str: ...
232
+ @property
233
+ def kind(self) -> str: ...
234
+ @property
235
+ def fields(self) -> BibFieldMap: ...
236
+ @property
237
+ def span(self) -> tuple[int, int]: ...
238
+
239
+ class BibEntryMap:
240
+ def unique_keys(self) -> list[str]: ...
241
+ def occurrence_keys(self) -> list[str]: ...
242
+ def occurrences(self) -> list[BibEntry]: ...
243
+ def get_all(self, key: str) -> list[BibEntry]: ...
244
+ def is_empty(self) -> bool: ...
245
+ def get_unique(self, key: str) -> BibEntry | None: ...
246
+ def __len__(self) -> int: ...
247
+ def __bool__(self) -> bool: ...
248
+ def __contains__(self, key: str) -> bool: ...
249
+ def __getitem__(self, key: str) -> BibEntry: ...
250
+
251
+ class BibDocument:
252
+ @property
253
+ def diagnostics(self) -> list[Diagnostic]: ...
254
+ @staticmethod
255
+ def read(path: str | PathLike[str]) -> BibDocument: ...
256
+ @staticmethod
257
+ def parse(source: str) -> BibDocument: ...
258
+ @property
259
+ def entries(self) -> BibEntryMap: ...
260
+ @property
261
+ def comments(self) -> list[str]: ...
262
+ @property
263
+ def preamble(self) -> str: ...
264
+ @property
265
+ def strings(self) -> dict[str, str]: ...
266
+ @property
267
+ def failed_blocks(self) -> list[RawFailedBlock]: ...
268
+ @property
269
+ def blocks(self) -> list[RawBlock]: ...
270
+ def to_bibtex(self) -> str: ...
271
+ def tidy(self, *, options: TidyOptions | None = None) -> TidyResult: ...
272
+ def write(self, path: str | PathLike[str]) -> None: ...
refkit/agent.py ADDED
@@ -0,0 +1,97 @@
1
+ """Use RefKit from code-mode agents."""
2
+
3
+ import sys as _sys
4
+ from importlib.metadata import version as _version
5
+ from pathlib import Path as _Path
6
+ from textwrap import indent as _indent
7
+ from types import ModuleType as _ModuleType
8
+
9
+ import agent_plugins as _agent_plugins
10
+
11
+ _DISTRIBUTION_NAME = "refkit"
12
+ _SKILL_NAME = "refkit"
13
+
14
+ AgentPluginError = _agent_plugins.AgentPluginError
15
+
16
+
17
+ def agent_plugin() -> _agent_plugins.Plugin:
18
+ """Return the Agent Plugin installed with this RefKit version.
19
+
20
+ Raises:
21
+ AgentPluginError: The installed distribution has no usable plugin marker.
22
+ """
23
+
24
+ return _agent_plugins.locate(_DISTRIBUTION_NAME)
25
+
26
+
27
+ def agent_skill() -> _agent_plugins.Skill:
28
+ """Return the packaged RefKit Agent Skill.
29
+
30
+ Raises:
31
+ AgentPluginError: The installed plugin or its RefKit skill cannot be resolved.
32
+ """
33
+
34
+ return agent_plugin().skill(_SKILL_NAME)
35
+
36
+
37
+ def instructions() -> str:
38
+ """Return the installed RefKit Agent Skill instructions as Markdown."""
39
+
40
+ return agent_skill().body.lstrip("\n")
41
+
42
+
43
+ def resources() -> dict[str, _Path]:
44
+ """Return installed skill files keyed by skill-relative path."""
45
+
46
+ skill = agent_skill()
47
+ return {path.relative_to(skill.path).as_posix(): path for path in skill.files}
48
+
49
+
50
+ def _module_help(summary: str) -> str:
51
+ introduction = f"""{summary}
52
+
53
+ Installed refkit version: {_version(_DISTRIBUTION_NAME)}.
54
+
55
+ Use `refkit.Library` to inspect normalized bibliography data, `refkit.Document`
56
+ to render ordered citations, and `refkit.BibDocument` to edit raw BibTeX.
57
+
58
+ import refkit.agent as agent
59
+
60
+ print(agent.instructions())
61
+ print(agent.resources()["references/inspect.md"].read_text(encoding="utf-8"))
62
+
63
+ Packaged instructions describe the installed API. Read the task resource before
64
+ executing its example. The website at https://peter-gy.github.io/refkit/ describes
65
+ the current published API and can differ from this installed version.
66
+ """
67
+ try:
68
+ skill = agent_skill()
69
+ tree = _indent(skill.tree(), " ")
70
+ except AgentPluginError as error:
71
+ return f"{introduction}\nAgent Plugin unavailable: {error}\nReinstall refkit.\n"
72
+ return f"{introduction}\nInstalled task resources:\n\n{tree}\n"
73
+
74
+
75
+ __all__ = [
76
+ "AgentPluginError",
77
+ "agent_plugin",
78
+ "agent_skill",
79
+ "instructions",
80
+ "resources",
81
+ ]
82
+
83
+
84
+ class _AgentModule(_ModuleType):
85
+ @property
86
+ def __doc__(self) -> str | None: # pyrefly: ignore [bad-override]
87
+ summary = self.__dict__.get("__doc__")
88
+ if not isinstance(summary, str): # pragma: no cover - interpreter module state
89
+ return None
90
+ return _module_help(summary)
91
+
92
+ @__doc__.setter
93
+ def __doc__(self, value: str | None) -> None: # pragma: no cover - interpreter hook
94
+ self.__dict__["__doc__"] = value
95
+
96
+
97
+ _sys.modules[__name__].__class__ = _AgentModule
refkit/py.typed ADDED
@@ -0,0 +1 @@
1
+