././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7328749 citeproc_py-0.8.2/0000755000175100001660000000000014764177724013467 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750223.0 citeproc_py-0.8.2/CHANGELOG.md0000644000175100001660000001130514764177717015302 0ustar00runnerdocker# v0.8.2 (Wed Mar 12 2025) #### 🏠 Internal - Explicitly specify utf-8 encoding while reading top level .md files for description [#162](https://github.com/citeproc-py/citeproc-py/pull/162) ([@yarikoptic](https://github.com/yarikoptic)) - Instruct that long description is in markdown and not ReST [#160](https://github.com/citeproc-py/citeproc-py/pull/160) ([@yarikoptic](https://github.com/yarikoptic)) #### Authors: 1 - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # v0.8.1 (Wed Mar 12 2025) #### 🏠 Internal - release: checkout with submodules [#159](https://github.com/citeproc-py/citeproc-py/pull/159) ([@yarikoptic](https://github.com/yarikoptic)) #### Authors: 1 - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # v0.8.0 (Wed Mar 12 2025) #### 🚀 Enhancement - release: use GitHUb App token for checkout and push [#158](https://github.com/citeproc-py/citeproc-py/pull/158) ([@tmorrell](https://github.com/tmorrell)) #### ⚠️ Pushed to `master` - Rename CHANGES to CHANGELOG ([@yarikoptic](https://github.com/yarikoptic)) #### 🏠 Internal - release: switch to using GitHub App to overcome branch protection [#157](https://github.com/citeproc-py/citeproc-py/pull/157) ([@tmorrell](https://github.com/tmorrell)) - Set up `auto` to automate releases [#153](https://github.com/citeproc-py/citeproc-py/pull/153) ([@jwodder](https://github.com/jwodder) [@yarikoptic](https://github.com/yarikoptic)) #### 📝 Documentation - Convert CHANGES.rst, CONTRIBUTING.rst, and README.md to markdown [#154](https://github.com/citeproc-py/citeproc-py/pull/154) ([@tmorrell](https://github.com/tmorrell)) #### Authors: 3 - John T. Wodder II ([@jwodder](https://github.com/jwodder)) - Tom Morrell ([@tmorrell](https://github.com/tmorrell)) - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # Release 0.7.0 (2025-02-19) Just to get a release out after long period. #### Bug fixes * Better handling of ordinals * Fix locator conditions (resolves #142) * Make family name optional * Allow date parts to not be integers * Support space macros * Fix multiple capitals * Fix parsing BibTex integer values #### Other changes: * Removed support for Python 3.6, 3.7, 3.8 and added for 3.10 - 3.13 * Switch versioning to versioneer # Release 0.6.0 (2021-05-27) #### Bug fixes * Various issues on Windows: testing, explicit utf-8 encoding * Strings with unescaped \ declared r"aw" #### Other changes: * Removed support for Python 2.7, 3.5 and added for 3.9 * Travis CI is removed in favor of GitHub actions testing across all 3 major OSes (MacOS, Windows, GNU/Linux Ubuntu) * CSL test-suite progressed from 5779a8c to c3db429 # Release 0.5.1 (2020-03-06) #### Bug fixed: * avoid rnc2rng 2.6.2 which breaks installation of citeproc-py # Release 0.5.0 (2020-02-09) #### Enhancements: * handle commas and ampersands in a functional style * Number: handle commas and ampersands * added symbol for textquotesingle * specify fallback locales for fr-CA and es-CL * improved page number and ranges parsing #### Bug fixed: * don't fail on empty page ranges (#90) (bbm) * detect end of file while parsing incorrect bib (#59) (John Vandenberg) #### Other changes: * Removed 3.2-3.4 and added 3.7, 3.8 to supported Pythons * Refactored locales handling # Release 0.4.0 (2017-06-23) #### New features: * allow specifying the encoding of a BibTeX database file (#20 and #25) * BibTeX 'month' field: support integers and " " values * BibTeX 'pages' field: support "10", "10+", "10-12" and "10--12" formats * BibTeX entry types: map the non-standard 'thesis' and 'report' entries * update the CSL schema to version 1.0.1 (#5) * update the CSL locales to commit 49bf3fc0 #### Bug fixed: * avoid crash when there is nothing to affix (David Lesieur) * fix BibTeX month to CSL month mapping (#24) * strip leading/trailing whitespace from BibTeX values (#37) # Release 0.3.0 (2014-11-07) #### Major improvements to the BibTeX parser: * split names into parts and assign them to the equivalent CSL name parts * fixed handling of accent macros and escaped characters * more compatible (La)TeX macro handling in general (but still basic) * handle standard Computer Modern ligatures such as --, ---, and << * added unit tests for the BibTeX and LaTeX parsers #### Other changes: * disable RelaxNG validation of CSL styles by default (API change) # Release 0.2.0 (2014-10-25) * bad cite callback function can determine how a bad cite is displayed (hetsch) * added option to disable RelaxNG validation (Jasper Op de Coul) * distutils was replaced with setuptools (Joshua Carp) * bug fixes (Yaroslav Halchenko, David Lesieur) * CitationStylesBibliography.bibliography() now returns the list of entries ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/LICENSE0000644000175100001660000000277614764177704014506 0ustar00runnerdockerCopyright 2011-2013 Brecht Machiels. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the copyright holder. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/MANIFEST.in0000644000175100001660000000042614764177704015225 0ustar00runnerdockerinclude LICENSE README.md CHANGELOG.md recursive-include citeproc/data/schema *.rnc *.md *.rng recursive-include docs *.html *.css *.png recursive-include examples *.py *.csl *.bib recursive-include tests *.py *.bib recursive-include tests/local *.txt prune tests/citeproc-test ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7328749 citeproc_py-0.8.2/PKG-INFO0000644000175100001660000002360214764177724014567 0ustar00runnerdockerMetadata-Version: 2.2 Name: citeproc-py Version: 0.8.2 Summary: Citations and bibliography formatter Home-page: https://github.com/brechtm/citeproc-py Author: Brecht Machiels Author-email: brecht@mos6581.org License: 2-clause BSD License Keywords: csl citation html rst bibtex xml Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Environment :: Other Environment Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: End Users/Desktop Classifier: Intended Audience :: Legal Industry Classifier: Intended Audience :: Other Audience Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Documentation Classifier: Topic :: Printing Classifier: Topic :: Software Development :: Documentation Classifier: Topic :: Software Development :: Libraries :: Python Modules Provides: citeproc Requires-Python: >=3.9 Description-Content-Type: text/markdown License-File: LICENSE Requires-Dist: lxml Dynamic: author Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: description-content-type Dynamic: home-page Dynamic: keywords Dynamic: license Dynamic: provides Dynamic: requires-dist Dynamic: requires-python Dynamic: summary # citeproc-py ![PyPI - Version](https://img.shields.io/pypi/v/citeproc-py) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/citeproc-py/citeproc-py/test.yml) ![Coveralls](https://img.shields.io/coverallsCoverage/github/citeproc-py/citeproc-py) citeproc-py is a [`CSL`](https://citationstyles.org/) processor for Python. It aims to implement the [CSL 1.0.1 specification](https://docs.citationstyles.org/en/1.0.1/specification.html). citeproc-py can output styled citations and bibliographies in a number of different output formats. Currently supported are plain text, reStructuredText and HTML. Other formats can be added easily. citeproc-py uses [semantic versioning](https://semver.org/). Currently, its major version number is still at 0, meaning the API is not yet stable. However, you should not expect to see any major API changes soon. ## Requirements citeproc-py supports Python 3.9 and up. It depends on [lxml](https://lxml.de/) for parsing and navigating the CSL style and locale files. # Installation The recommended way of installing citeproc-py is by using [pip](https://pip.pypa.io/en/latest/): pip install citeproc-py If lxml isn't installed, pip will try to install it for you. If you insist, you can manually install citeproc-py from distribution packages hosted at [PyPI](https://pypi.python.org/pypi/citeproc-py/). Please ignore the release archives offered by GitHub. ## Getting Started To get started with citeproc-py, take a look at the examples under `examples/`. Two examples are provided, one parsing references from a JSON representation of references as supported by citeproc-js, another parsing the references from a BibTeX file. Both show and explain how to cite references and render the bibliography. ## CSL Compatibility Currently, citeproc-py passes almost 60% of the (relevant) tests in the [citeproc-test suite](https://github.com/citation-style-language/test-suite). However, it is more than 60% complete, as citeproc-py doesn't take care of double spaces and repeated punctuation marks yet, making a good deal of the tests fail. In addition, the following features have not yet been implemented (there are probably some I forgot though): - disambiguation/year-suffix - et-al-subsequent-min/et-al-subsequent-use-first - collapsing - punctuation-in-quote - display Also, some [citeproc-js](https://github.com/juris-m/citeproc-js) functionality that is not part of the CSL spec is not (yet) supported: - raw dates - static-ordering - literal names ## Contributing citeproc-py is 100% volunteer maintained, and new contributions are always welcome. If you would like to contribute, please follow the guidelines in the [CONTRIBUTING.md](https://github.com/citeproc-py/citeproc-py/blob/master/CONTRIBUTING.md) file. ## Local Install and Running the Tests First clone the `citeproc-py` repository and install the submodules with `git submodule update --init` Then install with `pip install -e .` Then move to the `tests` directory and run `python citeproc-test.py` Run `citeproc-test.py --help` to see its usage information. The first time you run the script it will clone the [citeproc-test suite](https://github.com/citation-style-language/test-suite) repository into the `tests` directory and checkout the last tested version. By default failed tests are automatically added into the `failing_tests.txt` file and aren't shown when running the test suite again. If you want git to fully ignore the submodule, you can type `git update-index --assume-unchanged citeproc/data/schema` # v0.8.2 (Wed Mar 12 2025) #### 🏠 Internal - Explicitly specify utf-8 encoding while reading top level .md files for description [#162](https://github.com/citeproc-py/citeproc-py/pull/162) ([@yarikoptic](https://github.com/yarikoptic)) - Instruct that long description is in markdown and not ReST [#160](https://github.com/citeproc-py/citeproc-py/pull/160) ([@yarikoptic](https://github.com/yarikoptic)) #### Authors: 1 - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # v0.8.1 (Wed Mar 12 2025) #### 🏠 Internal - release: checkout with submodules [#159](https://github.com/citeproc-py/citeproc-py/pull/159) ([@yarikoptic](https://github.com/yarikoptic)) #### Authors: 1 - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # v0.8.0 (Wed Mar 12 2025) #### 🚀 Enhancement - release: use GitHUb App token for checkout and push [#158](https://github.com/citeproc-py/citeproc-py/pull/158) ([@tmorrell](https://github.com/tmorrell)) #### ⚠️ Pushed to `master` - Rename CHANGES to CHANGELOG ([@yarikoptic](https://github.com/yarikoptic)) #### 🏠 Internal - release: switch to using GitHub App to overcome branch protection [#157](https://github.com/citeproc-py/citeproc-py/pull/157) ([@tmorrell](https://github.com/tmorrell)) - Set up `auto` to automate releases [#153](https://github.com/citeproc-py/citeproc-py/pull/153) ([@jwodder](https://github.com/jwodder) [@yarikoptic](https://github.com/yarikoptic)) #### 📝 Documentation - Convert CHANGES.rst, CONTRIBUTING.rst, and README.md to markdown [#154](https://github.com/citeproc-py/citeproc-py/pull/154) ([@tmorrell](https://github.com/tmorrell)) #### Authors: 3 - John T. Wodder II ([@jwodder](https://github.com/jwodder)) - Tom Morrell ([@tmorrell](https://github.com/tmorrell)) - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # Release 0.7.0 (2025-02-19) Just to get a release out after long period. #### Bug fixes * Better handling of ordinals * Fix locator conditions (resolves #142) * Make family name optional * Allow date parts to not be integers * Support space macros * Fix multiple capitals * Fix parsing BibTex integer values #### Other changes: * Removed support for Python 3.6, 3.7, 3.8 and added for 3.10 - 3.13 * Switch versioning to versioneer # Release 0.6.0 (2021-05-27) #### Bug fixes * Various issues on Windows: testing, explicit utf-8 encoding * Strings with unescaped \ declared r"aw" #### Other changes: * Removed support for Python 2.7, 3.5 and added for 3.9 * Travis CI is removed in favor of GitHub actions testing across all 3 major OSes (MacOS, Windows, GNU/Linux Ubuntu) * CSL test-suite progressed from 5779a8c to c3db429 # Release 0.5.1 (2020-03-06) #### Bug fixed: * avoid rnc2rng 2.6.2 which breaks installation of citeproc-py # Release 0.5.0 (2020-02-09) #### Enhancements: * handle commas and ampersands in a functional style * Number: handle commas and ampersands * added symbol for textquotesingle * specify fallback locales for fr-CA and es-CL * improved page number and ranges parsing #### Bug fixed: * don't fail on empty page ranges (#90) (bbm) * detect end of file while parsing incorrect bib (#59) (John Vandenberg) #### Other changes: * Removed 3.2-3.4 and added 3.7, 3.8 to supported Pythons * Refactored locales handling # Release 0.4.0 (2017-06-23) #### New features: * allow specifying the encoding of a BibTeX database file (#20 and #25) * BibTeX 'month' field: support integers and " " values * BibTeX 'pages' field: support "10", "10+", "10-12" and "10--12" formats * BibTeX entry types: map the non-standard 'thesis' and 'report' entries * update the CSL schema to version 1.0.1 (#5) * update the CSL locales to commit 49bf3fc0 #### Bug fixed: * avoid crash when there is nothing to affix (David Lesieur) * fix BibTeX month to CSL month mapping (#24) * strip leading/trailing whitespace from BibTeX values (#37) # Release 0.3.0 (2014-11-07) #### Major improvements to the BibTeX parser: * split names into parts and assign them to the equivalent CSL name parts * fixed handling of accent macros and escaped characters * more compatible (La)TeX macro handling in general (but still basic) * handle standard Computer Modern ligatures such as --, ---, and << * added unit tests for the BibTeX and LaTeX parsers #### Other changes: * disable RelaxNG validation of CSL styles by default (API change) # Release 0.2.0 (2014-10-25) * bad cite callback function can determine how a bad cite is displayed (hetsch) * added option to disable RelaxNG validation (Jasper Op de Coul) * distutils was replaced with setuptools (Joshua Carp) * bug fixes (Yaroslav Halchenko, David Lesieur) * CitationStylesBibliography.bibliography() now returns the list of entries ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/README.md0000644000175100001660000000703014764177704014744 0ustar00runnerdocker# citeproc-py ![PyPI - Version](https://img.shields.io/pypi/v/citeproc-py) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/citeproc-py/citeproc-py/test.yml) ![Coveralls](https://img.shields.io/coverallsCoverage/github/citeproc-py/citeproc-py) citeproc-py is a [`CSL`](https://citationstyles.org/) processor for Python. It aims to implement the [CSL 1.0.1 specification](https://docs.citationstyles.org/en/1.0.1/specification.html). citeproc-py can output styled citations and bibliographies in a number of different output formats. Currently supported are plain text, reStructuredText and HTML. Other formats can be added easily. citeproc-py uses [semantic versioning](https://semver.org/). Currently, its major version number is still at 0, meaning the API is not yet stable. However, you should not expect to see any major API changes soon. ## Requirements citeproc-py supports Python 3.9 and up. It depends on [lxml](https://lxml.de/) for parsing and navigating the CSL style and locale files. # Installation The recommended way of installing citeproc-py is by using [pip](https://pip.pypa.io/en/latest/): pip install citeproc-py If lxml isn't installed, pip will try to install it for you. If you insist, you can manually install citeproc-py from distribution packages hosted at [PyPI](https://pypi.python.org/pypi/citeproc-py/). Please ignore the release archives offered by GitHub. ## Getting Started To get started with citeproc-py, take a look at the examples under `examples/`. Two examples are provided, one parsing references from a JSON representation of references as supported by citeproc-js, another parsing the references from a BibTeX file. Both show and explain how to cite references and render the bibliography. ## CSL Compatibility Currently, citeproc-py passes almost 60% of the (relevant) tests in the [citeproc-test suite](https://github.com/citation-style-language/test-suite). However, it is more than 60% complete, as citeproc-py doesn't take care of double spaces and repeated punctuation marks yet, making a good deal of the tests fail. In addition, the following features have not yet been implemented (there are probably some I forgot though): - disambiguation/year-suffix - et-al-subsequent-min/et-al-subsequent-use-first - collapsing - punctuation-in-quote - display Also, some [citeproc-js](https://github.com/juris-m/citeproc-js) functionality that is not part of the CSL spec is not (yet) supported: - raw dates - static-ordering - literal names ## Contributing citeproc-py is 100% volunteer maintained, and new contributions are always welcome. If you would like to contribute, please follow the guidelines in the [CONTRIBUTING.md](https://github.com/citeproc-py/citeproc-py/blob/master/CONTRIBUTING.md) file. ## Local Install and Running the Tests First clone the `citeproc-py` repository and install the submodules with `git submodule update --init` Then install with `pip install -e .` Then move to the `tests` directory and run `python citeproc-test.py` Run `citeproc-test.py --help` to see its usage information. The first time you run the script it will clone the [citeproc-test suite](https://github.com/citation-style-language/test-suite) repository into the `tests` directory and checkout the last tested version. By default failed tests are automatically added into the `failing_tests.txt` file and aren't shown when running the test suite again. If you want git to fully ignore the submodule, you can type `git update-index --assume-unchanged citeproc/data/schema` ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.713875 citeproc_py-0.8.2/bin/0000755000175100001660000000000014764177724014237 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/bin/csl_unsorted0000755000175100001660000000604214764177704016671 0ustar00runnerdocker#!/usr/bin/env python import os import sys import warnings from optparse import OptionParser # The references are parsed from a BibTeX database, so we import the # corresponding parser. from citeproc.source.bibtex import BibTeX # Import the citeproc-py classes we'll use below. from citeproc import frontend from citeproc import CitationStylesStyle, CitationStylesBibliography from citeproc import formatter from citeproc import Citation, CitationItem def main(): usage = \ """usage: %prog [options] ' Output a formatted bibliography from bibtex file to stdout You might want to put the path to your CSL styles in the `CSL_STYLES_PATH` environment variable with something like (bash shell):: export CSL_STYLES_PATH=$HOME/dev_trees/styles """ parser = OptionParser(usage) parser.add_option('-s', '--style', dest='style', default='harvard1', help='style file', metavar='STYLE_FILE') parser.add_option('-f', '--format', dest='format', default='rst', help='output type', metavar='FORMAT') (options, args) = parser.parse_args() if len(args) != 1: parser.print_usage() sys.exit(1) output_format = options.format try: output_format = getattr(formatter, options.format) except AttributeError: available_formatters = (attr for attr in dir(formatter) if not attr.startswith('__')) print('style should be one of: ' + ', '.join(available_formatters)) sys.exit(1) # Get styles path out of the environment variable env_path = os.environ.get('CSL_STYLES_PATH') if env_path is not None: frontend.STYLES_PATH = env_path # Silence lots of warnings warnings.simplefilter('ignore') # Read bibliography bib_source = BibTeX(args[0]) # load a CSL style (full path or name of style in style path) bib_style = CitationStylesStyle(options.style) # Create the citeproc-py bibliography, passing it the: # * CitationStylesStyle, # * BibliographySource (BibTeX in this case), and # * a formatter (plain, html, or rst) bibliography = CitationStylesBibliography(bib_style, bib_source, output_format) # Processing citations in a document need to be done in two passes as for # some CSL styles, a citation can depend on the order of citations in the # bibliography and thus on citations following the current one. # For this reason, we first need to register all citations with the # CitationStylesBibliography. # Just read every one in key order for name in sorted(bib_source): bibliography.register(Citation([CitationItem(name)])) # In the second pass, CitationStylesBibliography can generate citations. # CitationStylesBibliography.cite() requires a callback function to be # passed along to be called in case a CitationItem's key is not present in # the bibliography. for item in bibliography.bibliography(): print(str(item)) if __name__ == '__main__': main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7148752 citeproc_py-0.8.2/citeproc/0000755000175100001660000000000014764177724015277 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/__init__.py0000644000175100001660000000366014764177704017413 0ustar00runnerdocker import os import json from . import types, formatter DATA_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data') SCHEMA_PATH = os.path.join(DATA_PATH, 'schema', 'csl.rng') LOCALES_PATH = os.path.join(DATA_PATH, 'locales') STYLES_PATH = os.path.join(DATA_PATH, 'styles') NAMES = ['author', 'collection_editor', 'composer', 'container_author', 'editor', 'editorial_director', 'illustrator', 'interviewer', 'original_author', 'recipient', 'translator'] DATES = ['accessed', 'container', 'event_date', 'issued', 'original_date', 'submitted'] NUMBERS = ['chapter_number', 'collection_number', 'edition', 'issue', 'number', 'number_of_pages', 'number_of_volumes', 'volume'] VARIABLES = (['abstract', 'annote', 'archive', 'archive_location', 'archive_place', 'authority', 'call_number', 'citation_label', 'citation_number', 'collection_title', 'container_title', 'container_title_short', 'dimensions', 'DOI', 'event', 'event_place', 'first_reference_note_number', 'genre', 'ISBN', 'ISSN', 'jurisdiction', 'keyword', 'language', 'locator', 'medium', 'note', 'original_publisher', 'original_publisher_place', 'original_title', 'page', 'page_first', 'PMCID', 'PMID', 'publisher', 'publisher_place', 'references', 'section', 'source', 'status', 'title', 'title_short', 'URL', 'version', 'year_suffix'] + NAMES + DATES + NUMBERS) with open(os.path.join(LOCALES_PATH, 'locales.json'), encoding='utf-8') as file: locales_json = json.load(file) PRIMARY_DIALECTS = locales_json['primary-dialects'] LANGUAGE_NAMES = locales_json['language-names'] from .frontend import CitationStylesStyle, CitationStylesBibliography from .source import Citation, CitationItem, Locator from . import _version __version__ = _version.get_versions()['version'] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.733875 citeproc_py-0.8.2/citeproc/_version.py0000644000175100001660000000076114764177724017501 0ustar00runnerdocker # This file was generated by 'versioneer.py' (0.29) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' { "date": "2025-03-12T03:30:23+0000", "dirty": false, "error": null, "full-revisionid": "c71f0a52ed0e462080976cc17d8616a292c31fff", "version": "0.8.2" } ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7108753 citeproc_py-0.8.2/citeproc/data/0000755000175100001660000000000014764177724016210 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7258751 citeproc_py-0.8.2/citeproc/data/locales/0000755000175100001660000000000014764177724017632 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-af-ZA.xml0000644000175100001660000002427314764177705022701 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 toegang verkry en and others anonymous anon at available at by circa c. cited edition editions ed et al. voorhande van ibid. in in press internet interview letter no date n.d. online presented at the reference references ref. refs. opgehaal scale version AD BC th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth book books chapter chapters column columns figure figures folio folios number numbers reël reëls note notes opus opera bladsy bladsye bladsy bladsye paragraaf paragrawe part parts section sections sub verbo sub verbis verse verses volume volumes bk chap col fig f no l. n. op bl bll bl bll para pt sec s.v. s.vv. v vv vol vols ¶¶ § §§ director directors redakteur redakteurs editor editors illustrator illustrators vertaler vertalers editor & translator editors & translators dir. dirs. red reds ed. eds. ill. ills. vert verts ed. & tran. eds. & trans. by directed by onder redaksie van edited by illustrated by interview by to by vertaal deur edited & translated by dir. red ed. illus. verts ed. & trans. by Januarie Februarie Maart April Mei Junie Julie Augustus September Oktober November Desember Jan Feb Mrt Apr Mei Jun Jul Aug Sep Okt Nov Des Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-ar.xml0000644000175100001660000002116414764177705022401 0ustar00runnerdocker abdealikhurrum Dr. Ayman Saleh This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 تاريخ الوصول و وآخرون مجهول مجهول عند موجود في عن طريق حوالي حوالي وثق الطبعة الطبعات ط وآخرون التالي من المرجع السابق في قيد النشر انترنت مقابلة خطاب دون تاريخ د.ت مباشر على الإنترنت قُدَّم في مرجع مراجع مرجع مراجع استرجع في السلم الموسيقي إصدار ب.م. ق.م. " " ' ' الأول الثاني الثالث الرابع الخامس السادس السابع الثامن التاسع العاشر كتاب كتب فصل فصول عمود أعمدة رسم توضيحي رسوم توضيحية ورقة أوراق عدد أعداد سطر أسطر ملاحظة ملاحظات نوته موسيقية نوتات موسيقية صفحة صفحات صفحة صفحات فقرة فقرات جزء أجزاء قسم أقسام تفسير فرعي تفسيرات فرعية بيت شعر أبيات شعر مجلد مجلدات كتاب فصل عمود رسم توضيحي مطوية عدد سـ ملاحظة نوتة موسيقية ص ص ص ص فقرة ج قسم تفسير فرعي تفسيرات فرعية بيت شعر أبيات شعر م م ¶¶ § §§ إدارة تحقيق إدارة التحرير رسوم ترجمة ترجمة وتحقيق إنشاء إشراف تحقيق إعداد رسوم مقابلة مع المستلم مراجعة ترجمة تحقيق وترجمة يناير فبراير مارس أبريل مايو يونيو يوليو أغسطس سبتمبر أكتوبر نوفمبر ديسمبر ربيع صيف خريف شتاء ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-bg-BG.xml0000644000175100001660000003220114764177705022647 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2018-02-15T04:14:02+00:00 Valeriya Simeonova simeonova@fmi.uni-sofia.bg http://www.mendeley.com/profiles/valeriya-simeonova/ отворен на и и други анонимен анон. в достъпен на от около ок. цитиран издание издания изд. и съавт. предстоящ от пак там в под печат интернет интервю писмо без дата б.д. онлайн представен на източник източници изт. изт. изтеглен на скала версия сл.хр. пр.хр. то во ро то во ро то ти ви ри ти ви ри ти та ва ра та ва ра та първo вторo третo четвъртo петo шестo седмo осмo деветo десетo първи втори трети четверти пети шести седми осми девети десети първа втора трета четверта пета шеста седма осма девета десета книга книги глава глави колона колони фигура фигури фолио фолия брой броеве ред редове бележка бележки опус опуси страница страници брой страници абзац абзаци част части раздел раздели под раздел под раздели стихотворение стихове том томове кн. гл. кол. фиг. фол. бр. р. бел. оп. стр. бр.стр. абз. ч. разд. подразд. ст. том томове ¶¶ § §§ режисьор редактор редактори главен редактор редакторски колектив илюстрации преводач преводачи editor & translator editors & translators реж. ред. ред.кол. гл.ред. гл.ред.кол. ил. прев прев.кол. ред. & прев. ред.кол. & прев. от под общата редакция на редактиран от главен редактор илюстрации от интервюиран от до рецензент преведен от редактирано & преведено от п.о.р. ред. гл.ред. ил. прев. ред. & прев. от Януари Февруари Март Април Май Юни Юли Август Септември Октомври Ноември Декември Яну Фев Мар Апр Май Юни Юли Авг Сеп Окт Ное Дек Пролет Лято Есен Зима ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-ca-AD.xml0000644000175100001660000002407514764177705022650 0ustar00runnerdocker anidal javimat This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 consulta i i altres anònim anòn. a disponible a per circa c. citat edició edicions ed. et al. previst de ibíd. en en impremta internet entrevista carta sense data s.d. en línia presentat a referència referències ref. ref. recuperat escala versió dC aC « » - a primera segona tercera quarta cinquena sisena setena vuitena novena desena llibre llibres capítol capítols columna columnes figura figures foli folis número números línia línies nota notes opus opera pàgina pàgines pàgina pàgines paràgraf paràgrafs part parts secció seccions sub voce sub vocibus vers versos volum volums llib. cap. col. fig. f. núm. l. n. op. p. p. p. p. par. pt. sec. s.v. s.v. v. v. vol. vol. § § § § director directors editor editors editor editors il·lustrador il·lustradors traductor traductors editor i traductor editors i traductors dir. dir. ed. ed. ed. ed. il·lust. il·lust. trad. trad. ed. i trad. ed. i trad. per dirigit per editat per editat per il·lustrat per entrevistat per a per traduït per editat i traduït per dir. ed. ed. il·lust. trad. ed. i trad. per gener febrer març abril maig juny juliol agost setembre octubre novembre desembre gen. feb. març abr. maig juny jul. ago. set. oct. nov. des. primavera estiu tardor hivern ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-cs-CZ.xml0000644000175100001660000002453014764177705022716 0ustar00runnerdocker nosaal Andrew Dunning libora Michal Hoftich This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 viděno vid. a a další anonym anon. v dostupné z od asi cca. citován vydání vydání vyd. et al. nadcházející z ibid. in v tisku internet interview dopis nedatováno b.r. online prezentováno v reference reference ref. ref. získáno měřítko verze n. l. př. n. l. " ´ . první druhé třetí čtvrté páté šesté sedmé osmé deváté desáté kniha knihy kapitola kapitoly sloupec sloupce obrázek obrázky list listy číslo čísla řádek řádky poznámka poznámky opus opusy strana strany strana strany odstavec odstavce část části sekce sekce pod heslem pod hesly verš verše ročník ročníky k. kap. sl. obr. l. č. ř. pozn. op. s. s. s. s. odst. č. sek. s.v. s.v. v. v. roč. roč. ¶¶ § §§ ředitel ředitelé editor editoři vedoucí editor vedoucí editoři ilustrátor ilustrátoři překladatel překladatelé editor a překladatel editoři a překladatelé řed. řed. ed. ed. ed. ed. il. il. přel. přel. ed. a přel. ed. a přel. řídil editoval editoval ilustroval rozhovor vedl pro recenzoval přeložil editoval a přeložil řed. ed. ed. ilust. přel. ed. a přel. leden únor březen duben květen červen červenec srpen září říjen listopad prosinec led. úno. bře. dub. kvě. čer. čvc. srp. zář. říj. lis. pro. jaro léto podzim zima ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-cy-GB.xml0000644000175100001660000002452314764177705022702 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2014-10-08T12:00:00+00:00 gwelwyd a/ac ac eraill di-enw dienw at ar gael gan circa c. dyfynnwyd argraffiad argraffiadau arg. et al. ar fin ymddangos gan ibid. yn yn y wasg rhyngrwyd cyfweliad llythyr dim dyddiad d.d. arlein cyflwynwyd yn cyfeirnod cyfeirnodau cyf. cyf’au. gwelwyd graddfa fersiwn OC CC th af il ydd ed ed ed cyntaf ail trydydd pedwerydd pumed chweched seithfed wythfed nawfed degfed llyfr llyfrau pennod penodau colofn colofnau ffigwr ffigyrau ffolio ffolios rhifyn rhifynnau llinell llinellau nodyn nodiadau opus opera tudalen tudalennau tudalen tudalennau paragraff paragraffau rhan rhannau adran adrannau sub verbo sub verbis pennill penillion cyfrol cyfrolau llyfr. pen. col. ffig. ff. rhif. ll. n. op. t. tt. t. tt. para. rhan. adr. s.v. s.vv. p. pp. rhif. rhifu. ¶¶ § §§ cyfarwyddwr cyfarwyddwyr golygydd golygyddion cyfarwyddwr-golygyddol cyfarwyddwyr-golygyddol darlunydd darlunwyr cyfieithydd cyfieithwyr golygydd a chyfieithydd golygyddion a chyfieithwyr cyf. cyfy. gol. goln. gol. goln. darlun. darlun. cyf. cyf. gol. a chyf. goln. a chyf. gan cyfarwyddwyd gan golygwyd gan cyfarwyddwyd a golygwyd gan darlunwyd gan cyfweliad gan i gan cyfieithwyd gan golygwyd a chyfieithwyd gan cyf. gan gol. gan cyf.-gol. gan darlun. gan cyf. gan gol. a chyf. gan Ionawr Chwefror Mawrth Ebrill Mai Mehefin Gorffennaf Awst Medi Hydref Tachwedd Rhagfyr Ion. Chwe. Maw. Ebr. Mai Meh. Gorff. Aws. Med. Hyd. Tach. Rhag. Gwanwyn Haf Hydref Gaeaf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-da-DK.xml0000644000175100001660000002434114764177705022657 0ustar00runnerdocker Niels Erik Wille Jonas Nyrup hafnius This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 set og med flere anonym anon. tilgængelig hos af cirka ca. henvist udgave udgaver udg. m.fl. kommende fra ibid. i i trykken internet interview brev uden år u.å. online præsenteret ved reference referencer ref. refr. hentet skala version e.v.t. f.v.t. . første anden tredje fjerde femte sjette syvende ottende niende tiende bog bøger kapitel kapitler kolonne kolonner figur figurer folio folio nummer numre linje linjer note noter opus opus side sider side sider afsnit afsnit del dele paragraf paragraffer sub voce sub voce vers vers bind bind b. kap. kol. fig. fol. nr. l. n. op. s. s. s. s. afs. d. par. s.v. s.v. v. v. bd. bd. ¶¶ § §§ instruktør instruktører redaktør redaktører redaktør redaktører illustrator illustratorer oversætter oversættere redaktør & oversætter redaktører & oversættere instr. instr. red. red. red. red. ill. ill. overs. overs. red. & overs. red. & overs. af instrueret af redigeret af redigeret af illustreret af interviewet af modtaget af af oversat af redigeret & oversat af instr. red. red. illus. overs. red. & overs. af januar februar marts april maj juni juli august september oktober november december jan. feb. mar. apr. maj jun. jul. aug. sep. okt. nov. dec. Forår Sommer Efterår Vinter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-de-AT.xml0000644000175100001660000002570614764177705022677 0ustar00runnerdocker Till A. Heilmann Georg Duffner Sebastian Karcher Sylvester Keil jakov Frank Bennett This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 zugegriffen und und andere ohne Autor o. A. auf verfügbar unter von circa ca. zitiert Auflage Auflagen Aufl. u. a. i. E. von ebd. in im Druck Internet Interview Brief ohne Datum o. J. online gehalten auf der Referenz Referenzen Ref. Ref. abgerufen Maßstab Version  n. Chr.  v. Chr. . erster zweiter dritter vierter fünfter sechster siebter achter neunter zehnter Buch Bücher Kapitel Kapitel Spalte Spalten Abbildung Abbildungen Blatt Blätter Nummer Nummern Zeile Zeilen Note Noten Opus Opera Seite Seiten Seite Seiten Absatz Absätze Teil Teile Abschnitt Abschnitte sub verbo sub verbis Vers Verse Band Bände B. Kap. Sp. Abb. Fol. Nr. l. n. op. S. S. S. S. Abs. Teil Abschn. s. v. s. vv. V. V. Bd. Bd. ¶¶ § §§ Regisseur Regisseure Herausgeber Herausgeber Reihenherausgeber Reihenherausgeber Herausgeber Herausgeber Illustrator Illustratoren Übersetzer Übersetzer Herausgeber & Übersetzer Herausgeber & Übersetzer Reg. Reg. Hrsg. Hrsg. Hrsg. Hrsg. Hrsg. Hrsg. Ill. Ill. Übers. Übers. Hrsg. & Übers. Hrsg. & Übers von Regie von herausgegeben von herausgegeben von herausgegeben von illustriert von interviewt von an von übersetzt von herausgegeben und übersetzt von Reg. hg. von hg. von hg. von illus. von übers. von hg. & übers. von Jänner Februar März April Mai Juni Juli August September Oktober November Dezember Jän. Feb. März Apr. Mai Juni Juli Aug. Sep. Okt. Nov. Dez. Frühjahr Sommer Herbst Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-de-CH.xml0000644000175100001660000002465514764177705022667 0ustar00runnerdocker Till A. Heilmann Sylvester Keil jakov Sebastian Karcher This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 zugegriffen und und andere ohne Autor o. A. auf verfügbar unter von circa ca. zitiert Auflage Auflagen Aufl. u. a. i. E. von ebd. in im Druck Internet Interview Brief ohne Datum o. J. online gehalten auf der Referenz Referenzen Ref. Ref. abgerufen Massstab Version  n. Chr.  v. Chr. « » . erster zweiter dritter vierter fünfter sechster siebter achter neunter zehnter Buch Bücher Kapitel Kapitel Spalte Spalten Abbildung Abbildungen Blatt Blätter Nummer Nummern Zeile Zeilen Note Noten Opus Opera Seite Seiten Seite Seiten Absatz Absätze Teil Teile Abschnitt Abschnitte sub verbo sub verbis Vers Verse Band Bände B. Kap. Sp. Abb. Fol. Nr. l. n. op. S. S. S. S. Abs. Teil Abschn. s. v. s. vv. V. V. Bd. Bd. ¶¶ § §§ Regisseur Regisseure Herausgeber Herausgeber Herausgeber Herausgeber Illustrator Illustratoren Übersetzer Übersetzer Herausgeber & Übersetzer Herausgeber & Übersetzer Reg. Reg. Hrsg. Hrsg. Hrsg. Hrsg. Ill. Ill. Übers. Übers. Hrsg. & Übers. Hrsg. & Übers von Regie von herausgegeben von herausgegeben von illustriert von interviewt von an von übersetzt von herausgegeben und übersetzt von Reg. hg. von hg. von illus. von übers. von hg. & übers. von Januar Februar März April Mai Juni Juli August September Oktober November Dezember Jan. Feb. März Apr. Mai Juni Juli Aug. Sep. Okt. Nov. Dez. Frühjahr Sommer Herbst Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-de-DE.xml0000644000175100001660000002557314764177705022665 0ustar00runnerdocker Till A. Heilmann Ulrich Rintze M. Zelle Sebastian Karcher jakov This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 zugegriffen und und andere ohne Autor o. A. auf verfügbar unter von circa ca. zitiert Auflage Auflagen Aufl. u. a. i. E. von ebd. in im Druck Internet Interview Brief ohne Datum o. J. online gehalten auf der Referenz Referenzen Ref. Ref. abgerufen Maßstab Version  n. Chr.  v. Chr. . erster zweiter dritter vierter fünfter sechster siebter achter neunter zehnter Buch Bücher Kapitel Kapitel Spalte Spalten Abbildung Abbildungen Blatt Blätter Nummer Nummern Zeile Zeilen Note Noten Opus Opera Seite Seiten Seite Seiten Absatz Absätze Teil Teile Abschnitt Abschnitte sub verbo sub verbis Vers Verse Band Bände B. Kap. Sp. Abb. Fol. Nr. Z. N. op. S. S. S. S. Abs. Teil Abschn. s. v. s. vv. V. V. Bd. Bde. ¶¶ § §§ Regisseur Regisseure Herausgeber Herausgeber Reihenherausgeber Reihenherausgeber Herausgeber Herausgeber Illustrator Illustratoren Übersetzer Übersetzer Herausgeber & Übersetzer Herausgeber & Übersetzer Reg. Reg. Hrsg. Hrsg. Hrsg. Hrsg. Hrsg. Hrsg. Ill. Ill. Übers. Übers. Hrsg. & Übers. Hrsg. & Übers von Regie von herausgegeben von herausgegeben von herausgegeben von illustriert von interviewt von an von übersetzt von herausgegeben und übersetzt von Reg. hg. von hg. von hg. von illus. von übers. von hg. & übers. von Januar Februar März April Mai Juni Juli August September Oktober November Dezember Jan. Feb. März Apr. Mai Juni Juli Aug. Sep. Okt. Nov. Dez. Frühjahr Sommer Herbst Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-el-GR.xml0000644000175100001660000002731714764177705022713 0ustar00runnerdocker thanasis57 dimtamb This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2013-11-08T20:31:02+00:00 ημερομηνία πρόσβασης και και άλλοι ανώνυμο ανών. εφ. διαθέσιμο στο από περίπου περ. παρατίθεται έκδοση εκδόσεις έκδ. κ.ά. προσεχές από στο ίδιο στο υπό έκδοση διαδίκτυο συνέντευξη επιστολή χωρίς χρονολογία χ.χ. έκδοση σε ψηφιακή μορφή παρουσιάστηκε στο παραπομπή παραπομπές παρ. παρ. ανακτήθηκε κλίμακα εκδοχή μ.Χ. π.Χ. ' ' ο η ος πρώτος δεύτερος τρίτος τέταρτος πέμπτος έκτος έβδομος όγδοος ένατος δέκατος βιβλίο βιβλία κεφάλαιο κεφάλαια στήλη στήλες εικόνα εικόνες φάκελος φάκελοι τεύχος τεύχη σειρά σειρές σημείωση σημειώσεις έργο έργα σελίδα σελίδες σελίδα σελίδες παράγραφος παράγραφοι μέρος μέρη τμήμα τμήματα λήμμα λήμματα στίχος στίχοι τόμος τόμοι βιβ. κεφ. στ. εικ. φάκ τχ. γρ. σημ. έργ. σ. σσ. σ. σσ. παρ. μέρ. τμ. λήμ. λήμ. στ. στ. τ. τ. ¶¶ § §§ Διευθυντής Διευθυντές επιμελητής επιμελητές διευθυντής σειράς διευθυντές σειράς εικονογράφος εικονογράφοι μεταφραστής μεταφραστές μεταφραστής και επιμελητής μεταφραστές και επιμελητές δ/ντης. δ/ντές. επιμ. επιμ. δ/ντής σειράς δ/ντές σειρας εικ. εικ.. μτφ. μτφ. μτφ. και επιμ. μτφ. και επιμ. στον συλλ. τόμο διεύθυνση επιμέλεια διεύθυνση σειράς εικονογράφηση: συνέντευξη παραλήπτης συγγραφέας: μετάφραση μετάφραση και επιμέλεια διευθ. επιμέλ. δ/νση σειράς εικον. μετάφρ. μετάφρ. και επιμέλ. Ιανουάριος Φεβρουάριος Μάρτιος Απρίλιος Μάιος Ιούνιος Ιούλιος Αύγουστος Σεπτέμβριος Οκτώβριος Νοέμβριος Δεκέμβριος Ιανουαρίου Φεβρουαρίου Μαρτίου Απριλίου Μαΐου Ιουνίου Ιουλίου Αυγούστου Σεπτεμβρίου Οκτωβρίου Νοεμβρίου Δεκεμβρίου Άνοιξη Καλοκαίρι Φθινόπωρο Χειμώνας ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-en-GB.xml0000644000175100001660000002613714764177705022674 0ustar00runnerdocker Andrew Dunning Sebastian Karcher Rintze M. Zelle This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2015-10-10T23:31:02+00:00 accessed and and others anonymous anon. at available at by circa c. cited edition editions ed. et al. forthcoming from ibid. in in press internet interview letter no date n.d. online presented at the reference references ref. refs. retrieved scale version AD BC th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth book books chapter chapters column columns figure figures folio folios number numbers line lines note notes opus opera page pages page pages paragraph paragraphs part parts section sections sub verbo sub verbis verse verses volume volumes bk. bks chap. chaps col. cols fig. figs fol. fols no. nos. l. ll. n. nn. op. opp. p. pp. p. pp. para. paras pt. pts sec. secs s.v. s.vv. v. vv. vol. vols ¶¶ § §§ director directors editor editors editor editors illustrator illustrators translator translators editor & translator editors & translators dir. dirs. ed. eds. ed. eds. ill. ills. tran. trans. ed. & tran. eds. & trans. by directed by edited by edited by illustrated by interview by to by translated by edited & translated by dir. by ed. by ed. by illus. by trans. by ed. & trans. by January February March April May June July August September October November December Jan. Feb. Mar. Apr. May Jun. Jul. Aug. Sep. Oct. Nov. Dec. Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-en-US.xml0000644000175100001660000002615014764177705022726 0ustar00runnerdocker Andrew Dunning Sebastian Karcher Rintze M. Zelle This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2015-10-10T23:31:02+00:00 accessed and and others anonymous anon. at available at by circa c. cited edition editions ed. et al. forthcoming from ibid. in in press internet interview letter no date n.d. online presented at the reference references ref. refs. retrieved scale version AD BC th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth book books chapter chapters column columns figure figures folio folios number numbers line lines note notes opus opera page pages page pages paragraph paragraphs part parts section sections sub verbo sub verbis verse verses volume volumes bk. bks. chap. chaps. col. cols. fig. figs. fol. fols. no. nos. l. ll. n. nn. op. opp. p. pp. p. pp. para. paras. pt. pts. sec. secs. s.v. s.vv. v. vv. vol. vols. ¶¶ § §§ director directors editor editors editor editors illustrator illustrators translator translators editor & translator editors & translators dir. dirs. ed. eds. ed. eds. ill. ills. tran. trans. ed. & tran. eds. & trans. by directed by edited by edited by illustrated by interview by to by translated by edited & translated by dir. by ed. by ed. by illus. by trans. by ed. & trans. by January February March April May June July August September October November December Jan. Feb. Mar. Apr. May Jun. Jul. Aug. Sep. Oct. Nov. Dec. Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-es-CL.xml0000644000175100001660000002424314764177705022703 0ustar00runnerdocker Scott Sadowsky http://sadowsky.cl/ This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2013-10-28T13:57:31-04:00 accedido y et al. anónimo anón. en disponible en de circa c. citado edición ediciones ed. et al. en preparación a partir de ibid. en en imprenta internet entrevista carta sin fecha s. f. en línea presentado en referencia referencias ref. refs. recuperado escala versión d. C. a. C. ª primera segunda tercera cuarta quinta sexta séptima octava novena décima libro libros capítulo capítulos columna columnas figura figuras folio folios número números línea líneas nota notas opus opera página páginas página páginas párrafo párrafos parte partes sección secciones sub voce sub vocibus verso versos volumen volúmenes lib. cap. col. fig. f. l. n. op. p. pp. p. pp. párr. pt. sec. s. v. s. vv. v. vv. vol. vols. § § § § director directores editor editores coordinador coordinadores ilustrador ilustradores traductor traductores editor y traductor editores y traductores dir. dirs. ed. eds. coord. coords. ilust. ilusts. trad. trads. ed. y trad. eds. y trads. de dirigido por editado por coordinado por ilustrado por entrevistado por a por traducido por editado y traducido por dir. ed. coord. ilust. trad. ed. y trad. enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre ene. feb. mar. abr. may jun. jul. ago. sep. oct. nov. dic. primavera verano otoño invierno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-es-ES.xml0000644000175100001660000002412414764177705022712 0ustar00runnerdocker javimat This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 accedido y y otros anónimo anón. en disponible en de circa c. citado edición ediciones ed. et al. previsto a partir de ibid. en en imprenta internet entrevista carta sin fecha s. f. en línea presentado en referencia referencias ref. refs. recuperado escala versión d. C. a. C. « » - primera segunda tercera cuarta quinta sexta séptima octava novena décima libro libros capítulo capítulos columna columnas figura figuras folio folios número números línea líneas nota notas opus opera página páginas página páginas párrafo párrafos parte partes sección secciones sub voce sub vocibus verso versos volumen volúmenes lib. cap. col. fig. f. n.º l. n. op. p. pp. p. pp. párr. pt. sec. s. v. s. vv. v. vv. vol. vols. § § § § director directores editor editores editor editores ilustrador ilustradores traductor traductores editor y traductor editores y traductores dir. dirs. ed. eds. ed. eds. ilust. ilusts. trad. trads. ed. y trad. eds. y trads. de dirigido por editado por editado por ilustrado por entrevistado por a por traducido por editado y traducido por dir. ed. ed. ilust. trad. ed. y trad. enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre ene. feb. mar. abr. may jun. jul. ago. sep. oct. nov. dic. primavera verano otoño invierno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-es-MX.xml0000644000175100001660000002633714764177705022737 0ustar00runnerdocker Juan Ignacio Flores Salgado https://www.mendeley.com/profiles/juan-ignacio-flores-salgado/ This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2015-06-13T13:57:31-04:00 consultado y et al. anónimo anón. en disponible en de circa c. citado edición ediciones ed. eds. et al. en preparación a partir de ibid. en en imprenta internet entrevista carta sin fecha s/f en línea presentado en referencia referencias ref. refs. recuperado escala versión d. C. a. C. a a o primera segunda tercera cuarta quinta sexta séptima octava novena décima libro libros capítulo capítulos columna columnas figura figuras folio folios número números línea líneas nota notas opus opera página páginas página páginas párrafo párrafos parte partes sección secciones sub voce sub vocibus verso versos volumen volúmenes lib. libs. cap. caps. col. cols. fig. figs. f. ff. núm. núms. l. ls. n. nn. op. opp. p. pp. p. pp. párr. párrs. pt. pts. sec. secs. s. v. s. vv. v. vv. vol. vols. § § director directores editor editores coordinador coordinadores ilustrador ilustradores traductor traductores editor y traductor editores y traductores dir. dirs. ed. eds. coord. coords. ilust. ilusts. trad. trads. ed. y trad. eds. y trads. de dirigido por editado por coordinado por ilustrado por entrevistado por a por traducido por editado y traducido por dir. ed. coord. ilust. trad. ed. y trad. enero febrero marzo abril mayo junio julio agosto septiembre octubre noviembre diciembre ene. feb. mar. abr. may jun. jul. ago. sep. oct. nov. dic. primavera verano otoño invierno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-et-EE.xml0000644000175100001660000002404014764177705022672 0ustar00runnerdocker Andrew Dunning This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 vaadatud ja ja teised anonüümne anon available at umbes u tsiteeritud väljaanne väljaanded tr et al. ilmumisel ibid. trükis internet intervjuu kiri s.a. s.a. online esitatud viide viited viide viited salvestatud scale version pKr eKr . esimene teine kolmas neljas viies kuues seitsmes kaheksas üheksas kümnes raamat raamatud peatükk peatükid veerg veerud joonis joonised foolio fooliod number numbrid rida read viide viited opus opera lehekülg leheküljed lehekülg leheküljed lõik lõigud osa osad alajaotis alajaotised sub verbo sub verbis värss värsid köide köited rmt ptk v joon f nr l. n. op lk lk lk lk lõik osa alajaot. s.v. s.vv. v vv kd kd ¶¶ § §§ director directors toimetaja toimetajad toimetaja toimetajad illustrator illustrators tõlkija tõlkijad toimetaja & tõlkija toimetajad & tõlkijad dir. dirs. toim toim toim toim ill. ills. tõlk tõlk toim & tõlk toim & tõlk directed by toimetanud toimetanud illustrated by intervjueerinud by tõlkinud toimetanud & tõlkinud dir. toim toim illus. tõlk toim & tõlk jaanuar veebruar märts aprill mai juuni juuli august september oktoober november detsember jaan veebr märts apr mai juuni juuli aug sept okt nov dets kevad suvi sügis talv ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-eu.xml0000644000175100001660000002441514764177705022412 0ustar00runnerdocker Amaraun This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 eskuratua eta eta beste ezezaguna ezez. -(e)n available at -(e)k egina inguru ing. aipatua argitalpena argitalpenak arg. et al. bidean -(e)tik ibíd. in moldiztegian internet elkarrizketa gutuna datarik gabe d. g. sarean -(e)n aurkeztua aipamena aipamenak aip. aip. berreskuratua scale version K.a. K.o. « » . lehengo bigarren hirugarren laugarren bosgarren seigarren zazpigarren zortzigarren bederatzigarren hamargarren liburua liburuak kapitulua kapituluak zutabea zutabeak irudia irudiak orria orriak zenbakia zenbakiak lerroa lerroak oharra oharrak obra obrak orrialdea orrialdeak orrialdea orrialdeak paragrafoa paragrafoak zatia zatiak atala atalak sub voce sub vocem bertsoa bertsoak luburikia luburukiak lib. kap. zut. iru. or. zenb. l. n. op. or. or. or. or. par. zt. atal. s.v. s.v. b. bb. libk. libk. ¶¶ § § director directors argitaratzailea argitaratzaileak argitaratzailea argitaratzaileak illustrator illustrators itzultzailea itzultzaileak argitaratzaile eta itzultzailea argitaratzaile eta itzultzaileak dir. dirs. arg. arg. arg. arg. ill. ills. itzul. itzul. arg. eta itzul. arg. eta itzul. directed by -(e)k argitaratua -(e)k argitaratua illustrated by -(e)k elkarrizketatua -(r)entzat by -(e)k itzulia -(e)k argitaratu eta itzulia dir. arg. arg. illus. itzul. -(e)k arg. eta itzul. urtarrilak otsailak martxoak apirilak maiatzak ekainak uztailak abuztuak irailak urriak azaroak abenduak urt. ots. martx. apr. mai. eka. uzt. abz. ira. urr. aza. abe. udaberria uda udazkena negua ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-fa-IR.xml0000644000175100001660000002611014764177705022671 0ustar00runnerdocker Hamed Heydari abdealikhurrum This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 دسترسی و و دیگران ناشناس ناشناس در قابل دسترس در توسط تقریباً c. ارجاع شده ویرایش ویرایش‌های ویرایش و همکاران در دست انتشار از همان در زیر چاپ اینترنت مصاحبه نامه بدون تاریخ بدون تاریخ آنلاین ارائه شده در مرجع مراجع مرجع مراجع retrieved scale نسخه بعد از میلاد قبل از میلاد اول دوم سوم چهارم پنجم ششم هفتم هشتم نهم دهم کتاب کتاب‌های فصل فصل‌های ستون ستون‌های تصویر تصاویر برگ برگ‌های شماره شماره‌های خط خطوط یادداشت یادداشت‌های قطعه قطعات صفحه صفحات صفحه صفحات پاراگراف پاراگراف‌های بخش بخش‌های قسمت قسمت‌های در ذیلِ واژه در ذیلِ واژه‌های بیت بیت‌های جلد جلدهای کتاب فصل ستون تصویر برگ ش خط یادداشت قطعه ص صص ص صص پاراگراف بخش قسمت s.v s.vv بیت ابیات ج جج ¶¶ § §§ director directors ویراستار ویراستاران ویراستار ویراستاران طراح گرافیک طراحان گرافیک مترجم مترجمین ویراستار و مترجم ویراستاران و مترجمین dir. dirs. ویراستار ویراستاران ویراستار ویراستاران تصویرگر تصویرگران مترجم مترجمین ویراستار و مترجم ویراستاران و مترجمین توسط زیر نظر ویراسته‌ی ویراسته‌ی طراحی گرافیکی از مصاحبه توسط به بازبینی توسط ترجمه‌ی ترجمه و ویراسته‌ی dir. ویراسته‌ی ویراسته‌ی طراحی از ترجمه‌ی ترجمه و ویراسته‌ی ژانویه فوریه مارس آوریل می ژوئن جولای آگوست سپتامبر اکتبر نوامبر دسامبر ژانویه فوریه مارس آوریل می ژوئن جولای آگوست سپتامبر اکتبر نوامبر دسامبر بهار تابستان پاییز زمستان ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-fi-FI.xml0000644000175100001660000002456014764177705022674 0ustar00runnerdocker Janne Huovari snissine villelahtinen Juhana Venäläinen This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 viitattu ja ym. tuntematon tuntematon osoitteessa saatavissa tekijä noin n. viitattu painos painokset p. ym. tulossa osoitteesta mt. teoksessa painossa internet haastattelu kirje ei päivämäärää ei pvm. verkossa esitetty tilaisuudessa viittaus viittaukset viit. viit. noudettu mittakaava versio jaa. eaa. . ensimmäinen toinen kolmas neljäs viides kuudes seitsemäs kahdeksas yhdeksäs kymmenes kirja kirjat luku luvut palsta palstat kuvio kuviot folio foliot numero numerot rivi rivit huomautus huomautukset opus opukset sivu sivut sivu sivut kappale kappaleet osa osat osa osat sub verbo sub verbis säkeistö säkeistöt vuosikerta vuosikerrat kirja luku palsta kuv. fol. nro r. huom. op. s. ss. s. ss. kappale osa osa s.v. s.vv. säk. säk. vsk. vsk. ¶¶ § §§ ohjaaja ohjaajat toimittaja toimittajat toimittaja toimittajat kuvittaja kuvittajat kääntäjä kääntäjät toimittaja ja kääntäjä toimittajat ja kääntäjät ohj. ohj. toim. toim. toim. toim. kuv. kuv. käänt. käänt. toim. ja käänt. toim. ja käänt. ohjannut toimittanut toimittanut kuvittanut haastatellut vastaanottaja kääntänyt toimittanut ja kääntänyt ohj. toim. toim. kuv. käänt. toim. ja käänt. tammikuuta helmikuuta maaliskuuta huhtikuuta toukokuuta kesäkuuta heinäkuuta elokuuta syyskuuta lokakuuta marraskuuta joulukuuta tammi helmi maalis huhti touko kesä heinä elo syys loka marras joulu kevät kesä syksy talvi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-fr-CA.xml0000644000175100001660000002552114764177705022670 0ustar00runnerdocker Grégoire Colly This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 consulté le et et autres anonyme anon. sur disponible à par vers v. cité édition éditions éd. et al. à paraître à l'adresse ibid. dans sous presse Internet entretien lettre sans date s. d. en ligne présenté à référence références réf. réf. consulté échelle version apr. J.-C. av. J.-C. «   » ʳᵉ ᵉʳ premier deuxième troisième quatrième cinquième sixième septième huitième neuvième dixième livre livres chapitre chapitres colonne colonnes figure figures folio folios numéro numéros ligne lignes note notes opus opus page pages page pages paragraphe paragraphes partie parties section sections sub verbo sub verbis verset versets volume volumes liv. chap. col. fig. fᵒ fᵒˢ nᵒ nᵒˢ l. n. op. p. p. p. p. paragr. part. sect. s. v. s. vv. v. v. vol. vol. § § § § réalisateur réalisateurs éditeur éditeurs directeur directeurs illustrateur illustrateurs traducteur traducteurs éditeur et traducteur éditeurs et traducteurs réal. réal. éd. éd. dir. dir. ill. ill. trad. trad. éd. et trad. éd. et trad. par réalisé par édité par sous la direction de illustré par entretien réalisé par à par traduit par édité et traduit par réal. par éd. par ss la dir. de ill. par trad. par éd. et trad. par janvier février mars avril mai juin juillet août septembre octobre novembre décembre janv. févr. mars avr. mai juin juill. août sept. oct. nov. déc. printemps été automne hiver ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-fr-FR.xml0000644000175100001660000002552414764177705022717 0ustar00runnerdocker Grégoire Colly This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 consulté le et et autres anonyme anon. sur disponible sur par vers v. cité édition éditions éd. et al. à paraître à l'adresse ibid. in sous presse Internet entretien lettre sans date s. d. en ligne présenté à référence références réf. réf. consulté échelle version apr. J.-C. av. J.-C. «   » ʳᵉ ᵉʳ premier deuxième troisième quatrième cinquième sixième septième huitième neuvième dixième livre livres chapitre chapitres colonne colonnes figure figures folio folios numéro numéros ligne lignes note notes opus opus page pages page pages paragraphe paragraphes partie parties section sections sub verbo sub verbis verset versets volume volumes liv. chap. col. fig. fᵒ fᵒˢ nᵒ nᵒˢ l. n. op. p. p. p. p. paragr. part. sect. s. v. s. vv. v. v. vol. vol. § § § § réalisateur réalisateurs éditeur éditeurs directeur directeurs illustrateur illustrateurs traducteur traducteurs éditeur et traducteur éditeurs et traducteurs réal. réal. éd. éd. dir. dir. ill. ill. trad. trad. éd. et trad. éd. et trad. par réalisé par édité par sous la direction de illustré par entretien réalisé par à par traduit par édité et traduit par réal. par éd. par ss la dir. de ill. par trad. par éd. et trad. par janvier février mars avril mai juin juillet août septembre octobre novembre décembre janv. févr. mars avr. mai juin juill. août sept. oct. nov. déc. printemps été automne hiver ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-he-IL.xml0000644000175100001660000002510114764177705022670 0ustar00runnerdocker roypeled1 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 נבדק לאחרונה ו ואחרים אלמוני anon זמין ב על-ידי לערך c. מצוטט ב מהדורה מהדורות ed ואחרים צפוי מתוך שם בתוך בהדפסה אינטרנט ראיון מכתב אין נתונים nd מקוון הוצג ב הפניה הפניות ref. refs. אוחזר scale גירסה לספירה לפני הספירה th st nd rd th th th ראשון שני שלישי רביעי חמישי שישי שביעי שמיני תשיעי עשירי ספר ספרים פרק פרקים טור טורים figure figures פוליו פוליו מספר מספרים שורה שורות הערה הערות אופוס אופרה עמוד עמודים עמוד עמודים פיסקה פיסקאות חלק חלקים סעיף סעיפים sub verbo sub verbis בית בתים כרך כרכים bk chap col fig f no l. n. op 'עמ 'עמ 'עמ 'עמ para pt ס' s.v. s.vv. v vv vol vols ¶¶ § §§ במאי במאים עורך עורכים עורך ראשי עורכים ראשיים מאייר מאיירים מתרגם מתרגמים editor & translator editors & translators dir. dirs. ed eds ed. eds. ill. ills. tran trans ed. & tran. eds. & trans. by בוים ע"י נערך ע"י בוים ע"י אויר ע"י רואיין ע"י אל ע"י תורגם ע"י edited & translated by dir. ed ed. illus. trans ed. & trans. by ינואר פברואר מרץ אפריל מאי יוני יולי אוגוסט ספטמבר אוקטובר נובמבר דצמבר Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-hi-IN.xml0000644000175100001660000003203614764177705022703 0ustar00runnerdocker Neha Srivastava neha-srivastava@outlook.com This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2021-02-22T12:13:02+05:30 अंतिम उपयोग व अन्य अज्ञात अज्ञात पर पर उपलब्ध द्वारा सन सन. उल्लेखित संस्करण संस्करण ed. इत्यादि आगामी से उक्त में मुद्रण में इंटर्नेट साक्षात्कार पत्र दिनांक अज्ञात n.d. ऑनलाइन पर प्रस्तुत संदर्भ references ref. refs. पुनर्प्राप्त scale संस्करण CE BCE वाँ पहला पहली दूसरा दूसरी तीसरा तीसरी चौथा चौथी पाँचवा पाँचवी छठा छठी सातवाँ सातवीं आठवाँ आठवीं नवाँ नौवीं दसवाँ दसवीं पुस्तक पुस्तकें अध्याय अध्याय कॉलम columns चित्र चित्रों पर्ण folios संख्या संख्याएँ पंक्ति पंक्तियाँ नोट notes opus opera पृष्ठ पृष्ठ पृष्ठ संख्या पृष्ठों की संख्या अनुच्छेद paragraphs भाग parts अनुभाग sections sub verbo sub verbis पद verses वॉल्यूम वॉल्यूम्ज़ bk. bks. chap. chaps. col. cols. fig. figs. fol. fols. no. nos. l. ll. n. nn. op. opp. पृ. पृ. पृ. स. पृ. स. para. paras. pt. pts. sec. secs. s.v. s.vv. v. vv. vol. vols. ¶¶ § §§ निर्देशक directors सम्पादक editors सम्पादक editors चित्रकार illustrators अनुवादक translators सम्पादक & अनुवादक editors & translators dir. dirs. ed. eds. ed. eds. ill. ills. tran. trans. ed. & tran. eds. & trans. द्वारा निर्देशन सम्पादन निर्देशन चित्रकारी साक्षात्कारकर्ता सेवा में द्वारा अनुवाद सम्पादन & अनुवाद dir. by ed. by ed. by illus. by trans. by ed. & trans. by जनवरी फ़रवरी मार्च अप्रैल मई जून जुलाई अगस्त सितम्बर अक्टूबर नवम्बर दिसम्बर जन. फ़र. मार्च अप्रैल मई जून जुलाई अग. सित. अक्ट. नव. दिस. वसंत ऋतु ग्रीष्म ऋतु पतझड़ ऋतु शिशिर ऋतु ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-hr-HR.xml0000644000175100001660000002417614764177705022725 0ustar00runnerdocker tvrbanec This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 pristupljeno i i ostali anonimno anon. na dostupno na od oko oko citirano izdanje izdanja izd. i ostali u pripremi od ibid. u u tisku internet intervju pismo bez datuma bez dat. na internetu predstavljeno na reference reference ref. ref. preuzeto skala verzija pr. Kr. . prvi drugi treći četvrti peti šesti sedmi osmi deveti deseti knjiga knjige poglavlje poglavlja stupac stupci crtež crteži folija folije izdanje izdanja red redovi bilješka bilješke djelo djela stranica stranice stranica stranice pasus pasusi dio dijelova odjeljak odjeljci sub verbo sub verbis stih stihovi svezak svesci knj. pogl. stup. crt. fol. izd. red bilj. sv. str. str. str. str. par. dio od. s.v. s.vv. st. st. sv. sv. ¶¶ § §§ voditelj voditelji urednik urednici urednik urednici ilustrator ilustratori prevoditelj prevoditelji urednik & prevoditelj urednici & prevoditelji vod. vod. ur. ur. ur.-vod. ur.-vod. il. il. prev. prev. ur. & prev. ur. & prev. od vodio uredio uredio ilustrirao intervjuirao primatelj pregledao preveo uredio & preveo vod. ur. ur. vod. ilus. prev. ur. & prev. siječanj veljača ožujak travanj svibanj lipanj srpanj kolovoz rujan listopad studeni prosinac sij. velj. ožu. tra. svi. lip. srp. kol. ruj. lis. stu. pros. proljeće ljeto jesen zima ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-hu-HU.xml0000644000175100001660000002447714764177705022737 0ustar00runnerdocker Miklos Vajna This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2014-06-17T09:56:35+02:00 elérés és és mások szerző nélkül sz. n. elérhető by körülbelül kb. idézi kiadás kiadás kiad. és mtsai. megjelenés alatt forrás uo. in nyomtatás alatt internet interjú levél évszám nélkül é. n. online előadás hivatkozás hivatkozás hiv. hiv. elérés skála verzió Kr. u. Kr. e. i. sz. i. e. » « . első második harmadik negyedik ötödik hatodik hetedik nyolcadik kilencedik tizedik könyv könyv fejezet fejezet oszlop oszlop ábra ábra fóliáns fóliáns szám szám sor sor jegyzet jegyzet oldal oldal oldal oldal bekezdés bekezdés rész rész szakasz szakasz sub verbo sub verbis versszak versszak kötet kötet könyv fej. oszl. ábr. fol. sz. s. j. op. o. o. o. o. bek. rész szak. s. v. s. vv. vsz. vsz. köt. köt. ¶¶ § §§ igazgató igazgató szerkesztő szerkesztő szerkesztőségi igazgató szerkesztőségi igazgató illusztrátor illusztrátor fordító fordító szerkesztő & fordító szerkesztő & fordító ig. ig. szerk. szerk. szerk. ig. szerk. ig. ill. ill. ford. ford. szerk. & ford. szerk. & ford. by directed by szerkesztette edited by illusztrálta interjúkészítő címzett by fordította szerkesztette & fordította ig. szerk. ed. ill. ford. szerk. & ford. január február március április május június július augusztus szeptember október november december jan. febr. márc. ápr. máj. jún. júl. aug. szept. okt. nov. dec. tavasz nyár ősz tél ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-id-ID.xml0000644000175100001660000002464314764177705022672 0ustar00runnerdocker faizhabibullah Deden Habibi xbypass This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2015-08-05T23:31:02+00:00 diakses dan dan lainnya anonim anon. pada tersedia pada oleh circa ca. dikutip edisi edisi ed. dkk. mendatang dari ibid. dalam dalam proses cetakan internet wawancara surat tanpa tanggal t.t. daring dipresentasikan pada referensi referensi ref. ref. diambil skala versi M SM pertama kedua ketiga keempat kelima keenam ketujuh kedelapan kesembilan kesepuluh buku buku bab bab kolom kolom gambar gambar folio folio nomor nomor baris baris catatan catatan opus opera halaman halaman halaman halaman paragraf paragraf bagian bagian bagian bagian sub verbo sub verbis ayat ayat volume volume bk. bb. kol. gbr. fol. no. brs. ctt. op. hlm. hlm. hlm. hlm. para. bag. bag. s.v. s.vv. a. a. vol. vol. ¶¶ § §§ direktur direktur editor editor editor editor ilustrator ilustrator penerjemah penerjemah editor & penerjemah editor & penerjemah dir. dir. ed. ed. ed. ed. il. il. penerj. penerj. ed. & penerj. ed. & penerj. oleh diarahkan oleh disunting oleh disunting oleh diilustrasi oleh diwawancara oleh kepada oleh diterjemahkan oleh disunting & diterjemahkan oleh dir. oleh ed. oleh ed. oleh illus. oleh trans. oleh ed. & penerj. oleh Januari Februari Maret April Mei Juni Juli Agustus September Oktober November Desember Jan Feb Mar Apr Mei Jun Jul Agu Sep Okt Nov Des Semi Panas Gugur Dingin ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-is-IS.xml0000644000175100001660000002434414764177705022726 0ustar00runnerdocker dadamaster styrmirm This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 sótt og og fleiri nafnlaus nafnl. af aðgengilegt á eftir sirka u.þ.b. tilvitnun útgáfa útgáfur útg. o.fl. óbirt af sama heimild í í prentun rafrænt viðtal bréf engin dagsetning e.d. rafrænt flutt á tilvitnun tilvitnanir tilv. tilv. sótt scale útgáfa e.Kr. f.Kr. . fyrsti annar þriðji fjórði fimmti sjötti sjöundi áttundi níundi tíundi bók bækur kafli kaflar dálkur dálkar mynd myndir handrit handrit tölublað tölublöð lína línur athugasemd athugasemdir tónverk tónverk blaðsíða blaðsíður blaðsíða blaðsíður málsgrein málsgreinar hluti hlutar hluti hlutar sub verbo sub verbis vers vers bindi bindi bók k. d. mynd. handr. tbl. l. ath. tónv. bls. bls. bls. bls. málsgr. hl. hl. s.v. s.vv. v. v. b. b. ¶¶ § §§ leikstjóri leikstjórar ritstjóri ritstjórar ritstjóri ritstjórar höfundur myndskreytinga höfundar myndskreytinga þýðandi þýðendur ritstjóri og þýðandi ritstjórar og þýðendur leikstj. leikstj. ritstj. ritstj. ritstj. ritstj. höf. mynd. höf. mynd. þýð. þýð. ritstj. og þýð. ritstj. og þýð. eftir leikstýrt af ritstýrt af ritstýrt af myndskreytt af viðtal tók til by þýddi ritstýrt og þýtt af leikstj. ritstj. ritstj. myndskr. þýð. ritstj. og þýð. janúar febrúar mars apríl maí júní júlí ágúst september október nóvember desember jan. feb. mar. apr. maí jún. júl. ágú. sep. okt. nóv. des. vor sumar haust vetur ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-it-IT.xml0000644000175100001660000003010314764177705022716 0ustar00runnerdocker FI App Development Monica Thuegaz This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 consultato e e altri anonimo anon. a disponibile su su di circa c. citato edizione edizioni ed. et al. futuro da ibid. ibidem ibid. in in stampa internet intervista lettera senza data s.d. online presentato al reference references ref. refs. recuperato scala versione d.C. a.C. « » º º ª prima primo prima seconda secondo seconda terza terzo terza quarta quarto quarta quinta quinto quinta sesta sesto sesta settima settimo settima ottava ottavo ottava nona nono nona decima decimo decima libro libri capitolo capitoli colonna colonne figura figure foglio fogli numero numeri riga righe nota note opera opere pagina pagine pagina pagine capoverso capoversi parte parti paragrafo paragrafi sub verbo sub verbis verso versi volume volumi lib. cap. capp. col. fig. fgl. n. l. n. op. pag. pagg. pag. pagg. cpv. pt. par. s.v. s.vv. v. vv. vol. voll. ¶¶ § §§ director directors curatore curatori editor editors illustratore illustratori traduttore traduttori curatore e traduttore curatori e tradutori dir. dir. a c. di a c. di ed. ed. ill. ill. trad. trad. a c. di e trad. da a c. di e trad. da di diretto da a cura di edited by illustrato da intervista di a di tradotto da a cura di e tradotto da dir. da a c. di ed. ill. da trad. da a c. di e trad. da gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre gen. feb. mar. apr. mag. giu. lug. ago. set. ott. nov. dic. primavera estate autunno inverno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-ja-JP.xml0000644000175100001660000002435314764177705022703 0ustar00runnerdocker Shoji Takahashi This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 参照 and others anonymous anon at available at by circa c. cited ほか 近刊 から 前掲 in press internet interview letter no date 日付なし online presented at the reference references ref. refs. 読み込み scale version AD BC th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth book books chapter chapters column columns figure figures folio folios number numbers note notes opus opera ページ ページ ページ ページ 段落 段落 part parts section sections sub verbo sub verbis verse verses volume volumes bk. chap. col. fig. f. no. l. n. op. p. pp. p. pp. para. pt. sec. s.v. s.vv. v. vv. vol. vols. ¶¶ § §§ director directors editor editors illustrator illustrators 翻訳者 翻訳者 editor & translator editors & translators dir. dirs. ed. eds. ill. ills. 翻訳者 翻訳者 ed. & tran. eds. & trans. by directed by 編集者: edited by illustrated by interview by to by 翻訳者: edited & translated by dir. 編集者: ed. illus. 翻訳者: ed. & trans. by 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-km-KH.xml0000644000175100001660000002532314764177705022707 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 accessed and and others anonymous anon. at available at by circa c. cited edition editions ed. et al. forthcoming from ibid in in press internet interview letter no date n.d. online presented at the reference references ref. refs. retrieved scale version AD BC th st nd rd th th th ទីមួយ ទីពីរ ទីបី ទីបួន ទីប្រាំ ទីប្រាំមួយ ទីប្រាំពីរ ទីប្រាំបី ទីប្រាំបួន ទីដប់មួយ សៀវភៅ សៀវភៅ ជំពូក ជំពូក កាឡោន កាឡោន តួលេខ តួលេខ folio folios ចំនួន ចំនួន បន្ទាត់ បន្ទាត់ កំណត់ចំណាំ កំណត់ចំណាំ opus opera ទំព័រ ទំព័រ ទំព័រ ទំព័រ កថាខណ្ឌ កថាខណ្ឌ ជំពូក ជំពូក ផ្នែក ផ្នែក sub verbo sub verbis verse verses វ៉ុល វ៉ុល bk. chap. col. fig. f. no. l. n. op. p. pp. p. pp. para. pt. sec. s.v. s.vv. v. vv. vol. vols. ¶¶ § §§ director directors editor editors editors illustrator illustrators translator translator editor & translator editors & translators dir. dirs. ed. eds. ed. eds. ill. ills. tran. trans. ed. & tran. eds. & trans. by directed by edited by edited by illustrated by interview by to by translated by edited & translated by dir. ed. ed. illus. trans. ed. & trans. by មករា កុម្ភៈ មីនា មេសា ឧសភា មិថុនា កក្កដា សីហា កញ្ញា តុលា វិច្ឆិកា ធ្នូ Jan. Feb. Mar. Apr. May Jun. Jul. Aug. Sep. Oct. Nov. Dec. Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-ko-KR.xml0000644000175100001660000002427514764177705022730 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 접근된 와/과 and others anonymous anon at available at by circa c. cited edition editions ed 기타 근간 (으)로부터 ibid. in in press internet interview letter no date 일자 없음 online presented at the reference references ref. refs. retrieved scale version AD BC th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth book books chapter chapters column columns figure figures folio folios number numbers note notes opus opera 페이지 페이지 페이지 페이지 단락 단락 part parts section sections sub verbo sub verbis verse verses volume volumes bk chap col fig f l. n. op p pp p pp para pt sec s.v. s.vv. v vv vol vols ¶¶ § §§ director directors 편집자 편집자 editor editors illustrator illustrators 번역자 번역자 editor & translator editors & translators dir. dirs. 편집자 편집자 ed. eds. ill. ills. 번역자 번역자 ed. & tran. eds. & trans. by directed by 편집자: edited by illustrated by interview by to by 번역자: edited & translated by dir. ed ed. illus. trans ed. & trans. by 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월 1 2 3 4 5 6 7 8 9 10 11 12 Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-la.xml0000644000175100001660000002407314764177705022375 0ustar00runnerdocker Andrew Dunning This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2019-01-21T13:33:33+00:00 consultatus et et alii anonymus anon. ad praestatus ad a circa c. citatus editio editiones ed. et al. futurus ab ibid. in impressorio interrete congressus epistula sine die s.d. in linea praebitus ad relatio relationes rel. rell. recuperatus scala uersio A.D. A.C. º primus secundus tertius quartus quintus sextus septimus octauus nonus decimus liber libri capitulum capitula columna columnae figura figurae folium folii numerus numeri linea lineae nota notae opus opera pagina paginae pagina paginae paragraphus paragraphi pars partes paragraphus paragraphi sub uerbo sub uerbis versus versus tomus tomi lib. cap. col. fig. fol. n. l. n. op. p. pp. p. pp. par. pr. par. s.u. s.uu. u. uu. t. tt. ¶¶ § §§ director directores curator curatores editor editores illustrator illustratores interpres interpretes curator et interpres curatores et interpretes dir. dirs. cur. curs. ed. eds. ill. ills. interp. interps. cur. et interp. curs. et interps. a a directione a cura ab editione ab illustratione a congressione a a a interpretatione a cura et interpretatione dir. cur. ed. illus. interp. a cur. et interp. ianuarius februarius martius aprilis maius iunius iulius augustus september october nouember december ian. feb. mar. apr. mai. iun. iul. aug. sep. oct. nou. dec. uer aestas autumnus hiems ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-lt-LT.xml0000644000175100001660000002673514764177705022744 0ustar00runnerdocker Valdemaras Klumbys This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2017-01-18T10:31:02+00:00 žiūrėta ir ir kt. anonimas anon. adresas apie apie žiūrėta leidimas leidimai leid. ir kt. ruošiamas ten pat priimta spaudai prieiga per internetą interviu laiškas sine anno s.a. interaktyvus pristatytas nuoroda nuorodos nuor. nuor. gauta mastelis versija po Kr. pr. Kr. , -asis -asis -oji -iasis -asis -ioji -oji pirmasis antrasis trečiasis ketvirtasis penktasis šeštasis septintasis aštuntasis devintasis dešimtasis pirmoji antroji trečioji ketvirtoji penktoji šeštoji septintoji aštuntoji devintoji dešimtoji knyga knygos skyrius skyriai skiltis skiltys iliustracija iliustracijos lapas lapai numeris numeriai eilutė eilutės pastaba pastabos kūrinys kūriniai puslapis puslapiai puslapis puslapiai pastraipa pastraipos dalis dalys poskyris poskyriai žiūrėk žiūrėk eilėraštis eilėraščiai tomas tomai kn. sk. skilt. il. l. nr. eil. pstb. kūr. p. p. p. p. pastr. d. posk. žr. žr. eilėr. eilėr. t. t. ¶¶ § §§ vadovas vadovai sudarytojas sudarytojai atsakingasis redaktorius atsakingieji redaktoriai iliustratorius iliustratoriai vertėjas vertėjai sudarytojas ir vertėjas sudarytojai ir vertėjai vad. vad. sud. sud. ats. red. ats. red. iliustr. iliustr. vert. vert. sud. ir vert. sud. ir vert. vadovavo sudarė parengė iliustravo interviu ėmė gavo recenzavo vertė sudarė ir vertė vad. sud. pareng. iliustr. vert. sud. ir vert. sausio vasario kovo balandžio gegužės birželio liepos rugpjūčio rugsėjo spalio lapkričio gruodžio saus. vas. kovo bal. geg. birž. liep. rugpj. rugs. spal. lapkr. gruodž. pavasaris vasara ruduo žiema ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-lv-LV.xml0000644000175100001660000003023514764177705022736 0ustar00runnerdocker Andris Lupgins This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-12-27T11:40:58+02:00 skatīts m.ē. un un citi anonīms anon. pieejams p.m.ē. apmēram apm. citēts redakcija redakcijas red. u.c. gaidāms no turpat no presē internets intervija vēstule bez datuma b.g. tiešsaiste iesniegts atsauce atsauces ats. ats. iegūts mērogs versija " " " " -ais pirmais otrais trešais ceturtais piektais sestais septītais astotais devītais desmitais pirmā otrā trešā ceturtā piektā sestā septītā astotā devītā desmitā grāmata grāmatas nodaļa nodaļas sleja slejas ilustrācija ilustrācijas folio folio numurs numuri rinda rindas piezīme piezīmes opuss opusi lappuse lappuses lappuse lappuses rindkopa rindkopas daļa daļas apakšnodaļa apakšnodaļas skatīt skatīt pants panti sējums sējumi grām. nod. sl. il. fo. nr. r. piez. op. lpp. lpp. lpp. lpp. rindk. d. apakšnod. sk. sk. p. p. sēj. sēj. ¶¶ § §§ krājuma redaktors krājuma redaktori sastādītājs sastādītāji pamatmateriāla autors pamatmateriāla autori vadītājs vadītāji redaktors redaktors galvenais redaktors galvenie redaktori redaktors un tulkotājs redaktors un tulkotājs ilustrators ilustratori intervētājs intervētāji saņēmējs saņēmēji tulkotājs tulkotāji kr. red. kr. red. sast. sast. pamatmat. aut. pamatmat. aut. vad. vad. red. red. galv. red. galv. red. red. un tulk. red. un tulk. ilustr. ilustr. interv. interv. saņ. saņ. tulk. tulk. sastādīja vadīja sagatavoja sagatavoja sagatavoja un tulkoja ilustrēja intervēja saņēma tulkoja sast. sag. sag. ilustr. tulk. sag. un tulk. janvārī februārī martā aprīlī maijā jūnijā jūlijā augustā septembrī oktobrī novembrī decembrī janv. febr. mar. apr. mai. jūn. jūl. aug. sept. okt. nov. dec. pavasaris vasara rudens ziema ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-mn-MN.xml0000644000175100001660000002521614764177705022723 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 accessed and and others anonymous anon at available at by circa c. cited edition editions ed et al. forthcoming from ibid. in in press internet interview letter no date n.d. online presented at the reference references ref. refs. retrieved scale version AD BC « » -p нэгдүгээр хоёрдугаар гуравдугаар дөрөвдүгээр тавдугаар зургаадугаар долоодугаар наймдугаар есдүгээр аравдугаар ном номнууд chapter chapters багана баганууд figure figures folio folios тоо тоонууд шугам шугамнууд note notes opus opera хуудас хуудаснууд хуудас хуудаснууд paragraph paragraph part parts section sections sub verbo sub verbis verse verses volume volumes bk chap col fig f no l. n. op p pp p pp para pt sec s.v. s.vv. v vv vol vols ¶¶ § §§ director directors редактор редакторууд редактор редакторууд illustrator illustrators орчуулагч орчуулагчид редактор ба орчуулагч редакторууд ба орчуулагчид dir. dirs. ред. ред. ред. ред. ill. ills. орч орч ред. ба орч. ред. ба орч. by directed by edited by edited by illustrated by interview by to by translated by edited & translated by dir. ed ed. illus. trans ed. & trans. by Нэгдүгээр сар Хоёрдугаар сар Гуравдугаар сар Дөрөвдүгээр сар Тавдугаар сар Зургаадугаар сар Долдугаар сар Наймдугаар сар Есдүгээр сар Аравдугаар сар Арван нэгдүгээр сар Арван хоёрдугаар сар 1-р сар 2-р сар 3-р сар 4-р сар 5-р сар 6-р сар 7-р сар 8-р сар 9-р сар 10-р сар 11-р сар 12-р сар Хавар Зун Намар Өвөл ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-nb-NO.xml0000644000175100001660000002411614764177705022710 0ustar00runnerdocker Guttorm Flatabø This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2013-03-01T12:20:00+01:00 åpnet og med flere anonym anon. tilgjengelig på av circa ca. sitert utgave utgaver utg. mfl. kommende fra ibid. i i trykk Internett intervju brev ingen dato u.å. online presentert på referanse referanser ref. refr. hentet målestokk versjon fvt. evt. « » . første andre tredje fjerde femte sjette sjuende åttende niende tiende bok bøker kapittel kapitler kolonne kolonner figur figurer folio folioer nummer numre linje linjer note noter opus opus side side side sider avsnitt avsnitt del deler paragraf paragrafer sub verbo sub verbis vers vers bind bind b. kap. kol. fig. fol. nr. l. n. op. s. s. s. s. avsn. d. pargr. s.v. s.vv. v. v. bd. bd. ¶¶ § §§ regissør regissører redaktør redaktører redaktør redaktører illustratør illustratører oversetter oversettere redaktør & oversetter redaktører & oversettere regi regi red. red. red. red. ill. ills. overs. overs. red. & overs. red. & overs. av regissert av redigert av redigert av illustrert av intervjuet av til av oversatt av redigert & oversatt av regi red. red. illus. overs. red. & overs. av januar februar mars april mai juni juli august september oktober november desember jan. feb. mar. apr. mai jun. jul. aug. sep. okt. nov. des. vår sommer høst vinter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-nl-NL.xml0000644000175100001660000002612514764177705022721 0ustar00runnerdocker Rintze M. Zelle http://twitter.com/rintzezelle This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2017-04-01T12:00:00+00:00 geraadpleegd en en anderen anoniem anon. bij beschikbaar op door circa c. geciteerd druk drukken dr. e.a. in voorbereiding van ibid. in in druk internet interview brief zonder datum z.d. online gepresenteerd bij referentie referenties ref. refs. geraadpleegd schaal versie AD BC ste de de de de de de de de de de de de de de de de de de eerste tweede derde vierde vijfde zesde zevende achtste negende tiende boek boeken hoofdstuk hoofdstukken column columns figuur figuren folio folio's nummer nummers regel regels aantekening aantekeningen opus opera pagina pagina's pagina pagina's paragraaf paragrafen deel delen sectie secties sub verbo sub verbis vers versen volume volumes bk. hfdst. col. fig. f. nr. l. n. op. p. pp. p. pp. par. deel sec. s.v. s.vv. v. vv. vol. vols. ¶¶ § §§ regisseur regisseurs redacteur redacteuren redacteur redacteuren illustrator illustrators vertaler vertalers redacteur & vertaler redacteuren & vertalers reg. reg. red. red. red. red. ill. ill. vert. vert. red. & vert. red. & vert. door geregisseerd door onder redactie van onder redactie van geïllustreerd door geïnterviewd door ontvangen door door vertaald door bewerkt & vertaald door geregisseerd door onder redactie van bewerkt door geïllustreerd door vertaald door bewerkt & vertaald door januari februari maart april mei juni juli augustus september oktober november december jan. feb. mrt. apr. mei jun. jul. aug. sep. okt. nov. dec. lente zomer herst winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-nn-NO.xml0000644000175100001660000002407014764177705022723 0ustar00runnerdocker Guttorm Flatabø This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2013-03-01T12:20:00+01:00 vitja og med fleire anonym anon. tilgjengeleg på av circa ca. sitert utgåve utgåver utg. mfl. kommande frå ibid. i i trykk Internett intervju brev ingen dato u.å. online presentert på referanse referansar ref. refr. henta målestokk versjon fvt. evt. « » . første andre tredje fjerde femte sjette sjuande åttande niande tiande bok bøker kapittel kapittel kolonne kolonner figur figurar folio folioar nummer nummer linje linjer note notar opus opus side side side sider avsnitt avsnitt del deler paragraf paragrafar sub verbo sub verbis vers vers bind bind b. kap. kol. fig. fol. nr. l. n. op. s. s. s. s. avsn. d. par. s.v. s.vv. v. v. bd. bd. ¶¶ § §§ regissør regissørar redaktør redaktørar redaktør redaktørar illustratør illustratørar omsetjar omsetjarar redaktør & omsetjar redaktørar & omsetjarar regi regi red. red. red. red. ill. ills. oms. oms. red. & oms. red. & oms. av regissert av redigert av redigert av illustrert av intervjua av til av omsett av redigert & omsett av regi red. red. illus. oms. red. & oms. av januar februar mars april mai juni juli august september oktober november desember jan. feb. mar. apr. mai jun. jul. aug. sep. okt. nov. des. vår sommar haust vinter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-pl-PL.xml0000644000175100001660000002422014764177705022717 0ustar00runnerdocker pAo Michal This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 udostępniono i i inni anonim anon. na dostępne na przez około ok cytowane wydanie wydania wyd. i in. w przygotowaniu z ibid. w w druku internet wywiad list brak daty b.d. online zaprezentowano na referencja referencje ref. ref. pobrano skala wersja n.e. p.n.e. « » . pierwszy drugi trzeci czwarty piąty szósty siódmy ósmy dziewiąty dziesiąty książka książki rozdział rozdziały kolumna kolumny rycina ryciny folio folio numer numery wiersz wiersze notatka notatki opus opera strona strony strona strony akapit akapity część części sekcja sekcje sub verbo sub verbis wers wersy tom tomy książka rozdz. kol. ryc. fol. nr l. n. op. s. s. s. ss. akap. cz. sekc. s.v. s.vv. w. w. t. t. ¶¶ § §§ reżyser reżyserzy redaktor redaktorzy edytor edytorzy ilustrator ilustratorzy tłumacz tłumacze redaktor & tłumacz redaktorzy & tłumacze reż. reż. red. red. red. red. il. il. tłum. tłum. red.tłum. red.tłum. przez reżyserowane przez zredagowane przez zredagowane przez ilustrowane przez przeprowadzony przez dla przez przetłumaczone przez zredagowane i przetłumaczone przez reż. red. red. il. tłum. red.tłum. styczeń luty marzec kwiecień maj czerwiec lipiec sierpień wrzesień październik listopad grudzień sty. luty mar. kwi. maj cze. lip. sie. wrz. paź. lis. grudz. wiosna lato jesień zima ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-pt-BR.xml0000644000175100001660000002642514764177705022730 0ustar00runnerdocker José Antonio Meira da Rocha Meira da Rocha This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2016-05-16T00:00:00+03:00 acessado e e outros anônimo anon em disponível em por circa c. citado edição edições ed et al. a ser publicado de ibidem in no prelo internet entrevista carta sem data [s.d.] online apresentado em referência referências ref. refs. recuperado escala versão DC AC º ª º primeiro segundo terceiro quarto quinto sexto sétimo oitavo nono décimo primeira segunda terceira quarta quinta sexta sétima oitava nona décima livro livros capítulo capítulos coluna colunas figura figuras folio folios número números linha linhas nota notas opus opera página páginas página páginas parágrafo parágrafos parte partes seção seções sub verbo sub verbis verso versos volume volumes liv. cap. col. fig. f. l. n. op. p. p. p. p. parag. pt. seç. s.v. s.vv. v. vv. vol. vols. ¶¶ § §§ diretor diretores organizador organizadores editor editores ilustrador ilustradores tradutor tradutores editor e tradutor editores e tradutores dir. dirs. org. orgs. ed. eds. il. ils. trad. trads. ed. e trad. eds. e trads. por dirigido por organizado por editado por ilustrado por entrevista de para por traduzido por editado e traduzido por dir. org. ed. ilus. trad. ed. e trad. por janeiro fevereiro março abril maio junho julho agosto setembro outubro novembro dezembro jan. fev. mar. abr. maio jun. jul. ago. set. out. nov. dez. Primavera Verão Outono Inverno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-pt-PT.xml0000644000175100001660000002620314764177705022742 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2013-09-20T23:31:02+00:00 Jonadabe PT acedido e e outros anónimo anón. em disponível em por circa c. citado edição edições ed. et al. a publicar de ibid. em no prelo internet entrevista carta sem data sem data em linha apresentado na referência referências ref. refs. obtido scale versão AD BC « » primeiro primeira segundo segunda terceiro terceira quarto quarta quinto quinta sexto sexta sétimo sétima oitavo oitava nono nona décimo décima livro livros capítulo capítulos coluna colunas figura figuras fólio fólios número números linha linhas nota notas opus opera página páginas página páginas parágrafo parágrafos parte partes secção secções sub verbo sub verbis versículo versículos volume volumes liv. cap. col. fig. f. n. l. n. op. p. pp. p. pp. par. pt. sec. s.v. s.vv. v vv vol. vols. ¶¶ § §§ director directores editor editores editor editores ilustrador ilustradores tradutor tradutores editor & tradutor editores & tradutores dir. dirs. ed. eds. ed. eds. il. ils. trad. trads. ed. & trad. eds. & trads. por dirigido por editado por editorial de ilustrado por entrevistado por para revisto por traduzido por editado & traduzido por dir. ed. ed. ilus. trad. ed. & trad. por Janeiro Fevereiro Março Abril Maio Junho Julho Agosto Setembro Outubro Novembro Dezembro Jan. Fev. Mar. Abr. Mai. Jun. Jul. Ago. Set. Out. Nov. Dez. Primavera Verão Outono Inverno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-ro-RO.xml0000644000175100001660000002433514764177705022740 0ustar00runnerdocker Nicolae Turcan nturcan@gmail.com This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 data accesării și și alții anonim anon. la disponibil la de circa cca. citat ediția edițiile ed et al. în curs de apariție din ibidem în sub tipar internet interviu scrisoare fără dată f.a. online prezentat la referință referințe ref. ref. preluat în scală versiunea d.Hr. î.Hr. « » -lea primul al doilea al treilea al patrulea al cincilea al șaselea al șaptelea al optulea al nouălea al zecelea cartea cărțile capitolul capitolele coloana coloanele figura figurile folio folio numărul numerele linia liniile nota notele opusul opusurile pagina paginile pagina paginile paragraful paragrafele partea părțile secțiunea secțiunile sub verbo sub verbis versetul versetele volumul volumele cart. cap. col. fig. fol. nr. l. n. op. p. pp. p. pp. par. part. sec. s.v. s.vv. v. vv. vol. vol. ¶¶ § §§ director directori editor editori coordonator coordonatori ilustrator ilustratori traducător traducători editor și traducător editori și traducători dir. dir. ed. ed. coord. coord. ilustr. ilustr. trad. trad. ed. și trad. ed. și trad. de coordonat de ediție de coordonator ilustrații de interviu de în de traducere de ediție și traducere de dir. ed. coord. ilustr. trad. ed. și trad. de ianuarie februarie martie aprilie mai iunie iulie august septembrie octombrie noiembrie decembrie ian. feb. mar. apr. mai iun. iul. aug. sep. oct. nov. dec. primăvara vara toamna iarna ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-ru-RU.xml0000644000175100001660000003454614764177705022761 0ustar00runnerdocker Alexei Kouprianov alexei.kouprianov@gmail.com This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 просмотрено и и др. аноним анон. на доступно на около ок. цитируется по цит. по издание издания изд. и др. ожидается от там же в в печати Интернет интервью письмо без даты б. д. онлайн представлено на ссылка ссылки ссылка ссылки извлечено масштаб версия н. э. до н. э. « » первое второе третье четвертое пятое шестое седьмое восьмое девятое десятое первый второй третий четвертый пятый шестой седьмой восьмой девятый десятый первая вторая третья четвертая пятая шестая седьмая восьмая девятая десятая книга книги глава главы столбец столбцы рисунок рисунки лист листы выпуск выпуски строка строки примечание примечания сочинение сочинения страница страницы страница страницы параграф параграфы часть части раздел разделы смотри стих стихи том тома кн. гл. стб. рис. л. лл. вып. стр. прим. соч. с. сс. с. сс. п. пп. ч. чч. разд. см. ст. т. тт. ¶¶ § §§ режиссер режиссеры редактор редакторы ответственный редактор ответственные редакторы иллюстратор иллюстраторы переводчик переводчики редактор и переводчик редакторы и переводчики реж. ред. отв. ред. ил. пер. ред. и пер. режиссировано под редакцией под ответственной редакцией иллюстрировано интервью проведено к переведено под редакцией и переведено реж. под ред. под отв. ред. ил. пер. под ред. и пер. январь февраль март апрель май июнь июль август сентябрь октябрь ноябрь декабрь янв. фев. мар. апр. май июн. июл. авг. сен. окт. ноя. дек. весна лето осень зима ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-sk-SK.xml0000644000175100001660000002451714764177705022734 0ustar00runnerdocker Tomáš Ferianc kohafan This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2014-03-09T22:23:31+00:00 cit a a ďalší anonym anon. v available at by circa cca. cit vydanie vydania vyd. et al. nadchádzajúci z ibid. v v tlači internet osobná komunikácia list no date n.d. online prezentované na reference references ref. refs. cit scale version po Kr. pred Kr. th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth kniha knihy kapitola kapitoly stĺpec stĺpce obrázok obrázky list listy číslo čísla riadok riadky poznámka poznámky opus opera strana strany strana strany odstavec odstavce časť časti sekcia sekcie sub verbo sub verbis verš verše ročník ročníky k. kap. stĺp. obr. l. č. l. n. op. s. s. s. s. par. č. sek. s.v. s.vv. v. v. roč. roč. § § director directors editor editori zostavovateľ zostavovatelia illustrator illustrators prekladateľ prekladatelia zostavovateľ & prekladateľ zostavovatelia & prekladatelia dir. dirs. ed. ed. zost. zost. ill. ills. prel. prel. ed. & tran. eds. & trans. by directed by zostavil zostavil illustrated by rozhovor urobil adresát by preložil zostavil & preložil dir. ed. ed. illus. prel. zost. & prel. január február marec apríl máj jún júl august september október november december jan. feb. mar. apr. máj. jún. júl. aug. sep. okt. nov. dec. Jar Leto Jeseň Zima ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-sl-SI.xml0000644000175100001660000002413514764177705022727 0ustar00runnerdocker Kristof Ostir ratek1 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2014-11-06T09:41:02+00:00 pridobljeno in in drugi anonimni anon. pri dostopno na približno prib. citirano izdaja izdaje izd. idr. pred izidom s isto v v tisku internet intervju pismo brez datuma b. d. na spletu predstavljeno na referenca reference ref. ref. pridobljeno merilo različica n. št. pr. n. št. . prva druga tretja četrta peta šesta sedma osma deveta deseta knjiga knjige poglavje poglavja stolpec stolpci slika slike folio folii številka številke vrstica vrstice opomba opombe opus opusi stran strani stran strani odstavek odstavki del deli odsek odseki sub verbo sub verbis verz verzi letnik letniki knj. pogl. stolp. sl. fol. št. vrst. op. opus str. str. str. str. odst. del ods. s. v. s. v. v. v. let. let. ¶¶ § §§ režiser režiserji urednik uredniki glavni urednik glavni uredniki ilustrator ilustratorji prevajalec prevajalci urednik & prevajalec uredniki & prevajalci rež. rež. ur. ur. gl. ur. gl. ur. ilus. ilus. prev. prev. ur. & prev. ur. & prev. režiral uredil uredil ilustriral intervjuval za od prevedel uredil & prevedel rež. ured. ured. ilus. prev. ured. & prev. by januar februar marec april maj junij julij avgust september oktober november december jan. feb. mar. apr. maj jun. jul. avg. sep. okt. nov. dec. pomlad poletje jesen zima ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-sr-RS.xml0000644000175100001660000002552514764177705022752 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 приступљено и и остали анонимна анон. на available at by circa c. цитирано издање издања изд. и остали долазећи од ibid. у у штампи Интернет интервју писмо no date без датума на Интернету представљено на reference references ref. refs. преузето scale version AD BC th st nd rd th th th first second third fourth fifth sixth seventh eighth ninth tenth књига књиге поглавље поглавља колона колоне цртеж цртежи фолио фолији број бројеви линија линије белешка белешке опус опера страница странице страница странице параграф параграфи део делова одељак одељака sub verbo sub verbis строфа строфе том томова књига Пог. кол. црт. фолио изд. l. n. оп. стр. стр. стр. стр. пар. део од. s.v. s.vv. стр. стр. том томови ¶¶ § §§ director directors уредник урединици editor editors illustrator illustrators преводилац преводиоци editor & translator editors & translators dir. dirs. ур. ур. ed. eds. ill. ills. прев. прев. ed. & tran. eds. & trans. by directed by уредио edited by illustrated by интервјуисао прима by превео edited & translated by dir. ур. ed. illus. прев. ed. & trans. by Јануар Фебруар Март Април Мај Јуни Јули Август Септембар Октобар Новембар Децембар Јан. Феб. Март Апр. Мај Јуни Јули Авг. Сеп. Окт. Нов. Дец. Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-sv-SE.xml0000644000175100001660000002472614764177705022743 0ustar00runnerdocker torfeur Sylvester Keil Sebastian Karcher Ulf Harnhammar This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 åtkomstdatum och och andra anonym anon. vid tillgänglig vid av cirka ca citerad upplaga upplagor uppl. m.fl. kommande från ibid. i i tryck internet intervju brev utan årtal u.å. online presenterad vid referens referenser ref. ref. hämtad scale version e.Kr. f.Kr. :e :a :a :e :e första andra tredje fjärde femte sjätte sjunde åttonde nionde tionde bok böcker kapitel kapitel kolumn kolumner figur figurer folio folios nummer nummer rad rader not noter opus opera sida sidor sida sidor stycke stycken del delar avsnitt avsnitt sub verbo sub verbis vers verser volym volymer bok kap. kol. fig. f. nr l. n. op. s. s. s. s. st. del avs. s.v. s.vv. vers verser vol. vol. ¶¶ § §§ director directors redaktör redaktörer editor editors illustratör illustratörer översättare översättare redaktör & översättare redaktörer & översättare dir. dirs. red. red. ed. eds. ill. ill. övers. övers. red. & övers. red. & övers. av directed by redigerad av edited by illustrerad av intervjuad av till by översatt av redigerad & översatt av dir. red. ed. illus. övers. red. & övers. av januari februari mars april maj juni juli augusti september oktober november december jan. feb. mar. apr. maj juni juli aug. sep. okt. nov. dec. vår sommar höst vinter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-th-TH.xml0000644000175100001660000003015514764177705022723 0ustar00runnerdocker Dusit Laohasinnarong This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 สืบค้น และ และคณะ นิรนาม นิรนาม ที่ available at โดย โดยประมาณ ประมาณ อ้างถึง พิมพ์ครั้งที่ พิมพ์ครั้งที่ พิมพ์ครั้งที่ และคณะ เต็มใจให้ข้อมูล จาก ในที่เดียวกัน ใน กำลังรอตีพิมพ์ อินเทอร์เน็ต การสัมภาษณ์ จดหมาย ไม่ปรากฏปีที่พิมพ์ ม.ป.ป. ออนไลน์ นำเสนอที่ เอกสารอ้างอิง เอกสารอ้างอิง อ้างอิง อ้างอิง สืบค้น scale version ค.ศ. พ.ศ. หนึ่ง สอง สาม สี่ ห้า หก เจ็ด แปด เก้า สิบ หนังสือ หนังสือ บทที่ บทที่ สดมภ์ สดมภ์ รูปภาพ รูปภาพ หน้า หน้า ฉบับที่ ฉบับที่ บรรทัดที่ บรรทัดที่ บันทึก บันทึก บทประพันธ์ บทประพันธ์ หน้า หน้า หน้า หน้า ย่อหน้า ย่อหน้า ส่วนย่อย ส่วนย่อย หมวด หมวด ใต้คำ ใต้คำ ร้อยกรอง ร้อยกรอง ปีที่ ปีที่ หนังสือ บทที่ สดมภ์ รูปภาพ หน้า ฉบับที่ l. n. บทประพันธ์ น. น. น. น. ย่อหน้า ส่วนย่อย หมวด ใต้คำ ใต้คำ ร้อยกรอง ร้อยกรอง ปี ปี ¶¶ § §§ director directors บรรณาธิการ บรรณาธิการ ผู้อำนวยการบทบรรณาธิการ ผู้อำนวยการบทบรรณาธิการ illustrator illustrators ผู้แปล ผู้แปล บรรณาธิการและผู้แปล บรรณาธิการและผู้แปล dir. dirs. บ.ก. บ.ก. ผอ.บทบรรณาธิการ ผอ.บทบรรณาธิการ ill. ills. ผู้แปล ผู้แปล บ.ก. บ.ก. โดย directed by เรียบเรียงโดย เรียบเรียงโดย illustrated by สัมภาษณ์โดย ถึง by แปลโดย แปลและเรียบเรียงโดย dir. โดย โดย illus. แปล แปลและเรียบเรียงโดย มกราคม กุมภาพันธ์ มีนาคม เมษายน พฤษภาคม มิถุนายน กรกฎาคม สิงหาคม กันยายน ตุลาคาม พฤศจิกายน ธันวาคม ม.ค. ก.พ. มี.ค. เม.ย. พ.ค. มิ.ย. ก.ค. ส.ค. ก.ย. ต.ค. พ.ย. ธ.ค. ฤดูใบไม้ผลิ ฤดูร้อน ฤดูใบไม้ร่วง ฤดูหนาว ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-tr-TR.xml0000644000175100001660000002462014764177705022747 0ustar00runnerdocker ekizyener Binici cengiza Muhammet Tarakçı muhammettarakci@gmail.com This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 erişim ve ve diğerleri anonim anonim de erişim adresi by yaklaşık yakl. a.yer baskı baskı bs vd. gelecek gönderen a.g.e. içinde basımda internet mülakat mektup tarih yok t.y. çevrimiçi program adı: kaynak kaynaklar kay. kay. geliş tarihi ölçek versiyon M.S. M.Ö. - . birinci ikinci üçüncü dördüncü beşinci altıncı yedinci sekizinci dokuzuncu onuncu kitap kitaplar bölüm bölümler sütun sütunlar şekil şekiller folyo folyo sayı sayı satır satırlar not notlar eser eserler sayfa sayfalar sayfa sayısı sayfa sayıları paragraf paragraflar kısım kısımlar bölüm bölümler madde maddeler ayet ayetler cilt ciltler kit. böl. süt. şek. fl. sy satır n. a.yer s. ss. s. ss. par. ksm. blm. md. md. v. vv. c. c. ¶¶ § §§ direktör direktörler editör editörler sorumlu editör sorumlu editörler çizen çizenler çeviren çevirenler editör & çeviren editörler & çevirenler dir. dir. ed. ed. sor.ed. sor.ed. çzm. çzm. çev. çev. ed. & çev. ed. & çev. kitap editörü direktör editör sorumlu editör çizen röportaj yapan alıcı tanıtım yazarı çeviren düzenleyen & çeviren by dir. ed. sor.ed. çizen çev. ed. & çev. Ocak Şubat Mart Nisan Mayıs Haziran Temmuz Ağustos Eylül Ekim Kasım Aralık Oca. Şub. Mar. Nis. May. Haz. Tem. Ağu. Eyl. Eki. Kas. Ara. Bahar Yaz Sonbahar Kış ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-uk-UA.xml0000644000175100001660000002275614764177705022731 0ustar00runnerdocker This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2018-09-17T21:00:00+02:00 дата звернення і та інші анонімний анон. на доступний у відповідно до близько c. цит. за видання вид. et al. майбутній із там само в у пресі інтернет інтервю лист без дати б. д. online представлена на список використаних джерел джерела вилучено масштаб версія н. е. до н. е. « » ий перший другий третій четвертий п'ятий шостий сьомий восьмий дев'ятий десятий книга книги розділ розділи графа графи рисунок рисунки фоліант фоліанти випуск Рядок Рядки примітка примітки opus opera С. с. параграф параграфи частина частини розділ розділи sub verbo sub verbis verse verses Том Томи кн. розд. ряд. рис. ф. вип. л. прим. оп. с. с. пар. ч. сек. s.v. s.vv. с. вип. ¶¶ § §§ режисер режисери за ред. за ред. ілюстратор ілюстратори перекладач перекладачі За ред. & переклад реж. ред. ред. іл. пер. ред. & пер. by directed by edited by edited by illustrated by interview by to by translated by edited & translated by dir. ed ed. illus. trans ed. & trans. by Січень Лютий Березень Квітень Травень Червень Липень Серпень Вересень Жовтень Листопад Грудень Січ Лют Бер Квіт Трав Чер Лип Сер Вер Жов Лис Груд Spring Summer Autumn Winter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-vi-VN.xml0000644000175100001660000002507514764177705022743 0ustar00runnerdocker dowens76 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2012-07-04T23:31:02+00:00 truy cập and others vô danh v.d tại available at bởi circa c. cited ấn bản ấn bản a.b và c.s. sắp tới từ n.t. trong in press internet interview letter không ngày không ngày online được trình bày tại reference references ref. refs. truy vấn scale version AD BC th st nd rd th th th thứ nhất thứ hai thứ ba thứ tư thứ năm thứ sáu thứ bảy thứ tám thứ chính thứ mười sách sách chương chương column columns figure figures folio folios số số dòng dòng ghi chú ghi chú opus opera trang trang trang trang đoạn văn đoạn văn phần phần section sections sub verbo sub verbis câu câu tập tập sách ch col fig f số p.h d. gc. op tr tr tr tr para ph sec s.v. s.vv. v vv vol vols ¶¶ § §§ director directors biên tập viên biên tập viên biên tập viên biên tập viên họa sĩ họa sĩ biên dịch viên biên dịch viên biên tập viên & biên dịch viên biên tập viên & biên dịch viên dir. dirs. b.t.v b.t.v b.t.v b.t.v h.s h.s b.d.v b.d.v b.t.v & b.d.v b.t.v & b.d.v bởi directed by biên tập bởi biên tập bởi illustrated by interview by to bởi biên dịch bởi biên tập & biên dịch bởi dir. b.t b.t h.s b.d b.t & b.d bởi Tháng Giêng Tháng Hai Tháng Ba Tháng Tư Tháng Năm Tháng Sáu Tháng Bảy Tháng Tám Tháng Chín Tháng Mười Tháng Mười-Một Tháng Chạp tháng 1 tháng 2 tháng 3 tháng 4 tháng 5 tháng 6 tháng 7 tháng 8 tháng 9 tháng 10 tháng 11 tháng 12 Mùa Xuân Mùa Hè Mùa Thu Mùa Đông ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-zh-CN.xml0000644000175100001660000001760314764177705022721 0ustar00runnerdocker rongls sati-bodhi Heromyth This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2014-05-15T23:31:02+00:00 见于 及其他 作者不详 无名氏 载于 介于 见引于 版本 即将出版 同上 收入 送印中 网际网络 访谈 信函 日期不详 不详 在线 发表于 参考 取读于 比例 公元 公元前 图表 注脚 作品 总页数 段落 部分 另见 op. 另见 ¶¶ § §§ 导演 编辑 主编 绘图 翻译 编译 导演 主编 编译 指导 编辑 主编 绘图 采访 受函 校订 翻译 编译 主编 编译 一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales-zh-TW.xml0000644000175100001660000002037014764177705022746 0ustar00runnerdocker sati-bodhi This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License 2014-05-15T23:31:02+00:00 引見於 及其他 作者不詳 無名氏 載於 介於 見引於 版本 即將出版 同上 收入 印行中 互聯網 訪談 信函 日期不詳 不詳 線上 發表於 參考 讀取於 比例 西元 西元前 圖表 註腳 作品 總頁數 段落 部分 另見 op. 另見 ¶¶ § §§ 作者 導演 編輯 主編 繪圖師 採訪員 收信人 翻譯員 編譯員 評論人 作者 導演 編輯 主編 繪圖師 採訪員 收信人 翻譯員 編譯員 評論人 指導 編輯 點校 主編 繪圖 採訪 受函 點評 翻譯 編譯 一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/locales/locales.json0000644000175100001660000001276514764177705022161 0ustar00runnerdocker{ "primary-dialects": { "af": "af-ZA", "ar": "ar", "bg": "bg-BG", "ca": "ca-AD", "cs": "cs-CZ", "cy": "cy-GB", "da": "da-DK", "de": "de-DE", "el": "el-GR", "en": "en-US", "es": "es-ES", "et": "et-EE", "eu": "eu", "fa": "fa-IR", "fi": "fi-FI", "fr": "fr-FR", "he": "he-IL", "hi": "hi-IN", "hr": "hr-HR", "hu": "hu-HU", "id": "id-ID", "is": "is-IS", "it": "it-IT", "ja": "ja-JP", "km": "km-KH", "ko": "ko-KR", "la": "la", "lt": "lt-LT", "lv": "lv-LV", "mn": "mn-MN", "nb": "nb-NO", "nl": "nl-NL", "nn": "nn-NO", "pl": "pl-PL", "pt": "pt-PT", "ro": "ro-RO", "ru": "ru-RU", "sk": "sk-SK", "sl": "sl-SI", "sr": "sr-RS", "sv": "sv-SE", "th": "th-TH", "tr": "tr-TR", "uk": "uk-UA", "vi": "vi-VN", "zh": "zh-CN" }, "language-names": { "af-ZA": [ "Afrikaans", "Afrikaans" ], "ar": [ "العربية", "Arabic" ], "bg-BG": [ "Български", "Bulgarian" ], "ca-AD": [ "Català", "Catalan" ], "cs-CZ": [ "Čeština", "Czech" ], "cy-GB": [ "Cymraeg", "Welsh" ], "da-DK": [ "Dansk", "Danish" ], "de-AT": [ "Deutsch (Österreich)", "German (Austria)" ], "de-CH": [ "Deutsch (Schweiz)", "German (Switzerland)" ], "de-DE": [ "Deutsch (Deutschland)", "German (Germany)" ], "el-GR": [ "Ελληνικά", "Greek" ], "en-GB": [ "English (UK)", "English (UK)" ], "en-US": [ "English (US)", "English (US)" ], "es-CL": [ "Español (Chile)", "Spanish (Chile)" ], "es-ES": [ "Español (España)", "Spanish (Spain)" ], "es-MX": [ "Español (México)", "Spanish (Mexico)" ], "et-EE": [ "Eesti keel", "Estonian" ], "eu": [ "Euskara", "Basque" ], "fa-IR": [ "فارسی", "Persian" ], "fi-FI": [ "Suomi", "Finnish" ], "fr-CA": [ "Français (Canada)", "French (Canada)" ], "fr-FR": [ "Français (France)", "French (France)" ], "he-IL": [ "עברית", "Hebrew" ], "hi-IN": [ "हिंदी", "Hindi" ], "hr-HR": [ "Hrvatski", "Croatian" ], "hu-HU": [ "Magyar", "Hungarian" ], "id-ID": [ "Bahasa Indonesia", "Indonesian" ], "is-IS": [ "Íslenska", "Icelandic" ], "it-IT": [ "Italiano", "Italian" ], "ja-JP": [ "日本語", "Japanese" ], "km-KH": [ "ភាសាខ្មែរ", "Khmer" ], "ko-KR": [ "한국어", "Korean" ], "la": [ "Latina", "Latin" ], "lt-LT": [ "Lietuvių kalba", "Lithuanian" ], "lv-LV": [ "Latviešu", "Latvian" ], "mn-MN": [ "Монгол", "Mongolian" ], "nb-NO": [ "Norsk bokmål", "Norwegian (Bokmål)" ], "nl-NL": [ "Nederlands", "Dutch" ], "nn-NO": [ "Norsk nynorsk", "Norwegian (Nynorsk)" ], "pl-PL": [ "Polski", "Polish" ], "pt-BR": [ "Português (Brasil)", "Portuguese (Brazil)" ], "pt-PT": [ "Português (Portugal)", "Portuguese (Portugal)" ], "ro-RO": [ "Română", "Romanian" ], "ru-RU": [ "Русский", "Russian" ], "sk-SK": [ "Slovenčina", "Slovak" ], "sl-SI": [ "Slovenščina", "Slovenian" ], "sr-RS": [ "Српски / Srpski", "Serbian" ], "sv-SE": [ "Svenska", "Swedish" ], "th-TH": [ "ไทย", "Thai" ], "tr-TR": [ "Türkçe", "Turkish" ], "uk-UA": [ "Українська", "Ukrainian" ], "vi-VN": [ "Tiếng Việt", "Vietnamese" ], "zh-CN": [ "中文 (中国大陆)", "Chinese (PRC)" ], "zh-TW": [ "中文 (台灣)", "Chinese (Taiwan)" ] } } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.726875 citeproc_py-0.8.2/citeproc/data/schema/0000755000175100001660000000000014764177724017450 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/README.md0000644000175100001660000000127514764177705020733 0ustar00runnerdockerhttps://github.com/citation-style-language/schema/ is the official repository for the Citation Style Language (CSL) schema. The CSL schema consists of the files: * csl.rnc * csl-categories.rnc * csl-terms.rnc * csl-types.rnc * csl-variables.rnc CSL styles and locale files can be validated against csl.rnc, which incorporates the contents of the other four files. In addition, the repository contains the files csl-data.json and csl-citation.json, which describe the metadata model used by citeproc-js for its input data and for embedded citation data in word processor documents, respectively. At this point these JSON schemas are not yet normative. For more information, see CitationStyles.org.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl-categories.rnc0000644000175100001660000000132414764177705023057 0ustar00runnerdocker ## Categories for style metadata div { category.citation-format = "author" | "author-date" | "label" | "note" | "numeric" ## Use "generic-base" for styles that are non-discipline specific, such as ## APA, Harvard, etc. category.field = "anthropology" | "astronomy" | "biology" | "botany" | "chemistry" | "communications" | "engineering" | "generic-base" | "geography" | "geology" | "history" | "humanities" | "law" | "linguistics" | "literature" | "math" | "medicine" | "philosophy" | "physics" | "political_science" | "psychology" | "science" | "social_science" | "sociology" | "theology" | "zoology" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl-data.rnc0000644000175100001660000000555214764177705021652 0ustar00runnerdockernamespace dc = "http://purl.org/dc/elements/1.1/" dc:title [ "Citation Style Language Data" ] dc:creator [ "Bruce D'Arcus" ] dc:copyright [ "Bruce D'Arcus, 2009" ] dc:description [ "A schema for the CSL data model." ] include "csl-types.rnc" include "csl-variables.rnc" start = element references { reference+ } reference = element reference { type, id, uri?, container-uri?, (contributor* & date* & variable+) } ## Types div { type = attribute type { cs-types } } ## Identifiers div { ## The id is an identifier unique to the scope of the file id = attribute id { token } ## The URI is the global identity for the refererence; used to associate a citation reference to its data uri = attribute uri { xsd:anyURI } ## the URI for containing items (such as edited books or journals) container-uri = attribute container-uri { xsd:anyURI } } ## Contributors div { contributor = element contributor { attribute type { cs-names }, name-elements } name-elements = element name { text } | ((element given { text }? & element family { text }?) & element dropping-particle { text }? & element non-dropping-particle { text }? & element suffix { text }?) } ## Dates div { date = element date { attribute type { cs-dates }, attribute circa { xsd:boolean }?, (date-pattern | date-range) } date-pattern = year-pattern, ( ( month-pattern, day-pattern? ) | season-pattern )? date-range = element begin-date { date-pattern }, element end-date { date-pattern }? year-pattern = attribute year { xsd:integer { maxInclusive="-1" } | xsd:integer { minInclusive="1" } } month-pattern = attribute month { xsd:integer { minInclusive="1" maxInclusive="12" } } day-pattern = attribute day { xsd:integer { minInclusive="1" maxInclusive="31" } } # 1 = Spring, 2 = Summer, 3 = Fall, 4 = Winter season-pattern = attribute season { xsd:integer { minInclusive="1" maxInclusive="4" } } } ## Simple Variables div { variable = element variable { attribute type { cs-variables }, (simple-variable-pattern | rich-variable-pattern) } simple-variable-pattern = text rich-variable-pattern = (text | element abbr { text } | element b { text } | element cite { ## cited title which is a part (like an article), and so typically rendered in quotes, rather than italicized attribute class { "part" }?, text } | element i { text } | element sc { text } | element span { ## text whose case should not be transformed (as with proper nouns) attribute class { "protect" }?, text } | element sup { text } | element sub { text })+ } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl-relaxed.rnc0000644000175100001660000000064314764177705022361 0ustar00runnerdockernamespace cs = "http://purl.org/net/xbiblio/csl" namespace dc = "http://purl.org/dc/elements/1.1/" dc:title [ "Citation Style Language Schema - Relaxed" ] dc:creator [ "Bruce D'Arcus" ] dc:rights [ "Permission to freely use, copy and distribute." ] dc:description [ "Relaxes the need for a cs:updated value in the official CSL schema." ] include "csl.rnc"{ info-updated = element cs:updated { xsd:dateTime? } }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl-terms.rnc0000644000175100001660000000526214764177705022071 0ustar00runnerdocker ## Terms div { terms = terms.gender-assignable | terms.gender-variants | terms.locator | ## Contributor roles variables.names | "editortranslator" | ## Miscellaneous terms "accessed" | "ad" | "and" | "and others" | "anonymous" | "at" | "available at" | "bc" | "by" | "circa" | "cited" | "et-al" | "forthcoming" | "from" | "ibid" | "in" | "in press" | "internet" | "interview" | "letter" | "no date" | "online" | "presented at" | "reference" | "retrieved" | "scale" | "version" | ## Punctuation "open-quote" | "close-quote" | "open-inner-quote" | "close-inner-quote" | "page-range-delimiter" | ## Seasons "season-01" | "season-02" | "season-03" | "season-04" | ## (legacy; remove in CSL 1.1) category.field ## Terms to which a gender may be assigned terms.gender-assignable = ## Months "month-01" | "month-02" | "month-03" | "month-04" | "month-05" | "month-06" | "month-07" | "month-08" | "month-09" | "month-10" | "month-11" | "month-12" | terms.non-locator-number-variables | terms.locator-number-variables ## Terms for which gender variants may be specified terms.gender-variants = terms.ordinals | terms.long-ordinals terms.ordinals = ## Ordinals xsd:string { pattern = "ordinal(-\d{2})?" } terms.long-ordinals = ## Long ordinals "long-ordinal-01" | "long-ordinal-02" | "long-ordinal-03" | "long-ordinal-04" | "long-ordinal-05" | "long-ordinal-06" | "long-ordinal-07" | "long-ordinal-08" | "long-ordinal-09" | "long-ordinal-10" ## Locators terms.locator = terms.locator.testable | ## "sub verbo" is recognized as "sub" & "verbo" in attribute lists; term ## should be renamed to "sub-verbo" "sub verbo" ## Locator terms that can be tested with the "locator" conditional ## ("sub verbo" can be tested with "sub-verbo") terms.locator.testable = "book" | "chapter" | "column" | "figure" | "folio" | "line" | "note" | "opus" | "page" | "paragraph" | "part" | "section" | "verse" | terms.locator-number-variables ## Locator terms with matching number variables terms.locator-number-variables = "issue" | "volume" ## Non-locator terms accompanying number variables terms.non-locator-number-variables = "chapter-number" | "collection-number" | "edition" | "number" | "number-of-pages" | "number-of-volumes" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl-types.rnc0000644000175100001660000000124614764177705022101 0ustar00runnerdocker ## Item types div { item-types = "article" | "article-journal" | "article-magazine" | "article-newspaper" | "bill" | "book" | "broadcast" | "chapter" | "dataset" | "entry" | "entry-dictionary" | "entry-encyclopedia" | "figure" | "graphic" | "interview" | "legal_case" | "legislation" | "manuscript" | "map" | "motion_picture" | "musical_score" | "pamphlet" | "paper-conference" | "patent" | "personal_communication" | "post" | "post-weblog" | "report" | "review" | "review-book" | "song" | "speech" | "thesis" | "treaty" | "webpage" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl-variables.rnc0000644000175100001660000000340014764177705022677 0ustar00runnerdocker ## Variables div { ## All variables variables = variables.dates | variables.names | variables.numbers | variables.strings ## Standard variables variables.standard = variables.numbers | variables.strings ## Date variables variables.dates = "accessed" | "container" | "event-date" | "issued" | "original-date" | "submitted" ## Name variables variables.names = "author" | "collection-editor" | "composer" | "container-author" | "director" | "editor" | "editorial-director" | "illustrator" | "interviewer" | "original-author" | "recipient" | "reviewed-author" | "translator" ## Number variables variables.numbers = "chapter-number" | "collection-number" | "edition" | "issue" | "number" | "number-of-pages" | "number-of-volumes" | "volume" ## String variables variables.strings = "abstract" | "annote" | "archive" | "archive_location" | "archive-place" | "authority" | "call-number" | "citation-label" | "citation-number" | "collection-title" | "container-title" | "container-title-short" | "dimensions" | "DOI" | "event" | "event-place" | "first-reference-note-number" | "genre" | "ISBN" | "ISSN" | "jurisdiction" | "keyword" | "locator" | "medium" | "note" | "original-publisher" | "original-publisher-place" | "original-title" | "page" | "page-first" | "PMID" | "PMCID" | "publisher" | "publisher-place" | "references" | "reviewed-title" | "scale" | "section" | "source" | "status" | "title" | "title-short" | "URL" | "version" | "year-suffix" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/csl.rnc0000644000175100001660000010610414764177705020736 0ustar00runnerdockernamespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" namespace bibo = "http://purl.org/ontology/bibo/" namespace cs = "http://purl.org/net/xbiblio/csl" namespace dc = "http://purl.org/dc/elements/1.1/" namespace sch = "http://www.ascc.net/xml/schematron" namespace xhtml = "http://www.w3.org/1999/xhtml" # CSL schema metadata dc:title [ "Citation Style Language" ] dc:creator [ "Bruce D'Arcus" ] dc:creator [ "Simon Kornblith" ] bibo:editor [ "Frank Bennett" ] bibo:editor [ "Rintze Zelle" ] dc:rights [ "Copyright 2007-2012 by Frank Bennett, Bruce D'Arcus, Simon Kornblith, and Rintze Zelle. Permission to freely use, copy and distribute." ] dc:description [ "RELAX NG compact schema for the Citation Style Language (CSL)." ] # Embedded Schematron rules to detect calls to nonexistent macros sch:ns [ uri = "http://purl.org/net/xbiblio/csl" prefix = "cs" ] sch:pattern [ name = "Non-existing macros" sch:rule [ context = "//cs:text[@macro]" sch:assert [ test = "@macro = /cs:style/cs:macro/@name" "This macro call has no corresponding macro." ] ] sch:rule [ context = "//cs:key[@macro]" sch:assert [ test = "@macro = /cs:style/cs:macro/@name" "This macro call has no corresponding macro." ] ] ] ## Subparts of the CSL schema include "csl-terms.rnc" include "csl-types.rnc" include "csl-variables.rnc" include "csl-categories.rnc" [ a:documentation [ xhtml:h2 [ "cs:style and cs:locale - Root Elements" ] ] ] div { start = independent-style.style | dependent-style.style | locale-file.locale independent-style.style = element cs:style { ## Select whether citations appear in-text or as notes. attribute class { "in-text" | "note" }, style.default-locale, style.options, version, independent-style.style.info, (style.locale* & style.macro* & style.citation & style.bibliography?)? } dependent-style.style = element cs:style { style.default-locale, version, dependent-style.style.info, dependent-style.style.legacy-attributes } locale-file.locale = element cs:locale { ## Specify the locale of the locale file. attribute xml:lang { xsd:language }, version, locale-file.locale.info?, (locale.style-options & locale.date+ & locale.terms) } style.default-locale = ## Set a default style locale. attribute default-locale { xsd:language }? version = ## Indicate CSL version compatibility ("1.0" for CSL 1.0). [ a:defaultValue = "1.0" ] attribute version { "1.0" } ## Obsolete for dependent styles. Will be disallowed with CSL 1.1. dependent-style.style.legacy-attributes = attribute class { "in-text" | "note" }?, style.options } [ a:documentation [ xhtml:h2 [ "cs:info - Style and Locale File Metadata" ] ] ] div { ## Metadata for independent styles. independent-style.style.info = element cs:info { info.author* & info.category* & info.contributor* & info.id & info.issn* & info.eissn? & info.issnl? & independent-style.info.link* & info.published? & info.rights? & info.summary? & info.title & info.title-short? & info.updated } ## Metadata for dependent styles. dependent-style.style.info = element cs:info { info.author* & info.category* & info.contributor* & info.id & info.issn* & info.eissn? & info.issnl? & dependent-style.info.link+ & info.published? & info.rights? & info.summary? & info.title & info.title-short? & info.updated } ## Metadata for locale files. locale-file.locale.info = element cs:info { info.translator* & info.rights? & info.updated? } info.author = element cs:author { personal-details } info.contributor = element cs:contributor { personal-details } info.translator = element cs:translator { personal-details } personal-details = element cs:name { text } & element cs:email { text }? & element cs:uri { xsd:anyURI }? info.category = ## Specify the citation format of the style (using the "citation-format" ## attribute) or the fields and disciplines for which the style is ## relevant (using the "field" attribute). element cs:category { attribute citation-format { category.citation-format } | attribute field { category.field } } info.id = ## Specify the URI to establish the identity of the style. The URI ## should be stable, unique and dereferenceable URI. element cs:id { xsd:anyURI } info.issn = ## Specify the journal's ISSN(s) for journal-specific styles. An ISSN ## must consist of four digits, a hyphen, three digits, and a check ## digit (a numeral digit or roman X), e.g. "1234-1231". element cs:issn { issn } info.eissn = ## Specify the journal's eISSN for journal-specific styles. element cs:eissn { issn } info.issnl = ## Specify the journal's ISSN-L for journal-specific styles. element cs:issnl { issn } issn = xsd:string { pattern = "\d{4}\-\d{3}(\d|x|X)" } independent-style.info.link = element cs:link { attribute href { xsd:anyURI }, ## Specify how the URL relates to the style. attribute rel { ## The URI of the CSL style itself. "self" | ## URI of the style from which the current style is derived. "template" | ## URI of style documentation. "documentation" | ## Obsolete for independent styles. Will be disallowed with ## CSL 1.1. "independent-parent" }, info-text } dependent-style.info.link = element cs:link { attribute href { xsd:anyURI }, ## Specify how the URL relates to the style. attribute rel { ## The URI of the CSL style itself. "self" | ## URI of the CSL style whose content should be used for ## processing. Required for dependent styles. "independent-parent" | ## URI of style documentation. "documentation" | ## Obsolete for dependent styles. Will be disallowed with CSL ## 1.1. "template" }, info-text } info.published = ## Specify when the style was initially created or made available. element cs:published { xsd:dateTime } info.rights = element cs:rights { attribute license { xsd:anyURI }?, info-text } info.summary = element cs:summary { info-text } info.title = element cs:title { info-text } info.title-short = ## Specify an abbreviated style title (e.g., "APA") element cs:title-short { info-text } info.updated = ## Specify when the style was last updated (e.g., ## "2007-10-26T21:32:52+02:00") element cs:updated { xsd:dateTime } info-text = attribute xml:lang { xsd:language }?, text } [ a:documentation [ xhtml:h2 [ "cs:locale in Independent Styles" ] ] ] div { style.locale = ## Use to (re)define localized terms, dates and options. element cs:locale { ## Specify the affected locale(s). If "xml:lang" is not set, the ## "cs:locale" element affects all locales. attribute xml:lang { xsd:language }?, (locale.style-options? & locale.date* & locale.terms?) } } [ a:documentation [ xhtml:h2 [ "cs:locale Contents - Localization Data" ] ] ] div { ## Localized global options are specified as attributes in the ## cs:style-options element. If future versions of CSL include localized ## options that are citation or bibliography specific, the elements ## cs:citation-options and cs:bibliography-options can be added. locale.style-options = element cs:style-options { ## Limit the "ordinal" form to the first day of the month. [ a:defaultValue = "false" ] attribute limit-day-ordinals-to-day-1 { xsd:boolean }?, ## Specify whether punctuation (a period or comma) is placed within ## or outside (default) the closing quotation mark. [ a:defaultValue = "false" ] attribute punctuation-in-quote { xsd:boolean }? } locale.date = element cs:date { date.form, delimiter, font-formatting, text-case, locale.date.date-part+ } date.form = ## Select the localized date format ("text" or "numeric"). attribute form { ## Text date form (e.g., "December 15, 2005"). "text" | ## Numeric date form (e.g., "2005-12-15"). "numeric" } locale.date.date-part = element cs:date-part { affixes, font-formatting, text-case, (day | month | year) } locale.terms = element cs:terms { terms.term+ } ## The "cs:term" element can either hold a basic string, or "cs:single" and ## "cs:multiple" child elements to give singular and plural forms of the term. terms.term = element cs:term { term.attributes, (text | (term.single, term.multiple)) } term.attributes = (attribute name { terms }, [ a:defaultValue = "long" ] attribute form { term.form }?) | (attribute name { terms.ordinals }, attribute form { "long" }?, attribute gender-form { "masculine" | "feminine" }?, attribute match { "last-digit" | "last-two-digits" | "whole-number" }?) | (attribute name { terms.long-ordinals }, attribute form { "long" }?, attribute gender-form { "masculine" | "feminine" }) | (attribute name { terms.gender-assignable }, attribute form { "long" }?, attribute gender { "masculine" | "feminine" }) ## "verb-short" reverts to "verb" if the "verb-short" form is not available. ## "symbol" reverts to "short" if the "symbol" form is not available. ## "verb" and "short" revert to "long" if the specified form is not available. term.form = "long" | "verb" | "short" | "verb-short" | "symbol" term.single = ## Singular version of the term. element cs:single { text } term.multiple = ## Plural version of the term. element cs:multiple { text } } [ a:documentation [ xhtml:h2 [ "cs:macro" ] ] ] div { style.macro = ## Use to create collections of (reusable) formatting instructions. element cs:macro { attribute name { xsd:NMTOKEN }, rendering-element+ } rendering-element = rendering-element.names | rendering-element.date | rendering-element.label | rendering-element.text | rendering-element.number | rendering-element.choose | rendering-element.group } [ a:documentation [ xhtml:h2 [ "cs:citation and cs:bibliography" ] ] ] div { style.citation = ## Use to describe the formatting of citations. element cs:citation { citation.options, sort?, citation.layout } style.bibliography = ## Use to describe the formatting of the bibliography. element cs:bibliography { bibliography.options, sort?, bibliography.layout } citation.layout = element cs:layout { affixes, delimiter, font-formatting, rendering-element+ } bibliography.layout = element cs:layout { affixes, font-formatting, rendering-element+ } } [ a:documentation [ xhtml:h2 [ "cs:names Rendering Element" ] ] ] div { rendering-element.names = element cs:names { names.attributes, ((names.name?, names.et-al?) & names.label*), names.substitute? } names.attributes = attribute variable { list { variables.names+ } }, affixes, ## Specify the delimiter for name lists of name variables rendered by ## the same cs:names element. delimiter, display, font-formatting names.name = element cs:name { name.attributes, ## Select the "long" (first name + last name, for Western names), ## "short" (last name only, for Western names), or "count" name form ## (returning the number of names in the name variable, which can be ## useful for some sorting algorithms). [ a:defaultValue = "long" ] attribute form { "long" | "short" | "count" }?, affixes, ## Set the delimiter for names in a name variable (e.g., ", " in ## "Doe, Smith") [ a:defaultValue = ", " ] delimiter, font-formatting, name.name-part* } name.attributes = ## Use to separate the second-to-last and last name of a name list by ## the "and" term or ampersand. attribute and { ## Use the "and" term (e.g., "Doe, Johnson and Smith"). "text" | ## Use the "ampersand" (e.g., "Doe, Johnson & Smith"). "symbol" }?, ## Specify when the name delimiter is used between a truncated name list ## and the "et-al" (or "and others") term in case of et-al abbreviation ## (e.g., "Smith, Doe et al." or "Smith, Doe, et al."). [ a:defaultValue = "contextual" ] attribute delimiter-precedes-et-al { ## The name delimiter is only used when the truncated name list ## consists of two or more names. "contextual" | ## The name delimiter is always used. "always" | ## The name delimiter is never used. "never" | ## The name delimiter is only used if the preceding name is inverted as ## a result of the "name-as-sort-order" attribute. "after-inverted-name" }?, ## Specify when the name delimiter is used between the second-to-last ## and last name of a non-truncated name list. Only has an effect when ## the "and" term or ampersand is used (e.g., "Doe and Smith" or "Doe, ## and Smith"). [ a:defaultValue = "contextual" ] attribute delimiter-precedes-last { ## The name delimiter is only used when the name list consists of ## three or more names. "contextual" | ## The name delimiter is always used. "always" | ## The name delimiter is never used. "never" | ## The name delimiter is only used if the preceding name is inverted as ## a result of the "name-as-sort-order" attribute. "after-inverted-name" }?, ## Set the minimum number of names needed in a name variable to activate ## et-al abbreviation. attribute et-al-min { xsd:integer }?, ## Set the number of names to render when et-al abbreviation is active. attribute et-al-use-first { xsd:integer }?, ## As "et-al-min", but only affecting subsequent citations to an item. attribute et-al-subsequent-min { xsd:integer }?, ## As "et-al-use-first", but only affecting subsequent citations to an ## item. attribute et-al-subsequent-use-first { xsd:integer }?, ## If set to "true", the "et-al" (or "and others") term is replaced by ## an ellipsis followed by the last name of the name variable. [ a:defaultValue = "false" ] attribute et-al-use-last { xsd:boolean }?, ## If set to "false", names are not initialized and "initialize-with" ## only affects initials already present in the input data. [ a:defaultValue = "true" ] attribute initialize { xsd:boolean }?, ## Activate initializing of given names. The attribute value is appended ## to each initial (e.g., with ". ", "Orson Welles" becomes "O. Welles"). attribute initialize-with { text }?, ## Specify whether (and which) names should be rendered in their sort ## order (e.g., "Doe, John" instead of "John Doe"). attribute name-as-sort-order { ## Render the first name of each name variable in sort order. "first" | ## Render all names in sort order. "all" }?, ## Sets the delimiter for name-parts that have switched positions as a ## result of "name-as-sort-order" (e.g., ", " in "Doe, John"). [ a:defaultValue = ", " ] attribute sort-separator { text }? name.name-part = ## Use to format individual name parts (e.g., "Jane DOE"). element cs:name-part { attribute name { "family" | "given" }, affixes, font-formatting, text-case } names.et-al = ## Specify the term used for et-al abbreviation and its formatting. element cs:et-al { ## Select the term to use for et-al abbreviation. [ a:defaultValue = "et-al" ] attribute term { "et-al" | "and others" }?, font-formatting, names.et-al.legacy-attributes } ## Ignored in CSL 1.0.1. Will be disallowed with CSL 1.1. names.et-al.legacy-attributes = affixes ## Inherits variable from the parent cs:names element. names.label = element cs:label { [ a:defaultValue = "long" ] attribute form { term.form }?, label.attributes-shared } names.substitute = ## Specify substitution options when the name variables selected on the ## parent cs:names element are empty. element cs:substitute { (substitute.names | rendering-element)+ } ## Short version of cs:names, without children, allowed in cs:substitute. substitute.names = element cs:names { names.attributes } } [ a:documentation [ xhtml:h2 [ "cs:date Rendering Element" ] ] ] div { rendering-element.date = element cs:date { attribute variable { variables.dates }, (( ## Limit the date parts rendered. [ a:defaultValue = "year-month-day" ] attribute date-parts { ## Year, month and day "year-month-day" | ## Year and month "year-month" | ## Year only "year" }?, date.form, rendering-element.date.date-part.localized*) | (rendering-element.date.date-part.non-localized+, delimiter)), affixes, display, font-formatting, text-case } rendering-element.date.date-part.localized = ## Specify overriding formatting for localized dates (affixes ## cannot be overridden, as these are considered locale-specific). ## Example uses are forcing the use of leading-zeros, or of the ## "short" month form. Has no effect on which, and in what order, ## date parts are rendered. element cs:date-part { font-formatting, text-case, (day | month | year) } rendering-element.date.date-part.non-localized = ## Specify, in the desired order, the date parts that should be ## rendered and their formatting. element cs:date-part { affixes, font-formatting, text-case, (day | month | year) } day = attribute name { "day" }, ## Day forms: "numeric" ("5"), "numeric-leading-zeros" ("05"), "ordinal" ## ("5th"). [ a:defaultValue = "numeric" ] attribute form { "numeric" | "numeric-leading-zeros" | "ordinal" }?, range-delimiter month = attribute name { "month" }, ## Months forms: "long" (e.g., "January"), "short" ("Jan."), "numeric" ## ("1"), and "numeric-leading-zeros" ("01"). [ a:defaultValue = "long" ] attribute form { "long" | "short" | "numeric" | "numeric-leading-zeros" }?, range-delimiter, strip-periods year = attribute name { "year" }, ## Year forms: "long" ("2005"), "short" ("05"). [ a:defaultValue = "long" ] attribute form { "short" | "long" }?, range-delimiter range-delimiter = ## Specify a delimiter for date ranges (by default the en-dash). A custom ## delimiter is retrieved from the largest date part ("day", "month" or ## "year") that differs between the two dates. [ a:defaultValue = "–" ] attribute range-delimiter { text }? } [ a:documentation [ xhtml:h2 [ "cs:text Rendering Element" ] ] ] div { rendering-element.text = ## Use to call macros, render variables, terms, or verbatim text. element cs:text { text.attributes, affixes, display, font-formatting, quotes, strip-periods, text-case } text.attributes = ## Select a macro. attribute macro { xsd:NMTOKEN } | ( ## Select a term. attribute term { terms }, [ a:defaultValue = "long" ] attribute form { term.form }?, ## Specify term plurality: singular ("false") or plural ("true"). [ a:defaultValue = "false" ] attribute plural { xsd:boolean }?) | ## Specify verbatim text. attribute value { text } | ( ## Select a variable. attribute variable { variables.standard }, [ a:defaultValue = "long" ] attribute form { "short" | "long" }?) } [ a:documentation [ xhtml:h2 [ "cs:number Rendering Element" ] ] ] div { rendering-element.number = ## Use to render a number variable. element cs:number { number.attributes, affixes, display, font-formatting, text-case } number.attributes = attribute variable { variables.numbers }, ## Number forms: "numeric" ("4"), "ordinal" ("4th"), "long-ordinal" ## ("fourth"), "roman" ("iv"). [ a:defaultValue = "numeric" ] attribute form { "numeric" | "ordinal" | "long-ordinal" | "roman" }? } [ a:documentation [ xhtml:h2 [ "cs:label Rendering Element" ] ] ] div { rendering-element.label = ## Use to render a term whose pluralization depends on the content of a ## variable. E.g., if "page" variable holds a range, the plural label ## "pp." is selected instead of the singular "p.". element cs:label { label.attributes, label.attributes-shared } label.attributes = attribute variable { variables.numbers | "locator" | "page" }, [ a:defaultValue = "long" ] attribute form { "long" | "short" | "symbol" }? label.attributes-shared = ## Specify when the plural version of a term is selected. [ a:defaultValue = "contextual" ] attribute plural { "always" | "never" | "contextual" }?, affixes, font-formatting, strip-periods, text-case } [ a:documentation [ xhtml:h2 [ "cs:group Rendering Element" ] ] ] div { rendering-element.group = ## Use to group rendering elements. Groups are useful for setting a ## delimiter for the group children, for organizing the layout of ## bibliographic entries (using the "display" attribute), and for ## suppressing the rendering of terms and verbatim text when variables ## are empty. element cs:group { group.attributes, affixes, delimiter, display, font-formatting, rendering-element+ } group.attributes = notAllowed? } [ a:documentation [ xhtml:h2 [ "Options" ] ] ] div { style.options = style.demote-non-dropping-particle, style.initialize-with-hyphen, style.page-range-format, names-inheritable-options, name-inheritable-options citation.options = citation.cite-group-delimiter, citation.collapse-options, citation.disambiguate-options, citation.near-note-distance, names-inheritable-options, name-inheritable-options bibliography.options = bibliography.hanging-indent, bibliography.line-formatting-options, bibliography.second-field-align, bibliography.subsequent-author-substitute-options, names-inheritable-options, name-inheritable-options style.demote-non-dropping-particle = ## Specify whether the non-dropping particle is demoted in inverted ## names (e.g., "Koning, W. de"). [ a:defaultValue = "display-and-sort" ] attribute demote-non-dropping-particle { "never" | "sort-only" | "display-and-sort" }? style.initialize-with-hyphen = ## Specify whether compound given names (e.g., "Jean-Luc") are ## initialized with ("J-L") or without a hyphen ("JL"). [ a:defaultValue = "true" ] attribute initialize-with-hyphen { xsd:boolean }? style.page-range-format = ## Reformat page ranges in the "page" variable. attribute page-range-format { "chicago" | "expanded" | "minimal" | "minimal-two" }? citation.cite-group-delimiter = ## Activate cite grouping and specify the delimiter for cites within a ## cite group. [ a:defaultValue = ", " ] attribute cite-group-delimiter { text }? citation.collapse-options = ## Activate cite grouping and specify the method of citation collapsing. attribute collapse { ## Collapse ranges of numeric cites, e.g. from "[1,2,3]" to "[1-3]". "citation-number" | ## Collapse cites by suppressing repeated names, e.g. from "(Doe ## 2000, Doe 2001)" to "(Doe 2000, 2001)". "year" | ## Collapse cites as with "year", but also suppresses repeated ## years, e.g. from "(Doe 2000a, Doe 2000b)" to "(Doe 2000a, b)". "year-suffix" | ## Collapses cites as with "year-suffix", but also collapses ## ranges of year-suffixes, e.g. from "(Doe 2000a, Doe 2000b, ## Doe 2000c)" to "(Doe 2000a-c)". "year-suffix-ranged" }?, ## Specify the delimiter between year-suffixes. Defaults to the cite ## delimiter. attribute year-suffix-delimiter { text }?, ## Specify the delimiter following a group of collapsed cites. Defaults ## to the cite delimiter. attribute after-collapse-delimiter { text }? citation.disambiguate-options = ## Set to "true" to activate disambiguation by showing names that were ## originally hidden as a result of et-al abbreviation. [ a:defaultValue = "false" ] attribute disambiguate-add-names { xsd:boolean }?, ## Set to "true" to activate disambiguation by expanding names, showing ## initials or full given names. [ a:defaultValue = "false" ] attribute disambiguate-add-givenname { xsd:boolean }?, ## Set to "true" to activate disambiguation by adding year-suffixes ## (e.g., "(Doe 2007a, Doe 2007b)") for items from the same author(s) ## and year. [ a:defaultValue = "false" ] attribute disambiguate-add-year-suffix { xsd:boolean }?, ## Specify how name are expanded for disambiguation. [ a:defaultValue = "by-cite" ] attribute givenname-disambiguation-rule { ## Each ambiguous names is progressively transformed until ## disambiguated (when disambiguation is not possible, the name ## remains in its original form). "all-names" | ## As "all-names", but name expansion is limited to showing ## initials. "all-names-with-initials" | ## As "all-names", but disambiguation is limited to the first name ## of each cite. "primary-name" | ## As "all-names-with-initials", but disambiguation is limited to ## the first name of each cite. "primary-name-with-initials" | ## As "all-names", but only ambiguous names in ambiguous cites are ## expanded. "by-cite" }? citation.near-note-distance = ## Set the number of preceding notes (footnotes or endnotes) within ## which the current item needs to have been previously cited in order ## for the "near-note" position to be "true". [ a:defaultValue = "5" ] attribute near-note-distance { xsd:integer }? bibliography.hanging-indent = ## Set to "true" to render bibliographic entries with hanging indents. [ a:defaultValue = "false" ] attribute hanging-indent { xsd:boolean }? bibliography.line-formatting-options = ## Set the spacing between bibliographic entries. [ a:defaultValue = "1" ] attribute entry-spacing { xsd:nonNegativeInteger }?, ## Set the spacing between bibliographic lines. [ a:defaultValue = "1" ] attribute line-spacing { xsd:integer { minExclusive = "0" } }? bibliography.second-field-align = ## Use to align any subsequent lines of bibliographic entries with the ## beginning of the second field. attribute second-field-align { ## Align the first field with the margin. "flush" | ## Put the first field in the margin and align all subsequent ## lines of text with the margin. "margin" }? bibliography.subsequent-author-substitute-options = ## Substitute names that repeat in subsequent bibliographic entries by ## the attribute value. attribute subsequent-author-substitute { text }?, ## Specify the method of substitution of names repeated in subsequent ## bibliographic entries. [ a:defaultValue = "complete-all" ] attribute subsequent-author-substitute-rule { ## Requires a match of all rendered names in the name variable, and ## substitutes once for all names. "complete-all" | ## Requires a match of all rendered names in the name variable, ## and substitutes for each name. "complete-each" | ## Substitutes for each name, until the first mismatch. "partial-each" | ## Substitutes the first name if it matches. "partial-first" }? ## Options affecting cs:names, for cs:style, cs:citation and cs:bibliography. names-inheritable-options = ## Inheritable name option, companion for "delimiter" on cs:names. attribute names-delimiter { text }? ## Options affecting cs:name, for cs:style, cs:citation and cs:bibliography. name-inheritable-options = name.attributes, ## Inheritable name option, companion for "delimiter" on cs:name. attribute name-delimiter { text }?, ## Inheritable name option, companion for "form" on cs:name. [ a:defaultValue = "long" ] attribute name-form { "long" | "short" | "count" }? } [ a:documentation [ xhtml:h2 [ "cs:sort - Sorting" ] ] ] div { sort = ## Specify how cites and bibliographic entries should be sorted. By ## default, items appear in the order in which they were cited. element cs:sort { sort.key+ } sort.key = element cs:key { (attribute variable { variables } | attribute macro { xsd:NMTOKEN }), ## The minimum number of names needed in a name variable to activate ## name list truncation. Overrides the values set on any ## "et-al-(subsequent-)min" attributes. attribute names-min { xsd:integer }?, ## The number of names to render when name list truncation is ## activated. Overrides the values set on the ## "et-al-(subsequent-)use-first" attributes. attribute names-use-first { xsd:integer }?, ## Use to override the value of the "et-at-use-last" attribute. attribute names-use-last { xsd:boolean }?, ## Select between an ascending and descending sort. [ a:defaultValue = "ascending" ] attribute sort { "ascending" | "descending" }? } } [ a:documentation [ xhtml:h2 [ "cs:choose - Conditional Statements" ] ] ] div { rendering-element.choose = ## Use to conditionally render rendering elements. element cs:choose { choose.if, choose.else-if*, choose.else? } choose.if = element cs:if { condition+, match, rendering-element* } choose.else-if = element cs:else-if { condition+, match, rendering-element* } choose.else = element cs:else { rendering-element+ } condition = ## If used, the element content is only rendered if it disambiguates two ## otherwise identical citations. This attempt at disambiguation is only ## made after all other disambiguation methods have failed. [ a:defaultValue = "true" ] attribute disambiguate { "true" } | ## Tests whether the given variables contain numeric text. attribute is-numeric { list { variables+ } } | ## Tests whether the given date variables contain approximate dates. attribute is-uncertain-date { list { variables.dates+ } } | ## Tests whether the locator matches the given locator types. attribute locator { list { (terms.locator.testable | "sub-verbo")+ } } | ## Tests whether the cite position matches the given positions. attribute position { list { ("first" | "subsequent" | "ibid" | "ibid-with-locator" | "near-note")+ } } | ## Tests whether the item matches the given types. attribute type { list { item-types+ } } | ## Tests whether the default ("long") forms of the given variables ## contain non-empty values. attribute variable { list { variables+ } } match = ## Set the testing logic. [ a:defaultValue = "all" ] attribute match { ## Element only tests "true" when all conditions test "true" for all ## given test values. "all" | ## Element tests "true" when any condition tests "true" for any given ## test value. "any" | ## Element only tests "true" when none of the conditions test "true" ## for any given test value. "none" }? } ## Formatting attributes. div { affixes = [ a:defaultValue = "" ] attribute prefix { text }?, [ a:defaultValue = "" ] attribute suffix { text }? delimiter = attribute delimiter { text }? display = ## By default, bibliographic entries consist of continuous runs of text. ## With the "display" attribute, portions of each entry can be ## individually positioned. attribute display { ## Places the content in a block stretching from margin to margin. "block" | ## Places the content in a block starting at the left margin. "left-margin" | ## Places the content in a block to the right of a preceding ## "left-margin" block. "right-inline" | ## Places the content in a block indented to the right by a standard ## amount. "indent" }? ## The font-formatting attributes are based on those of CSS and XSL-FO. font-formatting = [ a:defaultValue = "normal" ] attribute font-style { "italic" | "normal" | "oblique" }?, [ a:defaultValue = "normal" ] attribute font-variant { "normal" | "small-caps" }?, [ a:defaultValue = "normal" ] attribute font-weight { "normal" | "bold" | "light" }?, [ a:defaultValue = "none" ] attribute text-decoration { "none" | "underline" }?, [ a:defaultValue = "baseline" ] attribute vertical-align { "baseline" | "sup" | "sub" }? quotes = ## When set to "true", quotes are placed around the rendered text. [ a:defaultValue = "false" ] attribute quotes { xsd:boolean }? strip-periods = ## When set to "true", periods are removed from the rendered text. [ a:defaultValue = "false" ] attribute strip-periods { xsd:boolean }? text-case = attribute text-case { ## Renders text in lowercase. "lowercase" | ## Renders text in uppercase. "uppercase" | ## Capitalizes the first character (other characters remain in ## their original case). "capitalize-first" | ## Capitalizes the first character of every word (other characters ## remain in their original case). "capitalize-all" | ## Renders text in title case. "title" | ## Renders text in sentence case. "sentence" }? } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750213.0 citeproc_py-0.8.2/citeproc/data/schema/test.rnc0000644000175100001660000000163414764177705021136 0ustar00runnerdocker namespace cs = "http://purl.org/net/xbiblio/csl" namespace dc = "http://purl.org/dc/elements/1.1/" namespace sch = "http://www.ascc.net/xml/schematron" namespace xhtml = "http://www.w3.org/1999/xhtml" dc:title [ "CSL Test Suite Schema" ] dc:creator [ "Bruce D'Arcus" ] dc:rights [ "Permission to freely use, copy and distribute." ] dc:description [ "Describes a simple format for CSL processor tests." ] include "csl.rnc"{ # here I've redefined the style pattern to allow an optional # no-namespace style link (not sure if it should be namespaced) style |= element style { attribute src { xsd:anyURI } } start = element test { input & style & style-locale* & description? & tag* & output } } input = element input { text } description = element description { text } tag = element tag { token } # right now plain text, but we can (should?) define an HTML output subset? output = element output { text } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.727875 citeproc_py-0.8.2/citeproc/data/styles/0000755000175100001660000000000014764177724017533 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/data/styles/harvard1.csl0000644000175100001660000001470314764177704021751 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.727875 citeproc_py-0.8.2/citeproc/formatter/0000755000175100001660000000000014764177724017302 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/formatter/__init__.py0000644000175100001660000000004014764177704021403 0ustar00runnerdocker from . import plain, html, rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/formatter/html.py0000644000175100001660000000212314764177704020614 0ustar00runnerdocker try: from html import escape except ImportError: from cgi import escape def preformat(text): return escape(str(text), quote=False) class TagWrapper(str): tag = None attributes = None @classmethod def _wrap(cls, text): if cls.attributes: attrib = ' ' + ' '.join(['{}="{}"'.format(key, value) for key, value in cls.attributes.items()]) else: attrib = '' return '<{tag}{attrib}>{text}'.format(tag=cls.tag, attrib=attrib,text=text) def __new__(cls, text): return super(TagWrapper, cls).__new__(cls, cls._wrap(text)) class Italic(TagWrapper): tag = 'i' class Oblique(Italic): pass class Bold(TagWrapper): tag = 'b' class Light(TagWrapper): tag = 'l' class Underline(TagWrapper): tag = 'u' class Superscript(TagWrapper): tag = 'sup' class Subscript(TagWrapper): tag = 'sub' class SmallCaps(TagWrapper): tag = 'span' attributes = {'style': 'font-variant:small-caps;'} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/formatter/plain.py0000644000175100001660000000023414764177704020754 0ustar00runnerdocker def preformat(text): return text Italic = str Oblique = str Bold = str Light = str Underline = str Superscript = str Subscript = str SmallCaps = str ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/formatter/rst.py0000644000175100001660000000130014764177704020454 0ustar00runnerdocker def escape(text): text = text.replace('*', r'\*') text = text.replace('`', r'\`') return text def preformat(text): return escape(str(text)) class RoleWrapper(str): role = None @classmethod def _wrap(cls, text): return ':{role}:`{text}`'.format(role=cls.role, text=text) def __new__(cls, text): return super(RoleWrapper, cls).__new__(cls, cls._wrap(text)) class Italic(RoleWrapper): role = 'emphasis' class Oblique(Italic): pass class Bold(RoleWrapper): role = 'strong' Light = str Underline = str class Superscript(RoleWrapper): role = 'superscript' class Subscript(RoleWrapper): role = 'subscript' SmallCaps = str ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/frontend.py0000644000175100001660000000730514764177704017473 0ustar00runnerdocker import os from warnings import warn from lxml import etree from . import SCHEMA_PATH, LOCALES_PATH, STYLES_PATH from .model import CitationStylesElement from .formatter import html class CitationStylesXML(object): def __init__(self, f, validate=True): lookup = etree.ElementNamespaceClassLookup() namespace = lookup.get_namespace('http://purl.org/net/xbiblio/csl') namespace[None] = CitationStylesElement namespace.update(dict([(cls.__name__.replace('_', '-').lower(), cls) for cls in CitationStylesElement.__subclasses__()])) self.parser = etree.XMLParser(remove_comments=True, encoding='UTF-8', no_network=True) self.parser.set_element_class_lookup(lookup) self.xml = etree.parse(f, self.parser)#, base_url=".") if validate: self.schema = etree.RelaxNG(etree.parse(SCHEMA_PATH)) if not self.schema.validate(self.xml): err = self.schema.error_log #raise Exception("XML file didn't pass schema validation:\n%s" % err) warn("XML file didn't pass schema validation:\n%s" % err) # TODO: proper error reporting self.root = self.xml.getroot() class CitationStylesLocale(CitationStylesXML): def __init__(self, locale, validate=True): locale_path = os.path.join(LOCALES_PATH, 'locales-{}.xml'.format(locale)) try: super(CitationStylesLocale, self).__init__(locale_path, validate=validate) except IOError: raise ValueError("'{}' is not a known locale".format(locale)) class CitationStylesStyle(CitationStylesXML): def __init__(self, style, locale=None, validate=True): try: if not os.path.exists(style): style = os.path.join(STYLES_PATH, '{}.csl'.format(style)) except TypeError: pass try: super(CitationStylesStyle, self).__init__( style, validate=validate) except IOError: raise ValueError("'{}' is not a known style".format(style)) if locale is None: locale = self.root.get('default-locale', 'en-US') self.root.set_locale_list(locale, validate=validate) def has_bibliography(self): return self.root.bibliography is not None def render_citation(self, citation, cites, callback=None): return self.root.citation.render(citation, cites, callback) def sort_bibliography(self, citation_items): return self.root.bibliography.sort(citation_items) def render_bibliography(self, citation_items): return self.root.bibliography.render(citation_items) class CitationStylesBibliography(object): def __init__(self, style, source, formatter=html): self.style = style self.source = source self.formatter = self.style.root.formatter = formatter self.keys = [] self.items = [] self._cites = [] def register(self, citation, callback=None): citation.bibliography = self for item in citation.cites: if item.key in self.source: if item.key not in self.keys: self.keys.append(item.key) self.items.append(item) elif callback is not None: callback(item) def sort(self): self.items = self.style.sort_bibliography(self.items) self.keys = [item.key for item in self.items] def cite(self, citation, callback): return self.style.render_citation(citation, self._cites, callback) def bibliography(self): return self.style.render_bibliography(self.items) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/model.py0000644000175100001660000016060514764177704016757 0ustar00runnerdocker import re import unicodedata import os from functools import cmp_to_key from glob import glob from operator import itemgetter from lxml import etree from . import NAMES, DATES, NUMBERS, PRIMARY_DIALECTS, LANGUAGE_NAMES from .source import VariableError, DateRange, LiteralDate from .string import String, join # Base class class SomewhatObjectifiedElement(etree.ElementBase): nsmap = {'cs': 'http://purl.org/net/xbiblio/csl', 'xml': 'http://www.w3.org/XML/1998/namespace'} # TODO: what about multiple instances of the same name? def __getattr__(self, name): return self.find('cs:' + name, self.nsmap) class CitationStylesElement(SomewhatObjectifiedElement): _default_options = {# global options 'initialize-with-hyphen': 'true', 'page-range-format': None, 'demote-non-dropping-particle': 'display-and-sort', # inheritable name(s) options 'and': None, 'delimiter-precedes-et-al': 'contextual', 'delimiter-precedes-last': 'contextual', 'et-al-min': 0, 'et-al-use-first': 1, 'et-al-subsequent-min': 0, 'et-al-subsequent-use-first': 1, 'et-al-use-last': 'false', 'initialize-with': None, 'name-as-sort-order': None, 'sort-separator': ', ', 'name-form': 'long', 'name-delimiter': ', ', 'names-delimiter': ''} def get_root(self): return self.getroottree().getroot() def xpath_search(self, expression): return self.xpath(expression, namespaces=self.nsmap) @property def loc(self): full_xpath = self.getroottree().getpath(self) xpath = '' tree = [] for i, node in enumerate(full_xpath.split('/')[1:]): xpath += '/' + node element = self.xpath(xpath)[0] namespace, tag = element.tag.split('}', 1) attribs = ''.join(' {}="{}"'.format(key, value) for key, value in element.attrib.items()) tree.append('{:>4}: {}<{}{}>'.format(element.sourceline, i * ' ', tag, attribs)) print('\n'.join(tree)) def get_option(self, name): return self.get(name, self._default_options[name]) def get_macro(self, name): expression = "cs:macro[@name='{}'][1]".format(name) return self.get_root().xpath_search(expression)[0] def get_layout(self): return self.xpath_search('./ancestor-or-self::cs:layout[1]')[0] def get_formatter(self): if isinstance(self.get_root(), Locale): return self.get_root().style.formatter else: return self.get_root().formatter def preformat(self, text): return self.get_formatter().preformat(text) def unicode_character(self, name): return self.preformat(unicodedata.lookup(name)) def render(self, *args, **kwargs): return self.markup(self.process(*args, **kwargs)) # TODO: Locale methods def get_term(self, name, form=None, fallback_locale=True, zero_padded=False): lg_key = "{http://www.w3.org/XML/1998/namespace}lang" if isinstance(self.get_root(), Locale): return self.get_root().get_term(name, form) else: locales = self.get_root().locales if not fallback_locale and len(locales) > 1: main_locale = locales[0] main_lg = main_locale.attrib.get(lg_key, None) if main_lg: new_locales = [main_locale] for locale in locales[1::]: if locale.get(lg_key, main_lg) == main_lg: new_locales.append(locale) locales = new_locales for locale in locales: try: return locale.get_term(name, form, zero_padded=zero_padded) except IndexError: # TODO: create custom exception continue def get_date(self, form): for locale in self.get_root().locales: try: return locale.get_date(form) except IndexError: continue def get_locale_option(self, name): for locale in self.get_root().locales: try: return locale.get_option(name) except IndexError: continue # Top level elements class Style(CitationStylesElement): def set_locale_list(self, output_locale, validate=True): """Set up list of locales in which to search for localizable units""" from .frontend import CitationStylesLocale self.locales = [] system_locales_added = set() def add_instyle_locale(locale): expr = ('./cs:locale[@xml:lang="{}"]'.format(locale) if locale else './cs:locale[not(@xml:lang)]') results = self.xpath_search(expr) if results: locale_element, = results self.locales.append(locale_element) def add_system_locale(locale): if locale not in system_locales_added: csl_locale = CitationStylesLocale(locale, validate=validate) self.locales.append(csl_locale.root) system_locales_added.add(locale) # 1) (in-style locale) chosen dialect add_instyle_locale(output_locale) # 2) (in-style locale) matching language language = output_locale.split('-')[0] add_instyle_locale(language) # 3) (in-style locale) no language set add_instyle_locale(None) # 4) (locale files) chosen or primary dialect if output_locale in LANGUAGE_NAMES: add_system_locale(output_locale) # 5) (locale files) fall back to primary language dialect if language in PRIMARY_DIALECTS: add_system_locale(PRIMARY_DIALECTS[language]) # 6) (locale files) default locale (en-US) add_system_locale('en-US') for locale in self.locales: locale.style = self class Locale(CitationStylesElement): _default_options = {'limit-day-ordinals-to-day-1': 'false', 'punctuation-in-quote': 'false'} def get_term(self, name, form=None, zero_padded=False): attributes = "@name='{}'".format(name) if form is not None: attributes += " and @form='{}'".format(form) else: attributes += " and not(@form)" if zero_padded: attributes += "and not(@match='whole-number')" attributes += "and not(@match='last-two-digits')" expr = './cs:term[{}]'.format(attributes) try: return self.terms.xpath_search(expr)[0] except AttributeError: raise IndexError def get_date(self, form): expr = "./cs:date[@form='{}']".format(form) return self.xpath_search(expr)[0] def get_option(self, name): options = self.find('cs:style-options', self.nsmap) if options is None: raise IndexError return options.get(name, self._default_options[name]) def get_formatter(self): return self.style.formatter class FormattingInstructions(object): def get_option(self, name): if name in self._default_options: return self.get(name, self._default_options[name]) else: return self.get(name, self.get_root().get_option(name)) def render(self, reference): raise NotImplementedError class Citation(FormattingInstructions, CitationStylesElement): _default_options = {# disambiguation 'disambiguate-add-names': False, 'disambiguate-add-givenname': False, 'givenname-disambiguation-rule': 'all-names', 'disambiguate-add-year-suffix': False, # citation collapsing 'collapse': None, 'year-suffix-delimiter': None, 'after-collapse-delimiter': None, # note distance 'near-note-distance': 5} def render(self, citation, cites, callback): self.cites = cites return self.layout.render_citation(citation, callback) class Bibliography(FormattingInstructions, CitationStylesElement): _default_options = {# whitespace 'hanging-indent': False, 'second-field-align': None, 'line-spacing': 1, 'entry-spacing': 1, # reference grouping 'subsequent-author-substitute': None} def sort(self, citation_items): return self.layout.sort_bibliography(citation_items) def render(self, citation_items): return self.layout.render_bibliography(citation_items) # Style behavior class Formatted(object): def format(self, string): if isinstance(string, (int, float)): string = str(string) text = self.font_style(string) text = self.font_variant(text) text = self.font_weight(text) text = self.text_decoration(text) text = self.vertical_align(text) return text def font_style(self, text): formatter = self.get_formatter() font_style = self.get('font-style', 'normal') if font_style == 'normal': formatted = text elif font_style == 'italic': formatted = formatter.Italic(text) elif font_style == 'oblique': formatted = formatter.Oblique(text) return formatted def font_variant(self, text): formatter = self.get_formatter() font_variant = self.get('font-variant', 'normal') if font_variant == 'normal': formatted = text elif font_variant == 'small-caps': formatted = formatter.SmallCaps(text) return formatted def font_weight(self, text): formatter = self.get_formatter() font_weight = self.get('font-weight', 'normal') if font_weight == 'normal': formatted = text elif font_weight == 'bold': formatted = formatter.Bold(text) elif font_weight == 'light': formatted = formatter.Light(text) return formatted def text_decoration(self, text): formatter = self.get_formatter() text_decoration = self.get('text-decoration', 'none') if text_decoration == 'none': formatted = text elif text_decoration == 'underline': formatted = formatter.Underline(text) return formatted def vertical_align(self, text): formatter = self.get_formatter() vertical_align = self.get('vertical-align', 'baseline') if vertical_align == 'baseline': formatted = text elif vertical_align == 'sup': formatted = formatter.Superscript(text) elif vertical_align == 'sub': formatted = formatter.Subscript(text) return formatted class Affixed(object): def wrap(self, string): if string is not None: prefix = self.get('prefix', '') suffix = self.get('suffix', '') return prefix + string + suffix return None class Delimited(object): def join(self, strings, default_delimiter=''): delimiter = self.get('delimiter', default_delimiter) try: text = join((s for s in strings if s is not None), delimiter) except: text = String('') return text class Displayed(object): pass class Quoted(object): def quote(self, string): piq = self.get_locale_option('punctuation-in-quote').lower() == 'true' if self.get('quotes', 'false').lower() == 'true': open_quote = self.get_term('open-quote').single close_quote = self.get_term('close-quote').single string = open_quote + string + close_quote ## quoted_string = QuotedString(string, open_quote, close_quote, piq) return string class StrippedPeriods(object): def strip_periods(self, string): strip_periods = self.get('strip-periods', 'false').lower() == 'true' if strip_periods: string = string.replace('.', '') return string class TextCased(object): _stop_words = ['a', 'an', 'and', 'as', 'at', 'but', 'by', 'down', 'for', 'from', 'in', 'into', 'nor', 'of', 'on', 'onto', 'or', 'over', 'so', 'the', 'till', 'to', 'up', 'via', 'with', 'yet'] def case(self, text, language=None): text_case = self.get('text-case') if text_case is not None: if language != 'en' and text_case == 'title': text_case = 'sentence' if text_case == 'lowercase': text = text.lower() elif text_case == 'uppercase': text = text.upper() elif text_case == 'capitalize-first': text = text.capitalize_first() elif text_case == 'capitalize-all': output = [] for word in text.words(): word = word.capitalize_first() output.append(word) text = ' '.join(output) elif text_case == 'title': output = [] prev = ':' #This ensures first word is capitilized for word in text.words(): if word.islower() and (str(word) not in self._stop_words or prev in (':', '.')): word = word.capitalize_first() elif word.islower(): #Lowercase stop words word = word.soft_lower() prev = word[-1] output.append(word) text = ' '.join(output) elif text_case == 'sentence': output = [] for i, word in enumerate(text.words()): if not text.isupper() and not word.isupper(): word = word.soft_lower() if i == 0: word = word.capitalize_first() output.append(word) text = ' '.join(output) return text # Locale elements class Term(CitationStylesElement): @property def single(self): try: text = self.find('cs:single', self.nsmap).text except AttributeError: text = self.text text = self.preformat(text or '') return String(text) @property def multiple(self): try: text = self.find('cs:multiple', self.nsmap).text except AttributeError: text = self.text text = self.preformat(text or '') return String(text) # Sorting elements class Sort(CitationStylesElement): def sort(self, items, context): # custom sort function to push items with None keys to bottom def multi_key_sort(items, keys, descending): lst = zip(items, *keys) comparers = [(itemgetter(i + 1), descending[i]) for i in range(len(keys))] def mycmp(left, right): for getter, desc in comparers: left_key, right_key = getter(left), getter(right) if left_key is not None and right_key is not None: try: left_key = str(left_key.lower()) right_key = str(right_key.lower()) except AttributeError: pass try: left_key, right_key = (int(str(left_key)), int(str(right_key))) except ValueError: pass result = (left_key > right_key) - (left_key < right_key) if result: return -1 * result if desc else result elif left_key is not None: return -1 elif right_key is not None: return 1 else: continue else: return 0 sorted_lst = sorted(lst, key=cmp_to_key(mycmp)) return [item[0] for item in sorted_lst] sort_descending = [] sort_keys = [] for key in self.findall('cs:key', self.nsmap): descending = key.get('sort', 'ascending').lower() == 'descending' sort_descending.append(descending) sort_keys.append(key.sort_keys(items, context)) return multi_key_sort(items, sort_keys, sort_descending) class Key(CitationStylesElement): def sort_keys(self, items, context): if 'variable' in self.attrib: variable = self.get('variable').replace('-', '_') if variable in NAMES: sort_keys = [self._format_name(item, variable) for item in items] elif variable in DATES: sort_keys = [] for item in items: date = item.reference.get(variable) if date is not None: sort_keys.append(date.sort_key()) else: sort_keys.append(None) elif variable in NUMBERS: sort_keys = [self._format_number(item, variable) for item in items] elif variable == 'citation_number': sort_keys = [item.number for item in items] else: sort_keys = [item.get_field(variable) for item in items] elif 'macro' in self.attrib: layout = context.get_layout() # override name options sort_options = {'name-as-sort-order': 'all'} for option in ('names-min', 'names-use-first', 'names-use-last'): if option in self.attrib: name = option.replace('names', 'et-al') sort_options[name] = self.get(option) macro = self.get_macro(self.get('macro')) sort_keys = [] for item in items: layout.repressed = {} sort_key = macro.render(item, context=context, sort_options=sort_options) sort_keys.append(sort_key) return sort_keys def _format_name(self, item, variable): names = item.reference.get(variable) if names is not None: output = [] for name in names: demote_ndp = self.get_root().get('demote-non-dropping-particle', 'display-and-sort').lower() sort_separator = self._default_options['sort-separator'] # TODO: encapsulate in function (to share with Name) given, family, dp, ndp, suffix = name.parts() if demote_ndp in ('sort-only', 'display-and-sort'): given = ' '.join([n for n in (given, dp, ndp) if n]) else: family = ' '.join([n for n in (ndp, family) if n]) given = ' '.join([n for n in (given, dp) if n]) order = family, given, suffix output.append(sort_separator.join([n for n in order if n])) return ';'.join(output) else: return None def _format_number(self, item, variable): date = item.reference.get(variable) if date is not None: try: return str(Number.re_numeric.match(date).group(1)) except AttributeError: return date else: return None # Rendering elements class Parent(object): def calls_variable(self): return any([child.calls_variable() for child in self.getchildren()]) def process_children(self, item, **kwargs): output = [] for child in self.iterchildren(): try: text = child.process(item, **kwargs) if text is not None: output.append(text) except VariableError: pass if output: return ''.join(output) else: return None def render_children(self, item, **kwargs): output = [] for child in self.iterchildren(): try: text = child.render(item, **kwargs) if text is not None: output.append(text) except VariableError: pass if output: return join(output) else: return None class Macro(CitationStylesElement, Parent): def process(self, item, context=None, sort_options=None): return self.process_children(item, context=context, sort_options=sort_options) def render(self, item, context=None, sort_options=None): return self.render_children(item, context=context, sort_options=sort_options) class Layout(CitationStylesElement, Parent, Formatted, Affixed, Delimited): def render_citation(self, citation, callback): # first sort citation items according to bibliography order bibliography = citation.bibliography good_cites = [cite for cite in citation.cites if not cite.is_bad()] bad_cites = [cite for cite in citation.cites if cite.is_bad()] good_cites.sort(key=lambda item: bibliography.keys.index(item.key)) # sort using citation/sort element if self.getparent().sort is not None: good_cites = self.getparent().sort.sort(good_cites, self) out = [] for item in good_cites: self.repressed = {} prefix = item.get('prefix', '') suffix = item.get('suffix', '') try: output = self.render_children(item) if output is not None: text = prefix + output + suffix out.append(text) self.getparent().cites.append(item) except VariableError: pass for item in bad_cites: callback_value = callback(item) out.append(callback_value or '{}?'.format(item.key)) return self.format(self.wrap(self.join(out))) def sort_bibliography(self, citation_items): sort = self.getparent().find('cs:sort', self.nsmap) if sort is not None: citation_items = sort.sort(citation_items, self) return citation_items def render_bibliography(self, citation_items): output_items = [] for item in citation_items: self.repressed = {} text = self.format(self.wrap(self.render_children(item))) if text is not None: output_items.append(text) return output_items class FormatNumber(object): def _process(self, value, variable): page_range_delimiter = (self.get_term('page-range-delimiter').single if variable.startswith('page') else None) range_delimiter = (page_range_delimiter or self.unicode_character('EN DASH')) en_dash = unicodedata.lookup('EN DASH') def format_number_or_range(item): try: first, last = (number.strip() for number in item.replace(en_dash, '-').split('-')) except ValueError: return self.format_number(item.strip()) first = self.format_number(first) if variable == 'page-first': return first last = self.format_number(self._format_last_page(first, last) if variable == 'page' else last) return join((first, last), range_delimiter) amp_delimiter = ' ' + self.unicode_character('AMPERSAND') + ' ' return join((join((format_number_or_range(item) for item in comma_item.split('&')), amp_delimiter) for comma_item in str(value).split(',')), delimiter=', ') def _format_last_page(self, first, last): def find_common(first, last): count = 0 for count, (f, l) in enumerate(zip(first, last)): if f != l: return count return count + 1 range_format = self.get_root().get_option('page-range-format') common = find_common(first, last) if range_format == 'chicago': m = re.search(r'\d+', first) if not m: return last first_number = int(m.group()) if first_number < 100 or first_number % 100 == 0: range_format = 'expanded' elif len(first) >= 4 and common < 2: range_format = 'expanded' elif first_number % 100 in range(1, 10): range_format = 'minimal' elif first_number % 100 in range(10, 100): range_format = 'minimal-two' if range_format in ('expanded', None): index = 0 elif range_format == 'minimal': index = common elif range_format == 'minimal-two': index = min(common, len(first) - 2) return last[index:] def format_number(self, number): return str(number) class Text(CitationStylesElement, FormatNumber, Formatted, Affixed, Quoted, TextCased, StrippedPeriods): generated_variables = ('year-suffix', 'citation-number') def calls_variable(self): if 'variable' in self.attrib: return self.get('variable') not in self.generated_variables elif 'macro' in self.attrib: return self.get_macro(self.get('macro')).calls_variable() else: return False def render(self, *args, **kwargs): text, language = self.process(*args, **kwargs) return self.markup(text, language) def process(self, item, context=None, **kwargs): if context is None: context = self try: language = item.reference.language[:2] except VariableError: language = self.get_root().get('default-locale', 'en')[:2] if 'variable' in self.attrib: text = self._variable(item, context) elif 'macro' in self.attrib: text = self.get_macro(self.get('macro')).render(item, context) elif 'term' in self.attrib: text = self._term(item) elif 'value' in self.attrib: text = String(self.preformat(self.get('value'))) return text, language def _variable(self, item, context): variable = self.get('variable') repressed = context.get_layout().repressed if self.tag in repressed and variable in repressed[self.tag]: return None if self.get('form') == 'short': short_variable = variable + '-short' if short_variable.replace('-', '_') in item.reference: variable = short_variable if variable.startswith('page'): text = self._process(item.reference.page, variable) elif variable == 'citation-number': text = item.number elif variable == 'locator': en_dash = self.unicode_character('EN DASH') text = str(item.locator.identifier).replace('-', en_dash) else: text = item.reference[variable.replace('-', '_')] return text def _term(self, item): form = self.get('form', 'long') plural = self.get('plural', 'false').lower() == 'true' if form == 'long': form = None term = self.get_term(self.get('term'), form) if plural: text = term.multiple else: text = term.single return text def markup(self, text, language): if text: tmp = self.format(self.case(self.strip_periods(text), language)) return self.wrap(self.quote(tmp)) else: return None class Date(CitationStylesElement, Parent, Formatted, Affixed, Delimited): def calls_variable(self): return True def is_locale_date(self): expr = './ancestor::cs:locale[1]' try: self.xpath_search(expr)[0] return True except IndexError: return False def render_single_date(self, date, show_parts=None, context=None): form = self.get('form') if context != self: parts = self.parts(date, show_parts, context) else: parts = self.parts(date, show_parts) if parts: style_context = context if self.is_locale_date() else self return style_context.join(parts) else: return None def render_date_range(self, date_range, show_parts=None, context=None): same_show_parts = [] if date_range.end.is_nil(): same = None diff_begin = self.render_single_date(date_range.begin, show_parts, context) diff_end = '' else: if date_range.begin.year == date_range.end.year: show_parts.remove('year') same_show_parts.append('year') try: if ('month' in show_parts and date_range.begin.month == date_range.end.month): show_parts.remove('month') same_show_parts.append('month') try: if ('day' in show_parts and date_range.begin.day == date_range.end.day): show_parts.remove('day') same_show_parts.append('day') except AttributeError: show_parts.remove('day') except AttributeError: show_parts.remove('month') same = self.render_single_date(date_range.end, same_show_parts, context) diff_begin = self.render_single_date(date_range.begin, show_parts, context) diff_end = self.render_single_date(date_range.end, show_parts, context) if not (diff_begin and diff_begin): return None diff = (diff_begin.rstrip() + self.unicode_character('EN DASH') + diff_end) if same: text = context.join([diff, same.rstrip()]) else: text = diff return text def process(self, item, variable=None, show_parts=None, context=None, **kwargs): if variable is None: variable = self.get('variable') if show_parts is None: show_parts = ['year', 'month', 'day'] if context is None: context = self form = self.get('form') date_parts = self.get('date-parts') if not self.is_locale_date() and form is not None: localized_date = self.get_date(form) if date_parts is not None: show_parts = date_parts.split('-') return localized_date.render(item, variable, show_parts=show_parts, context=self) else: date_or_range = item.reference[variable.replace('-', '_')] if not date_or_range: text = None elif isinstance(date_or_range, LiteralDate): text = date_or_range.text elif isinstance(date_or_range, DateRange): text = self.render_date_range(date_or_range, show_parts, context) else: text = self.render_single_date(date_or_range, show_parts, context) if text is not None: style_context = context if self.is_locale_date() else self return style_context.wrap(text) else: return None def parts(self, date, show_parts, context=None): output = [] for part in self.iterchildren(): if part.get('name') in show_parts: try: part_text = part.render(date, context) if part_text is not None: output.append(part_text) except VariableError: pass return output def markup(self, text): # TODO: fix return text class Date_Part(CitationStylesElement, Formatted, Affixed, TextCased, StrippedPeriods): def process(self, date, context=None): name = self.get('name') range_delimiter = self.get('range-delimiter', '-') attrib = self.attrib if context is None: context = self try: expr = './cs:date-part[@name="{}"]'.format(name) attrib.update(dict(context.xpath_search(expr)[0].attrib)) except (AttributeError, IndexError): pass if name == 'day': form = self.get('form', 'numeric') if (form == 'ordinal' and self.get_locale_option('limit-day-ordinals-to-day-1') .lower() == 'true' and date.day > 1): form = 'numeric' if form == 'numeric': text = date.day elif form == 'numeric-leading-zeros': text = '{:02}'.format(date.day) elif form == 'ordinal': text = to_ordinal(date.day, context) elif name == 'month': form = self.get('form', 'long') strip_periods = self.get('form', False) try: index = date.month term = 'month' except VariableError: index = date.season term = 'season' if form == 'long': text = context.get_term('{}-{:02}'.format(term, index)).single elif form == 'short': term = context.get_term('{}-{:02}'.format(term, index), 'short') text = term.single else: assert term == 'month' if form == 'numeric': text = '{}'.format(index) elif form == 'numeric-leading-zeros': text = '{:02}'.format(index) elif name == 'year': form = self.get('form', 'long') if form == 'long': text = str(abs(date.year)) if date.year < 0: text += context.get_term('bc').single elif date.year < 1000: text += context.get_term('ad').single elif form == 'short': text = str(date.year)[-2:] return text def markup(self, text): if text: return self.wrap(self.format(self.case(self.strip_periods(text)))) else: return None class Number(CitationStylesElement, FormatNumber, Formatted, Affixed, Displayed, TextCased, StrippedPeriods): def calls_variable(self): return True def process(self, item, context=None, **kwargs): variable = self.get('variable') if variable == 'locator': try: variable = item.locator.label value = item.locator.identifier except KeyError: return None elif variable == 'page-first': value = item.reference.page else: value = item.reference[variable] return self._process(value, variable) def format_number(self, number): form = self.get('form', 'numeric') try: number = int(number) except ValueError: return number if form == 'numeric': text = str(number) elif form == 'ordinal' or form == 'long-ordinal' and number > 10: text = to_ordinal(number, self) elif form == 'long-ordinal': text = self.get_term('long-ordinal-{:02}'.format(number)).single elif form == 'roman': text = romanize(number).lower() return text def markup(self, text): if text: return self.wrap(self.format(self.case(self.strip_periods(text)))) else: return None class Names(CitationStylesElement, Parent, Formatted, Affixed, Delimited): def calls_variable(self): return True def get_parent_delimiter(self, context=None): expr = './ancestor::*[self::cs:citation or self::cs:bibliography][1]' if context is None: context = self parent = context.xpath_search(expr)[0] return parent.get_option('names-delimiter') def substitute(self): expr = './cs:substitute[1]' try: result = self.xpath_search(expr)[0] except IndexError: result = None return result def process(self, item, names_context=None, context=None, **kwargs): if context is None: context = self if names_context is None: names_context = self roles = self.get('variable').split() try: ed_trans = (set(roles) == set(['editor', 'translator']) and item.reference.editor == item.reference.translator and self.get_term('editortranslator').getchildren()) if ed_trans: roles = ['editor'] except VariableError: ed_trans = False output = [] for role in roles: if role in item.reference: name_elem = names_context.name if name_elem is None: name_elem = Name() names_context.insert(0, name_elem) text = name_elem.render(item, role, context=context, **kwargs) plural = len(item.reference[role]) > 1 try: if ed_trans: role = 'editortranslator' label_element = names_context.label label = label_element.render(item, role, plural, **kwargs) if label is not None: if label_element is names_context.getchildren()[0]: text = label + text else: text = text + label except AttributeError: pass output.append(text) if output: try: total = sum(output) except TypeError: is_int = False else: is_int = isinstance(total, int) if is_int: text = str(total) if total > 0 else None else: text = self.join(output, self.get_parent_delimiter(context)) else: substitute = self.substitute() if substitute is not None: text = substitute.render(item, context=context, **kwargs) try: return text except NameError: raise VariableError def markup(self, text): if text: return self.wrap(self.format(text)) else: return None class Name(CitationStylesElement, Formatted, Affixed, Delimited): def get_option(self, name, context=None, sort_options=None): try: value = sort_options[name] except (TypeError, KeyError): expr = ('./ancestor::*[self::cs:citation or ' 'self::cs:bibliography][1]') if context is None: context = self parent = context.xpath_search(expr)[0] if name in ('form', 'delimiter'): value = self.get(name, parent.get_option('name-' + name)) else: value = self.get(name, parent.get_option(name)) if name in ('initialize-with-hyphen', 'et-al-use-last'): value = value.lower() == 'true' elif name.startswith('et-al'): value = int(value) return value def et_al(self): expr = './following-sibling::cs:et-al[1]' try: result = self.xpath_search(expr)[0].render() except IndexError: result = self.get_term('et-al').single return result def process(self, item, variable, context=None, sort_options=None, **kwargs): def get_option(name): return self.get_option(name, context, sort_options) and_ = get_option('and') delimiter = get_option('delimiter') delimiter_precedes_et_al = get_option('delimiter-precedes-et-al') delimiter_precedes_last = get_option('delimiter-precedes-last') et_al_min = get_option('et-al-min') et_al_use_first = get_option('et-al-use-first') et_al_subseq_min = get_option('et-al-subsequent-min') et_al_subseq_use_first = get_option('et-al-subsequent-use-first') et_al_use_last = get_option('et-al-use-last') initialize_with = get_option('initialize-with') name_as_sort_order = get_option('name-as-sort-order') sort_separator = get_option('sort-separator') form = get_option('form') demote_ndp = get_option('demote-non-dropping-particle') def format_name_parts(given, family): for part in self.findall('cs:name-part', self.nsmap): given, family = part.format_part(given, family) return given, family names = item.reference.get(variable, []) if and_ == 'text': and_term = self.get_term('and').single elif and_ == 'symbol': and_term = self.preformat('&') et_al = self.et_al() output = [] if form == 'count': count = min(len(names), et_al_use_first) output.append(count) return sum(output) else: et_al_truncate = (len(names) > 1 and et_al_min and len(names) >= et_al_min) et_al_last = et_al_use_last and et_al_use_first <= et_al_min - 2 if et_al_truncate: if et_al_last: names = names[:et_al_use_first] + [names[-1]] else: names = names[:et_al_use_first] for i, name in enumerate(names): given, family, dp, ndp, suffix = name.parts() if given is not None and initialize_with is not None: given = self.initialize(given, initialize_with, context) if form == 'long': if (name_as_sort_order == 'all' or (name_as_sort_order == 'first' and i == 0)): if demote_ndp in ('never', 'sort-only'): family = ' '.join([n for n in (ndp, family) if n]) given = ' '.join([n for n in (given, dp) if n]) else: given = ' '.join([n for n in (given, dp, ndp) if n]) given, family = format_name_parts(given, family) order = family, given, suffix text = sort_separator.join([n for n in order if n]) else: family = ' '.join([n for n in (dp, ndp, family) if n]) given, family = format_name_parts(given, family) order = given, family, suffix text = ' '.join([n for n in order if n]) elif form == 'short': family = ' '.join([n for n in (ndp, family) if n]) given, family = format_name_parts(given, family) text = family output.append(text) if et_al_truncate and et_al: if et_al_last: ellipsis = self.unicode_character('horizontal ellipsis') output[-1] = ellipsis + ' ' + output[-1] text = self.join(output, delimiter) elif (delimiter_precedes_et_al == 'always' or (delimiter_precedes_et_al == 'contextual' and len(output) >= 2)): output.append(et_al) text = self.join(output, delimiter) else: text = self.join(output, delimiter) + ' ' + et_al elif and_ is not None and len(output) > 1: text = self.join(output[:-1], ', ') if (delimiter_precedes_last == 'always' or (delimiter_precedes_last == 'contextual' and len(output) > 2)): text = self.join([text, '']) else: text += ' ' text += '{} '.format(and_term) + output[-1] else: text = self.join(output, delimiter) return text def initialize(self, given, mark, context): if self.get_option('initialize-with-hyphen', context): hyphen_parts = given.split('-') else: hyphen_parts = [given.replace('-', ' ')] result_parts = [] for hyphen_part in hyphen_parts: parts = hyphen_part.replace('.', ' ').split() hyphen_result = '' group = [] for part in parts: if part[0].isupper(): group.append(part[0]) else: # don't initialize particles (which aren't capitalized) hyphen_result += mark.join(group) + mark + ' ' + part + ' ' group = [] hyphen_result += mark.join(group) + mark # remove double spaces hyphen_result = ' '.join(hyphen_result.split()) result_parts.append(hyphen_result) return '-'.join(result_parts) def markup(self, text): if text: return self.wrap(self.format(text)) else: return None class Name_Part(CitationStylesElement, Formatted, Affixed, TextCased): def format_part(self, given, family): if self.get('name') == 'given': given = self.wrap(self.format(self.case(given))) elif self.get('name') == 'family': family = self.wrap(self.format(self.case(family))) return given, family class Et_Al(CitationStylesElement, Formatted, Affixed): def process(self): variable = self.get('term', 'et-al') term = self.get_term('variable') return term def markup(self, text): if text: return self.wrap(self.format(text)) else: return None class Substitute(CitationStylesElement, Parent): def render(self, item, context=None, **kwargs): for child in self.getchildren(): try: if isinstance(child, Names) and child.name is None: names = self.xpath_search('./parent::cs:names[1]')[0] text = child.render(item, names_context=names, context=context, **kwargs) else: text = child.render(item, context=context, **kwargs) except VariableError: continue if text: self.add_to_repressed_list(child, context) break try: return text except NameError: return None def add_to_repressed_list(self, child, context): layout = context.get_layout() tag_list = layout.repressed.get(child.tag, []) tag_list.append(child.get('variable')) layout.repressed[child.tag] = tag_list class Label(CitationStylesElement, Formatted, Affixed, StrippedPeriods, TextCased): def calls_variable(self): return self.get('variable') == 'locator' def process(self, item, variable=None, plural=None, context=None, **kwargs): if variable is None: variable = self.get('variable') form = self.get('form', 'long') plural_option = self.get('plural', 'contextual') if plural is None: plural = self._is_plural(item) if variable == 'locator' and item.has_locator: variable = item.locator.label if form == 'long': term = self.get_term(variable) else: term = self.get_term(variable, form) if (plural_option == 'contextual' and plural or plural_option == 'always'): text = term.multiple else: text = term.single return text def markup(self, text): if text: return self.wrap(self.format(self.case(self.strip_periods(text)))) else: return None RE_MULTIPLE_NUMBERS = re.compile(r'\d+[^\d]+\d+') def _is_plural(self, item): variable = self.get('variable') if variable == 'locator': value = item.locator.identifier else: try: value = item.reference[variable.replace('-', '_')] except VariableError: return False if variable.startswith('number-of') and int(item[variable]) > 1: return True else: return self.RE_MULTIPLE_NUMBERS.search(str(value)) is not None class Group(CitationStylesElement, Parent, Formatted, Affixed, Delimited): def calls_variable(self): return True def process(self, item, context=None, **kwargs): output = [] variable_called = False variable_rendered = False for child in self.iterchildren(): variable_called = variable_called or child.calls_variable() try: child_text = child.render(item, context=context, **kwargs) if child_text is not None: output.append(child_text) variable_rendered = (variable_rendered or child.calls_variable()) except VariableError: pass output = [item for item in output if item is not None] success = not variable_called or (variable_called and variable_rendered) if output and success: return self.join(output) else: raise VariableError def markup(self, text): if text: return self.wrap(self.format(text)) else: return None class ConditionFailed(Exception): pass class Choose(CitationStylesElement, Parent): def render(self, item, context=None, **kwargs): for child in self.getchildren(): try: return child.render(item, context=context, **kwargs) except ConditionFailed: continue return None class If(CitationStylesElement, Parent): def render(self, item, context=None, **kwargs): # TODO self.get('disambiguate') results = [] if 'type' in self.attrib: results += self._type(item) if 'variable' in self.attrib: results += self._variable(item) if 'is-numeric' in self.attrib: results += self._is_numeric(item) if 'is-uncertain-date' in self.attrib: results += self._is_uncertain_date(item) if 'locator' in self.attrib: results += self._locator(item) if 'position' in self.attrib: results += self._position(item, context) # TODO: 'match' also applies to individual tests above! if self.get('match') == 'any': result = any(results) elif self.get('match') == 'none': result = not any(results) else: result = all(results) if not result: raise ConditionFailed return self.render_children(item, context=context, **kwargs) def _type(self, item): return [typ.lower() == item.reference.type for typ in self.get('type').split()] def _variable(self, item): variables = [var.replace('-', '_') for var in self.get('variable').split()] output = [] for variable in variables: if variable == 'locator': output.append('locator' in item) else: output.append(variable in item.reference) return output re_numeric = re.compile(r'^([A-Z]*\d+[A-Z]*)$', re.I) def _is_numeric(self, item): numeric_match = self.re_numeric.match return [var.replace('-', '_') in item.reference and numeric_match(str(item.reference[var.replace('-', '_')])) for var in self.get('is-numeric').split()] def _is_uncertain_date(self, item): result = [] for date in self.get('is-uncertain-date').split(): date_variable = date.replace('-', '_') try: circa = item.reference[date_variable].get('circa', False) except VariableError: circa = False except AttributeError: circa = False result.append(circa) return result def _locator(self, item): return [item.has_locator and var.replace('-', ' ') == item.locator.label for var in self.get('locator').split()] def _position(self, item, context): if context is None: context = self if context.xpath_search('./ancestor::*[self::cs:bibliography]'): return [False] # citation node cites = context.get_layout().getparent().cites last_cite = cites[-1] if cites else None already_cited = item.key in (cite.key for cite in cites) possibly_ibid = (already_cited and item.key == last_cite.key and (item.citation is last_cite.citation or len(last_cite.citation.cites) == 1)) results = [] for position in self.get('position').split(): result = False if position == 'first': result = not already_cited elif position == 'subsequent': result = already_cited elif possibly_ibid and position == 'ibid': result = item.has_locator or not last_cite.has_locator elif possibly_ibid and position == 'ibid-with-locator': result = (item.has_locator and not last_cite.has_locator or (item.has_locator and last_cite.has_locator and item.locator != last_cite.locator)) elif already_cited and position == 'near-note': max_distance = self.get_root().get_option('near-note-distance') citations = 1 last_citation = None for cite in reversed(cites): if item.key == cite.key and citations <= max_distance: result = True break elif cite.citation is not last_citation: citations += 1 last_citation = cite.citation results.append(result) return results class Else_If(If, CitationStylesElement): pass class Else(CitationStylesElement, Parent): def render(self, item, context=None, **kwargs): return self.render_children(item, context=context, **kwargs) # utility functions def to_ordinal(number, context): zero_padded = False fallback_locale = False if len(str(number)) == 1: ordinal_term = f'ordinal-{number:02}' else: ordinal_term = f'ordinal-{number}' def get_ordinal_term(): return context.get_term(ordinal_term, fallback_locale=fallback_locale, zero_padded=zero_padded) if get_ordinal_term() is None: ordinal_term = f'ordinal-{int(str(number)[-1]):02}' zero_padded = True if get_ordinal_term() is None: zero_padded = False ordinal_term = f'ordinal' if get_ordinal_term() is None: fallback_locale = True return str(number) + get_ordinal_term().single def romanize(n): # by Kay Schluehr - from http://billmill.org/python_roman.html numerals = (('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100),('XC', 90),('L', 50),('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)) roman = [] for ltr, num in numerals: (k, n) = divmod(n, num) roman.append(ltr * k) return ''.join(roman) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.728875 citeproc_py-0.8.2/citeproc/source/0000755000175100001660000000000014764177724016577 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/__init__.py0000644000175100001660000001327214764177704020713 0ustar00runnerdocker # http://sourceforge.net/mailarchive/message.php?msg_id=25355232 # http://dret.net/bibconvert/tex2unicode from warnings import warn from .. import VARIABLES class CustomDict(dict): def __init__(self, args, required=set(), optional=set(), required_or=[]): passed_keywords = set(args.keys()) missing = required - passed_keywords if missing: raise TypeError('The following required arguments are missing: ' + ', '.join(missing)) required_or_merged = set() for required_options in required_or: if not passed_keywords & required_options: raise TypeError('Require at least one of: ' + ', '.join(required_options)) required_or_merged |= required_options unsupported = passed_keywords - required - optional - required_or_merged if unsupported: cls_name = self.__class__.__name__ warn('The following arguments for {} are '.format(cls_name) + 'unsupported: ' + ', '.join(unsupported)) self.update(args) def __setattr__(self, name, value): self[name] = value def __getattr__(self, name): return self[name] def __getitem__(self, key): try: return super(CustomDict, self).__getitem__(key) except KeyError: raise VariableError class Reference(CustomDict): def __init__(self, key, type, **args): self.key = key self.type = type #required_or = [set(csl.VARIABLES)] optional = ({'uri', 'container_uri', 'contributor', 'date'} | set(VARIABLES)) super(Reference, self).__init__(args, optional=optional) def __repr__(self): return '{}({})'.format(self.__class__.__name__, self.key) class VariableError(Exception): pass class Name(CustomDict): def __init__(self, **args): if 'literal' in args: required, optional = {'literal'}, set() else: required = set() optional = {'family', 'given', 'dropping-particle', 'non-dropping-particle', 'suffix'} super(Name, self).__init__(args, required, optional) def parts(self): if 'literal' in self: return (None, self['literal'], None, None, None) else: return (self.get('given'), self.get('family'), self.get('dropping-particle'), self.get('non-dropping-particle'), self.get('suffix')) class DateBase(CustomDict): def __init__(self, args, required=set(), optional=set()): optional = {'circa'} | optional super(DateBase, self).__init__(args, required, optional) # defaults if 'circa' not in self: self['circa'] = False class Date(DateBase): def __init__(self, **args): required = {'year'} optional = {'month', 'day', 'season'} if 'day' in args and 'month' not in args: raise TypeError('When specifying the day, you should also specify ' 'the month') for key, value in args.items(): try: args[key] = int(value) except ValueError: pass super(Date, self).__init__(args, required, optional) def sort_key(self): year = self.year month = self.get('month', 0) day = self.get('day', 0) return '{:05}{:02}{:02}'.format(year + 10000, month, day) def is_nil(self): return (self.year == 0 and self.get('month', 0) == 0 and self.get('day', 0) == 0) class LiteralDate(DateBase): def __init__(self, text, **args): self.text = text super(LiteralDate, self).__init__(args) def sort_key(self): return self.text class DateRange(DateBase): def __init__(self, **args): required = {'begin'} optional = {'end'} super(DateRange, self).__init__(args, required, optional) def sort_key(self): begin = self.begin.sort_key() end = self.get('end', Date(year=0)).sort_key() return begin + '-' + end def __eq__(self, other): # TODO: for sorting raise NotImplementedError class Citation(CustomDict): def __init__(self, cites, **kwargs): for cite in cites: cite.citation = self self.cites = cites super(Citation, self).__init__(kwargs) def __repr__(self): cites = ', '.join([cite.key for cite in self.cites]) return '{}({})'.format(self.__class__.__name__, cites) class CitationItem(CustomDict): def __init__(self, key, bibliography=None, **args): self.key = key.lower() optional = {'locator', 'prefix', 'suffix'} super(CitationItem, self).__init__(args, optional=optional) def __repr__(self): return '{}({})'.format(self.__class__.__name__, self.key) @property def bibliography(self): return self.citation.bibliography @property def reference(self): return self.bibliography.source[self.key] @property def number(self): return self.bibliography.keys.index(self.key) + 1 @property def has_locator(self): return 'locator' in self def get_field(self, field): string = self.reference.get(field) if string is not None: return self.bibliography.formatter.preformat(string) def is_bad(self): return self.key not in self.bibliography.keys class Locator(object): def __init__(self, label, identifier): self.label = label self.identifier = identifier class BibliographySource(dict): def add(self, entry): self[entry.key] = entry from . import bibtex, json ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.728875 citeproc_py-0.8.2/citeproc/source/bibtex/0000755000175100001660000000000014764177724020054 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/bibtex/__init__.py0000644000175100001660000000003414764177704022160 0ustar00runnerdocker from .bibtex import BibTeX ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/bibtex/bibparse.py0000644000175100001660000001564714764177704022230 0ustar00runnerdocker # http://maverick.inria.fr/~Xavier.Decoret/resources/xdkbibtex/bibtex_summary.html # http://www.lsv.ens-cachan.fr/~markey/bibla.php?lang=en class BibTeXEntry(dict): def __init__(self, document_type, attributes): super(BibTeXEntry, self).__init__(attributes) self.document_type = document_type class BibTeXDecodeError(Exception): """Exception raised when the encoding passed to BibTeXParser cannot decode the BibTeX database file.""" def __init__(self, decode_error, line_number): msg = ("'{}' decode error on line {}: {}. Please specify the BibTeX's " "database character encoding when instantiating BibTeXParser." .format(decode_error.encoding, line_number, decode_error.reason)) super(BibTeXDecodeError, self).__init__(msg) self.line_number = line_number self.decode_error = decode_error class BibTeXParser(dict): standard_variables = {'jan': 'January', 'feb': 'February', 'mar': 'March', 'apr': 'April', 'may': 'May', 'jun': 'June', 'jul': 'July', 'aug': 'August', 'sep': 'September', 'oct': 'October', 'nov': 'November', 'dec': 'December'} def __init__(self, file_or_filename, encoding='ascii'): try: self.file = open(file_or_filename, 'rt', encoding=encoding) except TypeError: self.file = file_or_filename self.variables = {} self.preamble = '' self._parse(self.file) self.file.close() def _parse(self, file): while True: try: entry = self._parse_entry(file) if entry is not None: entry_type, key, attributes = entry self[key] = BibTeXEntry(entry_type, attributes) except UnicodeDecodeError as decode_error: # I'm not convinced the following is robust safe_part = decode_error.object[:decode_error.start] line_number = len(safe_part.splitlines()) offset = file.tell() - len(decode_error.object) if offset > 0: file.seek(0) line_number += file.read(offset).count(file.newlines) raise BibTeXDecodeError(decode_error, line_number) except EOFError: break def _parse_entry(self, file): while True: char = file.read(1) if char == '@': break elif char == '': raise EOFError entry_type = '' while True: char = file.read(1) if char in '{(': sentinel = '}' if char == '{' else ')' break entry_type += char if entry_type.lower().startswith('comment'): self._jump_to_next_line(file) return None entry_type = entry_type.strip().lower() if entry_type == 'string': name = self._parse_name(file) value = self._parse_value(file) self.variables[name] = value assert self._eat_whitespace(file) == sentinel return None elif entry_type == 'preamble': self.preamble += self._parse_value(file) assert self._eat_whitespace(file) == sentinel return None key = self._parse_key(file) entry = {} while True: name = self._parse_name(file) value = self._parse_value(file) entry[name] = value char = self._eat_whitespace(file) if char != ',': if char != sentinel: assert char in ' \t\n\r' assert self._eat_whitespace(file) == sentinel break else: restore_point = file.tell() if self._eat_whitespace(file) == sentinel: break file.seek(restore_point) return entry_type.strip().lower(), key, entry def _parse_key(self, file): key = '' char = file.read(1) while char != ',': key += char char = file.read(1) if not char: raise ValueError('End of file while parsing key') return key.strip().lower() def _parse_name(self, file): name = '' char = self._eat_whitespace(file) while True: if char == '=': break name += char char = file.read(1) return name.strip().lower() def _parse_value(self, file): char = self._eat_whitespace(file) if char in '{"': value = self._parse_string(file, char) elif char.isalpha(): value = self._parse_variable(file, char) else: value = self._parse_integer(file, char) restore_position = file.tell() char = self._eat_whitespace(file) if char == '#': value += self._parse_value(file) else: file.seek(restore_position) return value def _parse_string(self, file, opening_character): closing_character = '"' if opening_character == '"' else '}' string = '' depth = 0 while True: char = file.read(1) if not char: raise ValueError('End of file while parsing string value') if char == '{': depth += 1 elif depth == 0 and char == closing_character: break elif char == '}': depth -= 1 string += char return string def _parse_variable(self, file, char): key = '' restore_point = file.tell() while char.isalnum() or char in '-_': key += char restore_point = file.tell() char = file.read(1) file.seek(restore_point) if key.lower() in self.variables: value = self.variables[key.lower()] else: value = self.standard_variables[key.lower()] return value def _parse_integer(self, file, char): integer = '' restore_point = file.tell() while char.isdigit(): integer += char restore_point = file.tell() char = file.read(1) file.seek(restore_point) return int(integer) # TODO: rename to next_token? def _eat_whitespace(self, file): char = file.read(1) while char in ' \t\n\r': char = file.read(1) return char def _jump_to_next_line(self, file): char = '' while char != '\n': restore_point = file.tell() char = file.read(1) file.seek(restore_point) def _split_name(self, name): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/bibtex/bibtex.py0000644000175100001660000003033514764177704021705 0ustar00runnerdocker import re import unicodedata from warnings import warn from ...types import (ARTICLE, ARTICLE_JOURNAL, BOOK, CHAPTER, MANUSCRIPT, PAMPHLET, PAPER_CONFERENCE, REPORT, THESIS) from ...string import String, MixedString, NoCase from .. import BibliographySource, Reference, Name, Date, DateRange from .bibparse import BibTeXParser from .latex import parse_latex from .latex.macro import NewCommand, Macro class BibTeX(BibliographySource): fields = {'abstract': 'abstract', 'address': 'publisher_place', 'annote': 'annote', 'author': 'author', 'booktitle': 'container_title', 'chapter': 'chapter_number', 'doi': 'DOI', 'edition': 'edition', 'editor': 'editor', # 'howpublished': None, # 'institution': None, 'journal': 'container_title', # 'month': None, 'note': 'note', 'number': 'issue', # 'organization': None, 'pages': 'page', 'pmid': 'PMID', 'publisher': 'publisher', # 'school': None, 'series': 'collection_title', 'title': 'title', # 'type': None, # 'year': None, 'volume': 'volume', # non-standard fields 'isbn': 'ISBN', 'issn': 'ISSN'} types = {# standard entry types 'article': ARTICLE_JOURNAL, 'book': BOOK, 'booklet': PAMPHLET, 'conference': PAPER_CONFERENCE, 'inbook': CHAPTER, 'incollection': ARTICLE_JOURNAL, 'inproceedings': PAPER_CONFERENCE, 'manual': BOOK, 'mastersthesis': THESIS, 'misc': ARTICLE, 'phdthesis': THESIS, 'proceedings': BOOK, 'techreport': REPORT, 'unpublished': MANUSCRIPT, # non-standard entry types 'thesis': THESIS, 'report': REPORT, } def __init__(self, filename, encoding='ascii'): bibtex_database = BibTeXParser(filename, encoding) self.preamble_macros = {} parse_latex(bibtex_database.preamble, {'newcommand': NewCommand(self.preamble_macros), 'mbox': Macro(1, '{0}'), 'cite': Macro(1, 'CITE({0})')}) for key, entry in bibtex_database.items(): self.add(self.create_reference(key, entry)) def _bibtex_to_csl(self, bibtex_entry): csl_dict = {} for field, value in bibtex_entry.items(): try: value = value.strip() except AttributeError: pass try: csl_field = self.fields[field] except KeyError: if field not in ('year', 'month', 'filename'): warn("Unsupported BibTeX field '{}'".format(field)) continue if field in ('number', 'volume'): try: value = int(value) except ValueError: pass elif field == 'pages': value = self._bibtex_to_csl_pages(value) elif field in ('author', 'editor'): value = [name for name in self._parse_author(value)] else: try: value = self._parse_string(value) except TypeError: value = str(value) csl_dict[csl_field] = value return csl_dict @staticmethod def _bibtex_to_csl_pages(value): value = value.replace(' ', '') if '-' in value: try: first, last = value.split('--') except ValueError: first, last = value.split('-') pages = '-'.join((first, last)) else: pages = value[:-1] if value.endswith('+') else value return pages def _bibtex_to_csl_date(self, bibtex_entry): if 'month' in bibtex_entry: begin_dict, end_dict = self._parse_month(bibtex_entry['month']) else: begin_dict, end_dict = {}, {} if 'year' in bibtex_entry: begin_dict['year'], end_dict['year'] \ = self._parse_year(bibtex_entry['year']) if not begin_dict: return None if begin_dict == end_dict: return Date(**begin_dict) else: return DateRange(begin=Date(**begin_dict), end=Date(**end_dict)) def _parse_year(self, year): try: year_str = parse_latex(year, self.preamble_macros) except TypeError: year_str = str(year) if EN_DASH in year_str: begin_year, end_year = year_str.split(EN_DASH) begin_len, end_len = len(begin_year), len(end_year) if end_len < begin_len: end_year = begin_year[:begin_len - end_len] + end_year else: begin_year = end_year = int(year_str) return begin_year, end_year MONTHS = ('jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec') RE_DAY = r'(?P\d+)' RE_MONTH = r'(?P\w+)' @staticmethod def _parse_month(month): def month_name_to_index(name): try: return BibTeX.MONTHS.index(name[:3].lower()) + 1 except ValueError: return int(name) begin = {} end = {} month = month.strip() month = month.replace(', ', '-') if month.isdecimal(): begin['month'] = end['month'] = month elif month.replace('-', '').isalpha(): if '-' in month: begin['month'], end['month'] = month.split('-') else: begin['month'] = end['month'] = month else: m = re.match(BibTeX.RE_DAY + '[ ~]*' + BibTeX.RE_MONTH, month) if m is None: m = re.match(BibTeX.RE_MONTH + '[ ~]*' + BibTeX.RE_DAY, month) begin['day'] = end['day'] = int(m.group('day')) begin['month'] = end['month'] = m.group('month') begin['month'] = month_name_to_index(begin['month']) end['month'] = month_name_to_index(end['month']) return begin, end def _parse_string(self, title): def make_string(string, top_level_group=False): unlatexed = parse_latex(string, self.preamble_macros) fixed_case = top_level_group and not string.startswith('\\') string_cls = NoCase if fixed_case else String return string_cls(unlatexed) output = MixedString() level = 0 string = '' for char in title: if char == '{': if level == 0: if string: output += make_string(string) string = '' level += 1 elif char == '}': level -= 1 if level == 0: output += make_string(string, True) string = '' else: string += char if level != 0: raise SyntaxError('Non-matching braces in "{}"'.format(title)) if string: output += make_string(string) return output def _parse_author(self, authors): csl_authors = [] for author in split_names(authors): first, von, last, jr = parse_name(author) csl_parts = {} for part, csl_label in [(first, 'given'), (von, 'non-dropping-particle'), (last, 'family'), (jr, 'suffix')]: if part is not None: csl_parts[csl_label] = parse_latex(part, self.preamble_macros) name = Name(**csl_parts) csl_authors.append(name) return csl_authors def create_reference(self, key, bibtex_entry): csl_type = self.types[bibtex_entry.document_type] csl_fields = self._bibtex_to_csl(bibtex_entry) csl_date = self._bibtex_to_csl_date(bibtex_entry) if csl_date: csl_fields['issued'] = csl_date return Reference(key, csl_type, **csl_fields) # BibTeX name handling # # references # - BibTeXing by Oren Patashnik (Feb 8, 1988), 4. Helpful Hints, item 18 # (BibTeX 0.99d - http://www.ctan.org/tex-archive/biblio/bibtex/base/btxdoc.pdf) # - A summary of BibTex by Xavier Décoret # (http://maverick.inria.fr/~Xavier.Decoret/resources/xdkbibtex/bibtex_summary.html) # - Tame the BeaST by Nicolas Markey # (http://tug.ctan.org/info/bibtex/tamethebeast/ttb_en.pdf) AND = ' and ' def split_names(string): """Split a string of names separated by 'and' into a list of names.""" brace_level = 0 names = [] last_index = 0 for i in range(len(string)): char = string[i] if brace_level == 0 and string[i:].startswith(AND): names.append(string[last_index:i]) last_index = i + len(AND) elif char == '{': brace_level += 1 elif char == '}': brace_level -= 1 last_name = string[last_index:] if last_name: names.append(last_name) return names def parse_name(name): """Parse a BibTeX name string and split it into First, von, Last and Jr parts. """ parts = split_name(name) if len(parts) == 1: # First von Last first_von_last, = parts index = 0 first, jr = [], [] for word in first_von_last[:-1]: if is_capitalized(word) not in (True, None): break first.append(word) index += 1 von_last = first_von_last[index:] elif len(parts) == 2: # von Last, First jr = [] von_last, first = parts elif len(parts) == 3: # von Last, Jr, First von_last, jr, first = parts von, last = split_von_last(von_last) join = ' '.join return join(first) or None, join(von) or None, join(last), join(jr) or None def split_name(name): """Split a name in into parts delimited by commas (at brace-level 0), and each part into words. Returns a list of of lists of words. """ brace_level = 0 parts = [] current_part = [] word = '' for char in name: if char in ' \t,': if brace_level == 0: if word: current_part.append(word) word = '' if char == ',': parts.append(current_part) current_part = [] continue elif char == '{': brace_level += 1 elif char == '}': brace_level -= 1 word += char if word: current_part.append(word) parts.append(current_part) return parts def is_capitalized(string): """Check if a BibTeX substring is capitalized. A string can be "case-less", in which case `None` is returned. """ brace_level = 0 special_char = False for char, next_char in lookahead_iter(string): if (brace_level == 0 or special_char) and char.isalpha(): return char.isupper() elif char == '{': brace_level += 1 if brace_level == 1 and next_char == '\\': special_char = True elif char == '}': brace_level -= 1 if brace_level == 0: special_char = False return None # case-less def split_von_last(words): """Split "von Last" name into von and Last parts.""" if len(words) > 1 and is_capitalized(words[0]) is False: for j, word in enumerate(reversed(words[:-1])): if is_capitalized(word) not in (True, None): return words[:-j - 1], words[-j - 1:] return [], words def lookahead_iter(iterable): """Iterator that also yields the next item along with each item. The next item is `None` when yielding the last item. """ items = iter(iterable) item = next(items) for next_item in items: yield item, next_item item = next_item yield item, None EN_DASH = unicodedata.lookup('EN DASH') ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.729875 citeproc_py-0.8.2/citeproc/source/bibtex/latex/0000755000175100001660000000000014764177724021171 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/bibtex/latex/__init__.py0000644000175100001660000001103314764177704023276 0ustar00runnerdocker import unicodedata from collections import namedtuple from warnings import warn __all__ = ['parse_latex', 'substitute_ligatures'] def parse_latex(string, macros={}): tokens = Tokenizer(string) output = '' for result in dispatch(tokens, macros): output += result return substitute_ligatures(output) Token = namedtuple('Token', ['type', 'value']) TOGGLE_MATH = 'TOGGLE-MATH' WHITESPACE = 'WHITESPACE' CLOSE_SCOPE = 'CLOSE-SCOPE' OPEN_SCOPE = 'OPEN-SCOPE' START_MACRO = 'START-MACRO' CHARACTER = 'CHARACTER' class Tokenizer(object): def __init__(self, string): self.string = string self._tokens = self.tokenize(string) self._next_token = None @staticmethod def tokenize(input_string): for char in input_string: if char == '\\': yield Token(START_MACRO, char) elif char == '{': yield Token(OPEN_SCOPE, char) elif char == '}': yield Token(CLOSE_SCOPE, char) elif char in ' \t\n': yield Token(WHITESPACE, char) elif char == '$': yield Token(TOGGLE_MATH, char) else: yield Token(CHARACTER, char) def __iter__(self): return self def __next__(self): if self._next_token: token = self._next_token self._next_token = None else: token = next(self._tokens) return token next = __next__ def peek(self): if self._next_token is None: self._next_token = next(self._tokens) return self._next_token def eat_whitespace(tokens): while tokens.peek().type == WHITESPACE: next(tokens) class ScopeClosing(Exception): pass def dispatch(tokens, macros, level=0): while True: try: next_token = tokens.peek() except StopIteration: if level > 0: warn("Unbalanced parenthesis in '{}'".format(tokens.string)) break if next_token.type == OPEN_SCOPE: yield handle_scope(tokens, macros, level) elif next_token.type == CLOSE_SCOPE: raise ScopeClosing elif next_token.type == START_MACRO: yield handle_macro(tokens, macros) elif next_token.type == TOGGLE_MATH: yield handle_math(tokens) else: assert next_token.type in (CHARACTER, WHITESPACE) yield next(tokens).value def handle_scope(tokens, macros, level): assert next(tokens).type == OPEN_SCOPE output = '' try: for result in dispatch(tokens, macros, level + 1): output += result except ScopeClosing: assert next(tokens).type == CLOSE_SCOPE return output def parse_argument(tokens, macros, level=0): eat_whitespace(tokens) return next(dispatch(tokens, macros, level)) def handle_macro(tokens, macros): assert next(tokens).type == START_MACRO name = parse_macro_name(tokens) try: macro = MACROS[name] except KeyError: macro = macros[name] return macro.parse_arguments_and_expand(tokens, macros) def parse_macro_name(tokens): token = next(tokens) assert token.type in (CHARACTER, TOGGLE_MATH, WHITESPACE) name = token.value if name.isalpha(): while tokens.peek().type == CHARACTER and tokens.peek().value.isalpha(): name += next(tokens).value eat_whitespace(tokens) return name def handle_math(tokens): assert next(tokens).type == TOGGLE_MATH output = '' for token in tokens: if token.type == START_MACRO: output += token.value token = next(tokens) elif token.type == TOGGLE_MATH: break output += token.value return '$' + output + '$' def substitute_ligatures(string): for chars, ligature in SUBSTITUTIONS.items(): string = string.replace(chars, unicodedata.lookup(ligature)) return string SUBSTITUTIONS = {"~": 'NO-BREAK SPACE', # ligatures defined in Computer Modern (symbol shortcuts) "--": 'EN DASH', "---": 'EM DASH', "''": 'RIGHT DOUBLE QUOTATION MARK', "``": 'LEFT DOUBLE QUOTATION MARK', "!`": 'INVERTED EXCLAMATION MARK', "?`": 'INVERTED QUESTION MARK', ",,": 'DOUBLE LOW-9 QUOTATION MARK', "<<": 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK', ">>": 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK', } from .macro import MACROS ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/bibtex/latex/macro.py0000644000175100001660000001745414764177704022655 0ustar00runnerdocker# coding: utf-8 import unicodedata from . import (parse_argument, eat_whitespace, parse_macro_name, OPEN_SCOPE, CLOSE_SCOPE, START_MACRO) __all__ = ['MACROS', 'NewCommand', 'Macro'] class MacroBase(object): def parse_arguments(self, tokens): raise NotImplementedError def parse_arguments_and_expand(self, tokens): raise NotImplementedError class NewCommand(MacroBase): r""" \newcommand{cmd}[args]{def} """ def __init__(self, macros): self.macros = macros @staticmethod def _parse_macro_name(tokens): eat_whitespace(tokens) token = next(tokens) in_group = token.type == OPEN_SCOPE if in_group: eat_whitespace(tokens) token = next(tokens) assert token.type == START_MACRO name = parse_macro_name(tokens) if in_group: eat_whitespace(tokens) assert next(tokens).type == CLOSE_SCOPE return name @staticmethod def _parse_optional_arguments(tokens, macros): eat_whitespace(tokens) if tokens.peek().value == '[': next(tokens) num_args = '' for token in tokens: if token.value == ']': break num_args += token.value else: num_args = 0 return int(num_args) def parse_arguments_and_expand(self, tokens, macros): name = self._parse_macro_name(tokens) num_args = self._parse_optional_arguments(tokens, macros) definition = parse_argument(tokens, macros) for i in range(10): definition = definition.replace('#{}'.format(i + 1), '{' + str(i) + '}') self.macros[name] = Macro(num_args, definition) return '' class Macro(object): def __init__(self, num_args, format_string): self.num_args = num_args self.format_string = format_string def parse_arguments_and_expand(self, tokens, macros): args = [parse_argument(tokens, macros) for _ in range(self.num_args)] return self.expand(args) def expand(self, arguments): assert len(arguments) == self.num_args return self.format_string.format(*arguments) class Symbol(Macro): def __init__(self, symbol): super(Symbol, self).__init__(0, symbol) class SymbolByName(Macro): def __init__(self, unicode_symbol_name): unicode_symbol = unicodedata.lookup(unicode_symbol_name) super(SymbolByName, self).__init__(0, unicode_symbol) class Combining(Macro): def __init__(self, unicode_accent_name): unicode_accent = unicodedata.lookup('COMBINING ' + unicode_accent_name) super(Combining, self).__init__(1, '{0}' + unicode_accent) DOTTED_CHARS = {'ı': 'i', 'ȷ': 'j'} def expand(self, arguments): assert len(arguments) == self.num_args accented, rest = arguments[0][0], arguments[0][1:] accented = self.DOTTED_CHARS.get(accented, accented) expanded = super(Combining, self).expand([accented]) return unicodedata.normalize('NFC', expanded) + rest MACROS = { # accents '`': Combining('GRAVE ACCENT'), "'": Combining('ACUTE ACCENT'), '^': Combining('CIRCUMFLEX ACCENT'), '"': Combining('DIAERESIS'), 'H': Combining('DOUBLE ACUTE ACCENT'), '~': Combining('TILDE'), 'c': Combining('CEDILLA'), 'k': Combining('OGONEK'), '=': Combining('MACRON'), 'b': Combining('MACRON BELOW'), '.': Combining('DOT ABOVE'), 'd': Combining('DOT BELOW'), 'r': Combining('RING ABOVE'), 'u': Combining('BREVE'), 'v': Combining('CARON'), # '|': Combining('VERTICAL LINE ABOVE'), # 'h': Combining('HOOK ABOVE'), 'G': Combining('DOUBLE GRAVE ACCENT'), 'U': Combining('DOUBLE VERTICAL LINE ABOVE'), 't': Combining('DOUBLE INVERTED BREVE'), 'textcircled': Combining('ENCLOSING CIRCLE'), # symbols 'o': SymbolByName('LATIN SMALL LETTER O WITH STROKE'), 'O': SymbolByName('LATIN CAPITAL LETTER O WITH STROKE'), 'i': SymbolByName('LATIN SMALL LETTER DOTLESS I'), 'l': SymbolByName('LATIN SMALL LETTER L WITH STROKE'), 'L': SymbolByName('LATIN CAPITAL LETTER L WITH STROKE'), 'oe': SymbolByName('LATIN SMALL LIGATURE OE'), 'OE': SymbolByName('LATIN CAPITAL LIGATURE OE'), 'ae': SymbolByName('LATIN SMALL LETTER AE'), 'AE': SymbolByName('LATIN CAPITAL LETTER AE'), 'aa': SymbolByName('LATIN SMALL LETTER A WITH RING ABOVE'), 'AA': SymbolByName('LATIN CAPITAL LETTER A WITH RING ABOVE'), 'ss': SymbolByName('LATIN SMALL LETTER SHARP S'), 'dh': SymbolByName('LATIN SMALL LETTER ETH'), 'DH': SymbolByName('LATIN CAPITAL LETTER ETH'), 'dj': SymbolByName('LATIN SMALL LETTER D WITH STROKE'), 'DJ': SymbolByName('LATIN CAPITAL LETTER D WITH STROKE'), 'ng': SymbolByName('LATIN SMALL LETTER ENG'), 'NG': SymbolByName('LATIN CAPITAL LETTER ENG'), 'th': SymbolByName('LATIN SMALL LETTER THORN'), 'TH': SymbolByName('LATIN CAPITAL LETTER THORN'), 'emspace': SymbolByName('EM SPACE'), 'enspace': SymbolByName('EN SPACE'), 'dag': SymbolByName('DAGGER'), 'ddag': SymbolByName('DOUBLE DAGGER'), 'dots': SymbolByName('HORIZONTAL ELLIPSIS'), 'ldots': SymbolByName('HORIZONTAL ELLIPSIS'), 'P': SymbolByName('PILCROW SIGN'), 'S': SymbolByName('SECTION SIGN'), 'copyright': SymbolByName('COPYRIGHT SIGN'), 'pounds': SymbolByName('POUND SIGN'), 'guillemotleft': SymbolByName('LEFT-POINTING DOUBLE ANGLE QUOTATION MARK'), 'guillemotright': SymbolByName('RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK'), 'guilsinglleft': SymbolByName('SINGLE LEFT-POINTING ANGLE QUOTATION MARK'), 'guilsinglright': SymbolByName('SINGLE RIGHT-POINTING ANGLE QUOTATION MARK'), 'quotedblbase': SymbolByName('DOUBLE LOW-9 QUOTATION MARK'), 'quotesinglbase': SymbolByName('SINGLE LOW-9 QUOTATION MARK'), 'thinspace': SymbolByName('THIN SPACE'), 'textasciicircum': Symbol('^'), 'textasciitilde': Symbol('~'), 'textasteriskcentered': Symbol('*'), 'textbackslash': Symbol('\\'), 'textbar': Symbol('|'), 'textbraceleft': Symbol('{'), 'textbraceright': Symbol('}'), 'textbullet': SymbolByName('BULLET'), 'textcopyright': SymbolByName('COPYRIGHT SIGN'), 'textdagger': SymbolByName('DAGGER'), 'textdaggerdbl': SymbolByName('DOUBLE DAGGER'), 'textdollar': Symbol('$'), 'textellipsis': SymbolByName('HORIZONTAL ELLIPSIS'), 'textemdash': SymbolByName('EM DASH'), 'textendash': SymbolByName('EN DASH'), 'textexclamdown': SymbolByName('INVERTED EXCLAMATION MARK'), 'textgreater': Symbol('>'), 'textless': Symbol('<'), 'textordfeminine': SymbolByName('FEMININE ORDINAL INDICATOR'), 'textordmasculine': SymbolByName('MASCULINE ORDINAL INDICATOR'), 'textparagraph': SymbolByName('PILCROW SIGN'), 'textperiodcentered': SymbolByName('MIDDLE DOT'), 'textquestiondown': SymbolByName('INVERTED QUESTION MARK'), 'textquotesingle': Symbol("'"), # from the textcomp package 'textquotedbl': Symbol('"'), 'textquotedblleft': SymbolByName('LEFT DOUBLE QUOTATION MARK'), 'textquotedblright': SymbolByName('RIGHT DOUBLE QUOTATION MARK'), 'textquoteleft': SymbolByName('LEFT SINGLE QUOTATION MARK'), 'textquoteright': SymbolByName('RIGHT SINGLE QUOTATION MARK'), 'textregistered': SymbolByName('REGISTERED SIGN'), 'textsection': SymbolByName('SECTION SIGN'), 'textsterling': SymbolByName('POUND SIGN'), 'texttrademark': SymbolByName('TRADE MARK SIGN'), 'textunderscore': Symbol('_'), 'textvisiblespace': SymbolByName('OPEN BOX'), 'TeX': Macro(0, 'TeX'), # escaped characters ' ': Symbol(' '), '&': Symbol('&'), '$': Symbol('$'), '{': Symbol('{'), '}': Symbol('}'), '%': Symbol('%'), '#': Symbol('#'), '_': Symbol('_'), } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/source/json.py0000644000175100001660000000630314764177704020122 0ustar00runnerdocker import sys import unicodedata from . import BibliographySource, Reference from . import Name, Date, DateRange, LiteralDate from ..string import String, MixedString, NoCase from .. import NAMES, DATES class CiteProcJSON(BibliographySource): def __init__(self, json_data): for ref in json_data: ref_data = {} for key, value in ref.items(): python_key = key.replace('-', '_') if python_key == 'id': ref_key = str(value).lower() continue elif python_key == 'type': ref_type = value continue elif python_key == 'key': # conflicts with the ref_key, so ignore continue if python_key == 'shortTitle': python_key = 'title_short' if python_key in NAMES: value = self.parse_names(value) elif python_key in DATES: value = self.parse_date(value) elif key not in ('language', ): value = self.parse_string(value) ref_data[python_key] = value self.add(Reference(ref_key, ref_type, **ref_data)) start_tag = '' end_tag = '' def parse_string(self, string): string = str(string) lower_string = string.lower() end = 0 output = MixedString() try: while True: start = lower_string.index(self.start_tag, end) regular = string[end:start] if regular: output += String(regular) end = lower_string.index(self.end_tag, start + 1) start += len(self.start_tag) no_case = string[start:end] output += NoCase(no_case) end += len(self.end_tag) except ValueError: regular = string[end:] if regular: output += String(regular) return output def parse_names(self, json_data): names = [] for name_data in json_data: name = Name(**name_data) names.append(name) return names def parse_date(self, json_data): def parse_single_date(json_date): date_data = {} try: for i, part in enumerate(('year', 'month', 'day')): date_data[part] = json_date[i] except IndexError: pass return date_data dates = [] for json_date in json_data.get('date-parts', []): date = parse_single_date(json_date) if 'season' in json_data: date['season'] = json_data['season'] dates.append(date) circa = json_data.get('circa', 0) != 0 if len(dates) == 1: return Date(circa=circa, **dates[0]) elif len(dates) > 1: return DateRange(begin=Date(**dates[0]), end=Date(**dates[1]), circa=circa) elif 'literal' in json_data: return LiteralDate(json_data['literal'], circa=circa) else: return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/string.py0000644000175100001660000000666314764177704017170 0ustar00runnerdocker from functools import wraps, reduce def discard_empty_other(method): """Decorator for addition operator methods that returns the object itself if `other` is the empty string.""" @wraps(method) def wrapper(obj, other): if other == '': return obj else: return method(obj, other) return wrapper class String(str): @discard_empty_other def __radd__(self, other): return MixedString([other]).__add__(self) @discard_empty_other def __add__(self, other): return MixedString([self]).__add__(other) def __iadd__(self, other): return self.__add__(other) def replace(self, *args, **kwargs): return self.__class__(super(String, self).replace(*args, **kwargs)) def rstrip(self, *args, **kwargs): return self.__class__(super(String, self).rstrip(*args, **kwargs)) def lower(self): return self.__class__(super(String, self).lower()) def upper(self): return self.__class__(super(String, self).upper()) def soft_lower(self): return self.lower() def soft_upper(self): return self.upper() def capitalize_first(self): return self.__class__(self[0].upper() + self[1:]) def words(self): for word in self.split(): yield self.__class__(word) class MixedString(list): @discard_empty_other def __add__(self, other): super_obj = super(MixedString, self) try: return self.__class__(super_obj.__add__(other)) except TypeError: return self.__class__(super_obj.__add__(MixedString([other]))) @discard_empty_other def __radd__(self, other): return self.__class__([other]).__add__(self) def __iadd__(self, other): return self.__add__(other) def __str__(self): return ''.join(map(str, self)) def __getitem__(self, index): return str(self)[index] def replace(self, *args): return self.__class__([string.replace(*args) for string in self]) def translate(self, table): return self.__class__([string.translate(table) for string in self]) def lower(self): return self.__class__([string.lower() for string in self]) def upper(self): return self.__class__([string.upper() for string in self]) def title(self): return self.__class__([string.title() for string in self]) def capitalize_first(self): self_iter = iter(self) output = [next(self_iter).capitalize_first()] output += [string for string in self_iter] return self.__class__(output) def isupper(self): return all(string.isupper() for string in self) def split(self, *args, **kwargs): return str(self).split(*args, **kwargs) def rstrip(self, *args, **kwargs): rev_iter = reversed(self) output = [next(rev_iter).rstrip(*args, **kwargs)] output += [string for string in rev_iter] return self.__class__(reversed(output)) def words(self): for string in self: for word in string.words(): yield word class NoCase(String): def __repr__(self): return '{}({})'.format(self.__class__.__name__, str(self)) def soft_lower(self): return self def soft_upper(self): return self def capitalize_first(self): return self def join(items, delimiter=''): return reduce(lambda a, b: a + delimiter + b, items) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/citeproc/types.py0000644000175100001660000000151514764177704017015 0ustar00runnerdocker ARTICLE = 'article' ARTICLE_JOURNAL = 'article-journal' ARTICLE_MAGAZINE = 'article-magazine' ARTICLE_NEWSPAPER = 'article-newspaper' BILL = 'bill' BOOK = 'book' BROADCAST = 'broadcast' CHAPTER = 'chapter' ENTRY = 'entry' ENTRY_DICTIONARY = 'entry-dictionary' ENTRY_ENCYCLOPEDIA = 'entry-encyclopedia' FIGURE = 'figure' GRAPHIC = 'graphic' INTERVIEW = 'interview' LEGAL_CASE = 'legal_case' LEGISLATION = 'legislation' MANUSCRIPT = 'manuscript' MAP = 'map' MOTION_PICTURE = 'motion_picture' MUSICAL_SCORE = 'musical_score' PAMPHLET = 'pamphlet' PAPER_CONFERENCE = 'paper-conference' PATENT = 'patent' PERSONAL_COMMUNICATION = 'personal_communication' POST = 'post' POST_WEBLOG = 'post-weblog' REPORT = 'report' REVIEW = 'review' REVIEW_BOOK = 'review-book' SONG = 'song' SPEECH = 'speech' THESIS = 'thesis' TREATY = 'treaty' WEBPAGE = 'webpage' ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7328749 citeproc_py-0.8.2/citeproc_py.egg-info/0000755000175100001660000000000014764177724017501 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750227.0 citeproc_py-0.8.2/citeproc_py.egg-info/PKG-INFO0000644000175100001660000002360214764177723020600 0ustar00runnerdockerMetadata-Version: 2.2 Name: citeproc-py Version: 0.8.2 Summary: Citations and bibliography formatter Home-page: https://github.com/brechtm/citeproc-py Author: Brecht Machiels Author-email: brecht@mos6581.org License: 2-clause BSD License Keywords: csl citation html rst bibtex xml Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Environment :: Other Environment Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: End Users/Desktop Classifier: Intended Audience :: Legal Industry Classifier: Intended Audience :: Other Audience Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Documentation Classifier: Topic :: Printing Classifier: Topic :: Software Development :: Documentation Classifier: Topic :: Software Development :: Libraries :: Python Modules Provides: citeproc Requires-Python: >=3.9 Description-Content-Type: text/markdown License-File: LICENSE Requires-Dist: lxml Dynamic: author Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: description-content-type Dynamic: home-page Dynamic: keywords Dynamic: license Dynamic: provides Dynamic: requires-dist Dynamic: requires-python Dynamic: summary # citeproc-py ![PyPI - Version](https://img.shields.io/pypi/v/citeproc-py) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/citeproc-py/citeproc-py/test.yml) ![Coveralls](https://img.shields.io/coverallsCoverage/github/citeproc-py/citeproc-py) citeproc-py is a [`CSL`](https://citationstyles.org/) processor for Python. It aims to implement the [CSL 1.0.1 specification](https://docs.citationstyles.org/en/1.0.1/specification.html). citeproc-py can output styled citations and bibliographies in a number of different output formats. Currently supported are plain text, reStructuredText and HTML. Other formats can be added easily. citeproc-py uses [semantic versioning](https://semver.org/). Currently, its major version number is still at 0, meaning the API is not yet stable. However, you should not expect to see any major API changes soon. ## Requirements citeproc-py supports Python 3.9 and up. It depends on [lxml](https://lxml.de/) for parsing and navigating the CSL style and locale files. # Installation The recommended way of installing citeproc-py is by using [pip](https://pip.pypa.io/en/latest/): pip install citeproc-py If lxml isn't installed, pip will try to install it for you. If you insist, you can manually install citeproc-py from distribution packages hosted at [PyPI](https://pypi.python.org/pypi/citeproc-py/). Please ignore the release archives offered by GitHub. ## Getting Started To get started with citeproc-py, take a look at the examples under `examples/`. Two examples are provided, one parsing references from a JSON representation of references as supported by citeproc-js, another parsing the references from a BibTeX file. Both show and explain how to cite references and render the bibliography. ## CSL Compatibility Currently, citeproc-py passes almost 60% of the (relevant) tests in the [citeproc-test suite](https://github.com/citation-style-language/test-suite). However, it is more than 60% complete, as citeproc-py doesn't take care of double spaces and repeated punctuation marks yet, making a good deal of the tests fail. In addition, the following features have not yet been implemented (there are probably some I forgot though): - disambiguation/year-suffix - et-al-subsequent-min/et-al-subsequent-use-first - collapsing - punctuation-in-quote - display Also, some [citeproc-js](https://github.com/juris-m/citeproc-js) functionality that is not part of the CSL spec is not (yet) supported: - raw dates - static-ordering - literal names ## Contributing citeproc-py is 100% volunteer maintained, and new contributions are always welcome. If you would like to contribute, please follow the guidelines in the [CONTRIBUTING.md](https://github.com/citeproc-py/citeproc-py/blob/master/CONTRIBUTING.md) file. ## Local Install and Running the Tests First clone the `citeproc-py` repository and install the submodules with `git submodule update --init` Then install with `pip install -e .` Then move to the `tests` directory and run `python citeproc-test.py` Run `citeproc-test.py --help` to see its usage information. The first time you run the script it will clone the [citeproc-test suite](https://github.com/citation-style-language/test-suite) repository into the `tests` directory and checkout the last tested version. By default failed tests are automatically added into the `failing_tests.txt` file and aren't shown when running the test suite again. If you want git to fully ignore the submodule, you can type `git update-index --assume-unchanged citeproc/data/schema` # v0.8.2 (Wed Mar 12 2025) #### 🏠 Internal - Explicitly specify utf-8 encoding while reading top level .md files for description [#162](https://github.com/citeproc-py/citeproc-py/pull/162) ([@yarikoptic](https://github.com/yarikoptic)) - Instruct that long description is in markdown and not ReST [#160](https://github.com/citeproc-py/citeproc-py/pull/160) ([@yarikoptic](https://github.com/yarikoptic)) #### Authors: 1 - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # v0.8.1 (Wed Mar 12 2025) #### 🏠 Internal - release: checkout with submodules [#159](https://github.com/citeproc-py/citeproc-py/pull/159) ([@yarikoptic](https://github.com/yarikoptic)) #### Authors: 1 - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # v0.8.0 (Wed Mar 12 2025) #### 🚀 Enhancement - release: use GitHUb App token for checkout and push [#158](https://github.com/citeproc-py/citeproc-py/pull/158) ([@tmorrell](https://github.com/tmorrell)) #### ⚠️ Pushed to `master` - Rename CHANGES to CHANGELOG ([@yarikoptic](https://github.com/yarikoptic)) #### 🏠 Internal - release: switch to using GitHub App to overcome branch protection [#157](https://github.com/citeproc-py/citeproc-py/pull/157) ([@tmorrell](https://github.com/tmorrell)) - Set up `auto` to automate releases [#153](https://github.com/citeproc-py/citeproc-py/pull/153) ([@jwodder](https://github.com/jwodder) [@yarikoptic](https://github.com/yarikoptic)) #### 📝 Documentation - Convert CHANGES.rst, CONTRIBUTING.rst, and README.md to markdown [#154](https://github.com/citeproc-py/citeproc-py/pull/154) ([@tmorrell](https://github.com/tmorrell)) #### Authors: 3 - John T. Wodder II ([@jwodder](https://github.com/jwodder)) - Tom Morrell ([@tmorrell](https://github.com/tmorrell)) - Yaroslav Halchenko ([@yarikoptic](https://github.com/yarikoptic)) --- # Release 0.7.0 (2025-02-19) Just to get a release out after long period. #### Bug fixes * Better handling of ordinals * Fix locator conditions (resolves #142) * Make family name optional * Allow date parts to not be integers * Support space macros * Fix multiple capitals * Fix parsing BibTex integer values #### Other changes: * Removed support for Python 3.6, 3.7, 3.8 and added for 3.10 - 3.13 * Switch versioning to versioneer # Release 0.6.0 (2021-05-27) #### Bug fixes * Various issues on Windows: testing, explicit utf-8 encoding * Strings with unescaped \ declared r"aw" #### Other changes: * Removed support for Python 2.7, 3.5 and added for 3.9 * Travis CI is removed in favor of GitHub actions testing across all 3 major OSes (MacOS, Windows, GNU/Linux Ubuntu) * CSL test-suite progressed from 5779a8c to c3db429 # Release 0.5.1 (2020-03-06) #### Bug fixed: * avoid rnc2rng 2.6.2 which breaks installation of citeproc-py # Release 0.5.0 (2020-02-09) #### Enhancements: * handle commas and ampersands in a functional style * Number: handle commas and ampersands * added symbol for textquotesingle * specify fallback locales for fr-CA and es-CL * improved page number and ranges parsing #### Bug fixed: * don't fail on empty page ranges (#90) (bbm) * detect end of file while parsing incorrect bib (#59) (John Vandenberg) #### Other changes: * Removed 3.2-3.4 and added 3.7, 3.8 to supported Pythons * Refactored locales handling # Release 0.4.0 (2017-06-23) #### New features: * allow specifying the encoding of a BibTeX database file (#20 and #25) * BibTeX 'month' field: support integers and " " values * BibTeX 'pages' field: support "10", "10+", "10-12" and "10--12" formats * BibTeX entry types: map the non-standard 'thesis' and 'report' entries * update the CSL schema to version 1.0.1 (#5) * update the CSL locales to commit 49bf3fc0 #### Bug fixed: * avoid crash when there is nothing to affix (David Lesieur) * fix BibTeX month to CSL month mapping (#24) * strip leading/trailing whitespace from BibTeX values (#37) # Release 0.3.0 (2014-11-07) #### Major improvements to the BibTeX parser: * split names into parts and assign them to the equivalent CSL name parts * fixed handling of accent macros and escaped characters * more compatible (La)TeX macro handling in general (but still basic) * handle standard Computer Modern ligatures such as --, ---, and << * added unit tests for the BibTeX and LaTeX parsers #### Other changes: * disable RelaxNG validation of CSL styles by default (API change) # Release 0.2.0 (2014-10-25) * bad cite callback function can determine how a bad cite is displayed (hetsch) * added option to disable RelaxNG validation (Jasper Op de Coul) * distutils was replaced with setuptools (Joshua Carp) * bug fixes (Yaroslav Halchenko, David Lesieur) * CitationStylesBibliography.bibliography() now returns the list of entries ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750227.0 citeproc_py-0.8.2/citeproc_py.egg-info/SOURCES.txt0000644000175100001660000000672114764177723021372 0ustar00runnerdockerCHANGELOG.md LICENSE MANIFEST.in README.md setup.cfg setup.py versioneer.py bin/csl_unsorted citeproc/__init__.py citeproc/_version.py citeproc/frontend.py citeproc/model.py citeproc/string.py citeproc/types.py citeproc/data/locales/locales-af-ZA.xml citeproc/data/locales/locales-ar.xml citeproc/data/locales/locales-bg-BG.xml citeproc/data/locales/locales-ca-AD.xml citeproc/data/locales/locales-cs-CZ.xml citeproc/data/locales/locales-cy-GB.xml citeproc/data/locales/locales-da-DK.xml citeproc/data/locales/locales-de-AT.xml citeproc/data/locales/locales-de-CH.xml citeproc/data/locales/locales-de-DE.xml citeproc/data/locales/locales-el-GR.xml citeproc/data/locales/locales-en-GB.xml citeproc/data/locales/locales-en-US.xml citeproc/data/locales/locales-es-CL.xml citeproc/data/locales/locales-es-ES.xml citeproc/data/locales/locales-es-MX.xml citeproc/data/locales/locales-et-EE.xml citeproc/data/locales/locales-eu.xml citeproc/data/locales/locales-fa-IR.xml citeproc/data/locales/locales-fi-FI.xml citeproc/data/locales/locales-fr-CA.xml citeproc/data/locales/locales-fr-FR.xml citeproc/data/locales/locales-he-IL.xml citeproc/data/locales/locales-hi-IN.xml citeproc/data/locales/locales-hr-HR.xml citeproc/data/locales/locales-hu-HU.xml citeproc/data/locales/locales-id-ID.xml citeproc/data/locales/locales-is-IS.xml citeproc/data/locales/locales-it-IT.xml citeproc/data/locales/locales-ja-JP.xml citeproc/data/locales/locales-km-KH.xml citeproc/data/locales/locales-ko-KR.xml citeproc/data/locales/locales-la.xml citeproc/data/locales/locales-lt-LT.xml citeproc/data/locales/locales-lv-LV.xml citeproc/data/locales/locales-mn-MN.xml citeproc/data/locales/locales-nb-NO.xml citeproc/data/locales/locales-nl-NL.xml citeproc/data/locales/locales-nn-NO.xml citeproc/data/locales/locales-pl-PL.xml citeproc/data/locales/locales-pt-BR.xml citeproc/data/locales/locales-pt-PT.xml citeproc/data/locales/locales-ro-RO.xml citeproc/data/locales/locales-ru-RU.xml citeproc/data/locales/locales-sk-SK.xml citeproc/data/locales/locales-sl-SI.xml citeproc/data/locales/locales-sr-RS.xml citeproc/data/locales/locales-sv-SE.xml citeproc/data/locales/locales-th-TH.xml citeproc/data/locales/locales-tr-TR.xml citeproc/data/locales/locales-uk-UA.xml citeproc/data/locales/locales-vi-VN.xml citeproc/data/locales/locales-zh-CN.xml citeproc/data/locales/locales-zh-TW.xml citeproc/data/locales/locales.json citeproc/data/schema/README.md citeproc/data/schema/csl-categories.rnc citeproc/data/schema/csl-data.rnc citeproc/data/schema/csl-relaxed.rnc citeproc/data/schema/csl-terms.rnc citeproc/data/schema/csl-types.rnc citeproc/data/schema/csl-variables.rnc citeproc/data/schema/csl.rnc citeproc/data/schema/test.rnc citeproc/data/styles/harvard1.csl citeproc/formatter/__init__.py citeproc/formatter/html.py citeproc/formatter/plain.py citeproc/formatter/rst.py citeproc/source/__init__.py citeproc/source/json.py citeproc/source/bibtex/__init__.py citeproc/source/bibtex/bibparse.py citeproc/source/bibtex/bibtex.py citeproc/source/bibtex/latex/__init__.py citeproc/source/bibtex/latex/macro.py citeproc_py.egg-info/PKG-INFO citeproc_py.egg-info/SOURCES.txt citeproc_py.egg-info/dependency_links.txt citeproc_py.egg-info/requires.txt citeproc_py.egg-info/top_level.txt examples/bibtex.py examples/citeproc_json.py examples/xampl.bib tests/check_string.py tests/citeproc-test.py tests/test.bib tests/test_base.py tests/test_bibliography.py tests/test_bibparse.py tests/test_bibtex.py tests/test_latex.py tests/local/condition_LocatorVariables.txt././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750227.0 citeproc_py-0.8.2/citeproc_py.egg-info/dependency_links.txt0000644000175100001660000000000114764177723023546 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750227.0 citeproc_py-0.8.2/citeproc_py.egg-info/requires.txt0000644000175100001660000000000514764177723022073 0ustar00runnerdockerlxml ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750227.0 citeproc_py-0.8.2/citeproc_py.egg-info/top_level.txt0000644000175100001660000000001114764177723022222 0ustar00runnerdockerciteproc ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.730875 citeproc_py-0.8.2/examples/0000755000175100001660000000000014764177724015305 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/examples/bibtex.py0000755000175100001660000000470514764177704017143 0ustar00runnerdocker#!/usr/bin/env python # The references are parsed from a BibTeX database, so we import the # corresponding parser. from citeproc.source.bibtex import BibTeX # Import the citeproc-py classes we'll use below. from citeproc import CitationStylesStyle, CitationStylesBibliography from citeproc import formatter from citeproc import Citation, CitationItem # Parse the BibTeX database. bib_source = BibTeX('xampl.bib') # load a CSL style (from the current directory) bib_style = CitationStylesStyle('harvard1', validate=False) # Create the citeproc-py bibliography, passing it the: # * CitationStylesStyle, # * BibliographySource (BibTeX in this case), and # * a formatter (plain, html, or you can write a custom formatter) bibliography = CitationStylesBibliography(bib_style, bib_source, formatter.plain) # Processing citations in a document needs to be done in two passes as for some # CSL styles, a citation can depend on the order of citations in the # bibliography and thus on citations following the current one. # For this reason, we first need to register all citations with the # CitationStylesBibliography. citation1 = Citation([CitationItem('whole-collection')]) citation2 = Citation([CitationItem('whole-set'), CitationItem('misc-full')]) citation3 = Citation([CitationItem('techreport-full')]) citation4 = Citation([CitationItem('mastersthesis-minimal')]) citation5 = Citation([CitationItem('inproceedings-full'), CitationItem('unpublished-full')]) bibliography.register(citation1) bibliography.register(citation2) bibliography.register(citation3) bibliography.register(citation4) bibliography.register(citation5) # In the second pass, CitationStylesBibliography can generate citations. # CitationStylesBibliography.cite() requires a callback function to be passed # along to be called in case a CitationItem's key is not present in the # bibliography. def warn(citation_item): print("WARNING: Reference with key '{}' not found in the bibliography." .format(citation_item.key)) print('Citations') print('---------') print(bibliography.cite(citation1, warn)) print(bibliography.cite(citation2, warn)) print(bibliography.cite(citation3, warn)) print(bibliography.cite(citation4, warn)) print(bibliography.cite(citation5, warn)) # And finally, the bibliography can be rendered. print('') print('Bibliography') print('------------') for item in bibliography.bibliography(): print(str(item)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/examples/citeproc_json.py0000755000175100001660000001032714764177704020524 0ustar00runnerdocker#!/usr/bin/env python # We'll use json.loads for parsing the JSON data. import json # Import the citeproc-py classes we'll use below. from citeproc import CitationStylesStyle, CitationStylesBibliography from citeproc import Citation, CitationItem from citeproc import formatter from citeproc.source.json import CiteProcJSON # The following JSON data describes 5 references picked from the CSL test suite. json_input = """ [ { "id": "ITEM-1", "issued": { "date-parts": [[1987, 8, 3], [2003, 10, 23]] }, "title": "Ignore me", "type": "book" }, { "id" : "ITEM-2", "page" : "1-7", "type" : "article-journal", "issued" : { "date-parts": [[2006]] } }, { "author": [ { "family": "Doe", "given": "John" } ], "id": "ITEM-3", "issued": { "date-parts": [["1965", "6", "1"]] }, "title": "His Anonymous Life", "type": "book" }, { "author": [ { "family": "Grignon", "given": "Cyril" }, { "family": "Sentenac", "given": "Corey" } ], "id": "ITEM-4", "issued": { "date-parts": [[2000]] }, "type": "book" }, { "id": "ITEM-5", "title":"Boundaries of Dissent: Protest and State Power in the Media Age", "author": [ { "family": "D'Arcus", "given": "Bruce", "static-ordering": false } ], "publisher": "Routledge", "publisher-place": "New York", "issued": { "date-parts":[[2006]] }, "type": "book", "URL": "http://www.test01.com" } ] """ # Parse the JSON input using json.loads() # (parsing from a file object can be done with json.load) json_data = json.loads(json_input) # Process the JSON data to generate a citeproc-py BibliographySource. bib_source = CiteProcJSON(json_data) ##for key, entry in bib_source.items(): ## print(key) ## for name, value in entry.items(): ## print(' {}: {}'.format(name, value)) # load a CSL style (from the current directory) bib_style = CitationStylesStyle('harvard1', validate=False) # Create the citeproc-py bibliography, passing it the: # * CitationStylesStyle, # * BibliographySource (CiteProcJSON in this case), and # * a formatter (plain, html, or you can write a custom formatter) bibliography = CitationStylesBibliography(bib_style, bib_source, formatter.html) # Processing citations in a document needs to be done in two passes as for some # CSL styles, a citation can depend on the order of citations in the # bibliography and thus on citations following the current one. # For this reason, we first need to register all citations with the # CitationStylesBibliography. citation1 = Citation([CitationItem('ITEM-3')]) citation2 = Citation([CitationItem('ITEM-1'), CitationItem('ITEM-2')]) citation3 = Citation([CitationItem('ITEM-4')]) citation4 = Citation([CitationItem('ITEM-5')]) citation5 = Citation([CitationItem('MISSING')]) bibliography.register(citation1) bibliography.register(citation2) bibliography.register(citation3) bibliography.register(citation4) bibliography.register(citation5) # In the second pass, CitationStylesBibliography can generate citations. # CitationStylesBibliography.cite() requires a callback function to be passed # along to be called in case a CitationItem's key is not present in the # bibliography. def warn(citation_item): print("WARNING: Reference with key '{}' not found in the bibliography." .format(citation_item.key)) print('Citations') print('---------') print(bibliography.cite(citation1, warn)) print(bibliography.cite(citation2, warn)) print(bibliography.cite(citation3, warn)) print(bibliography.cite(citation4, warn)) print(bibliography.cite(citation5, warn)) # And finally, the bibliography can be rendered. print('') print('Bibliography') print('------------') for item in bibliography.bibliography(): print(str(item)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/examples/xampl.bib0000644000175100001660000002362514764177704017112 0ustar00runnerdocker% Copyright (C) 1988, 2010 Oren Patashnik. % Unlimited copying and redistribution of this file are permitted if it % is unmodified. Modifications (and their redistribution) are also % permitted, as long as the resulting file is renamed. @preamble{ "\newcommand{\noopsort}[1]{} " # "\newcommand{\printfirst}[2]{#1} " # "\newcommand{\singleletter}[1]{#1} " # "\newcommand{\switchargs}[2]{#2#1} " } @ARTICLE{article-minimal, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, } @ARTICLE{article-full, author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, pages = "73+", month = jul, note = "This is a full ARTICLE entry", } The KEY field is here to override the KEY field in the journal being cross referenced (so is the NOTE field, in addition to its imparting information). @ARTICLE{article-crossref, crossref = {WHOLE-JOURNAL}, key = "", author = {L[eslie] A. Aamport}, title = {The Gnats and Gnus Document Preparation System}, pages = "73+", note = "This is a cross-referencing ARTICLE entry", } @ARTICLE{whole-journal, key = "GAJ", journal = {\mbox{G-Animal's} Journal}, year = 1986, volume = 41, number = 7, month = jul, note = {The entire issue is devoted to gnats and gnus (this entry is a cross-referenced ARTICLE (journal))}, } @INBOOK{inbook-minimal, author = "Donald E. Knuth", title = "Fundamental Algorithms", publisher = "Addison-Wesley", year = "{\noopsort{1973b}}1973", chapter = "1.2", } @INBOOK{inbook-full, author = "Donald E. Knuth", title = "Fundamental Algorithms", volume = 1, series = "The Art of Computer Programming", publisher = "Addison-Wesley", address = "Reading, Massachusetts", edition = "Second", month = "10~" # jan, year = "{\noopsort{1973b}}1973", type = "Section", chapter = "1.2", pages = "10--119", note = "This is a full INBOOK entry", } @INBOOK{inbook-crossref, crossref = "whole-set", title = "Fundamental Algorithms", volume = 1, series = "The Art of Computer Programming", edition = "Second", year = "{\noopsort{1973b}}1973", type = "Section", chapter = "1.2", note = "This is a cross-referencing INBOOK entry", } @BOOK{book-minimal, author = "Donald E. Knuth", title = "Seminumerical Algorithms", publisher = "Addison-Wesley", year = "{\noopsort{1973c}}1981", } @BOOK{book-full, author = "Donald E. Knuth", title = "Seminumerical Algorithms", volume = 2, series = "The Art of Computer Programming", publisher = "Addison-Wesley", address = "Reading, Massachusetts", edition = "Second", month = "10~" # jan, year = "{\noopsort{1973c}}1981", note = "This is a full BOOK entry", } @BOOK{book-crossref, crossref = "whole-set", title = "Seminumerical Algorithms", volume = 2, series = "The Art of Computer Programming", edition = "Second", year = "{\noopsort{1973c}}1981", note = "This is a cross-referencing BOOK entry", } @BOOK{whole-set, author = "Donald E. Knuth", publisher = "Addison-Wesley", title = "The Art of Computer Programming", series = "Four volumes", year = "{\noopsort{1973a}}{\switchargs{--90}{1968}}", note = "Seven volumes planned (this is a cross-referenced set of BOOKs)", } @BOOKLET{booklet-minimal, key = "Kn{\printfirst{v}{1987}}", title = "The Programming of Computer Art", } @BOOKLET{booklet-full, author = "Jill C. Knvth", title = "The Programming of Computer Art", howpublished = "Vernier Art Center", address = "Stanford, California", month = feb, year = 1988, note = "This is a full BOOKLET entry", } @INCOLLECTION{incollection-minimal, author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", booktitle = "High Speed Computer and Algorithm Organization", publisher = "Academic Press", year = 1977, } @INCOLLECTION{incollection-full, author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", booktitle = "High Speed Computer and Algorithm Organization", number = 23, series = "Fast Computers", chapter = 3, type = "Part", pages = "179--183", publisher = "Academic Press", address = "New York", edition = "Third", month = sep, year = 1977, note = "This is a full INCOLLECTION entry", } @INCOLLECTION{incollection-crossref, crossref = "whole-collection", author = "Daniel D. Lincoll", title = "Semigroups of Recurrences", pages = "179--183", note = "This is a cross-referencing INCOLLECTION entry", } @BOOK{whole-collection, editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", title = "High Speed Computer and Algorithm Organization", booktitle = "High Speed Computer and Algorithm Organization", number = 23, series = "Fast Computers", publisher = "Academic Press", address = "New York", edition = "Third", month = sep, year = 1977, note = "This is a cross-referenced BOOK (collection) entry", } @MANUAL{manual-minimal, key = "Manmaker", title = "The Definitive Computer Manual", } @MANUAL{manual-full, author = "Larry Manmaker", title = "The Definitive Computer Manual", organization = "Chips-R-Us", address = "Silicon Valley", edition = "Silver", month = apr # "-" # may, year = 1986, note = "This is a full MANUAL entry", } @MASTERSTHESIS{mastersthesis-minimal, author = "{\'{E}}douard Masterly", title = "Mastering Thesis Writing", school = "Stanford University", year = 1988, } @MASTERSTHESIS{mastersthesis-full, author = "{\'{E}}douard Masterly", title = "Mastering Thesis Writing", school = "Stanford University", type = "Master's project", address = "English Department", month = jun # "-" # aug, year = 1988, note = "This is a full MASTERSTHESIS entry", } @MISC{misc-minimal, key = "Missilany", note = "This is a minimal MISC entry", } @MISC{misc-full, author = "Joe-Bob Missilany", title = "Handing out random pamphlets in airports", howpublished = "Handed out at O'Hare", month = oct, year = 1984, note = "This is a full MISC entry", } @STRING{STOC-key = "OX{\singleletter{stoc}}"} @STRING{ACM = "The OX Association for Computing Machinery"} @STRING{STOC = " Symposium on the Theory of Computing"} @INPROCEEDINGS{inproceedings-minimal, author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", booktitle = "Proc. Fifteenth Annual ACM" # STOC, year = 1983, } @INPROCEEDINGS{inproceedings-full, author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", editor = "Wizard V. Oz and Mihalis Yannakakis", booktitle = "Proc. Fifteenth Annual ACM" # STOC, number = 17, series = "All ACM Conferences", pages = "133--139", month = mar, year = 1983, address = "Boston", organization = ACM, publisher = "Academic Press", note = "This is a full INPROCEDINGS entry", } @INPROCEEDINGS{inproceedings-crossref, crossref = "whole-proceedings", author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", title = "On Notions of Information Transfer in {VLSI} Circuits", organization = "", pages = "133--139", note = "This is a cross-referencing INPROCEEDINGS entry", } @PROCEEDINGS{proceedings-minimal, key = STOC-key, title = "Proc. Fifteenth Annual" # STOC, year = 1983, } @PROCEEDINGS{proceedings-full, editor = "Wizard V. Oz and Mihalis Yannakakis", title = "Proc. Fifteenth Annual" # STOC, number = 17, series = "All ACM Conferences", month = mar, year = 1983, address = "Boston", organization = ACM, publisher = "Academic Press", note = "This is a full PROCEEDINGS entry", } @PROCEEDINGS{whole-proceedings, key = STOC-key, organization = ACM, title = "Proc. Fifteenth Annual" # STOC, address = "Boston", year = 1983, booktitle = "Proc. Fifteenth Annual ACM" # STOC, note = "This is a cross-referenced PROCEEDINGS", } @PHDTHESIS{phdthesis-minimal, author = "F. Phidias Phony-Baloney", title = "Fighting Fire with Fire: Festooning {F}rench Phrases", school = "Fanstord University", year = 1988, } @PHDTHESIS{phdthesis-full, author = "F. Phidias Phony-Baloney", title = "Fighting Fire with Fire: Festooning {F}rench Phrases", school = "Fanstord University", type = "{PhD} Dissertation", address = "Department of French", month = jun # "-" # aug, year = 1988, note = "This is a full PHDTHESIS entry", } @TECHREPORT{techreport-minimal, author = "Tom Terrific", title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm", institution = "Fanstord University", year = 1988, } @TECHREPORT{techreport-full, author = "Tom T{\'{e}}rrific", title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm", institution = "Fanstord University", type = "Wishful Research Result", number = "7", address = "Computer Science Department, Fanstord, California", month = oct, year = 1988, note = "This is a full TECHREPORT entry", } @UNPUBLISHED{unpublished-minimal, author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot", title = "Lower Bounds for Wishful Research Results", note = "Talk at Fanstord University (this is a minimal UNPUBLISHED entry)", } @UNPUBLISHED{unpublished-full, author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot", title = "Lower Bounds for Wishful Research Results", month = nov # ", " # dec, year = 1988, note = "Talk at Fanstord University (this is a full UNPUBLISHED entry)", } @MISC{random-note-crossref, key = {Volume-2}, note = "Volume~2 is listed under Knuth \cite{book-full}" } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.733875 citeproc_py-0.8.2/setup.cfg0000644000175100001660000000035114764177724015307 0ustar00runnerdocker[bdist_wheel] universal = 0 [versioneer] VCS = git style = pep440 versionfile_source = citeproc/_version.py versionfile_build = citeproc/_version.py tag_prefix = v parentdir_prefix = citeproc- [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/setup.py0000755000175100001660000000646214764177704015212 0ustar00runnerdocker#!/usr/bin/env python """ Setup script for citeproc-py """ import io import os import re import sys from datetime import datetime from subprocess import Popen, PIPE from setuptools import setup, find_packages from setuptools.command.build_py import build_py from setuptools.command.develop import develop import versioneer PACKAGE = 'citeproc' BASE_PATH = os.path.dirname(os.path.abspath(__file__)) PACKAGE_ABSPATH = os.path.join(BASE_PATH, PACKAGE) VERSION_FILE = os.path.join(PACKAGE_ABSPATH, 'version.py') # All external commands are relative to BASE_PATH os.chdir(BASE_PATH) def long_description(): with open(os.path.join(BASE_PATH, 'README.md'), encoding='utf-8') as readme: result = readme.read() result += '\n\n' with open(os.path.join(BASE_PATH, 'CHANGELOG.md'), encoding='utf-8') as changes: result += changes.read() return result CSL_SCHEMA_RNC = 'citeproc/data/schema/csl.rnc' def convert_rnc(): import rnc2rng filename_root, _ = os.path.splitext(CSL_SCHEMA_RNC) root = rnc2rng.load(CSL_SCHEMA_RNC) with io.open(filename_root + '.rng', 'w', encoding='utf-8') as rng: rnc2rng.dump(root, rng) class custom_build_py(build_py): def run(self): convert_rnc() build_py.run(self) class custom_develop(develop): def run(self): convert_rnc() develop.run(self) setup( name='citeproc-py', version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass({'build_py': custom_build_py, 'develop': custom_develop}), packages=find_packages(), package_data={PACKAGE: ['data/locales/*.xml', 'data/locales/locales.json', 'data/schema/*.rng', 'data/styles/*.csl']}, python_requires='>=3.9', scripts=['bin/csl_unsorted'], setup_requires=['rnc2rng>=2.6.1,!=2.6.2'], install_requires=['lxml'], provides=[PACKAGE], #test_suite='nose.collector', author='Brecht Machiels', author_email='brecht@mos6581.org', description='Citations and bibliography formatter', long_description=long_description(), long_description_content_type='text/markdown', url='https://github.com/brechtm/citeproc-py', keywords='csl citation html rst bibtex xml', license='2-clause BSD License', classifiers = [ 'Development Status :: 3 - Alpha', 'Environment :: Console', 'Environment :: Other Environment', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'Intended Audience :: Education', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: Legal Industry', 'Intended Audience :: Other Audience', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Topic :: Documentation', 'Topic :: Printing', 'Topic :: Software Development :: Documentation', 'Topic :: Software Development :: Libraries :: Python Modules', ] ) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741750227.731875 citeproc_py-0.8.2/tests/0000755000175100001660000000000014764177724014631 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/check_string.py0000644000175100001660000000051614764177704017646 0ustar00runnerdockerfrom citeproc.string import String, NoCase a = String('a ') b = String(' b ') nocase = NoCase('NoCase') nocase2 = NoCase('NoCaseTwo') c = a + nocase + b + nocase2 print(c) print(c.upper()) print(c.lower()) print('test' + b) print('test ' + nocase) print(a + 'test') print(nocase + ' test') print('test ' + c) print(c + ' test') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/citeproc-test.py0000644000175100001660000003742714764177704020003 0ustar00runnerdocker import glob import io import os import sys import traceback from codecs import utf_8_encode from functools import reduce from optparse import OptionParser from subprocess import Popen, PIPE from citeproc import CitationStylesStyle, CitationStylesBibliography from citeproc.source import Citation, CitationItem, Locator from citeproc.source.json import CiteProcJSON CITEPROC_TEST_REPOSITORY = 'https://github.com/citation-style-language/test-suite.git' CITEPROC_TEST_COMMIT = '4001cdada66cd30f2ba1b8ae45a8da20f407dec0' CITEPROC_TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'test-suite')) TEST_PARSER_PATH = os.path.join(CITEPROC_TEST_PATH, 'processor.py') TESTS_PATH = os.path.join(CITEPROC_TEST_PATH, 'processor-tests', 'humans') LOCAL_TESTS_PATH = os.path.join(os.path.dirname(__file__), "local") FAILING_TESTS_FILE = 'failing_tests.txt' # The results of the following tests are ignored, since they don't test CSL # features, but citeproc-js specific features IGNORED_RESULS = { 'date_Accessed': 'raw date', 'date_LopsidedDataYearSuffixCollapse': 'raw date', 'date_SeasonRange1': 'raw date', 'date_SeasonRange2': 'raw date', 'date_SeasonRange3': 'raw date', 'date_String': 'raw date', } class ProcessorTest(object): """Parses atest fixture and provides a method for processing the tests defined in it.""" bib_prefix = '
' bib_suffix = '
' item_prefix = '
' item_suffix = '
' def __init__(self, filename): self.csl_test = CslTest({}, None, (filename, ), os.path.basename(filename)) self.csl_test.parse() csl_io = io.BytesIO(utf_8_encode(self.data['csl'])[0]) self.style = CitationStylesStyle(csl_io) self._fix_input(self.data['input']) self.references = [item['id'] for item in self.data['input']] self.references_dict = CiteProcJSON(self.data['input']) self.bibliography = CitationStylesBibliography(self.style, self.references_dict) self.expected = self.data['result'].splitlines() @property def data(self): return self.csl_test.data @staticmethod def _fix_input(input_data): for i, ref in enumerate(input_data): if 'id' not in ref: ref['id'] = i if 'type' not in ref: ref['type'] = 'book' def execute(self): if self.data['citation_items']: citations = [self.parse_citation(item) for item in self.data['citation_items']] elif self.data['citations']: citations = [] for cit in self.data['citations']: cit = cit[0] citation_items = [self.parse_citation_item(cititem) for cititem in cit['citationItems']] citation = Citation(citation_items) citation.key = cit['citationID'] citation.note_index = cit['properties']['noteIndex'] citations.append(citation) elif self.data['bibentries']: citation_items = [self.parse_citation_item({'id': entry}) for entry in self.data['bibentries'][-1]] citations = [Citation(citation_items)] else: citation_items = [self.parse_citation_item({'id': ref}) for ref in self.references] citations = [Citation(citation_items)] for citation in citations: self.bibliography.register(citation) if self.style.has_bibliography(): self.bibliography.sort() results = [] do_nothing = lambda x: None # callback passed to cite() if self.data['mode'] == 'citation': if self.data['citations']: for i, citation in enumerate(citations): if i == len(citations) - 1: dots_or_other = '>>' else: dots_or_other = '..' results.append('{}[{}] '.format(dots_or_other, i) + self.bibliography.cite(citation, do_nothing)) else: for citation in citations: results.append(self.bibliography.cite(citation, do_nothing)) elif self.data['mode'] in ('bibliography', 'bibliography-nosort'): results.append(self.bib_prefix) for entry in self.bibliography.bibliography(): text = self.item_prefix + str(entry) + self.item_suffix results.append(text) results.append(self.bib_suffix) return results def parse_citation(self, citation_data): citation_items = [] for item in citation_data: citation_item = self.parse_citation_item(item) citation_items.append(citation_item) return Citation(citation_items) def parse_citation_item(self, citation_item_data): options = {} for key, value in citation_item_data.items(): python_key = key.replace('-', '_') if python_key == 'id': reference_key = str(value) continue elif python_key == 'locator': try: options['locator'] = Locator(citation_item_data['label'], value) except KeyError: # some tests don't specify the label options['locator'] = Locator('page', value) elif python_key == 'label': pass else: options[python_key] = value return CitationItem(reference_key, **options) class FailedTests(object): """Read the known failed tests from a file and update the file with the results from a new test run.""" def __init__(self, filename): self.filename = filename with open(filename, 'r') as file: self.lines = file.readlines() self.now_failing = {} self.updated_lines = [] def mark_failure(self, test_name, reason=None): self.now_failing[test_name] = reason def compare(self): assert not self.updated_lines was_failing = set() new_failing_tests = [] new_fixed_tests = [] for line in self.lines: test_name, comment = (line.split('#') if '#' in line else (line, None)) test_name = test_name.strip() if test_name and test_name not in self.now_failing: new_fixed_tests.append(test_name) continue was_failing.add(test_name) self.updated_lines.append(line) for test_name in sorted(self.now_failing.keys()): if test_name not in was_failing: reason = self.now_failing[test_name] line = ('{:<66} # {}'.format(test_name, reason) if reason else test_name) self.updated_lines.append(line + '\n') new_failing_tests.append(test_name) return new_failing_tests, new_fixed_tests def update_file(self): assert self.updated_lines with open(self.filename, 'w') as file: file.writelines(self.updated_lines) def execute_git_command(args, echo=False): """Execute a git command, exiting this script when it returns a non-zero error code.""" command = ['git'] + args if echo: print(' '.join(command)) process = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE) out, err = process.communicate() if process.returncode: print('Calling git failed. Make sure git is installed. Aborting.') sys.exit(1) return out, err def clone_test_suite(): """Clone the citeproc-test repository if it is not present. Otherwise, check whether the correct commit is checked out.""" if not os.path.exists(CITEPROC_TEST_PATH): git_clone = ['clone', CITEPROC_TEST_REPOSITORY, CITEPROC_TEST_PATH] print('Cloning the test-suite repository...') execute_git_command(git_clone, echo=True) git_checkout = ['-C', CITEPROC_TEST_PATH, 'checkout', CITEPROC_TEST_COMMIT] print('Checking out the specified commit...') execute_git_command(git_checkout) else: git_ref = ['-C', CITEPROC_TEST_PATH, 'rev-parse', 'HEAD'] commit_ref, _ = execute_git_command(git_ref) if commit_ref.strip() != CITEPROC_TEST_COMMIT.encode('ascii'): print('The checked-out commit of test-suite does not match \n' 'the one recorded in this test script. Aborting.') sys.exit(1) git_fetch = ['-C', CITEPROC_TEST_PATH, 'fetch'] execute_git_command(git_fetch) git_ref = ['-C', CITEPROC_TEST_PATH, 'rev-parse', 'origin/master'] commit_ref, _ = execute_git_command(git_ref) has_updates = commit_ref.strip() != CITEPROC_TEST_COMMIT.encode('ascii') return has_updates RED = '\033[91m' GREEN = '\033[92m' BOLD = '\033[1m' END = '\033[0m' if __name__ == '__main__': usage = ('usage: %prog [options] glob_pattern\n\n' 'glob_pattern limits the tests that are executed, for example:\n' ' %prog *Sort*\n' 'runs only test fixtures that have "Sort" in the filename') parser = OptionParser(usage) parser.add_option('-m', '--max', dest='max', default=-1, help='run up to MAX tests', metavar='MAX') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='print results for each test') parser.add_option('-r', '--raise', dest='catch_exceptions', default=True, action='store_false', help='do not catch exceptions (aborts program)') parser.add_option('-s', '--summary', dest='summary', action='store_true', default=False, help='print a summary of the test results') parser.add_option('-n', '--no-update', dest='update', action='store_false', default=True, help='do not update {}' .format(FAILING_TESTS_FILE)) parser.add_option('-f', '--file', dest='file', default=None, help='write output to FILE', metavar='FILE') (options, args) = parser.parse_args() max_tests = int(options.max) try: destination = open(options.file, 'wt', encoding='utf-8') class UnicodeWriter(object): def write(self, s): destination.write(str(s)) sys.stderr = UnicodeWriter() except TypeError: destination = sys.stdout def out(*args): if not args: destination.write('\n') else: print(*args, file=destination) def print_result(name, passed, total): out(' {:<13} {:>3} / {:>3} ({:>4.0%})'.format(name, passed, total, passed / total)) try: glob_pattern = args[0] run_all_tests = False except IndexError: glob_pattern = '*' run_all_tests = True test_repo_has_updates = clone_test_suite() # import the text fixture parser included with citeproc-test try: # Python 3.3+ from importlib.machinery import SourceFileLoader loader = SourceFileLoader('processor', TEST_PARSER_PATH) processor = loader.load_module() except ImportError: # older Python versions from imp import load_source processor = load_source('processor', TEST_PARSER_PATH) from processor import CslTest global CslTest total_count = {} passed_count = {} failed_tests = FailedTests(os.path.join(os.path.dirname(__file__), FAILING_TESTS_FILE)) count = 0 test_files = list(glob.glob(os.path.join(TESTS_PATH, '{}.txt'.format(glob_pattern)))) test_files += list(glob.glob(os.path.join(LOCAL_TESTS_PATH, '{}.txt'.format(glob_pattern)))) for filename in sorted(test_files): test_name, _ = os.path.basename(filename).split('.txt') category, _ = os.path.basename(filename).split('_') passed_count.setdefault(category, 0) if count == max_tests: break reason = None try: if test_name not in IGNORED_RESULS: total_count[category] = total_count.get(category, 0) + 1 count += 1 t = ProcessorTest(filename) if run_all_tests and (t.data['mode'] == 'bibliography-header' or t.data['bibsection']): continue if options.verbose: out('>>> Testing {}'.format(os.path.basename(filename))) out('EXP: ' + '\n '.join(t.expected)) results = t.execute() results = reduce(lambda x, y: x+y, [item.split('\n') for item in results]) results = [item.replace('&', '&') for item in results] if options.verbose: out('RES: ' + '\n '.join(results)) if results == t.expected: if test_name not in IGNORED_RESULS: passed_count[category] += 1 if options.verbose: out('<<< SUCCESS\n') continue else: if options.verbose: out('<<< FAILED\n') del t except Exception as e: if not options.catch_exceptions: raise if options.verbose: out('Exception in', os.path.basename(filename)) traceback.print_exc() out('<<< FAILED\n') reason = 'uncaught exception' if test_name not in IGNORED_RESULS: failed_tests.mark_failure(test_name, reason) success = False if sum(total_count.values()) == 0: print(': check README.md file for instructions') else: if run_all_tests: new_failing, new_fixed = failed_tests.compare() success = not (new_failing or new_fixed) if options.update: failed_tests.update_file() if new_failing: out(BOLD + 'New failing tests:' + END) for test_name in new_failing: out(' ' + RED + test_name + END) if new_failing or new_fixed: out() else: out('All is well.') if new_fixed: out(BOLD + 'Fixed tests:' + END) for test_name in new_fixed: out(' ' + GREEN + test_name + END) out() out('You need to fix the newly failing tests and may commit the \n' 'removal of the fixed tests from {}'.format(FAILING_TESTS_FILE)) if test_repo_has_updates: out() out(BOLD + 'The test-suite repository has updates! Consider ' 'updating the test script.' + END) else: failing = sorted(failed_tests.now_failing.keys()) success = not failing out(BOLD + 'Failing tests:' + END) for test_name in failing: out(' ' + RED + test_name + END) if options.summary: out() out(BOLD + 'Summary:' + END) for category in sorted(total_count.keys()): print_result(category, passed_count[category], total_count[category]) out() print_result('total', sum(passed_count.values()), sum(total_count.values())) try: destination.close() except AttributeError: pass sys.exit(0 if success else 1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741750227.7328749 citeproc_py-0.8.2/tests/local/0000755000175100001660000000000014764177724015723 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/local/condition_LocatorVariables.txt0000644000175100001660000000405014764177704023763 0ustar00runnerdocker>>===== MODE =====>> citation <<===== MODE =====<< >>===== DESCRIPTION =====>> <<===== DESCRIPTION =====<< >>===== RESULT =====>> (Doe) (Doe 23) <<===== RESULT =====<< >>===== CITATION-ITEMS =====>> [ [ { "id": "ITEM-1" } ], [ { "id": "ITEM-1", "label": "page", "locator": 23 } ] ] <<===== CITATION-ITEMS =====<< >>===== CSL =====>> <<===== CSL =====<< >>===== INPUT =====>> [ { "id": "ITEM-1", "type": "book", "author": [ { "family": "Doe", "given": "John" } ], "issued": { "date-parts": [ [ "1984" ] ] }, "title": "Title" } ] <<===== INPUT =====<< >>===== VERSION =====>> 1.0 <<===== VERSION =====<< ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/test.bib0000644000175100001660000000101714764177704016263 0ustar00runnerdocker@INPROCEEDINGS{Blakley1979, AUTHOR = {Blakley, G. R.}, BOOKTITLE = {Proceedings of the National Computer Conference}, DOI = {10.1109/AFIPS.1979.98}, LOCATION = {Los Alamitos, CA, USA}, PAGES = {313}, PUBLISHER = {IEEE Computer Society}, TITLE = {{Safeguarding cryptographic key’s}}, URL = {http://www.computer.org/csdl/proceedings/afips/1979/5087/00/50870313-abs.html http://www.computer.org/csdl/proceedings/afips/1979/5087/00/50870313.pdf}, VOLUME = {0}, YEAR = {1979}, }././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/test_base.py0000644000175100001660000000024314764177704017151 0ustar00runnerdockerfrom citeproc import __version__ def test_version(): assert len(__version__.split(".")) >= 3, f"__version__ should have MAJOR.MINOR.PATCH, got {__version__}" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/test_bibliography.py0000644000175100001660000000372714764177704020724 0ustar00runnerdocker# coding: utf-8 import os from citeproc import ( Citation, CitationItem, CitationStylesBibliography, CitationStylesStyle, formatter, source, ) from unittest import TestCase from citeproc.source.bibtex.bibparse import BibTeXParser template = { "type": "book", "title": "La Rettorica", "author": [{"literal": "Brunetto Latini"}], "issued": {"date-parts": [[1968]]}, "editor": [{"literal": "Francesco Maggini"}], "publisher": "Le Monnier", "location": "Firenze", } def _pp(string): return string.split(" ")[5] class TestBibliographyGeneration(TestCase): def test_generate(self): expected_ordinals = { "en-US": {0: "1st", 1: "2nd", 3: "4th", 19: "20th"}, "de-DE": {0: "1.", 9: "10."}, "es-ES": {0: "1.ª"}, "fr-FR": {0: "1ʳᵉ", 9: "10ᵉ"}, "hi-IN": {0: "1"}, "it-IT": {0: "1º"} } for lg, ordinals in expected_ordinals.items(): bib_style = CitationStylesStyle("harvard1", lg) entries = [] for edition in range(1, 26): template["id"] = str(edition) template["edition"] = edition entries.append(template.copy()) bib = source.json.CiteProcJSON(entries) bibliography = CitationStylesBibliography(bib_style, bib, formatter.plain) citations = [CitationItem(str(x)) for x in range(1, 26)] bibliography.register(Citation(citations)) generated_ordinals = [_pp(x) for x in bibliography.style.render_bibliography(citations)] for index, expected_value in ordinals.items(): assert generated_ordinals[index] == expected_value, f"Failed for {lg} at index {index}. Expected: {expected_value}, Got: {generated_ordinals[index]}" # print(lg, # " ".join( # ordinals # ) # ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/test_bibparse.py0000644000175100001660000000540014764177704020026 0ustar00runnerdocker# coding: utf-8 import os from io import StringIO from unittest import TestCase from citeproc.source.bibtex.bibparse import BibTeXParser, BibTeXDecodeError TEST_BIB = os.path.join(os.path.dirname(__file__), 'test.bib') class TestBibTeXParser(TestCase): def test_parse(self): file = StringIO(sample) bib = BibTeXParser(file) self.print_entries(bib) # TODO: perform useful checks def test_parse_file(self): test_bib = BibTeXParser(TEST_BIB, encoding='utf-8') self.print_entries(test_bib) def test_parse_file_bad_encoding(self): with self.assertRaises(BibTeXDecodeError): BibTeXParser(TEST_BIB) @staticmethod def print_entries(bib): for key, entry in bib.items(): print(key) for name, value in entry.items(): print(' {}: {}'.format(name, value)) # based on the sample BibTeX database by Xavier Décoret # http://artis.imag.fr/~Xavier.Decoret/resources/xdkbibtex/bibtex_summary.html sample = r""" @Article(py03, author = {Xavier D\'ecoret}, title = "PyBiTex", year = 2003 ) @Article{key03, title = "A {bunch {of} braces {in}} title" } @Article{key01a, author = "Simon {"}the {saint"} Templar", } @Article{key01b, title = "The history of @ sign" } Some {{comments} with unbalanced braces ....and a "commented" entry... Book{landru21, author = {Landru, Henri D\'esir\'e}, title = {A hundred recipes for you wife}, publisher = {Culinary Expert Series}, year = 1921 } ..some other comments..before a valid entry... @Book{steward03a, author = { Martha Steward }, title = {Cooking behind bars}, publisher = {Culinary Expert Series}, year = 2003 } ...and finally an entry commented by the use of the special @Comment entry type. @Comment{steward03b, author = {Martha Steward}, title = {Cooking behind bars}, publisher = {Culinary Expert Series}, year = 2003 } @Comment{ @Book{steward03c, author = {Martha Steward}, title = {Cooking behind bars}, publisher = {Culinary Expert Series}, year = 2003 } } @String(mar = "march") @Book{sweig42, Author = { Stefan Sweig }, title = { The impossible book }, publisher = { Dead Poet Society}, year = 1942, month = mar } @String {firstname = "Xavier"} @String {lastname = "Decoret"} @String {email = firstname # "." # lastname # "@imag.fr"} @preamble{ "\newcommand{\noopsort}[1]{} " # "\newcommand{\printfirst}[2]{#1} " # "\newcommand{\singleletter}[1]{#1} " # "\newcommand{\switchargs}[2]{#2#1} " } @INBOOK{inbook-minimal, author = "Donald E. Knuth", title = "Fundamental Algorithms", publisher = "Addison-Wesley", year = "{\noopsort{1973b}}1973", chapter = "1.2", } """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/test_bibtex.py0000644000175100001660000003477414764177704017534 0ustar00runnerdocker# coding: utf-8 from unittest import TestCase from citeproc.source.bibtex import BibTeX from citeproc.source.bibtex.bibtex import split_names, split_name, parse_name class TestBibTeX(TestCase): def test_split_names(self): for names, parts in SPLIT_NAMES: print(names, split_names(names)) self.assertEqual(split_names(names), parts) def test_split_name(self): for name, parts in SPLIT_NAME: self.assertEqual(split_name(name), parts) def test_parse_name(self): for name, reference in DECORET_NAMES: print('{:24} {}'.format(name, parse_name(name))) self.assertEqual(parse_name(name), reference) for name, parts in PYBTEX_NAMES: reference = tuple(' '.join(pieces) if pieces else None for pieces in parts) print('{:24} {}'.format(name, parse_name(name))) self.assertEqual(parse_name(name), reference) for name, reference in EXTRA_NAMES: print('{:24} {}'.format(name, parse_name(name))) self.assertEqual(parse_name(name), reference) def test_date_months(self): for january in ['jan', 'JAN', '01']: self.assertEqual(BibTeX._parse_month(january), ({'month': 1}, ) * 2) self.assertEqual(BibTeX._parse_month("10~jan"), ({'month': 1, 'day': 10}, ) * 2) self.assertEqual(BibTeX._parse_month("jul~4"), ({'month': 7, 'day': 4}, ) * 2) def test_pages(self): def test(bibtex, csl): self.assertEqual(BibTeX._bibtex_to_csl_pages(bibtex), csl) test('313', '313') test('R112', 'R112') test('12+', '12') # page ranges test('1--3', '1-3') test('1-3', '1-3') test('i-iv', 'i-iv') test('11.1--11.27', '11.1-11.27') test('S43--S67', 'S43-S67') # Arabic letters test('ا-ي', 'ا-ي') SPLIT_NAMES = [ ('AA BB', ['AA BB']), ('AA and BB', ['AA', 'BB']), ('AA{ and }BB', ['AA{ and }BB']), ('AA{ }and BB', ['AA{ }and BB']), ] SPLIT_NAME = [ ('aa bb cc', [['aa', 'bb', 'cc']]), ('aa{ }bb cc', [['aa{ }bb', 'cc']]), ('aa{, }bb cc', [['aa{, }bb', 'cc']]), ('aa {bb} cc', [['aa', '{bb}', 'cc']]), ('aa bb, cc', [['aa', 'bb'], ['cc']]), ] # http://maverick.inria.fr/~Xavier.Decoret/resources/xdkbibtex/bibtex_summary.html DECORET_NAMES = [ # name string First von Last Jr ( 'AA BB' , ( 'AA' , None , 'BB' , None )), # Testing simple case with no von. ( 'AA' , ( None , None , 'AA' , None )), # Testing that Last cannot be empty. ( 'AA bb' , ( 'AA' , None , 'bb' , None )), # Idem. ( 'aa' , ( None , None , 'aa' , None )), # Idem. ( 'AA bb CC' , ( 'AA' , 'bb' , 'CC' , None )), # Testing simple von. ( 'AA bb CC dd EE' , ( 'AA' , 'bb CC dd' , 'EE' , None )), # Testing simple von (with inner uppercase words) ( 'AA 1B cc dd' , ( 'AA 1B' , 'cc' , 'dd' , None )), # Testing that digits are caseless (B fixes the case of 1B to uppercase). ( 'AA 1b cc dd' , ( 'AA' , '1b cc' , 'dd' , None )), # Testing that digits are caseless (b fixes the case of 1b to lowercase) ( 'AA {b}B cc dd' , ( 'AA {b}B' , 'cc' , 'dd' , None )), # Testing that pseudo letters are caseless. ( 'AA {b}b cc dd' , ( 'AA' , '{b}b cc' , 'dd' , None )), # Idem. ( 'AA {B}b cc dd' , ( 'AA' , '{B}b cc' , 'dd' , None )), # Idem. ( 'AA {B}B cc dd' , ( 'AA {B}B' , 'cc' , 'dd' , None )), # Idem. (r'AA \BB{b} cc dd', (r'AA \BB{b}', 'cc' , 'dd' , None )), # Testing that non letters are case less (in particular show how latex command are considered). (r'AA \bb{b} cc dd', ( 'AA' ,r'\bb{b} cc' , 'dd' , None )), # Idem. ( 'AA {bb} cc DD' , ( 'AA {bb}' , 'cc' , 'DD' , None )), # Testing that caseless words are grouped with First primilarily and then with Last. ( 'AA bb {cc} DD' , ( 'AA' , 'bb' , '{cc} DD' , None )), # Idem. ( 'AA {bb} CC' , ( 'AA {bb}' , None , 'CC' , None )), # Idem. ( 'bb CC, AA' , ('AA' , 'bb' , 'CC' , None )), # Simple case. Case do not matter for First. ( 'bb CC, aa' , ('aa' , 'bb' , 'CC' , None )), # Idem. ( 'bb CC dd EE, AA', ('AA' , 'bb CC dd' , 'EE' , None )), # Testing simple von (with inner uppercase). ( 'bb, AA' , ('AA' , None , 'bb' , None )), # Testing that the Last part cannot be empty. ( 'BB,' , ( None , None , 'BB' , None )), # Testing that first can be empty after coma ( 'bb CC,XX, AA' , ('AA' , 'bb' , 'CC' , 'XX' )), # Simple Jr. Case do not matter for it. ( 'bb CC,xx, AA' , ('AA' , 'bb' , 'CC' , 'xx' )), # Idem. ( 'BB,, AA' , ('AA' , None , 'BB' , None )), # Testing that jr can be empty in between comas. (r"Paul \'Emile Victor" , (r"Paul \'Emile" , None , "Victor", None)), (r"Paul {\'E}mile Victor" , (r"Paul {\'E}mile", None , "Victor", None)), (r"Paul \'emile Victor" , ( "Paul" , r"\'emile" , "Victor", None)), (r"Paul {\'e}mile Victor" , ( "Paul" , r"{\'e}mile", "Victor", None)), (r"Victor, Paul \'Emile" , (r"Paul \'Emile" , None , "Victor", None)), (r"Victor, Paul {\'E}mile", (r"Paul {\'E}mile", None , "Victor", None)), (r"Victor, Paul \'emile" , (r"Paul \'emile" , None , "Victor", None)), (r"Victor, Paul {\'e}mile", (r"Paul {\'e}mile", None , "Victor", None)), ('Dominique Galouzeau de Villepin', ('Dominique Galouzeau', 'de' , 'Villepin' , None)), ('Dominique {G}alouzeau de Villepin', ('Dominique' , '{G}alouzeau de', 'Villepin' , None)), ('Galouzeau de Villepin, Dominique', ('Dominique' , None , 'Galouzeau de Villepin', None)), ] # from Pybtex - /pybtex/tests/parse_name_test.py PYBTEX_NAMES = [ ('A. E. Siegman', (['A.', 'E.'], [], ['Siegman'], [])), ('A. G. W. Cameron', (['A.', 'G.', 'W.'], [], ['Cameron'], [])), ('A. Hoenig', (['A.'], [], ['Hoenig'], [])), ('A. J. Van Haagen', (['A.', 'J.', 'Van'], [], ['Haagen'], [])), ('A. S. Berdnikov', (['A.', 'S.'], [], ['Berdnikov'], [])), ('A. Trevorrow', (['A.'], [], ['Trevorrow'], [])), ('Adam H. Lewenberg', (['Adam', 'H.'], [], ['Lewenberg'], [])), ('Addison-Wesley Publishing Company', (['Addison-Wesley', 'Publishing'], [], ['Company'], [])), ('Advogato (Raph Levien)', (['Advogato', '(Raph'], [], ['Levien)'], [])), ('Andrea de Leeuw van Weenen', (['Andrea'], ['de', 'Leeuw', 'van'], ['Weenen'], [])), ('Andreas Geyer-Schulz', (['Andreas'], [], ['Geyer-Schulz'], [])), ("Andr{\\'e} Heck", (["Andr{\\'e}"], [], ['Heck'], [])), ('Anne Br{\\"u}ggemann-Klein', (['Anne'], [], ['Br{\\"u}ggemann-Klein'], [])), ('Anonymous', ([], [], ['Anonymous'], [])), ('B. Beeton', (['B.'], [], ['Beeton'], [])), ('B. Hamilton Kelly', (['B.', 'Hamilton'], [], ['Kelly'], [])), ('B. V. Venkata Krishna Sastry', (['B.', 'V.', 'Venkata', 'Krishna'], [], ['Sastry'], [])), ('Benedict L{\\o}fstedt', (['Benedict'], [], ['L{\\o}fstedt'], [])), ('Bogus{\\l}aw Jackowski', (['Bogus{\\l}aw'], [], ['Jackowski'], [])), ('Christina A. L.\\ Thiele', (['Christina', 'A.', 'L.\\'], [], ['Thiele'], [])), ("D. Men'shikov", (['D.'], [], ["Men'shikov"], [])), ("Darko \\v{Z}ubrini{\\'c}", (['Darko'], [], ["\\v{Z}ubrini{\\'c}"], [])), ("Dunja Mladeni{\\'c}", (['Dunja'], [], ["Mladeni{\\'c}"], [])), ('Edwin V. {Bell, II}', (['Edwin', 'V.'], [], ['{Bell, II}'], [])), ('Frank G. {Bennett, Jr.}', (['Frank', 'G.'], [], ['{Bennett, Jr.}'], [])), ("Fr{\\'e}d{\\'e}ric Boulanger", (["Fr{\\'e}d{\\'e}ric"], [], ['Boulanger'], [])), ('Ford, Jr., Henry', (['Henry'], [], ['Ford'], ['Jr.'])), ('mr Ford, Jr., Henry', (['Henry'], ['mr'], ['Ford'], ['Jr.'])), ('Fukui Rei', (['Fukui'], [], ['Rei'], [])), ('G. Gr{\\"a}tzer', (['G.'], [], ['Gr{\\"a}tzer'], [])), ('George Gr{\\"a}tzer', (['George'], [], ['Gr{\\"a}tzer'], [])), ('Georgia K. M. Tobin', (['Georgia', 'K.', 'M.'], [], ['Tobin'], [])), ('Gilbert van den Dobbelsteen', (['Gilbert'], ['van', 'den'], ['Dobbelsteen'], [])), ('Gy{\\"o}ngyi Bujdos{\\\'o}', (['Gy{\\"o}ngyi'], [], ["Bujdos{\\'o}"], [])), ('Helmut J{\\"u}rgensen', (['Helmut'], [], ['J{\\"u}rgensen'], [])), ('Herbert Vo{\\ss}', (['Herbert'], [], ['Vo{\\ss}'], [])), ("H{\\'a}n Th{\\^e}\\llap{\\raise 0.5ex\\hbox{\\'{\\relax}}} Th{\\'a}nh", (["H{\\'a}n", "Th{\\^e}\\llap{\\raise 0.5ex\\hbox{\\'{\\relax}}}"], [], ["Th{\\'a}nh"], [])), ("H{\\`a}n Th\\^e\\llap{\\raise0.5ex\\hbox{\\'{\\relax}}} Th{\\`a}nh", (['H{\\`a}n', "Th\\^e\\llap{\\raise0.5ex\\hbox{\\'{\\relax}}}"], [], ['Th{\\`a}nh'], [])), ("J. Vesel{\\'y}", (['J.'], [], ["Vesel{\\'y}"], [])), ("Javier Rodr\\'{\\i}guez Laguna", (['Javier', "Rodr\\'{\\i}guez"], [], ['Laguna'], [])), ("Ji\\v{r}\\'{\\i} Vesel{\\'y}", (["Ji\\v{r}\\'{\\i}"], [], ["Vesel{\\'y}"], [])), ("Ji\\v{r}\\'{\\i} Zlatu{\\v{s}}ka", (["Ji\\v{r}\\'{\\i}"], [], ['Zlatu{\\v{s}}ka'], [])), ("Ji\\v{r}{\\'\\i} Vesel{\\'y}", (["Ji\\v{r}{\\'\\i}"], [], ["Vesel{\\'y}"], [])), ("Ji\\v{r}{\\'{\\i}}Zlatu{\\v{s}}ka", ([], [], ["Ji\\v{r}{\\'{\\i}}Zlatu{\\v{s}}ka"], [])), ('Jim Hef{}feron', (['Jim'], [], ['Hef{}feron'], [])), ('J{\\"o}rg Knappen', (['J{\\"o}rg'], [], ['Knappen'], [])), ('J{\\"o}rgen L. Pind', (['J{\\"o}rgen', 'L.'], [], ['Pind'], [])), ("J{\\'e}r\\^ome Laurens", (["J{\\'e}r\\^ome"], [], ['Laurens'], [])), ('J{{\\"o}}rg Knappen', (['J{{\\"o}}rg'], [], ['Knappen'], [])), ('K. Anil Kumar', (['K.', 'Anil'], [], ['Kumar'], [])), ("Karel Hor{\\'a}k", (['Karel'], [], ["Hor{\\'a}k"], [])), ("Karel P\\'{\\i}{\\v{s}}ka", (['Karel'], [], ["P\\'{\\i}{\\v{s}}ka"], [])), ("Karel P{\\'\\i}{\\v{s}}ka", (['Karel'], [], ["P{\\'\\i}{\\v{s}}ka"], [])), ("Karel Skoup\\'{y}", (['Karel'], [], ["Skoup\\'{y}"], [])), ("Karel Skoup{\\'y}", (['Karel'], [], ["Skoup{\\'y}"], [])), ('Kent McPherson', (['Kent'], [], ['McPherson'], [])), ('Klaus H{\\"o}ppner', (['Klaus'], [], ['H{\\"o}ppner'], [])), ('Lars Hellstr{\\"o}m', (['Lars'], [], ['Hellstr{\\"o}m'], [])), ('Laura Elizabeth Jackson', (['Laura', 'Elizabeth'], [], ['Jackson'], [])), ("M. D{\\'{\\i}}az", (['M.'], [], ["D{\\'{\\i}}az"], [])), ('M/iche/al /O Searc/oid', (['M/iche/al', '/O'], [], ['Searc/oid'], [])), ("Marek Ry{\\'c}ko", (['Marek'], [], ["Ry{\\'c}ko"], [])), ('Marina Yu. Nikulina', (['Marina', 'Yu.'], [], ['Nikulina'], [])), ("Max D{\\'{\\i}}az", (['Max'], [], ["D{\\'{\\i}}az"], [])), ('Merry Obrecht Sawdey', (['Merry', 'Obrecht'], [], ['Sawdey'], [])), ("Miroslava Mis{\\'a}kov{\\'a}", (['Miroslava'], [], ["Mis{\\'a}kov{\\'a}"], [])), ('N. A. F. M. Poppelier', (['N.', 'A.', 'F.', 'M.'], [], ['Poppelier'], [])), ('Nico A. F. M. Poppelier', (['Nico', 'A.', 'F.', 'M.'], [], ['Poppelier'], [])), ('Onofrio de Bari', (['Onofrio'], ['de'], ['Bari'], [])), ("Pablo Rosell-Gonz{\\'a}lez", (['Pablo'], [], ["Rosell-Gonz{\\'a}lez"], [])), ('Paco La Bruna', (['Paco', 'La'], [], ['Bruna'], [])), ('Paul Franchi-Zannettacci', (['Paul'], [], ['Franchi-Zannettacci'], [])), ('Pavel \\v{S}eve\\v{c}ek', (['Pavel'], [], ['\\v{S}eve\\v{c}ek'], [])), ('Petr Ol{\\v{s}}ak', (['Petr'], [], ['Ol{\\v{s}}ak'], [])), ("Petr Ol{\\v{s}}{\\'a}k", (['Petr'], [], ["Ol{\\v{s}}{\\'a}k"], [])), ('Primo\\v{z} Peterlin', (['Primo\\v{z}'], [], ['Peterlin'], [])), ('Prof. Alban Grimm', (['Prof.', 'Alban'], [], ['Grimm'], [])), ("P{\\'e}ter Husz{\\'a}r", (["P{\\'e}ter"], [], ["Husz{\\'a}r"], [])), ("P{\\'e}ter Szab{\\'o}", (["P{\\'e}ter"], [], ["Szab{\\'o}"], [])), ('Rafa{\\l}\\.Zbikowski', ([], [], ['Rafa{\\l}\\.Zbikowski'], [])), ('Rainer Sch{\\"o}pf', (['Rainer'], [], ['Sch{\\"o}pf'], [])), ('T. L. (Frank) Pappas', (['T.', 'L.', '(Frank)'], [], ['Pappas'], [])), ('TUG 2004 conference', (['TUG', '2004'], [], ['conference'], [])), # ('TUG {\\sltt DVI} Driver Standards Committee', # (['TUG', '{\\sltt DVI}', 'Driver', 'Standards'], [], ['Committee'], [])), ('University of M{\\"u}nster', (['University'], ['of'], ['M{\\"u}nster'], [])), ('Walter van der Laan', (['Walter'], ['van', 'der'], ['Laan'], [])), ('Wendy G. McKay', (['Wendy', 'G.'], [], ['McKay'], [])), ('Wendy McKay', (['Wendy'], [], ['McKay'], [])), ('W{\\l}odek Bzyl', (['W{\\l}odek'], [], ['Bzyl'], [])), ('\\LaTeX Project Team', (['\\LaTeX', 'Project'], [], ['Team'], [])), ('\\rlap{Lutz Birkhahn}', ([], [], ['\\rlap{Lutz Birkhahn}'], [])), ('{Jim Hef{}feron}', ([], [], ['{Jim Hef{}feron}'], [])), ('{Kristoffer H\\o{}gsbro Rose}', ([], [], ['{Kristoffer H\\o{}gsbro Rose}'], [])), ('{TUG} {Working} {Group} on a {\\TeX} {Directory} {Structure}', (['{TUG}', '{Working}', '{Group}'], ['on', 'a'], ['{\\TeX}', '{Directory}', '{Structure}'], [])), ('{The \\TUB{} Team}', ([], [], ['{The \\TUB{} Team}'], [])), ('{\\LaTeX} project team', (['{\\LaTeX}'], ['project'], ['team'], [])), ('{\\NTG{} \\TeX{} future working group}', ([], [], ['{\\NTG{} \\TeX{} future working group}'], [])), ('{{\\LaTeX\\,3} Project Team}', ([], [], ['{{\\LaTeX\\,3} Project Team}'], [])), ('Johansen Kyle, Derik Mamania M.', (['Derik', 'Mamania', 'M.'], [], ['Johansen', 'Kyle'], [])), ] EXTRA_NAMES = [ ('others', (None, None, 'others', None)), ('Charles Louis Xavier Joseph de la Vall{\’e}e Poussin', ('Charles Louis Xavier Joseph', 'de la', 'Vall{\’e}e Poussin', None)), # the following name of the Pybtex tests doesn't agree with BibTeX's output # (verified using Xavier Décoret's names.bst) ('TUG {\\sltt DVI} Driver Standards Committee', ('TUG', '{\\sltt DVI}', 'Driver Standards Committee', None)), ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/tests/test_latex.py0000644000175100001660000000710014764177704017353 0ustar00runnerdocker# coding: utf-8 from unittest import TestCase from citeproc.source.bibtex.latex import parse_latex, substitute_ligatures class TestLatex(TestCase): # from "A TEX Primer for Scientists" (sections 5.2 and 5.3) # by Stanley A. Sawyer, Steven G. Krantz MACROS = [("Æsop's fables", r"\AE sop's fables"), ('Æ is a Latin ligature', r"\AE\ is a Latin ligature"), ('A TeX expert is a TeXnician.', r"A \TeX\ expert is a \TeX nician."), ('This book is ©ed.', r"This book is \copyright ed."), ('Umeå, Sweden', r"Ume\aa, Sweden"), ('Your serial number is Å1102.', r"Your serial number is \AA1102."), ('Your serial number is Å1102.', r"Your serial number is \AA 1102."), ('$22.50 plus $ 4.07 tax.', r"\$22.50 plus \$ 4.07 tax."), ('Crève Cœur, Missouri', r"Cr\`eve C\oe ur, Missouri"), ('Pëtr, meet Françoise', r"P\"etr, meet Fran\c coise"), ('Pëtr Pëtr Pëtr', r'P\" etr P\" etr ' 'P\\"\tetr'), ] ACCENT_MACROS = [('très élevé', r"tr\`es \'elev\'e"), ('übel Föhn', r'\"ubel F\"ohn'), ('Andō Tokutarō', r"And\=o Tokutar\=o"), ('García Lorca', r"Garc\'\i a Lorca"), ('naïve', r'na\"\i ve'), ('hát hàt hȧt hät hāt', r"h\'at h\`at h\.at h\"at h\=at"), ('hãt hât ha̧t ha̱t', r"h\~at h\^at h\c at h\b at"), ('hạt hǎt ha̋t', "h\\d at h\\v at h\\H at"), ('hăt ha͡at', "h\\u at h\\t aat"), ('øre', r"\o re"), ('Øre', r"\O re"), ('łódka', r"\l\'odka"), ('Łodz', r"\L odz"), ('Altstraße', r"Altstra\ss e"), ('æsthete', r"\ae sthete"), ('Ålm', r"\AA lm"), # ('', r"{\it\$}5"), ('Œuvre', r"\OE uvre"), ] # assorted string with macros ASSORTED = [('Escobar, María José', r"Escobar, Mar{\'\i}a Jos{\'e}"), ('Escobar, María-José', r"Escobar, Mar\'{\i}a-Jos\'{e}")] WARNINGS = [('Åke José Édouard Gödel', r"\AA{ke} {Jos{\'{e}} {\'{E}douard} G{\"o}del", "Unbalanced parenthesis")] MATH = [(r'An $O(n \log n / \! \log\log n)$ Sorting Algorithm', r"An $O(n \log n / \! \log\log n)$ Sorting Algorithm")] def test_parse_latex(self): for reference, string in self.MACROS: self.assertEqual(reference, parse_latex(string)) for reference, string in self.ACCENT_MACROS: self.assertEqual(reference, parse_latex(string)) for reference, string in self.ASSORTED: self.assertEqual(reference, parse_latex(string)) for reference, string, warning in self.WARNINGS: with self.assertWarns(UserWarning) as record: self.assertEqual(reference, parse_latex(string)) message, = (rec.message.args[0] for rec in record.warnings) assert warning in message for reference, string in self.MATH: self.assertEqual(reference, parse_latex(string)) LIGATURES = [('¿Que pasa?', "?`Que pasa?"), ('¡Que!', "!`Que!")] def test_substitute_ligatures(self): for reference, string in self.LIGATURES: self.assertEqual(reference, substitute_ligatures(string)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741750212.0 citeproc_py-0.8.2/versioneer.py0000644000175100001660000025122514764177704016227 0ustar00runnerdocker # Version: 0.29 """The Versioneer - like a rocketeer, but for versions. The Versioneer ============== * like a rocketeer, but for versions! * https://github.com/python-versioneer/python-versioneer * Brian Warner * License: Public Domain (Unlicense) * Compatible with: Python 3.7, 3.8, 3.9, 3.10, 3.11 and pypy3 * [![Latest Version][pypi-image]][pypi-url] * [![Build Status][travis-image]][travis-url] This is a tool for managing a recorded version number in setuptools-based python projects. The goal is to remove the tedious and error-prone "update the embedded version string" step from your release process. Making a new release should be as easy as recording a new tag in your version-control system, and maybe making new tarballs. ## Quick Install Versioneer provides two installation modes. The "classic" vendored mode installs a copy of versioneer into your repository. The experimental build-time dependency mode is intended to allow you to skip this step and simplify the process of upgrading. ### Vendored mode * `pip install versioneer` to somewhere in your $PATH * A [conda-forge recipe](https://github.com/conda-forge/versioneer-feedstock) is available, so you can also use `conda install -c conda-forge versioneer` * add a `[tool.versioneer]` section to your `pyproject.toml` or a `[versioneer]` section to your `setup.cfg` (see [Install](INSTALL.md)) * Note that you will need to add `tomli; python_version < "3.11"` to your build-time dependencies if you use `pyproject.toml` * run `versioneer install --vendor` in your source tree, commit the results * verify version information with `python setup.py version` ### Build-time dependency mode * `pip install versioneer` to somewhere in your $PATH * A [conda-forge recipe](https://github.com/conda-forge/versioneer-feedstock) is available, so you can also use `conda install -c conda-forge versioneer` * add a `[tool.versioneer]` section to your `pyproject.toml` or a `[versioneer]` section to your `setup.cfg` (see [Install](INSTALL.md)) * add `versioneer` (with `[toml]` extra, if configuring in `pyproject.toml`) to the `requires` key of the `build-system` table in `pyproject.toml`: ```toml [build-system] requires = ["setuptools", "versioneer[toml]"] build-backend = "setuptools.build_meta" ``` * run `versioneer install --no-vendor` in your source tree, commit the results * verify version information with `python setup.py version` ## Version Identifiers Source trees come from a variety of places: * a version-control system checkout (mostly used by developers) * a nightly tarball, produced by build automation * a snapshot tarball, produced by a web-based VCS browser, like github's "tarball from tag" feature * a release tarball, produced by "setup.py sdist", distributed through PyPI Within each source tree, the version identifier (either a string or a number, this tool is format-agnostic) can come from a variety of places: * ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows about recent "tags" and an absolute revision-id * the name of the directory into which the tarball was unpacked * an expanded VCS keyword ($Id$, etc) * a `_version.py` created by some earlier build step For released software, the version identifier is closely related to a VCS tag. Some projects use tag names that include more than just the version string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool needs to strip the tag prefix to extract the version identifier. For unreleased software (between tags), the version identifier should provide enough information to help developers recreate the same tree, while also giving them an idea of roughly how old the tree is (after version 1.2, before version 1.3). Many VCS systems can report a description that captures this, for example `git describe --tags --dirty --always` reports things like "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has uncommitted changes). The version identifier is used for multiple purposes: * to allow the module to self-identify its version: `myproject.__version__` * to choose a name and prefix for a 'setup.py sdist' tarball ## Theory of Operation Versioneer works by adding a special `_version.py` file into your source tree, where your `__init__.py` can import it. This `_version.py` knows how to dynamically ask the VCS tool for version information at import time. `_version.py` also contains `$Revision$` markers, and the installation process marks `_version.py` to have this marker rewritten with a tag name during the `git archive` command. As a result, generated tarballs will contain enough information to get the proper version. To allow `setup.py` to compute a version too, a `versioneer.py` is added to the top level of your source tree, next to `setup.py` and the `setup.cfg` that configures it. This overrides several distutils/setuptools commands to compute the version when invoked, and changes `setup.py build` and `setup.py sdist` to replace `_version.py` with a small static file that contains just the generated version data. ## Installation See [INSTALL.md](./INSTALL.md) for detailed installation instructions. ## Version-String Flavors Code which uses Versioneer can learn about its version string at runtime by importing `_version` from your main `__init__.py` file and running the `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can import the top-level `versioneer.py` and run `get_versions()`. Both functions return a dictionary with different flavors of version information: * `['version']`: A condensed version string, rendered using the selected style. This is the most commonly used value for the project's version string. The default "pep440" style yields strings like `0.11`, `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section below for alternative styles. * `['full-revisionid']`: detailed revision identifier. For Git, this is the full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". * `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the commit date in ISO 8601 format. This will be None if the date is not available. * `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that this is only accurate if run in a VCS checkout, otherwise it is likely to be False or None * `['error']`: if the version string could not be computed, this will be set to a string describing the problem, otherwise it will be None. It may be useful to throw an exception in setup.py if this is set, to avoid e.g. creating tarballs with a version string of "unknown". Some variants are more useful than others. Including `full-revisionid` in a bug report should allow developers to reconstruct the exact code being tested (or indicate the presence of local changes that should be shared with the developers). `version` is suitable for display in an "about" box or a CLI `--version` output: it can be easily compared against release notes and lists of bugs fixed in various releases. The installer adds the following text to your `__init__.py` to place a basic version in `YOURPROJECT.__version__`: from ._version import get_versions __version__ = get_versions()['version'] del get_versions ## Styles The setup.cfg `style=` configuration controls how the VCS information is rendered into a version string. The default style, "pep440", produces a PEP440-compliant string, equal to the un-prefixed tag name for actual releases, and containing an additional "local version" section with more detail for in-between builds. For Git, this is TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and that this commit is two revisions ("+2") beyond the "0.11" tag. For released software (exactly equal to a known tag), the identifier will only contain the stripped tag, e.g. "0.11". Other styles are available. See [details.md](details.md) in the Versioneer source tree for descriptions. ## Debugging Versioneer tries to avoid fatal errors: if something goes wrong, it will tend to return a version of "0+unknown". To investigate the problem, run `setup.py version`, which will run the version-lookup code in a verbose mode, and will display the full contents of `get_versions()` (including the `error` string, which may help identify what went wrong). ## Known Limitations Some situations are known to cause problems for Versioneer. This details the most significant ones. More can be found on Github [issues page](https://github.com/python-versioneer/python-versioneer/issues). ### Subprojects Versioneer has limited support for source trees in which `setup.py` is not in the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are two common reasons why `setup.py` might not be in the root: * Source trees which contain multiple subprojects, such as [Buildbot](https://github.com/buildbot/buildbot), which contains both "master" and "slave" subprojects, each with their own `setup.py`, `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI distributions (and upload multiple independently-installable tarballs). * Source trees whose main purpose is to contain a C library, but which also provide bindings to Python (and perhaps other languages) in subdirectories. Versioneer will look for `.git` in parent directories, and most operations should get the right version string. However `pip` and `setuptools` have bugs and implementation details which frequently cause `pip install .` from a subproject directory to fail to find a correct version string (so it usually defaults to `0+unknown`). `pip install --editable .` should work correctly. `setup.py install` might work too. Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in some later version. [Bug #38](https://github.com/python-versioneer/python-versioneer/issues/38) is tracking this issue. The discussion in [PR #61](https://github.com/python-versioneer/python-versioneer/pull/61) describes the issue from the Versioneer side in more detail. [pip PR#3176](https://github.com/pypa/pip/pull/3176) and [pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve pip to let Versioneer work correctly. Versioneer-0.16 and earlier only looked for a `.git` directory next to the `setup.cfg`, so subprojects were completely unsupported with those releases. ### Editable installs with setuptools <= 18.5 `setup.py develop` and `pip install --editable .` allow you to install a project into a virtualenv once, then continue editing the source code (and test) without re-installing after every change. "Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a convenient way to specify executable scripts that should be installed along with the python package. These both work as expected when using modern setuptools. When using setuptools-18.5 or earlier, however, certain operations will cause `pkg_resources.DistributionNotFound` errors when running the entrypoint script, which must be resolved by re-installing the package. This happens when the install happens with one version, then the egg_info data is regenerated while a different version is checked out. Many setup.py commands cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into a different virtualenv), so this can be surprising. [Bug #83](https://github.com/python-versioneer/python-versioneer/issues/83) describes this one, but upgrading to a newer version of setuptools should probably resolve it. ## Updating Versioneer To upgrade your project to a new release of Versioneer, do the following: * install the new Versioneer (`pip install -U versioneer` or equivalent) * edit `setup.cfg` and `pyproject.toml`, if necessary, to include any new configuration settings indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. * re-run `versioneer install --[no-]vendor` in your source tree, to replace `SRC/_version.py` * commit any changed files ## Future Directions This tool is designed to make it easily extended to other version-control systems: all VCS-specific components are in separate directories like src/git/ . The top-level `versioneer.py` script is assembled from these components by running make-versioneer.py . In the future, make-versioneer.py will take a VCS name as an argument, and will construct a version of `versioneer.py` that is specific to the given VCS. It might also take the configuration arguments that are currently provided manually during installation by editing setup.py . Alternatively, it might go the other direction and include code from all supported VCS systems, reducing the number of intermediate scripts. ## Similar projects * [setuptools_scm](https://github.com/pypa/setuptools_scm/) - a non-vendored build-time dependency * [minver](https://github.com/jbweston/miniver) - a lightweight reimplementation of versioneer * [versioningit](https://github.com/jwodder/versioningit) - a PEP 518-based setuptools plugin ## License To make Versioneer easier to embed, all its code is dedicated to the public domain. The `_version.py` that it creates is also in the public domain. Specifically, both are released under the "Unlicense", as described in https://unlicense.org/. [pypi-image]: https://img.shields.io/pypi/v/versioneer.svg [pypi-url]: https://pypi.python.org/pypi/versioneer/ [travis-image]: https://img.shields.io/travis/com/python-versioneer/python-versioneer.svg [travis-url]: https://travis-ci.com/github/python-versioneer/python-versioneer """ # pylint:disable=invalid-name,import-outside-toplevel,missing-function-docstring # pylint:disable=missing-class-docstring,too-many-branches,too-many-statements # pylint:disable=raise-missing-from,too-many-lines,too-many-locals,import-error # pylint:disable=too-few-public-methods,redefined-outer-name,consider-using-with # pylint:disable=attribute-defined-outside-init,too-many-arguments import configparser import errno import json import os import re import subprocess import sys from pathlib import Path from typing import Any, Callable, cast, Dict, List, Optional, Tuple, Union from typing import NoReturn import functools have_tomllib = True if sys.version_info >= (3, 11): import tomllib else: try: import tomli as tomllib except ImportError: have_tomllib = False class VersioneerConfig: """Container for Versioneer configuration parameters.""" VCS: str style: str tag_prefix: str versionfile_source: str versionfile_build: Optional[str] parentdir_prefix: Optional[str] verbose: Optional[bool] def get_root() -> str: """Get the project root directory. We require that all commands are run from the project root, i.e. the directory that contains setup.py, setup.cfg, and versioneer.py . """ root = os.path.realpath(os.path.abspath(os.getcwd())) setup_py = os.path.join(root, "setup.py") pyproject_toml = os.path.join(root, "pyproject.toml") versioneer_py = os.path.join(root, "versioneer.py") if not ( os.path.exists(setup_py) or os.path.exists(pyproject_toml) or os.path.exists(versioneer_py) ): # allow 'python path/to/setup.py COMMAND' root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) setup_py = os.path.join(root, "setup.py") pyproject_toml = os.path.join(root, "pyproject.toml") versioneer_py = os.path.join(root, "versioneer.py") if not ( os.path.exists(setup_py) or os.path.exists(pyproject_toml) or os.path.exists(versioneer_py) ): err = ("Versioneer was unable to run the project root directory. " "Versioneer requires setup.py to be executed from " "its immediate directory (like 'python setup.py COMMAND'), " "or in a way that lets it use sys.argv[0] to find the root " "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools # tree) execute all dependencies in a single python process, so # "versioneer" may be imported multiple times, and python's shared # module-import table will cache the first one. So we can't use # os.path.dirname(__file__), as that will find whichever # versioneer.py was first imported, even in later projects. my_path = os.path.realpath(os.path.abspath(__file__)) me_dir = os.path.normcase(os.path.splitext(my_path)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir and "VERSIONEER_PEP518" not in globals(): print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(my_path), versioneer_py)) except NameError: pass return root def get_config_from_root(root: str) -> VersioneerConfig: """Read the project setup.cfg file to determine Versioneer config.""" # This might raise OSError (if setup.cfg is missing), or # configparser.NoSectionError (if it lacks a [versioneer] section), or # configparser.NoOptionError (if it lacks "VCS="). See the docstring at # the top of versioneer.py for instructions on writing your setup.cfg . root_pth = Path(root) pyproject_toml = root_pth / "pyproject.toml" setup_cfg = root_pth / "setup.cfg" section: Union[Dict[str, Any], configparser.SectionProxy, None] = None if pyproject_toml.exists() and have_tomllib: try: with open(pyproject_toml, 'rb') as fobj: pp = tomllib.load(fobj) section = pp['tool']['versioneer'] except (tomllib.TOMLDecodeError, KeyError) as e: print(f"Failed to load config from {pyproject_toml}: {e}") print("Try to load it from setup.cfg") if not section: parser = configparser.ConfigParser() with open(setup_cfg) as cfg_file: parser.read_file(cfg_file) parser.get("versioneer", "VCS") # raise error if missing section = parser["versioneer"] # `cast`` really shouldn't be used, but its simplest for the # common VersioneerConfig users at the moment. We verify against # `None` values elsewhere where it matters cfg = VersioneerConfig() cfg.VCS = section['VCS'] cfg.style = section.get("style", "") cfg.versionfile_source = cast(str, section.get("versionfile_source")) cfg.versionfile_build = section.get("versionfile_build") cfg.tag_prefix = cast(str, section.get("tag_prefix")) if cfg.tag_prefix in ("''", '""', None): cfg.tag_prefix = "" cfg.parentdir_prefix = section.get("parentdir_prefix") if isinstance(section, configparser.SectionProxy): # Make sure configparser translates to bool cfg.verbose = section.getboolean("verbose") else: cfg.verbose = section.get("verbose") return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" # these dictionaries contain VCS-specific tools LONG_VERSION_PY: Dict[str, str] = {} HANDLERS: Dict[str, Dict[str, Callable]] = {} def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator """Create decorator to mark a method as the handler of a VCS.""" def decorate(f: Callable) -> Callable: """Store f in HANDLERS[vcs][method].""" HANDLERS.setdefault(vcs, {})[method] = f return f return decorate def run_command( commands: List[str], args: List[str], cwd: Optional[str] = None, verbose: bool = False, hide_stderr: bool = False, env: Optional[Dict[str, str]] = None, ) -> Tuple[Optional[str], Optional[int]]: """Call the given command(s).""" assert isinstance(commands, list) process = None popen_kwargs: Dict[str, Any] = {} if sys.platform == "win32": # This hides the console window if pythonw.exe is used startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW popen_kwargs["startupinfo"] = startupinfo for command in commands: try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git process = subprocess.Popen([command] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None), **popen_kwargs) break except OSError as e: if e.errno == errno.ENOENT: continue if verbose: print("unable to run %s" % dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %s" % (commands,)) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: if verbose: print("unable to run %s (error)" % dispcmd) print("stdout was %s" % stdout) return None, process.returncode return stdout, process.returncode LONG_VERSION_PY['git'] = r''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build # directories (produced by setup.py build) will contain a much shorter file # that just contains the computed version number. # This file is released into the public domain. # Generated by versioneer-0.29 # https://github.com/python-versioneer/python-versioneer """Git implementation of _version.py.""" import errno import os import re import subprocess import sys from typing import Any, Callable, Dict, List, Optional, Tuple import functools def get_keywords() -> Dict[str, str]: """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords class VersioneerConfig: """Container for Versioneer configuration parameters.""" VCS: str style: str tag_prefix: str parentdir_prefix: str versionfile_source: str verbose: bool def get_config() -> VersioneerConfig: """Create, populate and return the VersioneerConfig() object.""" # these strings are filled in when 'setup.py versioneer' creates # _version.py cfg = VersioneerConfig() cfg.VCS = "git" cfg.style = "%(STYLE)s" cfg.tag_prefix = "%(TAG_PREFIX)s" cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" cfg.verbose = False return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" LONG_VERSION_PY: Dict[str, str] = {} HANDLERS: Dict[str, Dict[str, Callable]] = {} def register_vcs_handler(vcs: str, method: str) -> Callable: # decorator """Create decorator to mark a method as the handler of a VCS.""" def decorate(f: Callable) -> Callable: """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command( commands: List[str], args: List[str], cwd: Optional[str] = None, verbose: bool = False, hide_stderr: bool = False, env: Optional[Dict[str, str]] = None, ) -> Tuple[Optional[str], Optional[int]]: """Call the given command(s).""" assert isinstance(commands, list) process = None popen_kwargs: Dict[str, Any] = {} if sys.platform == "win32": # This hides the console window if pythonw.exe is used startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW popen_kwargs["startupinfo"] = startupinfo for command in commands: try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git process = subprocess.Popen([command] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None), **popen_kwargs) break except OSError as e: if e.errno == errno.ENOENT: continue if verbose: print("unable to run %%s" %% dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %%s" %% (commands,)) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: if verbose: print("unable to run %%s (error)" %% dispcmd) print("stdout was %%s" %% stdout) return None, process.returncode return stdout, process.returncode def versions_from_parentdir( parentdir_prefix: str, root: str, verbose: bool, ) -> Dict[str, Any]: """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %%s but none started with prefix %%s" %% (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords: Dict[str, str] = {} try: with open(versionfile_abs, "r") as fobj: for line in fobj: if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) except OSError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords( keywords: Dict[str, str], tag_prefix: str, verbose: bool, ) -> Dict[str, Any]: """Get version information from git keywords.""" if "refnames" not in keywords: raise NotThisMethod("Short version file found") date = keywords.get("date") if date is not None: # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = {r.strip() for r in refnames.strip("()").split(",")} # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %%d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = {r for r in refs if re.search(r'\d', r)} if verbose: print("discarding '%%s', no digits" %% ",".join(refs - tags)) if verbose: print("likely tags: %%s" %% ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] # Filter out refs that exactly match prefix or that don't start # with a number once the prefix is stripped (mostly a concern # when prefix is '') if not re.match(r'\d', r): continue if verbose: print("picking %%s" %% r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs( tag_prefix: str, root: str, verbose: bool, runner: Callable = run_command ) -> Dict[str, Any]: """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] # GIT_DIR can interfere with correct operation of Versioneer. # It may be intended to be passed to the Versioneer-versioned project, # but that should not change where we get our version from. env = os.environ.copy() env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) if rc != 0: if verbose: print("Directory %%s not under git control" %% root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = runner(GITS, [ "describe", "--tags", "--dirty", "--always", "--long", "--match", f"{tag_prefix}[[:digit:]]*" ], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces: Dict[str, Any] = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") branch_name = branch_name.strip() if branch_name == "HEAD": # If we aren't exactly on a branch, pick a branch which represents # the current commit. If all else fails, we are on a branchless # commit. branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) # --contains was added in git-1.5.4 if rc != 0 or branches is None: raise NotThisMethod("'git branch --contains' returned error") branches = branches.split("\n") # Remove the first line if we're running detached if "(" in branches[0]: branches.pop(0) # Strip off the leading "* " from the list of branches. branches = [branch[2:] for branch in branches] if "master" in branches: branch_name = "master" elif not branches: branch_name = None else: # Pick the first branch that is returned. Good or bad. branch_name = branches[0] pieces["branch"] = branch_name # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%%s'" %% describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%%s' doesn't start with prefix '%%s'" print(fmt %% (full_tag, tag_prefix)) pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" %% (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) pieces["distance"] = len(out.split()) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = runner(GITS, ["show", "-s", "--format=%%ci", "HEAD"], cwd=root)[0].strip() # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def plus_or_dot(pieces: Dict[str, Any]) -> str: """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces: Dict[str, Any]) -> str: """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_branch(pieces: Dict[str, Any]) -> str: """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch). Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" rendered += "+untagged.%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: """Split pep440 version string at the post-release segment. Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present). """ vc = str.split(ver, ".post") return vc[0], int(vc[1] or 0) if len(vc) == 2 else None def render_pep440_pre(pieces: Dict[str, Any]) -> str: """TAG[.postN.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post0.devDISTANCE """ if pieces["closest-tag"]: if pieces["distance"]: # update the post release segment tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: rendered += ".post%%d.dev%%d" %% (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%%d" %% (pieces["distance"]) else: # no commits, use the tag as the version rendered = pieces["closest-tag"] else: # exception #1 rendered = "0.post0.dev%%d" %% pieces["distance"] return rendered def render_pep440_post(pieces: Dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%%s" %% pieces["short"] else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%%s" %% pieces["short"] return rendered def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . The ".dev0" means not master branch. Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%%s" %% pieces["short"] if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += "+g%%s" %% pieces["short"] if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_old(pieces: Dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces: Dict[str, Any]) -> str: """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces: Dict[str, Any]) -> str: """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-branch": rendered = render_pep440_branch(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-post-branch": rendered = render_pep440_post_branch(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%%s'" %% style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} def get_versions() -> Dict[str, Any]: """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. cfg = get_config() verbose = cfg.verbose try: return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass try: root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. for _ in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to find root of source tree", "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) return render(pieces, cfg.style) except NotThisMethod: pass try: if cfg.parentdir_prefix: return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) except NotThisMethod: pass return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} ''' @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs: str) -> Dict[str, str]: """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords: Dict[str, str] = {} try: with open(versionfile_abs, "r") as fobj: for line in fobj: if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) except OSError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords( keywords: Dict[str, str], tag_prefix: str, verbose: bool, ) -> Dict[str, Any]: """Get version information from git keywords.""" if "refnames" not in keywords: raise NotThisMethod("Short version file found") date = keywords.get("date") if date is not None: # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = {r.strip() for r in refnames.strip("()").split(",")} # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = {r for r in refs if re.search(r'\d', r)} if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] # Filter out refs that exactly match prefix or that don't start # with a number once the prefix is stripped (mostly a concern # when prefix is '') if not re.match(r'\d', r): continue if verbose: print("picking %s" % r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs( tag_prefix: str, root: str, verbose: bool, runner: Callable = run_command ) -> Dict[str, Any]: """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] # GIT_DIR can interfere with correct operation of Versioneer. # It may be intended to be passed to the Versioneer-versioned project, # but that should not change where we get our version from. env = os.environ.copy() env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) if rc != 0: if verbose: print("Directory %s not under git control" % root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = runner(GITS, [ "describe", "--tags", "--dirty", "--always", "--long", "--match", f"{tag_prefix}[[:digit:]]*" ], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces: Dict[str, Any] = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") branch_name = branch_name.strip() if branch_name == "HEAD": # If we aren't exactly on a branch, pick a branch which represents # the current commit. If all else fails, we are on a branchless # commit. branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) # --contains was added in git-1.5.4 if rc != 0 or branches is None: raise NotThisMethod("'git branch --contains' returned error") branches = branches.split("\n") # Remove the first line if we're running detached if "(" in branches[0]: branches.pop(0) # Strip off the leading "* " from the list of branches. branches = [branch[2:] for branch in branches] if "master" in branches: branch_name = "master" elif not branches: branch_name = None else: # Pick the first branch that is returned. Good or bad. branch_name = branches[0] pieces["branch"] = branch_name # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) pieces["distance"] = len(out.split()) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def do_vcs_install(versionfile_source: str, ipy: Optional[str]) -> None: """Git-specific installation logic for Versioneer. For Git, this means creating/changing .gitattributes to mark _version.py for export-subst keyword substitution. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] files = [versionfile_source] if ipy: files.append(ipy) if "VERSIONEER_PEP518" not in globals(): try: my_path = __file__ if my_path.endswith((".pyc", ".pyo")): my_path = os.path.splitext(my_path)[0] + ".py" versioneer_file = os.path.relpath(my_path) except NameError: versioneer_file = "versioneer.py" files.append(versioneer_file) present = False try: with open(".gitattributes", "r") as fobj: for line in fobj: if line.strip().startswith(versionfile_source): if "export-subst" in line.strip().split()[1:]: present = True break except OSError: pass if not present: with open(".gitattributes", "a+") as fobj: fobj.write(f"{versionfile_source} export-subst\n") files.append(".gitattributes") run_command(GITS, ["add", "--"] + files) def versions_from_parentdir( parentdir_prefix: str, root: str, verbose: bool, ) -> Dict[str, Any]: """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") SHORT_VERSION_PY = """ # This file was generated by 'versioneer.py' (0.29) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' %s ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) """ def versions_from_file(filename: str) -> Dict[str, Any]: """Try to determine the version from _version.py if present.""" try: with open(filename) as f: contents = f.read() except OSError: raise NotThisMethod("unable to read _version.py") mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) def write_to_version_file(filename: str, versions: Dict[str, Any]) -> None: """Write the given version number to the given _version.py file.""" contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) print("set %s to '%s'" % (filename, versions["version"])) def plus_or_dot(pieces: Dict[str, Any]) -> str: """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces: Dict[str, Any]) -> str: """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_branch(pieces: Dict[str, Any]) -> str: """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch). Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def pep440_split_post(ver: str) -> Tuple[str, Optional[int]]: """Split pep440 version string at the post-release segment. Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present). """ vc = str.split(ver, ".post") return vc[0], int(vc[1] or 0) if len(vc) == 2 else None def render_pep440_pre(pieces: Dict[str, Any]) -> str: """TAG[.postN.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post0.devDISTANCE """ if pieces["closest-tag"]: if pieces["distance"]: # update the post release segment tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%d" % (pieces["distance"]) else: # no commits, use the tag as the version rendered = pieces["closest-tag"] else: # exception #1 rendered = "0.post0.dev%d" % pieces["distance"] return rendered def render_pep440_post(pieces: Dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%s" % pieces["short"] return rendered def render_pep440_post_branch(pieces: Dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . The ".dev0" means not master branch. Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += "+g%s" % pieces["short"] if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_old(pieces: Dict[str, Any]) -> str: """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces: Dict[str, Any]) -> str: """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces: Dict[str, Any]) -> str: """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces: Dict[str, Any], style: str) -> Dict[str, Any]: """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-branch": rendered = render_pep440_branch(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-post-branch": rendered = render_pep440_post_branch(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%s'" % style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} class VersioneerBadRootError(Exception): """The project root directory is unknown or missing key files.""" def get_versions(verbose: bool = False) -> Dict[str, Any]: """Get the project version from whatever source is available. Returns dict with two keys: 'version' and 'full'. """ if "versioneer" in sys.modules: # see the discussion in cmdclass.py:get_cmdclass() del sys.modules["versioneer"] root = get_root() cfg = get_config_from_root(root) assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or bool(cfg.verbose) # `bool()` used to avoid `None` assert cfg.versionfile_source is not None, \ "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) # extract version from first of: _version.py, VCS command (e.g. 'git # describe'), parentdir. This is meant to work for developers using a # source checkout, for users of a tarball created by 'setup.py sdist', # and for users of a tarball/zipball created by 'git archive' or github's # download-from-tag feature or the equivalent in other VCSes. get_keywords_f = handlers.get("get_keywords") from_keywords_f = handlers.get("keywords") if get_keywords_f and from_keywords_f: try: keywords = get_keywords_f(versionfile_abs) ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) if verbose: print("got version from expanded keyword %s" % ver) return ver except NotThisMethod: pass try: ver = versions_from_file(versionfile_abs) if verbose: print("got version from file %s %s" % (versionfile_abs, ver)) return ver except NotThisMethod: pass from_vcs_f = handlers.get("pieces_from_vcs") if from_vcs_f: try: pieces = from_vcs_f(cfg.tag_prefix, root, verbose) ver = render(pieces, cfg.style) if verbose: print("got version from VCS %s" % ver) return ver except NotThisMethod: pass try: if cfg.parentdir_prefix: ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) if verbose: print("got version from parentdir %s" % ver) return ver except NotThisMethod: pass if verbose: print("unable to compute version") return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} def get_version() -> str: """Get the short version string for this project.""" return get_versions()["version"] def get_cmdclass(cmdclass: Optional[Dict[str, Any]] = None): """Get the custom setuptools subclasses used by Versioneer. If the package uses a different cmdclass (e.g. one from numpy), it should be provide as an argument. """ if "versioneer" in sys.modules: del sys.modules["versioneer"] # this fixes the "python setup.py develop" case (also 'install' and # 'easy_install .'), in which subdependencies of the main project are # built (using setup.py bdist_egg) in the same python process. Assume # a main project A and a dependency B, which use different versions # of Versioneer. A's setup.py imports A's Versioneer, leaving it in # sys.modules by the time B's setup.py is executed, causing B to run # with the wrong versioneer. Setuptools wraps the sub-dep builds in a # sandbox that restores sys.modules to it's pre-build state, so the # parent is protected against the child's "import versioneer". By # removing ourselves from sys.modules here, before the child build # happens, we protect the child from the parent's versioneer too. # Also see https://github.com/python-versioneer/python-versioneer/issues/52 cmds = {} if cmdclass is None else cmdclass.copy() # we add "version" to setuptools from setuptools import Command class cmd_version(Command): description = "report generated version string" user_options: List[Tuple[str, str, str]] = [] boolean_options: List[str] = [] def initialize_options(self) -> None: pass def finalize_options(self) -> None: pass def run(self) -> None: vers = get_versions(verbose=True) print("Version: %s" % vers["version"]) print(" full-revisionid: %s" % vers.get("full-revisionid")) print(" dirty: %s" % vers.get("dirty")) print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) cmds["version"] = cmd_version # we override "build_py" in setuptools # # most invocation pathways end up running build_py: # distutils/build -> build_py # distutils/install -> distutils/build ->.. # setuptools/bdist_wheel -> distutils/install ->.. # setuptools/bdist_egg -> distutils/install_lib -> build_py # setuptools/install -> bdist_egg ->.. # setuptools/develop -> ? # pip install: # copies source tree to a tempdir before running egg_info/etc # if .git isn't copied too, 'git describe' will fail # then does setup.py bdist_wheel, or sometimes setup.py install # setup.py egg_info -> ? # pip install -e . and setuptool/editable_wheel will invoke build_py # but the build_py command is not expected to copy any files. # we override different "build_py" commands for both environments if 'build_py' in cmds: _build_py: Any = cmds['build_py'] else: from setuptools.command.build_py import build_py as _build_py class cmd_build_py(_build_py): def run(self) -> None: root = get_root() cfg = get_config_from_root(root) versions = get_versions() _build_py.run(self) if getattr(self, "editable_mode", False): # During editable installs `.py` and data files are # not copied to build_lib return # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) cmds["build_py"] = cmd_build_py if 'build_ext' in cmds: _build_ext: Any = cmds['build_ext'] else: from setuptools.command.build_ext import build_ext as _build_ext class cmd_build_ext(_build_ext): def run(self) -> None: root = get_root() cfg = get_config_from_root(root) versions = get_versions() _build_ext.run(self) if self.inplace: # build_ext --inplace will only build extensions in # build/lib<..> dir with no _version.py to write to. # As in place builds will already have a _version.py # in the module dir, we do not need to write one. return # now locate _version.py in the new build/ directory and replace # it with an updated value if not cfg.versionfile_build: return target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) if not os.path.exists(target_versionfile): print(f"Warning: {target_versionfile} does not exist, skipping " "version update. This can happen if you are running build_ext " "without first running build_py.") return print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) cmds["build_ext"] = cmd_build_ext if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe # type: ignore # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION # "product_version": versioneer.get_version(), # ... class cmd_build_exe(_build_exe): def run(self) -> None: root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _build_exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.setuptools_buildexe import py2exe as _py2exe # type: ignore except ImportError: from py2exe.distutils_buildexe import py2exe as _py2exe # type: ignore class cmd_py2exe(_py2exe): def run(self) -> None: root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _py2exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["py2exe"] = cmd_py2exe # sdist farms its file list building out to egg_info if 'egg_info' in cmds: _egg_info: Any = cmds['egg_info'] else: from setuptools.command.egg_info import egg_info as _egg_info class cmd_egg_info(_egg_info): def find_sources(self) -> None: # egg_info.find_sources builds the manifest list and writes it # in one shot super().find_sources() # Modify the filelist and normalize it root = get_root() cfg = get_config_from_root(root) self.filelist.append('versioneer.py') if cfg.versionfile_source: # There are rare cases where versionfile_source might not be # included by default, so we must be explicit self.filelist.append(cfg.versionfile_source) self.filelist.sort() self.filelist.remove_duplicates() # The write method is hidden in the manifest_maker instance that # generated the filelist and was thrown away # We will instead replicate their final normalization (to unicode, # and POSIX-style paths) from setuptools import unicode_utils normalized = [unicode_utils.filesys_decode(f).replace(os.sep, '/') for f in self.filelist.files] manifest_filename = os.path.join(self.egg_info, 'SOURCES.txt') with open(manifest_filename, 'w') as fobj: fobj.write('\n'.join(normalized)) cmds['egg_info'] = cmd_egg_info # we override different "sdist" commands for both environments if 'sdist' in cmds: _sdist: Any = cmds['sdist'] else: from setuptools.command.sdist import sdist as _sdist class cmd_sdist(_sdist): def run(self) -> None: versions = get_versions() self._versioneer_generated_versions = versions # unless we update this, the command will keep using the old # version self.distribution.metadata.version = versions["version"] return _sdist.run(self) def make_release_tree(self, base_dir: str, files: List[str]) -> None: root = get_root() cfg = get_config_from_root(root) _sdist.make_release_tree(self, base_dir, files) # now locate _version.py in the new base_dir directory # (remembering that it may be a hardlink) and replace it with an # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds CONFIG_ERROR = """ setup.cfg is missing the necessary Versioneer configuration. You need a section like: [versioneer] VCS = git style = pep440 versionfile_source = src/myproject/_version.py versionfile_build = myproject/_version.py tag_prefix = parentdir_prefix = myproject- You will also need to edit your setup.py to use the results: import versioneer setup(version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), ...) Please read the docstring in ./versioneer.py for configuration instructions, edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. """ SAMPLE_CONFIG = """ # See the docstring in versioneer.py for instructions. Note that you must # re-run 'versioneer.py setup' after changing this section, and commit the # resulting files. [versioneer] #VCS = git #style = pep440 #versionfile_source = #versionfile_build = #tag_prefix = #parentdir_prefix = """ OLD_SNIPPET = """ from ._version import get_versions __version__ = get_versions()['version'] del get_versions """ INIT_PY_SNIPPET = """ from . import {0} __version__ = {0}.get_versions()['version'] """ def do_setup() -> int: """Do main VCS-independent setup function for installing Versioneer.""" root = get_root() try: cfg = get_config_from_root(root) except (OSError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (OSError, configparser.NoSectionError)): print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) return 1 print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") maybe_ipy: Optional[str] = ipy if os.path.exists(ipy): try: with open(ipy, "r") as f: old = f.read() except OSError: old = "" module = os.path.splitext(os.path.basename(cfg.versionfile_source))[0] snippet = INIT_PY_SNIPPET.format(module) if OLD_SNIPPET in old: print(" replacing boilerplate in %s" % ipy) with open(ipy, "w") as f: f.write(old.replace(OLD_SNIPPET, snippet)) elif snippet not in old: print(" appending to %s" % ipy) with open(ipy, "a") as f: f.write(snippet) else: print(" %s unmodified" % ipy) else: print(" %s doesn't exist, ok" % ipy) maybe_ipy = None # Make VCS-specific changes. For git, this means creating/changing # .gitattributes to mark _version.py for export-subst keyword # substitution. do_vcs_install(cfg.versionfile_source, maybe_ipy) return 0 def scan_setup_py() -> int: """Validate the contents of setup.py against Versioneer's expectations.""" found = set() setters = False errors = 0 with open("setup.py", "r") as f: for line in f.readlines(): if "import versioneer" in line: found.add("import") if "versioneer.get_cmdclass()" in line: found.add("cmdclass") if "versioneer.get_version()" in line: found.add("get_version") if "versioneer.VCS" in line: setters = True if "versioneer.versionfile_source" in line: setters = True if len(found) != 3: print("") print("Your setup.py appears to be missing some important items") print("(but I might be wrong). Please make sure it has something") print("roughly like the following:") print("") print(" import versioneer") print(" setup( version=versioneer.get_version(),") print(" cmdclass=versioneer.get_cmdclass(), ...)") print("") errors += 1 if setters: print("You should remove lines like 'versioneer.VCS = ' and") print("'versioneer.versionfile_source = ' . This configuration") print("now lives in setup.cfg, and should be removed from setup.py") print("") errors += 1 return errors def setup_command() -> NoReturn: """Set up Versioneer and exit with appropriate error code.""" errors = do_setup() errors += scan_setup_py() sys.exit(1 if errors else 0) if __name__ == "__main__": cmd = sys.argv[1] if cmd == "setup": setup_command()