···11+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
22+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
33+44+name: Python package
55+66+on:
77+ push:
88+ branches: [ main ]
99+ pull_request:
1010+ branches: [ main ]
1111+1212+jobs:
1313+ build:
1414+1515+ runs-on: ubuntu-latest
1616+ strategy:
1717+ fail-fast: false
1818+ matrix:
1919+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
2020+2121+ steps:
2222+ - uses: actions/checkout@v2
2323+ - name: Set up Python ${{ matrix.python-version }}
2424+ uses: actions/setup-python@v2
2525+ with:
2626+ python-version: ${{ matrix.python-version }}
2727+ - name: Install dependencies
2828+ run: |
2929+ python -m pip install --upgrade pip
3030+ python -m pip install mypy pylint pytest cbor2==5.4.1
3131+ if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
3232+ - name: Test with pytest
3333+ run: |
3434+ pytest
3535+ - name: Lint with mypy
3636+ run: |
3737+ mypy --strict dag_cbor
3838+ - name: Lint with pylint
3939+ run: |
4040+ pylint --errors-only --rcfile=.pylintrc dag_cbor
4141+ pylint --exit-zero --rcfile=.pylintrc --disable=fixme dag_cbor
+132
vendor/git/dag-cbor/.gitignore
···11+# Byte-compiled / optimized / DLL files
22+__pycache__/
33+*.py[cod]
44+*$py.class
55+66+# C extensions
77+*.so
88+99+# Distribution / packaging
1010+.Python
1111+build/
1212+develop-eggs/
1313+dist/
1414+downloads/
1515+eggs/
1616+.eggs/
1717+lib/
1818+lib64/
1919+parts/
2020+sdist/
2121+var/
2222+wheels/
2323+pip-wheel-metadata/
2424+share/python-wheels/
2525+*.egg-info/
2626+.installed.cfg
2727+*.egg
2828+MANIFEST
2929+3030+# PyInstaller
3131+# Usually these files are written by a python script from a template
3232+# before PyInstaller builds the exe, so as to inject date/other infos into it.
3333+*.manifest
3434+*.spec
3535+3636+# Installer logs
3737+pip-log.txt
3838+pip-delete-this-directory.txt
3939+4040+# Unit test / coverage reports
4141+htmlcov/
4242+.tox/
4343+.nox/
4444+.coverage
4545+.coverage.*
4646+.cache
4747+nosetests.xml
4848+coverage.xml
4949+*.cover
5050+*.py,cover
5151+.hypothesis/
5252+.pytest_cache/
5353+5454+# Translations
5555+*.mo
5656+*.pot
5757+5858+# Django stuff:
5959+*.log
6060+local_settings.py
6161+db.sqlite3
6262+db.sqlite3-journal
6363+6464+# Flask stuff:
6565+instance/
6666+.webassets-cache
6767+6868+# Scrapy stuff:
6969+.scrapy
7070+7171+# Sphinx documentation
7272+docs/_build/
7373+7474+# PyBuilder
7575+target/
7676+7777+# Jupyter Notebook
7878+.ipynb_checkpoints
7979+8080+# IPython
8181+profile_default/
8282+ipython_config.py
8383+8484+# pyenv
8585+.python-version
8686+8787+# pipenv
8888+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
8989+# However, in case of collaboration, if having platform-specific dependencies or dependencies
9090+# having no cross-platform support, pipenv may install dependencies that don't work, or not
9191+# install all needed dependencies.
9292+#Pipfile.lock
9393+9494+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
9595+__pypackages__/
9696+9797+# Celery stuff
9898+celerybeat-schedule
9999+celerybeat.pid
100100+101101+# SageMath parsed files
102102+*.sage.py
103103+104104+# Environments
105105+.env
106106+.venv
107107+env/
108108+venv/
109109+ENV/
110110+env.bak/
111111+venv.bak/
112112+113113+# Spyder project settings
114114+.spyderproject
115115+.spyproject
116116+117117+# Rope project settings
118118+.ropeproject
119119+120120+# mkdocs documentation
121121+/site
122122+123123+# mypy
124124+.mypy_cache/
125125+.dmypy.json
126126+dmypy.json
127127+128128+# Pyre type checker
129129+.pyre/
130130+131131+# local README proof from readme_renderer
132132+README-PROOF.html
···11+# Read the Docs configuration file for Sphinx projects
22+33+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
44+55+66+# Required
77+88+version: 2
99+1010+1111+# Set the OS, Python version and other tools you might need
1212+1313+build:
1414+1515+ os: ubuntu-22.04
1616+1717+ tools:
1818+1919+ python: "3.12"
2020+2121+ # You can also specify other tool versions:
2222+2323+ # nodejs: "20"
2424+2525+ # rust: "1.70"
2626+2727+ # golang: "1.20"
2828+2929+3030+# Build documentation in the "docs/" directory with Sphinx
3131+3232+sphinx:
3333+3434+ configuration: docs/conf.py
3535+3636+ # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
3737+3838+ # builder: "dirhtml"
3939+4040+ # Fail on all warnings to avoid broken references
4141+4242+ # fail_on_warning: true
4343+4444+4545+# Optionally build your docs in additional formats such as PDF and ePub
4646+4747+# formats:
4848+4949+# - pdf
5050+5151+# - epub
5252+5353+5454+# Optional but recommended, declare the Python requirements required
5555+5656+# to build your documentation
5757+5858+# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
5959+6060+python:
6161+6262+ install:
6363+6464+ - requirements: docs/requirements.txt
···11+# Contributor Covenant Code of Conduct
22+33+## Our Pledge
44+55+We as members, contributors, and leaders pledge to make participation in our
66+community a harassment-free experience for everyone, regardless of age, body
77+size, visible or invisible disability, ethnicity, sex characteristics, gender
88+identity and expression, level of experience, education, socio-economic status,
99+nationality, personal appearance, race, religion, or sexual identity
1010+and orientation.
1111+1212+We pledge to act and interact in ways that contribute to an open, welcoming,
1313+diverse, inclusive, and healthy community.
1414+1515+## Our Standards
1616+1717+Examples of behavior that contributes to a positive environment for our
1818+community include:
1919+2020+* Demonstrating empathy and kindness toward other people
2121+* Being respectful of differing opinions, viewpoints, and experiences
2222+* Giving and gracefully accepting constructive feedback
2323+* Accepting responsibility and apologizing to those affected by our mistakes,
2424+ and learning from the experience
2525+* Focusing on what is best not just for us as individuals, but for the
2626+ overall community
2727+2828+Examples of unacceptable behavior include:
2929+3030+* The use of sexualized language or imagery, and sexual attention or
3131+ advances of any kind
3232+* Trolling, insulting or derogatory comments, and personal or political attacks
3333+* Public or private harassment
3434+* Publishing others' private information, such as a physical or email
3535+ address, without their explicit permission
3636+* Other conduct which could reasonably be considered inappropriate in a
3737+ professional setting
3838+3939+## Enforcement Responsibilities
4040+4141+Community leaders are responsible for clarifying and enforcing our standards of
4242+acceptable behavior and will take appropriate and fair corrective action in
4343+response to any behavior that they deem inappropriate, threatening, offensive,
4444+or harmful.
4545+4646+Community leaders have the right and responsibility to remove, edit, or reject
4747+comments, commits, code, wiki edits, issues, and other contributions that are
4848+not aligned to this Code of Conduct, and will communicate reasons for moderation
4949+decisions when appropriate.
5050+5151+## Scope
5252+5353+This Code of Conduct applies within all community spaces, and also applies when
5454+an individual is officially representing the community in public spaces.
5555+Examples of representing our community include using an official e-mail address,
5656+posting via an official social media account, or acting as an appointed
5757+representative at an online or offline event.
5858+5959+## Enforcement
6060+6161+Instances of abusive, harassing, or otherwise unacceptable behavior may be
6262+reported to the community leaders responsible for enforcement at
6363+community@hashberg.io.
6464+All complaints will be reviewed and investigated promptly and fairly.
6565+6666+All community leaders are obligated to respect the privacy and security of the
6767+reporter of any incident.
6868+6969+## Enforcement Guidelines
7070+7171+Community leaders will follow these Community Impact Guidelines in determining
7272+the consequences for any action they deem in violation of this Code of Conduct:
7373+7474+### 1. Correction
7575+7676+**Community Impact**: Use of inappropriate language or other behavior deemed
7777+unprofessional or unwelcome in the community.
7878+7979+**Consequence**: A private, written warning from community leaders, providing
8080+clarity around the nature of the violation and an explanation of why the
8181+behavior was inappropriate. A public apology may be requested.
8282+8383+### 2. Warning
8484+8585+**Community Impact**: A violation through a single incident or series
8686+of actions.
8787+8888+**Consequence**: A warning with consequences for continued behavior. No
8989+interaction with the people involved, including unsolicited interaction with
9090+those enforcing the Code of Conduct, for a specified period of time. This
9191+includes avoiding interactions in community spaces as well as external channels
9292+like social media. Violating these terms may lead to a temporary or
9393+permanent ban.
9494+9595+### 3. Temporary Ban
9696+9797+**Community Impact**: A serious violation of community standards, including
9898+sustained inappropriate behavior.
9999+100100+**Consequence**: A temporary ban from any sort of interaction or public
101101+communication with the community for a specified period of time. No public or
102102+private interaction with the people involved, including unsolicited interaction
103103+with those enforcing the Code of Conduct, is allowed during this period.
104104+Violating these terms may lead to a permanent ban.
105105+106106+### 4. Permanent Ban
107107+108108+**Community Impact**: Demonstrating a pattern of violation of community
109109+standards, including sustained inappropriate behavior, harassment of an
110110+individual, or aggression toward or disparagement of classes of individuals.
111111+112112+**Consequence**: A permanent ban from any sort of public interaction within
113113+the community.
114114+115115+## Attribution
116116+117117+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118118+version 2.0, available at
119119+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120120+121121+Community Impact Guidelines were inspired by [Mozilla's code of conduct
122122+enforcement ladder](https://github.com/mozilla/diversity).
123123+124124+[homepage]: https://www.contributor-covenant.org
125125+126126+For answers to common questions about this code of conduct, see the FAQ at
127127+https://www.contributor-covenant.org/faq. Translations are available at
128128+https://www.contributor-covenant.org/translations.
+88
vendor/git/dag-cbor/CONTRIBUTING.md
···11+22+# Contributing
33+44+All contributions, big and small, are very appreciated!
55+[File an issue](#file-an-issue) for bug reports, suggestions and questions, or [make a pull request](#make-a-pull-request) to actively contribute to the code or documentation.
66+77+However you decide to help, please refer to our [code of conduct](CODE_OF_CONDUCT.md) for what we expect from our community.
88+99+1010+## File an Issue
1111+1212+Issues can be filed at https://github.com/hashberg-io/dag-cbor/issues. You can file an issue to:
1313+1414+- report a bug (using the `bug` label)
1515+- suggest a new feature (using the `enhancement` label)
1616+- suggest improvements to our documentation (using the `documentation` label)
1717+- ask for information and start a discussion thread (using the `question` label)
1818+1919+If you are reporting a bug, please include the following information:
2020+2121+- project version (PyPI version number or commit number)
2222+- Python version
2323+- version of installed dependencies
2424+- how the bug manifests (e.g. what you expect to happen vs what actually happens)
2525+- how others can reproduce the bug
2626+2727+Please try to be concise in your description, providing a minimal reproducible example whenever possible.
2828+2929+If you're proposing a new feature, please describe it in detail, with a few examples of it might be implemented and of its intended usage.
3030+3131+3232+## Make a Pull Request
3333+3434+You can [make a pull request](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) to:
3535+3636+- fix a bug which is reported and discussed in an open issue
3737+- implement a new feature which is suggested and discussed in an open issue
3838+- improve our documentation in ways suggested and discussed in an open issue
3939+4040+You should [link your pull request to the issue(s)](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) that it addresses. Once your pull request passes all continuous integration checks, we will review it and either:
4141+4242+- approve the pull request and merge it
4343+- start a discussion on how to improve the pull request before it can be approved
4444+- reject the pull request, with an explanation as to why we don't consider it viable for improvement
4545+4646+4747+### Continuous Integration
4848+4949+You can perform continuous integration checks on all supported versions by running [tox](https://tox.readthedocs.io/en/latest/) in the main project folder:
5050+5151+```
5252+tox
5353+```
5454+5555+Continuous integration involves the following individual checks:
5656+5757+1. testing with [pytest](https://docs.pytest.org/):
5858+5959+```
6060+pytest test
6161+```
6262+6363+2. static type-checking with [mypy](http://mypy-lang.org/):
6464+6565+```
6666+mypy dag-cbor
6767+```
6868+6969+3. linting with [pylint](https://www.pylint.org/):
7070+7171+```
7272+pylint dag-cbor
7373+```
7474+7575+Whenever relevant, please consider contributing some additional tests pertaining to your implementation.
7676+7777+7878+### Documentation
7979+8080+The API documentation for this project is generated by [Sphinx](https://www.sphinx-doc.org/): please document any code changes and additions using [reST](https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html) docstrings. The documentation is generated by running the following commands in the [docs/](docs/) folder:
8181+8282+```
8383+docs>make api
8484+docs>make clean
8585+docs>make html
8686+```
8787+8888+The script `make-api-clean-html.bat` automates the procedure on Windows. If you edit the [readme page](README.rst), please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
+21
vendor/git/dag-cbor/LICENSE
···11+MIT License
22+33+Copyright (c) 2021 Hashberg Ltd
44+55+Permission is hereby granted, free of charge, to any person obtaining a copy
66+of this software and associated documentation files (the "Software"), to deal
77+in the Software without restriction, including without limitation the rights
88+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99+copies of the Software, and to permit persons to whom the Software is
1010+furnished to do so, subject to the following conditions:
1111+1212+The above copyright notice and this permission notice shall be included in all
1313+copies or substantial portions of the Software.
1414+1515+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121+SOFTWARE.
···11+# Security Policy
22+33+We take security of this package very seriously.
44+55+## Supported Versions
66+77+We will issue security updates for [PyPI releases](https://pypi.org/project/dag-cbor/) with the latest minor version number (regardless of micro version), by releasing a new minor version.
88+99+If you find a vulnerability which is not in any of the PyPI releases with the latest minor version, you should instead report it as a bug by [filing an issue](https://github.com/hashberg-io/dag-cbor/issues).
1010+1111+## Reporting a Vulnerability
1212+1313+To report a vulnerability, please send an email to security@hashberg.io with the following information:
1414+1515+- how we can contact you privately
1616+- how you wish to be publicly identified for the purpose of credit when we disclose the vulnerability
1717+- which package releases are affected
1818+- the Python version (including OS, if relevant) and the versions of all dependencies that you used when confirming the vulnerability
1919+- detailed description of the vulnerability, including how we can reproduce it
2020+2121+We will come back to you within 24 hours to acknowledge your report and we will provide a detailed response within 48 hours, including an initial assessment of how we intend to address the vulnerability you disclosed. If the fix requires a prolonged amount of time (> 1 week), we will send you weekly updates on our progress.
2222+2323+## Disclosure Process
2424+2525+1. Upon initial acknowledgment, we will assign a Unique ID `UID` to your security report, which we will reference in all our communications using the header `[security report #UID]`.
2626+2. Fixes are prepared and held locally in a new branch, without pushing to the public repository.
2727+3. When all fixes are ready to be pushed, an issue announcing the existence of a vulnerability is opened on GitHub: this includes package versions affected, security report UID and embargo date (typically 72 hours from the issue being opened), but no further information.
2828+4. On the embargo date, the fix branch is pushed and merged into the main branch, closing the issue, and a new minor version is released on both PyPI and GitHub. The release notes on GitHub provide a detailed description of the vulnerability, including credit to the initial discloser(s), as well as a summary of how the vulnerability was patched.
···11+r"""
22+ Utility functions used to produce messages for DAG-CBOR decoding errors.
33+"""
44+55+from __future__ import annotations # See https://peps.python.org/pep-0563/
66+77+from typing import List, Optional, Tuple
88+99+from .err import CBORDecodingError
1010+from ._stream import StreamSnapshot
1111+1212+_TRUNC_BYTES = 16
1313+1414+def _bytes2hex(bs: bytes) -> str:
1515+ r"""
1616+ Converts bytes to a hex string, showing a truncated string if the number of bytes exceeds 16.
1717+ """
1818+ if len(bs) <= _TRUNC_BYTES:
1919+ return bs.hex()
2020+ return bs[:1].hex()+"..."+bs[-1:].hex() # fixed length 7 < 2*_TRUNC_BYTES
2121+2222+def _decode_error_msg_lines(*snapshots: StreamSnapshot, details: Optional[str] = None,
2323+ start: int = 0,
2424+ end: Optional[int] = None,
2525+ pad_start: int = 0,
2626+ hl_start: int = 0,
2727+ hl_len: Optional[int] = None,
2828+ dots: bool = False,
2929+ ) -> List[str]:
3030+ r"""
3131+ This utility function takes one or more stream snapshots as input and collates the chunks of read bytes. Let ``bs`` be the bytes read across the
3232+ snapshots (which are assumed to be sequential) and ``pos`` be the position in the stream of the first byte of ``bs`` (he ``start`` and ``end`` arguments
3333+ can be used to focus on a sub-range):
3434+3535+ .. code-block:: python
3636+3737+ bs = b"".join((snapshot.latest_read for snapshot in snapshots))[start:end]
3838+ pos = snapshots[0].latest_read_start+start
3939+4040+ Th utility function returns one or two lines of error message, based on that information:
4141+4242+ 1. The first line shows (a selection of) the bytes read and the position of the first byte in the stream
4343+ 2. If ``details`` is specified, the second line highlights a selection of bytes from the first line, followed by the given details
4444+4545+ The following optional keyword arguments can be used to customise the selection of read bytes and the highlighting.
4646+4747+ - The ``pad_start`` arguments can be used to specify whitespace padding at the start of the bytes shown, to align them to bytes on other error lines.
4848+ - The ``hl_start`` and ``hl_len`` arguments can be used to specify the start byte and lenght of the range of bytes highlighted in the second line.
4949+ - The ``dots`` argument can be used to specify that three dots '...' should be added after the bytes, to indicate continuation.
5050+5151+ """
5252+ # pylint: disable = too-many-locals, too-many-arguments
5353+ assert snapshots
5454+ bs = b"".join((snapshot.latest_read for snapshot in snapshots))[start:end]
5555+ pos = snapshots[0].latest_read_start+start
5656+ bs_str = _bytes2hex(bs)
5757+ truncated = len(bs_str) != 2*len(bs)
5858+ if not bs_str:
5959+ bs_str = "<EOF>"
6060+ bs_tab = "^"*len(bs_str)
6161+ else:
6262+ if hl_len is None:
6363+ hl_len = len(bs)-hl_start
6464+ else:
6565+ assert 0 <= hl_len <= len(bs)-start
6666+ if truncated and not (hl_len == 1 and (hl_start in {0, len(bs)-1})):
6767+ bs_tab = "^"*len(bs_str)
6868+ else:
6969+ bs_tab = " "*hl_start+"^^"*hl_len
7070+ bs_str = " "*pad_start+bs_str
7171+ bs_tab = " "*pad_start+bs_tab
7272+ bytes_line = f"At byte #{pos}: {bs_str}"
7373+ if truncated:
7474+ last_byte_idx = pos+len(bs)-1
7575+ bytes_line += f" (last byte #{last_byte_idx})"
7676+ if dots:
7777+ bytes_line += "..."
7878+ lines = [bytes_line]
7979+ if details is not None:
8080+ details_line = f" {' '*len(str(pos))} {bs_tab} {details}"
8181+ lines.append(details_line)
8282+ return lines
8383+8484+def _decode_error_msg(msg: str, *snapshots: StreamSnapshot, details: Optional[str] = None,
8585+ start: int = 0,
8686+ end: Optional[int] = None,
8787+ hl_start: int = 0,
8888+ hl_len: Optional[int] = None,
8989+ dots: bool = False,
9090+ ) -> str:
9191+ r"""
9292+ Creates a detailed, multi-line error message, starting from a given ``msg`` and taking into account the information from one or more stream snapshots.
9393+ The resulting error message has ``msg`` on the first line, followed by the lines returned by :func:`_decode_error_msg_lines`.
9494+ """
9595+ # pylint: disable = too-many-arguments
9696+ lines = [msg]
9797+ if snapshots:
9898+ lines.extend(_decode_error_msg_lines(*snapshots, details=details,
9999+ start=start, end=end, hl_start=hl_start, hl_len=hl_len,
100100+ dots=dots))
101101+ return "\n".join(lines)
102102+103103+104104+def _extract_error_cause_lines(e: CBORDecodingError) -> List[str]:
105105+ r""" Extracts lines of error description from a :class:`CBORDecodingError`. """
106106+ lines = str(e).split("\n")
107107+ return [(r"\ " if idx == 0 else " ")+line for idx, line in enumerate(lines)]
108108+109109+110110+def _cid_error_template(cid_head_snapshots: Tuple[StreamSnapshot, StreamSnapshot], *explanation: str) -> str:
111111+ r""" Template for CID errors. """
112112+ lines = [
113113+ "Error while decoding CID.",
114114+ *_decode_error_msg_lines(*cid_head_snapshots, details="CID tag", dots=True),
115115+ *explanation
116116+ ]
117117+ return "\n".join(lines)
+91
vendor/git/dag-cbor/dag_cbor/decoding/_stream.py
···11+r"""
22+ Byte-streams and snapshots used in DAG-CBOR decoding, keeping track of latest and previous read byte chunks for error reporting purposes.
33+"""
44+55+from __future__ import annotations # See https://peps.python.org/pep-0563/
66+77+from io import BufferedIOBase, BytesIO
88+from typing import Optional
99+1010+class StreamSnapshot:
1111+ r""" A snapshot of the current state of a byte-stream being decoded. """
1212+1313+ _bs: bytes
1414+ _pos: int
1515+1616+ def __new__(cls, latest_read: bytes, next_read_start: int) -> "StreamSnapshot":
1717+ instance = object.__new__(cls)
1818+ instance._bs = latest_read
1919+ instance._pos = next_read_start
2020+ return instance
2121+2222+ @property
2323+ def latest_read(self) -> bytes:
2424+ r""" The latest byte chunk read from the stream. """
2525+ return self._bs
2626+2727+ @property
2828+ def latest_read_size(self) -> int:
2929+ r""" Size of the latest byte chunk read from the stream. """
3030+ return len(self._bs)
3131+3232+ @property
3333+ def latest_read_start(self) -> int:
3434+ r""" Start position in the stream for the latest byte chunk read. """
3535+ return self._pos-len(self._bs)
3636+3737+ @property
3838+ def num_bytes_read(self) -> int:
3939+ r""" Total number of bytes read so far from the stream. """
4040+ return self._pos
4141+4242+4343+class Stream:
4444+ r"""
4545+ Container for the byte-stream being decoded, offering additional book-keeping functionality used to produce detailed error messages.
4646+ """
4747+4848+ _buf: BufferedIOBase
4949+ _bs: bytes
5050+ _pos: int
5151+ _prev_bs: bytes
5252+ _prev_pos: int
5353+5454+ def __new__(cls, buffer: Optional[BufferedIOBase] = None, init_bytes_read: bytes = bytes()) -> "Stream":
5555+ if buffer is None:
5656+ buffer = BytesIO(bytes())
5757+ instance = object.__new__(cls)
5858+ instance._buf = buffer
5959+ instance._bs = init_bytes_read
6060+ instance._pos = len(init_bytes_read)
6161+ instance._prev_bs = bytes()
6262+ instance._prev_pos = 0
6363+ return instance
6464+6565+ @property
6666+ def curr_snapshot(self) -> "StreamSnapshot":
6767+ r""" A snapshot of the current state of the stream. """
6868+ return StreamSnapshot(self._bs, self._pos)
6969+7070+ @property
7171+ def prev_snapshot(self) -> "StreamSnapshot":
7272+ r""" A snapshot of the state of the stream immediately before the latest non-extending read. """
7373+ return StreamSnapshot(self._prev_bs, self._prev_pos)
7474+7575+ def read(self, num_bytes: Optional[int] = None, *, extend: bool = False) -> bytes:
7676+ r"""
7777+ Read the given number of bytes from the stream. If :obj:`None`, reads all remaining bytes.
7878+ If ``extend`` is set to :obj:`True`, the current stream snapshot (see :attr:`Stream.curr_snapshot`) is extended with the bytes just read,
7979+ and the previous stream snapshot (see :attr:`Stream.prev_snapshot`) is kept.
8080+ Otherwise, the previous snapshot is replaced with the current snaptshot, and a new current snapshot is created with the bytes just read.
8181+ """
8282+ bs = self._buf.read(num_bytes)
8383+ if extend:
8484+ self._bs += bs
8585+ self._pos += len(bs)
8686+ else:
8787+ self._prev_bs = self._bs
8888+ self._prev_pos = self._pos
8989+ self._bs = bs
9090+ self._pos += len(bs)
9191+ return bs
+15
vendor/git/dag-cbor/dag_cbor/decoding/err.py
···11+r"""
22+ Errors for the :mod:`dag_cbor.decoding` submodule.
33+"""
44+55+from ..encoding.err import CBORError, DAGCBORError
66+77+class CBORDecodingError(CBORError):
88+ """
99+ Class for decoding errors due to the CBOR specification.
1010+ """
1111+1212+class DAGCBORDecodingError(CBORDecodingError, DAGCBORError):
1313+ """
1414+ Class for decoding errors due to the DAG-CBOR specification.
1515+ """
+272
vendor/git/dag-cbor/dag_cbor/encoding/__init__.py
···11+"""
22+ Encoding functions for DAG-CBOR codec.
33+"""
44+55+from __future__ import annotations # See https://peps.python.org/pep-0563/
66+77+from io import BufferedIOBase, BytesIO
88+import math
99+import struct
1010+from typing import Any, Dict, List, Optional, overload, Union
1111+import unicodedata
1212+1313+from typing_extensions import Literal, TypedDict
1414+from typing_validation import validate
1515+1616+from multiformats import varint, multicodec, CID
1717+1818+from ..ipld import IPLDKind, IPLDObjPath
1919+from .err import CBOREncodingError, DAGCBOREncodingError
2020+2121+__all__ = ("CBOREncodingError", "DAGCBOREncodingError")
2222+2323+_dag_cbor_multicodec = multicodec.get("dag-cbor")
2424+_dag_cbor_code: int = _dag_cbor_multicodec.code
2525+_dag_cbor_code_bytes: bytes = varint.encode(_dag_cbor_code)
2626+_dag_cbor_code_nbytes: int = len(_dag_cbor_code_bytes)
2727+2828+def check_key_compliance(value: Dict[str, Any]) -> None:
2929+ """
3030+ Enforces DAG-CBOR compliance for keys in a mapping.
3131+ """
3232+ validate(value, Dict[str, Any])
3333+ _check_key_compliance(value)
3434+3535+def canonical_order_dict(value: Dict[str, Any]) -> Dict[str, Any]:
3636+ """
3737+ Returns a dictionary with canonically ordered keys, according to the DAG-CBOR specification.
3838+ Specifically, keys are sorted increasingly first by length and then by the lexicographic ordering of the corresponding UTF-8 bytestrings.
3939+ """
4040+ validate(value, Dict[str, Any])
4141+ _check_key_compliance(value)
4242+ # sort keys canonically
4343+ return _canonical_order_dict(value)
4444+4545+4646+@overload
4747+def encode(data: IPLDKind, stream: None = None, *,
4848+ include_multicodec: bool = False,
4949+ normalize_strings: Optional[Literal["NFC", "NFKC", "NFD", "NFKD"]] = None
5050+ ) -> bytes:
5151+ ... # pragma: no cover
5252+5353+@overload
5454+def encode(data: IPLDKind, stream: BufferedIOBase, *,
5555+ include_multicodec: bool = False,
5656+ normalize_strings: Optional[Literal["NFC", "NFKC", "NFD", "NFKD"]] = None
5757+ ) -> int:
5858+ ... # pragma: no cover
5959+6060+def encode(data: IPLDKind, stream: Optional[BufferedIOBase] = None, *,
6161+ include_multicodec: bool = False,
6262+ normalize_strings: Optional[Literal["NFC", "NFKC", "NFD", "NFKD"]] = None
6363+ ) -> Union[bytes, int]:
6464+ r"""
6565+ Encodes the given data with the DAG-CBOR codec.
6666+6767+ By default, the encoded data is written to an internal stream and the bytes are returned at the end (as a `bytes` object).
6868+6969+ .. code-block:: python
7070+7171+ def encode(data: IPLDKind, stream: None = None) -> bytes:
7272+ ...
7373+7474+ Example usage:
7575+7676+ >>> dag_cbor.encode({'a': 12, 'b': 'hello!'})
7777+ b'\xa2aa\x0cabfhello!'
7878+7979+ If a ``stream`` is given, the encoded data is written to the stream and the number of bytes written is returned:
8080+8181+ .. code-block:: python
8282+8383+ def encode(data: IPLDKind, stream: BufferedIOBase) -> int:
8484+ ...
8585+8686+ Example usage with a stream:
8787+8888+ >>> from io import BytesIO
8989+ >>> stream = BytesIO()
9090+ >>> dag_cbor.encode({'a': 12, 'b': 'hello!'}, stream=stream)
9191+ 13
9292+ >>> stream.getvalue()
9393+ b'\xa2aa\x0cabfhello!'
9494+9595+ :param data: the DAG data to be encoded
9696+ :param stream: an optional stream into which the encoded data should be written
9797+ :param include_multicodec: if :obj:`True`, the encoded data is prefixed by the multicodec code for ``'dag-cbor'``
9898+ (see `multicodec.wrap <https://multiformats.readthedocs.io/en/latest/api/multiformats.multicodec.html#wrap>`_).
9999+ :param normalize_strings: whether strings should be normalised prior to encoding
100100+101101+ :raises CBOREncodingError: if an :obj:`int` outside of ``range(-2**64, 2**64)`` is encountered
102102+ :raises DAGCBOREncodingError: if a value of type other than :obj:`None`, :obj:`bool`, :obj:`int`, :obj:`float`, :obj:`str`,
103103+ :obj:`bytes`, :obj:`list`, :obj:`dict`, or :class:`~multiformats.cid.CID` is encountered
104104+ :raises DAGCBOREncodingError: if attempting to encode the special :obj:`float` values ``NaN``, ``Infinity`` and ``-Infinity``
105105+ :raises DAGCBOREncodingError: if a key of a dictionary is not a string
106106+107107+ """
108108+ validate(stream, Optional[BufferedIOBase])
109109+ validate(include_multicodec, bool)
110110+ options: _EncodeOptions = {}
111111+ if normalize_strings is not None:
112112+ validate(normalize_strings, Literal["NFC", "NFKC", "NFD", "NFKD"])
113113+ options["normalize_strings"] = normalize_strings
114114+ path = IPLDObjPath()
115115+ if stream is None:
116116+ internal_stream = BytesIO()
117117+ if include_multicodec:
118118+ internal_stream.write(_dag_cbor_code_bytes)
119119+ _encode(internal_stream, data, path, options)
120120+ return internal_stream.getvalue()
121121+ num_bytes = 0
122122+ if include_multicodec:
123123+ stream.write(_dag_cbor_code_bytes)
124124+ num_bytes += _dag_cbor_code_nbytes
125125+ num_bytes += _encode(stream, data, path, options)
126126+ return num_bytes
127127+128128+class _EncodeOptions(TypedDict, total=False):
129129+ r""" Options passed around to encoding sub-routines. """
130130+131131+ normalize_strings: Literal["NFC", "NFKC", "NFD", "NFKD"]
132132+ r""" Optional Unicode normalization to be performed on UTF-8 strings prior to byte encoding. """
133133+134134+def _encode(stream: BufferedIOBase, value: IPLDKind, path: IPLDObjPath, options: _EncodeOptions) -> int:
135135+ # pylint: disable = too-many-return-statements, too-many-branches
136136+ if isinstance(value, bool): # must go before int check
137137+ # major type 0x7 (additional info 20 and 21)
138138+ return _encode_bool(stream, value, path, options)
139139+ if isinstance(value, int):
140140+ # major types 0x0 and 0x1
141141+ return _encode_int(stream, value, path, options)
142142+ if isinstance(value, bytes):
143143+ # major type 0x2
144144+ return _encode_bytes(stream, value, path, options)
145145+ if isinstance(value, str):
146146+ # major type 0x3
147147+ return _encode_str(stream, value, path, options)
148148+ if isinstance(value, list):
149149+ # major type 0x4
150150+ return _encode_list(stream, value, path, options)
151151+ if isinstance(value, dict):
152152+ # major type 0x5
153153+ return _encode_dict(stream, value, path, options)
154154+ if isinstance(value, CID):
155155+ # major type 0x6
156156+ return _encode_cid(stream, value, path, options)
157157+ if value is None:
158158+ # major type 0x7 (additional info 22)
159159+ return _encode_none(stream, value, path, options)
160160+ if isinstance(value, float):
161161+ # major type 0x7 (additional info 27)
162162+ return _encode_float(stream, value, path, options)
163163+ err = f"Error encoding value at {path}: value is not of IPLD kind (found type {type(value)})."
164164+ raise DAGCBOREncodingError(err)
165165+166166+def _encode_head(stream: BufferedIOBase, major_type: int, arg: int) -> int:
167167+ if arg < 24:
168168+ # argument value as additional info in leading byte
169169+ head = struct.pack(">B", (major_type<<5)|arg)
170170+ elif arg <= 255:
171171+ # leading byte + 1 byte argument value (additional info = 24)
172172+ head = struct.pack(">BB", (major_type<<5)|24, arg)
173173+ elif arg <= 65535:
174174+ # leading byte + 2 bytes argument value (additional info = 25)
175175+ head = struct.pack(">BH", (major_type<<5)|25, arg)
176176+ elif arg <= 4294967295:
177177+ # leading byte + 4 bytes argument value (additional info = 26)
178178+ head = struct.pack(">BL", (major_type<<5)|26, arg)
179179+ else:
180180+ # leading byte + 8 bytes argument value (additional info = 27)
181181+ head = struct.pack(">BQ", (major_type<<5)|27, arg)
182182+ stream.write(head)
183183+ return len(head)
184184+185185+def _encode_int(stream: BufferedIOBase, value: int, path: IPLDObjPath, options: _EncodeOptions) -> int:
186186+ if value >= 18446744073709551616:
187187+ # unsigned int must be < 2**64
188188+ err = f"Error encoding integer value at {path}: Unsigned integer out of range."
189189+ raise CBOREncodingError(err)
190190+ if value < -18446744073709551616:
191191+ # negative int must be >= -2**64
192192+ err = f"Error encoding integer value at {path}: Negative integer out of range."
193193+ raise CBOREncodingError(err)
194194+ if value >= 0:
195195+ # unsigned int
196196+ return _encode_head(stream, 0x0, value)
197197+ # negative int
198198+ return _encode_head(stream, 0x1, -1-value)
199199+200200+def _encode_bytes(stream: BufferedIOBase, value: bytes, path: IPLDObjPath, options: _EncodeOptions) -> int:
201201+ num_head_bytes = _encode_head(stream, 0x2, len(value))
202202+ stream.write(value)
203203+ return num_head_bytes+len(value)
204204+205205+def _encode_str(stream: BufferedIOBase, value: str, path: IPLDObjPath, options: _EncodeOptions) -> int:
206206+ if "normalize_strings" in options:
207207+ value = unicodedata.normalize(options["normalize_strings"], value)
208208+ utf8_value: bytes = value.encode("utf-8", errors="strict")
209209+ num_head_bytes = _encode_head(stream, 0x3, len(utf8_value))
210210+ stream.write(utf8_value)
211211+ return num_head_bytes+len(utf8_value)
212212+213213+def _encode_list(stream: BufferedIOBase, value: List[Any], path: IPLDObjPath, options: _EncodeOptions) -> int:
214214+ num_bytes_written = _encode_head(stream, 0x4, len(value))
215215+ for idx, item in enumerate(value):
216216+ num_bytes_written += _encode(stream, item, path/idx, options)
217217+ return num_bytes_written
218218+219219+def _encode_dict(stream: BufferedIOBase, value: Dict[str, Any], path: IPLDObjPath, options: _EncodeOptions) -> int:
220220+ _check_key_compliance(value, path)
221221+ if "normalize_strings" in options:
222222+ nf = options["normalize_strings"]
223223+ value = {unicodedata.normalize(nf, k): v for k, v in value.items()}
224224+ utf8key_val_pairs = [(k, k.encode("utf-8", errors="strict"), v)
225225+ for k, v in value.items()]
226226+ # 1. sort keys canonically:
227227+ sorted_utf8key_val_pairs = sorted(utf8key_val_pairs, key=lambda i: (len(i[1]), i[1]))
228228+ # 2. encode key-value pairs (keys already utf-8 encoded):
229229+ num_bytes_written = _encode_head(stream, 0x5, len(value))
230230+ for k, utf8k, v in sorted_utf8key_val_pairs:
231231+ num_bytes_written += _encode_head(stream, 0x3, len(utf8k))
232232+ stream.write(utf8k)
233233+ num_bytes_written += len(utf8k)
234234+ num_bytes_written += _encode(stream, v, path/k, options)
235235+ return num_bytes_written
236236+237237+def _encode_cid(stream: BufferedIOBase, value: CID, path: IPLDObjPath, options: _EncodeOptions) -> int:
238238+ num_bytes_written = _encode_head(stream, 0x6, 42)
239239+ num_bytes_written += _encode_bytes(stream, b"\0" + bytes(value), path, options)
240240+ return num_bytes_written
241241+242242+def _encode_bool(stream: BufferedIOBase, value: bool, path: IPLDObjPath, options: _EncodeOptions) -> int:
243243+ return _encode_head(stream, 0x7, 21 if value else 20)
244244+245245+def _encode_none(stream: BufferedIOBase, value: None, path: IPLDObjPath, options: _EncodeOptions) -> int:
246246+ return _encode_head(stream, 0x7, 22)
247247+248248+def _encode_float(stream: BufferedIOBase, value: float, path: IPLDObjPath, options: _EncodeOptions) -> int:
249249+ if math.isnan(value):
250250+ err = f"Error encoding float value at {path}: NaN is not allowed."
251251+ raise DAGCBOREncodingError(err)
252252+ if math.isinf(value):
253253+ s = "" if value > 0 else "-"
254254+ err = f"Error encoding float value at {path}: {s}Infinity is not allowed."
255255+ raise DAGCBOREncodingError(err)
256256+ # special head, with double encoding for 4B argument value
257257+ head = struct.pack(">Bd", (0x7<<5)|27, value)
258258+ stream.write(head)
259259+ return len(head)
260260+261261+def _check_key_compliance(value: Dict[str, Any], path: Optional[IPLDObjPath] = None) -> None:
262262+ """ Check keys for DAG-CBOR compliance. """
263263+ for idx, k in enumerate(value.keys()):
264264+ if not isinstance(k, str):
265265+ err = "" if path is None else f"Error encoding value of map kind at {path}: "
266266+ err += f"key for key-value pair at position {idx} is not a string."
267267+ raise DAGCBOREncodingError(err)
268268+269269+def _canonical_order_dict(value: Dict[str, Any]) -> Dict[str, Any]:
270270+ utf8key_key_val_pairs = [(k.encode("utf-8", errors="strict"), k, v) for k, v in value.items()]
271271+ sorted_utf8key_key_val_pairs = sorted(utf8key_key_val_pairs, key=lambda i: (len(i[0]), i[0]))
272272+ return {k: v for _, k, v in sorted_utf8key_key_val_pairs}
+23
vendor/git/dag-cbor/dag_cbor/encoding/err.py
···11+r"""
22+ Errors for the :mod:`dag_cbor.encoding` submodule.
33+"""
44+55+class CBORError(Exception):
66+ """
77+ Parent class for all errors due to the CBOR specification.
88+ """
99+1010+class DAGCBORError(CBORError):
1111+ """
1212+ Parent class for all errors due to the DAG-CBOR specification.
1313+ """
1414+1515+class CBOREncodingError(CBORError):
1616+ """
1717+ Class for encoding errors due to the CBOR specification.
1818+ """
1919+2020+class DAGCBOREncodingError(CBOREncodingError, DAGCBORError):
2121+ """
2222+ Class for encoding errors due to the DAG-CBOR specification.
2323+ """
+292
vendor/git/dag-cbor/dag_cbor/ipld.py
···11+r"""
22+ Types and functions relating to the IPLD data model `IPLD data model <https://ipld.io/docs/data-model/>`_.
33+"""
44+55+# Part of the dag-cbor library.
66+# Copyright (C) 2023 Hashberg Ltd
77+88+# This library is free software; you can redistribute it and/or
99+# modify it under the terms of the GNU Lesser General Public
1010+# License as published by the Free Software Foundation; either
1111+# version 2.1 of the License, or (at your option) any later version.
1212+1313+# This library is distributed in the hope that it will be useful,
1414+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1515+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1616+# Lesser General Public License for more details.
1717+1818+# You should have received a copy of the GNU Lesser General Public
1919+# License along with this library; if not, write to the Free Software
2020+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
2121+# USA
2222+2323+from __future__ import annotations # See https://peps.python.org/pep-0563/
2424+2525+from typing import ClassVar, Dict, Iterator, List, MutableMapping, overload, Sequence, Tuple, Union
2626+from weakref import WeakValueDictionary
2727+2828+from typing_validation import validate
2929+3030+from multiformats import CID
3131+3232+IPLDScalarKind = Union[None, bool, int, float, str, bytes, CID]
3333+r"""
3434+ Python type alias for scalar `kinds <https://ipld.io/docs/data-model/kinds/>`_ in the IPLD data model:
3535+3636+ - :obj:`None` for the `Null kind <https://ipld.io/docs/data-model/kinds/#null-kind>`_
3737+ - :obj:`bool` for the `Boolean kind <https://ipld.io/docs/data-model/kinds/#boolean-kind>`_
3838+ - :obj:`int` for the `Integer kind <https://ipld.io/docs/data-model/kinds/#integer-kind>`_
3939+ - :obj:`float` for the `Float kind <https://ipld.io/docs/data-model/kinds/#float-kind>`_
4040+ - :obj:`str` for the `String kind <https://ipld.io/docs/data-model/kinds/#string-kind>`_
4141+ - :obj:`bytes` for the `Bytes kind <https://ipld.io/docs/data-model/kinds/#bytes-kind>`_
4242+ - :class:`CID` for the `Link kind <https://ipld.io/docs/data-model/kinds/#link-kind>`_
4343+4444+"""
4545+4646+IPLDKind = Union[IPLDScalarKind, List["IPLDKind"], Dict[str, "IPLDKind"]]
4747+r"""
4848+ Python type alias for `kinds <https://ipld.io/docs/data-model/kinds/>`_ in the IPLD data model:
4949+5050+ - :obj:`None` for the `Null kind <https://ipld.io/docs/data-model/kinds/#null-kind>`_
5151+ - :obj:`bool` for the `Boolean kind <https://ipld.io/docs/data-model/kinds/#boolean-kind>`_
5252+ - :obj:`int` for the `Integer kind <https://ipld.io/docs/data-model/kinds/#integer-kind>`_
5353+ - :obj:`float` for the `Float kind <https://ipld.io/docs/data-model/kinds/#float-kind>`_
5454+ - :obj:`str` for the `String kind <https://ipld.io/docs/data-model/kinds/#string-kind>`_
5555+ - :obj:`bytes` for the `Bytes kind <https://ipld.io/docs/data-model/kinds/#bytes-kind>`_
5656+ - :class:`CID` for the `Link kind <https://ipld.io/docs/data-model/kinds/#link-kind>`_
5757+ - :obj:`List` for the `List kind <https://ipld.io/docs/data-model/kinds/#list-kind>`_
5858+ - :obj:`Dict` for the `Map kind <https://ipld.io/docs/data-model/kinds/#map-kind>`_
5959+6060+"""
6161+6262+IPLDObjPathSegment = Union[int, str]
6363+r"""
6464+ An individual segment in a :class:`IPLDObjPath` within a IPLD value (see :obj:`IPLDKind` for the ). A segment can be an :obj:`int` or a :obj:`str`:
6565+6666+ - an :obj:`int` segment is a position, indexing an item in a value of List :obj:`IPLDKind` (a :obj:`List` in Python)
6767+ - an :obj:`str` segment is a key, indexing a value in a value of Map :obj:`IPLDKind` (a :obj:`Dict` in Python)
6868+6969+"""
7070+7171+_IPLDObjPathSegments = Tuple[IPLDObjPathSegment, ...]
7272+r"""
7373+ Short type alias for multiple segments.
7474+"""
7575+7676+class IPLDObjPath(Sequence[IPLDObjPathSegment]):
7777+ r"""
7878+ Path within an object of :obj:`IPLDKind`, as a sequence of :obj:`IPLDObjPathSegment`.
7979+ Paths are immutable and hashable, and a path is a :obj:`Sequence` of the segments that constitute it.
8080+ """
8181+8282+ _instances: ClassVar[MutableMapping[_IPLDObjPathSegments, IPLDObjPath]] = WeakValueDictionary()
8383+8484+ @staticmethod
8585+ def parse(path_str: str) -> IPLDObjPath:
8686+ r"""
8787+ Parses a :class:`IPLDObjPath` from a string representation where segments are separated by `"/"`, such as that returned by
8888+ :meth:`IPLDObjPath.__repr__`.
8989+ """
9090+ if path_str.startswith("IPLDObjPath()"):
9191+ path_str = path_str[6:]
9292+ if not path_str.startswith("/"):
9393+ raise ValueError("Path must start with '/' or 'IPLDObjPath()/'.")
9494+ segs: List[IPLDObjPathSegment] = []
9595+ seg_str_list = path_str[1:].split("/")
9696+ for idx, seg_str in enumerate(seg_str_list):
9797+ if seg_str.startswith("'"):
9898+ if not seg_str.endswith("'"):
9999+ raise ValueError(f"At segment {idx}: opening single quote without closing single quote.")
100100+ segs.append(seg_str[1:-1])
101101+ elif seg_str.startswith('"'):
102102+ if not seg_str.endswith('"'):
103103+ raise ValueError(f"At segment {idx}: opening double quote without closing double quote.")
104104+ segs.append(seg_str[1:-1])
105105+ else:
106106+ if not seg_str.isnumeric():
107107+ raise ValueError(f"At segment {idx}: segment is unquoted and not numeric.")
108108+ segs.append(int(seg_str))
109109+ return IPLDObjPath._new_instance(tuple(segs))
110110+111111+ @staticmethod
112112+ def _new_instance(segments: Tuple[IPLDObjPathSegment, ...]) -> IPLDObjPath:
113113+ r"""
114114+ Returns an instance of :class:`IPLDObjPath` with given segments, without performing any validation.
115115+ """
116116+ instance = IPLDObjPath._instances.get(segments)
117117+ if instance is None:
118118+ instance = object.__new__(IPLDObjPath)
119119+ instance._segments = segments
120120+ IPLDObjPath._instances[segments] = instance
121121+ return instance
122122+123123+ _segments: _IPLDObjPathSegments
124124+125125+ def __new__(cls, *segments: IPLDObjPathSegment) -> IPLDObjPath:
126126+ r""" Constructor for :class:`IPLDObjPath`. """
127127+ validate(segments, _IPLDObjPathSegments)
128128+ return IPLDObjPath._new_instance(segments)
129129+130130+ def access(self, value: IPLDKind) -> IPLDKind:
131131+ r"""
132132+ Accesses the sub-value at this path in the given IPLD value.
133133+ Can be written more expressively as `self >> value`, see :meth:`IPLDObjPath.__rshift__`.
134134+ """
135135+ return _access(self, value)
136136+137137+ def __truediv__(self, other: Union[IPLDObjPathSegment, IPLDObjPath]) -> IPLDObjPath:
138138+ r"""
139139+ The `/` operator can be used to create paths by concatenating segments. Below we use `_` as a suggestive name for an empty path, acting as root:
140140+141141+ >>> _ = IPLDObjPath()
142142+ >>> p = _/2/'red'
143143+ >>> p
144144+ /2/'red'
145145+146146+ Concatenating an existing path with one or more segments returns a new path, extended by the given segments:
147147+148148+ >>> p/3
149149+ /2/'red'/3
150150+ >>> p/0/'blue'
151151+ /2/'red'/0/'blue'
152152+153153+ Concatenating two paths yields a new path, where the end of the first path is treated as the root for the second:
154154+155155+ >>> q = _/0/'blue'
156156+ >>> p/q
157157+ /2/'red'/0/'blue'
158158+ """
159159+ if isinstance(other, (int, str)):
160160+ return IPLDObjPath._new_instance(self._segments+(other,))
161161+ if isinstance(other, IPLDObjPath):
162162+ return IPLDObjPath._new_instance(self._segments+other._segments)
163163+ return NotImplemented
164164+165165+ def __rtruediv__(self, other: Union[IPLDObjPathSegment, IPLDObjPath]) -> IPLDObjPath:
166166+ r"""
167167+ It is possible to prepend a single segment at a time to an existing path using `/` (a new path is returned):
168168+169169+ >>> _ = IPLDObjPath()
170170+ >>> p = _/2/'red'
171171+ >>> 1/p
172172+ /1/2/'red'
173173+174174+ Prepending multiple segments requires brackets (because the `/` operator associates to the left):
175175+176176+ >>> 0/(1/p)
177177+ /0/1/2/'red'
178178+ """
179179+ if isinstance(other, (int, str)):
180180+ return IPLDObjPath._new_instance((other,)+self._segments)
181181+ return NotImplemented
182182+183183+ def __len__(self) -> int:
184184+ return len(self._segments)
185185+186186+ def __iter__(self) -> Iterator[IPLDObjPathSegment]:
187187+ return iter(self._segments)
188188+189189+ @overload
190190+ def __getitem__(self, idx: int) -> IPLDObjPathSegment:
191191+ ...
192192+193193+ @overload
194194+ def __getitem__(self, idx: slice) -> IPLDObjPath:
195195+ ...
196196+197197+ def __getitem__(self, idx: Union[int, slice]) -> Union[IPLDObjPathSegment, IPLDObjPath]:
198198+ if isinstance(idx, int):
199199+ return self._segments[idx]
200200+ return IPLDObjPath._new_instance(self._segments[idx])
201201+202202+ def __le__(self, other: IPLDObjPath) -> bool:
203203+ r"""
204204+ The `<` and `<=` operators can be used to check whether a path is a (strict) sub-path of another path, starting at the same root:
205205+206206+ >>> _ = IPLDObjPath()
207207+ >>> p = _/0/'red'
208208+ >>> q = p/1/2
209209+ >>> p == q
210210+ False
211211+ >>> p <= q
212212+ True
213213+ >>> p < q
214214+ True
215215+216216+ """
217217+ if isinstance(other, IPLDObjPath):
218218+ return len(self) <= len(other) and all(a == b for a, b in zip(self, other))
219219+ return NotImplemented
220220+221221+ def __lt__(self, other: IPLDObjPath) -> bool:
222222+ r""" See :meth:`IPLDObjPath.__le__`. """
223223+ if isinstance(other, IPLDObjPath):
224224+ return len(self) < len(other) and all(a == b for a, b in zip(self, other))
225225+ return NotImplemented
226226+227227+ def __repr__(self) -> str:
228228+ r"""
229229+ .. code-block:: python
230230+231231+ return "/"+"/".join(repr(seg) for seg in self)
232232+ """
233233+ return "/"+"/".join(repr(seg) for seg in self)
234234+235235+ def __rshift__(self, value: IPLDKind) -> IPLDKind:
236236+ r"""
237237+ Accesses the sub-value at this path in the given IPLD value:
238238+239239+ >>> _ = IPLDObjPath()
240240+ >>> _ >> [0, False, {"a": b"hello", "b": "bye"}]
241241+ [0, False, {'a': b'hello', 'b': 'bye'}]
242242+ >>> _/2 >> [0, False, {"a": b"hello", "b": "bye"}]
243243+ {'a': b'hello', 'b': 'bye'}
244244+ >>> _/2/'b' >> [0, False, {"a": b"hello", "b": "bye"}]
245245+ 'bye'
246246+247247+ :raises ValueError: if attempting to access a sub-value in a value of :obj:`IPLDScalarKind`
248248+ :raises ValueError: if attempting to access a sub-value indexed by a :obj:`str` segment in a value of list :obj:`IPLDKind` (a Python :obj:`List`)
249249+ :raises ValueError: if attempting to access a sub-value keyed by a :obj:`int` segment in a value of map :obj:`IPLDKind` (a Python :obj:`Dict`)
250250+ :raises IndexError: if attempting to access a sub-value in a value of list kind, where the :obj:`int` segment is not a valid index for the list
251251+ :raises KeyError: if attempting to access a sub-value in a value of map kind, where the :obj:`str` segment is not a valid key for the map
252252+ :raises TypeError: if any of the sub-values along the path is not of IPLD :obj:`IPLDKind` at the top level
253253+ """
254254+ return _access(self, value)
255255+256256+257257+_scalar_kinds = (type(None), bool, int, float, str, bytes, CID)
258258+_recursive_kinds = (list, dict)
259259+260260+def _access(path: IPLDObjPath, value: IPLDKind, idx: int = 0) -> IPLDKind:
261261+ r"""
262262+ Implementation for :func:`IPLDObjPath.access` and :func:`IPLDObjPath.__rshift__`.
263263+ """
264264+ if isinstance(value, _scalar_kinds):
265265+ if len(path) > idx:
266266+ err = f"Error trying to access value at {path[:idx+1]}: value at {path[:idx]} is of scalar kind."
267267+ raise ValueError(err)
268268+ return value
269269+ if isinstance(value, list):
270270+ if idx >= len(path):
271271+ return value
272272+ key = path[idx]
273273+ if not isinstance(key, int):
274274+ err = f"Error trying to access value at {path[:idx+1]}: value at {path[:idx]} is of list kind, but segment {repr(path[idx])} is not integer."
275275+ raise ValueError(err)
276276+ if key not in range(len(value)):
277277+ err = f"Error trying to access value at {path[:idx+1]}: segment {repr(path[idx])} is not a valid index for list at {path[:idx]}."
278278+ raise IndexError(err)
279279+ return _access(path, value[key], idx + 1)
280280+ if isinstance(value, dict):
281281+ if idx >= len(path):
282282+ return value
283283+ key = path[idx]
284284+ if not isinstance(key, str):
285285+ err = f"Error trying to access value at {path[:idx+1]}: value at {path[:idx]} is of map kind, but segment {repr(path[idx])} is not a string."
286286+ raise ValueError(err)
287287+ if key not in value:
288288+ err = f"Error trying to access value at {path[:idx+1]}: segment {repr(path[idx])} is not a valid key for map at {path[:idx]}."
289289+ raise KeyError(err)
290290+ return _access(path, value[key], idx + 1)
291291+ err = f"Error trying to access value at {path[:idx+1]}: value at {path[:idx]} is not of IPLD kind (found type {type(value)})."
292292+ raise TypeError(err)
vendor/git/dag-cbor/dag_cbor/py.typed
This is a binary file and will not be displayed.
+601
vendor/git/dag-cbor/dag_cbor/random.py
···11+"""
22+ Functions to generate random data.
33+"""
44+# pylint: disable = global-statement
55+66+from __future__ import annotations # See https://peps.python.org/pep-0563/
77+88+from contextlib import contextmanager
99+import math
1010+from random import Random # pylint: disable = import-self
1111+import sys
1212+from types import MappingProxyType
1313+from typing import Any, Dict, Iterator, List, Mapping, Optional, Tuple
1414+from typing_validation import validate
1515+1616+from multiformats import multicodec, multibase, multihash, CID
1717+1818+from .ipld import IPLDKind
1919+from .encoding import encode, _canonical_order_dict
2020+2121+_min_int = -18446744073709551616
2222+_max_int = 18446744073709551615
2323+_min_float = -sys.float_info.max
2424+_max_float = sys.float_info.max
2525+_min_codepoint = 0x00
2626+_max_codepoint = 0x10FFFF
2727+2828+_default_options: Dict[str, Any] = {
2929+ "min_int": -100,
3030+ "max_int": 100,
3131+ "min_bytes": 0,
3232+ "max_bytes": 8,
3333+ "min_chars": 0,
3434+ "max_chars": 8,
3535+ "min_codepoint": 0x21,
3636+ "max_codepoint": 0x7e,
3737+ "min_len": 0,
3838+ "max_len": 8,
3939+ "max_nesting": 2,
4040+ "canonical": True,
4141+ "min_float": -100.0,
4242+ "max_float": 100.0,
4343+ "float_decimals": 3,
4444+ "include_cid": True,
4545+}
4646+4747+_options = _default_options
4848+_rand = Random(0)
4949+5050+def reset_options() -> None:
5151+ """
5252+ Resets random generation options to their default values.
5353+ """
5454+ global _options
5555+ global _rand
5656+ _options = _default_options
5757+ _rand = Random(0)
5858+5959+def default_options() -> Mapping[str, Any]:
6060+ """
6161+ Readonly view of the default random generation options.
6262+ """
6363+ return MappingProxyType(_default_options)
6464+6565+def get_options() -> Mapping[str, Any]:
6666+ """
6767+ Readonly view of the current random generation options.
6868+ """
6969+ return MappingProxyType(_options)
7070+7171+@contextmanager
7272+def options(*,
7373+ seed: Optional[int] = None,
7474+ min_int: Optional[int] = None,
7575+ max_int: Optional[int] = None,
7676+ min_bytes: Optional[int] = None,
7777+ max_bytes: Optional[int] = None,
7878+ min_chars: Optional[int] = None,
7979+ max_chars: Optional[int] = None,
8080+ min_codepoint: Optional[int] = None,
8181+ max_codepoint: Optional[int] = None,
8282+ min_len: Optional[int] = None,
8383+ max_len: Optional[int] = None,
8484+ max_nesting: Optional[int] = None,
8585+ canonical: Optional[bool] = None,
8686+ min_float: Optional[float] = None,
8787+ max_float: Optional[float] = None,
8888+ float_decimals: Optional[int] = None,
8989+ include_cid: Optional[bool] = None,) -> Iterator[None]:
9090+ """
9191+ Returns with-statement context manager for temporary option setting:
9292+9393+ .. code-block:: python
9494+9595+ with options(**options):
9696+ for value in rand_data(num_samples):
9797+ ...
9898+9999+ Options available:
100100+101101+ .. code-block::
102102+103103+ seed: int # set new random number generator, with this seed
104104+ min_int: int # smallest `int` value
105105+ max_int: int # largest `int` value
106106+ min_bytes: int # min length of `bytes` value
107107+ max_bytes: int # max length of `bytes` value
108108+ min_chars: int # min length of `str` value
109109+ max_chars: int # max length of `str` value
110110+ min_codepoint: int # min utf-8 codepoint in `str` value
111111+ max_codepoint: int # max utf-8 codepoint in `str` value
112112+ min_len: int # min length of `list` and `dict` values
113113+ max_len: int # max length of `list` and `dict` values
114114+ max_nesting: int # max nesting of collections
115115+ canonical: bool # whether `dict` values have canonically ordered keys
116116+ min_float: float # smallest `float` value
117117+ max_float: float # largest `float` value
118118+ float_decimals: int # number of decimals to keep in floats
119119+ include_cid: bool # whether to generate CID values
120120+ """
121121+ # pylint: disable = too-many-locals, too-many-arguments
122122+ global _options
123123+ global _rand
124124+ _old_options = _options
125125+ _old_rand = _rand
126126+ try:
127127+ set_options(seed=seed,
128128+ min_int=min_int, max_int=max_int,
129129+ min_bytes=min_bytes, max_bytes=max_bytes,
130130+ min_chars=min_chars, max_chars=max_chars,
131131+ min_codepoint=min_codepoint, max_codepoint=max_codepoint,
132132+ min_len=min_len, max_len=max_len,
133133+ max_nesting=max_nesting, canonical=canonical,
134134+ min_float=min_float, max_float=max_float,
135135+ float_decimals=float_decimals, include_cid=include_cid)
136136+ yield
137137+ finally:
138138+ _options = _old_options
139139+ _rand = _old_rand
140140+141141+def set_options(*,
142142+ seed: Optional[int] = None,
143143+ min_int: Optional[int] = None,
144144+ max_int: Optional[int] = None,
145145+ min_bytes: Optional[int] = None,
146146+ max_bytes: Optional[int] = None,
147147+ min_chars: Optional[int] = None,
148148+ max_chars: Optional[int] = None,
149149+ min_codepoint: Optional[int] = None,
150150+ max_codepoint: Optional[int] = None,
151151+ min_len: Optional[int] = None,
152152+ max_len: Optional[int] = None,
153153+ max_nesting: Optional[int] = None,
154154+ canonical: Optional[bool] = None,
155155+ min_float: Optional[float] = None,
156156+ max_float: Optional[float] = None,
157157+ float_decimals: Optional[int] = None,
158158+ include_cid: Optional[bool] = None,) -> None:
159159+ """
160160+ Permanently sets random generation options. See :func:`options` for the available options.
161161+162162+ """
163163+ # pylint: disable = too-many-branches, too-many-locals, too-many-statements, too-many-arguments
164164+ for iarg in (seed, min_int, max_int, min_bytes, max_bytes, min_chars, max_chars,
165165+ min_codepoint, max_codepoint, min_len, max_len, max_nesting, float_decimals):
166166+ validate(iarg, Optional[int])
167167+ for barg in (canonical, include_cid):
168168+ validate(barg, Optional[bool])
169169+ for farg in (min_float, max_float):
170170+ validate(farg, Optional[float])
171171+ global _options
172172+ global _rand
173173+ # set newly passed options
174174+ _new_options: Dict[str, Any] = {}
175175+ if seed is not None:
176176+ _rand = Random(seed)
177177+ if min_int is not None:
178178+ if min_int < _min_int:
179179+ raise ValueError("Value for min_int is not a valid CBOR integer.")
180180+ _new_options["min_int"] = min_int
181181+ if max_int is not None:
182182+ if max_int > _max_int:
183183+ raise ValueError("Value for max_int is not a valid CBOR integer.")
184184+ _new_options["max_int"] = max_int
185185+ if min_bytes is not None:
186186+ if min_bytes < 0:
187187+ raise ValueError("Value for min_bytes is negative.")
188188+ _new_options["min_bytes"] = min_bytes
189189+ if max_bytes is not None:
190190+ if max_bytes < 0:
191191+ raise ValueError("Value for max_bytes is negative.")
192192+ _new_options["max_bytes"] = max_bytes
193193+ if min_chars is not None:
194194+ if min_chars < 0:
195195+ raise ValueError("Value for min_chars is negative.")
196196+ _new_options["min_chars"] = min_chars
197197+ if max_chars is not None:
198198+ if max_chars < 0:
199199+ raise ValueError("Value for max_chars is negative.")
200200+ _new_options["max_chars"] = max_chars
201201+ if min_codepoint is not None:
202202+ if min_codepoint < _min_codepoint or min_codepoint > _max_codepoint:
203203+ raise ValueError("Value for min_codepoint not a valid utf-8 codepoint.")
204204+ _new_options["min_codepoint"] = min_codepoint
205205+ if max_codepoint is not None:
206206+ if max_codepoint < _min_codepoint or max_codepoint > _max_codepoint:
207207+ raise ValueError("Value for max_codepoint not a valid utf-8 codepoint.")
208208+ _new_options["max_codepoint"] = max_codepoint
209209+ if min_len is not None:
210210+ if min_len < 0:
211211+ raise ValueError("Value for min_len is negative.")
212212+ _new_options["min_len"] = min_len
213213+ if max_len is not None:
214214+ if max_len < 0:
215215+ raise ValueError("Value for max_len is negative.")
216216+ _new_options["max_len"] = max_len
217217+ if max_nesting is not None:
218218+ if max_nesting < 0:
219219+ raise ValueError("Value for max_nesting is negative.")
220220+ _new_options["max_nesting"] = max_nesting
221221+ if canonical is not None:
222222+ _new_options["canonical"] = canonical
223223+ if min_float is not None:
224224+ if math.isnan(min_float) or math.isinf(min_float):
225225+ raise ValueError("Value for min_float is not a valid CBOR float.")
226226+ _new_options["min_float"] = min_float
227227+ if max_float is not None:
228228+ if math.isnan(max_float) or math.isinf(max_float):
229229+ raise ValueError("Value for max_float is not a valid CBOR float.")
230230+ _new_options["max_float"] = max_float
231231+ if float_decimals is not None:
232232+ if float_decimals < 0:
233233+ raise ValueError("Value for float_decimals is negative.")
234234+ _new_options["float_decimals"] = float_decimals
235235+ if include_cid is not None:
236236+ _new_options["include_cid"] = include_cid
237237+ # pass-through other options with former values
238238+ for k, v in _options.items():
239239+ if k not in _new_options:
240240+ _new_options[k] = v
241241+ # check compatibility conditions
242242+ if _new_options["min_bytes"] > _new_options["max_bytes"]:
243243+ raise ValueError("Value for min_bytes is larger than value for max_bytes.")
244244+ if _new_options["min_chars"] > _new_options["max_chars"]:
245245+ raise ValueError("Value for min_chars is larger than value for max_chars.")
246246+ if _new_options["min_codepoint"] > _new_options["max_codepoint"]:
247247+ raise ValueError("Value for min_codepoint is larger than value for max_codepoint.")
248248+ if _new_options["min_len"] > _new_options["max_len"]:
249249+ raise ValueError("Value for min_len is larger than value for max_len.")
250250+ # update options
251251+ _options = _new_options
252252+253253+254254+def rand_data(n: Optional[int] = None, *, max_nesting: Optional[int] = None) -> Iterator[IPLDKind]:
255255+ r"""
256256+ Generates a stream of random data.
257257+258258+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
259259+ :param max_nesting: the maximum nesting level for containers; if :obj:`None`, value from :func:`get_options` is used
260260+261261+ Maximum nesting level for containers:
262262+263263+ - the integer value -1 means no containers will be generated
264264+ - integer values >= 0 mean that containers will be generated, with items generated by ``random_data(max_nesting=max_nesting-1)``
265265+ - no other values are valid
266266+267267+ """
268268+ validate(n, Optional[int])
269269+ validate(max_nesting, Optional[int])
270270+ return _rand_data(n, max_nesting=max_nesting)
271271+272272+def _rand_data(n: Optional[int] = None, *, max_nesting: Optional[int] = None) -> Iterator[IPLDKind]:
273273+ if n is not None and n < 0:
274274+ raise ValueError()
275275+ if max_nesting is None:
276276+ max_nesting = _options["max_nesting"]
277277+ elif max_nesting < -1:
278278+ raise ValueError("Value for max_nesting must be >= -1 (with -1 indicating no containers).")
279279+ include_cid = _options["include_cid"]
280280+ data_generators: List[Iterator[Any]] = [
281281+ _rand_list(max_nesting=max_nesting) if max_nesting >= 0 else iter([]),
282282+ _rand_dict(max_nesting=max_nesting) if max_nesting >= 0 else iter([]),
283283+ _rand_int(),
284284+ _rand_bytes(),
285285+ _rand_str(),
286286+ _rand_bool_none(),
287287+ _rand_float(),
288288+ _rand_cid()
289289+ ]
290290+ num_data_generators = len(data_generators) if include_cid else len(data_generators)-1
291291+ i = 0
292292+ while n is None or i < n:
293293+ if max_nesting == -1:
294294+ # exclude containers
295295+ datatype = _rand.randrange(0x2, num_data_generators)
296296+ else:
297297+ # include containers
298298+ datatype = _rand.randrange(0x0, num_data_generators)
299299+ try:
300300+ yield next(data_generators[datatype])
301301+ except StopIteration as e:
302302+ raise RuntimeError("All random streams are infinite, this should not happen.") from e
303303+ i += 1
304304+305305+def rand_list(n: Optional[int] = None, *, length: Optional[int] = None, max_nesting: Optional[int] = None) -> Iterator[List[Any]]:
306306+ """
307307+ Generates a stream of random :obj:`list` data.
308308+309309+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
310310+ :param length: size for the lists; if :obj:`None`, a random value is sampled according to the :func:`options`
311311+ :param max_nesting: the maximum nesting level for containers; if :obj:`None`, value from :func:`get_options` is used
312312+ """
313313+ validate(n, Optional[int])
314314+ validate(length, Optional[int])
315315+ validate(max_nesting, Optional[int])
316316+ return _rand_list(n, length=length, max_nesting=max_nesting)
317317+318318+def _rand_list(n: Optional[int] = None, *, length: Optional[int] = None, max_nesting: Optional[int] = None) -> Iterator[List[Any]]:
319319+ if n is not None and n < 0:
320320+ raise ValueError()
321321+ if length is not None and length < 0:
322322+ raise ValueError()
323323+ if max_nesting is None:
324324+ max_nesting = _options["max_nesting"]
325325+ elif max_nesting < 0:
326326+ raise ValueError("Value for max_nesting is negative.")
327327+ min_len = _options["min_len"]
328328+ max_len = _options["max_len"]
329329+ i = 0
330330+ while n is None or i < n:
331331+ _length = length if length is not None else _rand.randint(min_len, max_len)
332332+ yield list(_rand_data(_length, max_nesting=max_nesting-1))
333333+ i += 1
334334+335335+def rand_dict(n: Optional[int] = None, *, length: Optional[int] = None, max_nesting: Optional[int] = None) -> Iterator[Dict[str, Any]]:
336336+ """
337337+ Generates a stream of random :obj:`dict` data.
338338+339339+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
340340+ :param length: size for the dicts; if :obj:`None`, a random value is sampled according to the :func:`options`
341341+ :param max_nesting: the maximum nesting level for containers; if :obj:`None`, value from :func:`get_options` is used
342342+ """
343343+ validate(n, Optional[int])
344344+ validate(length, Optional[int])
345345+ validate(max_nesting, Optional[int])
346346+ return _rand_dict(n, length=length, max_nesting=max_nesting)
347347+348348+def _rand_dict(n: Optional[int] = None, *, length: Optional[int] = None, max_nesting: Optional[int] = None) -> Iterator[Dict[str, Any]]:
349349+ # pylint: disable = too-many-locals, too-many-branches
350350+ if n is not None and n < 0:
351351+ raise ValueError()
352352+ if length is not None and length < 0:
353353+ raise ValueError()
354354+ if max_nesting is None:
355355+ max_nesting = _options["max_nesting"]
356356+ elif max_nesting < 0:
357357+ raise ValueError("Value for max_nesting is negative.")
358358+ min_len = _options["min_len"]
359359+ max_len = _options["max_len"]
360360+ canonical = _options["canonical"]
361361+ min_chars = _options["min_chars"]
362362+ max_chars = _options["max_chars"]
363363+ max_codepoint = _options["max_codepoint"]
364364+ num_codepoints = max_codepoint-_options["min_codepoint"]
365365+ i = 0
366366+ while n is None or i < n:
367367+ _length = length if length is not None else _rand.randint(min_len, max_len)
368368+ # check whether we have enough distinct strings to generate a random dictionary of desired length
369369+ if num_codepoints == 1:
370370+ num_strings = max_chars-min_chars+1
371371+ else:
372372+ num_strings = (num_codepoints**min_chars)*(num_codepoints**(max_chars-min_chars+1)-1)//(num_codepoints-1)
373373+ if num_strings < _length:
374374+ raise ValueError(f"Not enough distinct strings available to make a dictionary of length {_length}")
375375+ # generate distinct dictionary keys
376376+ if num_codepoints == 1:
377377+ key_lengths = _rand.sample(range(min_chars, max_chars+1), _length)
378378+ keys = [chr(max_codepoint)*l for l in key_lengths]
379379+ else:
380380+ keys = []
381381+ keys_set = set()
382382+ str_generator = _rand_str()
383383+ while len(keys) < _length:
384384+ try:
385385+ s = next(str_generator)
386386+ except StopIteration as e:
387387+ raise RuntimeError("Random string stream is infinite, this should not happen.") from e
388388+ if s not in keys_set:
389389+ keys.append(s)
390390+ keys_set.add(s)
391391+ # generate dictionary
392392+ raw_dict = dict(zip(keys, _rand_data(_length, max_nesting=max_nesting-1)))
393393+ if canonical:
394394+ yield _canonical_order_dict(raw_dict)
395395+ else:
396396+ yield raw_dict
397397+ i += 1
398398+399399+def rand_int(n: Optional[int] = None) -> Iterator[int]:
400400+ """
401401+ Generates a stream of random :obj:`int` data.
402402+403403+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
404404+ """
405405+ validate(n, Optional[int])
406406+ return _rand_int(n)
407407+408408+def _rand_int(n: Optional[int] = None) -> Iterator[int]:
409409+ if n is not None and n < 0:
410410+ raise ValueError()
411411+ min_int = _options["min_int"]
412412+ max_int = _options["max_int"]
413413+ i = 0
414414+ while n is None or i < n:
415415+ yield _rand.randint(min_int, max_int)
416416+ i += 1
417417+418418+def rand_bytes(n: Optional[int] = None, *, length: Optional[int] = None) -> Iterator[bytes]:
419419+ """
420420+ Generates a stream of random :obj:`bytes` data.
421421+422422+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
423423+ :param length: length of the bytestrings; if :obj:`None`, a random value is sampled according to the :func:`options`
424424+ """
425425+ validate(n, Optional[int])
426426+ validate(length, Optional[int])
427427+ return _rand_bytes(n, length=length)
428428+429429+def _rand_bytes(n: Optional[int] = None, *, length: Optional[int] = None) -> Iterator[bytes]:
430430+ if n is not None and n < 0:
431431+ raise ValueError()
432432+ if length is not None and length < 0:
433433+ raise ValueError()
434434+ min_bytes = _options["min_bytes"]
435435+ max_bytes = _options["max_bytes"]
436436+ i = 0
437437+ while n is None or i < n:
438438+ _length = length if length is not None else _rand.randint(min_bytes, max_bytes)
439439+ yield bytes([_rand.randint(0, 255) for _ in range(_length)])
440440+ i += 1
441441+442442+def rand_str(n: Optional[int] = None, *, length: Optional[int] = None) -> Iterator[str]:
443443+ """
444444+ Generates a stream of random :obj:`str` data.
445445+446446+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
447447+ :param length: length of the strings; if :obj:`None`, a random value is sampled according to the :func:`options`
448448+ """
449449+ validate(n, Optional[int])
450450+ validate(length, Optional[int])
451451+ return _rand_str(n, length=length)
452452+453453+def _rand_str(n: Optional[int] = None, *, length: Optional[int] = None) -> Iterator[str]:
454454+ if n is not None and n < 0:
455455+ raise ValueError()
456456+ if length is not None and length < 0:
457457+ raise ValueError()
458458+ min_chars = _options["min_chars"]
459459+ max_chars = _options["max_chars"]
460460+ min_codepoint = _options["min_codepoint"]
461461+ max_codepoint = _options["max_codepoint"]
462462+ i = 0
463463+ while n is None or i < n:
464464+ _length = length if length is not None else _rand.randint(min_chars, max_chars)
465465+ codepoints = [_rand.randint(min_codepoint, max_codepoint) for _ in range(_length)]
466466+ try:
467467+ string = "".join(chr(c) for c in codepoints)
468468+ string.encode("utf-8", errors="strict")
469469+ yield string
470470+ i += 1
471471+ except UnicodeError:
472472+ continue
473473+474474+def rand_bool(n: Optional[int] = None) -> Iterator[bool]:
475475+ """
476476+ Generates a stream of random :obj:`bool` data.
477477+478478+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
479479+ """
480480+ validate(n, Optional[int])
481481+ return _rand_bool(n)
482482+483483+def _rand_bool(n: Optional[int] = None) -> Iterator[bool]:
484484+ if n is not None and n < 0:
485485+ raise ValueError()
486486+ i = 0
487487+ while n is None or i < n:
488488+ x = _rand.randint(0, 1)
489489+ yield x == 1
490490+ i += 1
491491+492492+def rand_bool_none(n: Optional[int] = None) -> Iterator[Optional[bool]]:
493493+ """
494494+ Generates a stream of random :obj:`bool` or :obj:`None` data.
495495+496496+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
497497+ """
498498+ validate(n, Optional[int])
499499+ return _rand_bool_none(n)
500500+501501+def _rand_bool_none(n: Optional[int] = None) -> Iterator[Optional[bool]]:
502502+ if n is not None and n < 0:
503503+ raise ValueError()
504504+ i = 0
505505+ while n is None or i < n:
506506+ x = _rand.randint(0, 2)
507507+ yield None if x == 2 else x == 1
508508+ i += 1
509509+510510+def rand_float(n: Optional[int] = None) -> Iterator[float]:
511511+ """
512512+ Generates a stream of random :obj:`float` data.
513513+514514+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
515515+ """
516516+ validate(n, Optional[int])
517517+ return _rand_float(n)
518518+519519+def _rand_float(n: Optional[int] = None) -> Iterator[float]:
520520+ if n is not None and n < 0:
521521+ raise ValueError()
522522+ min_float = _options["min_float"]
523523+ max_float = _options["max_float"]
524524+ float_decimals = _options["float_decimals"]
525525+ eps = 10.0**-float_decimals
526526+ if min_float >= 0 or max_float <= 0:
527527+ # no overflow in `min_float + (max_float-min_float) * random()`, can use `Random.uniform`
528528+ i = 0
529529+ while n is None or i < n:
530530+ x = _rand.uniform(min_float, max_float)
531531+ yield x-x%eps
532532+ i += 1
533533+ else:
534534+ # overflow in `min_float + (max_float-min_float) * random()`, cannot use `Random.uniform`
535535+ i = 0
536536+ while n is None or i < n:
537537+ x = 1/(1+max_float/(-min_float))
538538+ # x is (-min_float)/(max_float-min_float), the probability of sampling a number in (-min_float, 0)
539539+ if _rand.random() < x:
540540+ x = _rand.random()*min_float
541541+ else:
542542+ x = _rand.random()*max_float
543543+ yield x-x%eps
544544+ i += 1
545545+546546+_cid_multibase = multibase.get("base58btc") # the default base for binary CIDs
547547+_cid_version = 1
548548+_cid_multicodec = multicodec.get("dag-cbor")
549549+_cid_multihash = multihash.get("sha3-512")
550550+551551+def rand_data_cid(n: Optional[int] = None, *, max_nesting: Optional[int] = None) -> Iterator[Tuple[IPLDKind, CID]]:
552552+ r"""
553553+ Generates a stream of random DAG-CBOR data and associated CIDs:
554554+555555+ - multibase 'base32'
556556+ - CIDv1
557557+ - multicodec 'dag-cbor'
558558+ - multihash 'sha3-512', with full 512-bit digest
559559+560560+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
561561+ :param max_nesting: the maximum nesting level for containers; if :obj:`None`, value from :func:`get_options` is used
562562+563563+ """
564564+ validate(n, Optional[int])
565565+ return _rand_data_cid(n, max_nesting=max_nesting)
566566+567567+def rand_cid(n: Optional[int] = None, *, max_nesting: Optional[int] = None) -> Iterator[CID]:
568568+ """
569569+ Generates a stream of random CIDs:
570570+571571+ - multibase 'base32'
572572+ - CIDv1
573573+ - multicodec 'dag-cbor'
574574+ - multihash 'sha3-512', with full 512-bit digest
575575+576576+ :param n: the number of samples to be yielded; if :obj:`None`, an infinite stream is yielded
577577+ :param max_nesting: the maximum nesting level for containers; if :obj:`None`, value from :func:`get_options` is used
578578+ """
579579+ validate(n, Optional[int])
580580+ return _rand_cid(n, max_nesting=max_nesting)
581581+582582+def _rand_cid(n: Optional[int] = None, *, max_nesting: Optional[int] = None) -> Iterator[CID]:
583583+ return (cid for _, cid in _rand_data_cid(n, max_nesting=max_nesting))
584584+585585+def _rand_data_cid(n: Optional[int] = None, *, max_nesting: Optional[int] = None) -> Iterator[Tuple[IPLDKind, CID]]:
586586+ if n is not None and n < 0:
587587+ raise ValueError()
588588+ if max_nesting is None:
589589+ max_nesting = _options["max_nesting"]
590590+ elif max_nesting < 0:
591591+ raise ValueError("Value for max_nesting is negative.")
592592+ i = 0
593593+ rand_data_generator = _rand_data(max_nesting=max_nesting-1)
594594+ while n is None or i < n:
595595+ try:
596596+ dag_cbor_data = next(rand_data_generator)
597597+ binary_data = encode(dag_cbor_data)
598598+ except StopIteration as e:
599599+ raise RuntimeError("Random digest stream is infinite, this should not happen.") from e
600600+ yield (dag_cbor_data, CID(_cid_multibase, _cid_version, _cid_multicodec, _cid_multihash.digest(binary_data)))
601601+ i += 1
+23
vendor/git/dag-cbor/docs/Makefile
···11+# Minimal makefile for Sphinx documentation
22+#
33+44+# You can set these variables from the command line, and also
55+# from the environment for the first two.
66+SPHINXOPTS ?=
77+SPHINXBUILD ?= sphinx-build
88+SOURCEDIR = .
99+BUILDDIR = _build
1010+1111+# Put it first so that "make" without argument is like "make help".
1212+help:
1313+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1414+1515+.PHONY: help Makefile
1616+1717+api:
1818+ python make-api.py
1919+2020+# Catch-all target: route all unknown targets to Sphinx using the new
2121+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
2222+%: Makefile
2323+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
···11+# pylint: disable = all
22+# Configuration file for the Sphinx documentation builder.
33+#
44+# This file only contains a selection of the most common options. For a full
55+# list see the documentation:
66+# https://www.sphinx-doc.org/en/master/usage/configuration.html
77+88+# -- Path setup --------------------------------------------------------------
99+1010+# If extensions (or modules to document with autodoc) are in another directory,
1111+# add these directories to sys.path here. If the directory is relative to the
1212+# documentation root, use os.path.abspath to make it absolute, like shown here.
1313+#
1414+1515+from __future__ import annotations
1616+1717+import inspect
1818+import json
1919+import os
2020+import sys
2121+sys.path.insert(0, os.path.abspath('..'))
2222+import sphinx_rtd_theme # type: ignore
2323+2424+2525+# -- Project information -----------------------------------------------------
2626+2727+project = 'dag-cbor'
2828+copyright = '2023, Hashberg'
2929+author = 'Hashberg'
3030+3131+3232+# The version info for the project you"re documenting, acts as replacement for
3333+# |version| and |release|, also used in various other places throughout the
3434+# built documents.
3535+#
3636+# The full version, including alpha/beta/rc tags.
3737+release = "0.3.0"
3838+# The short X.Y version.
3939+version = "0.3.0"
4040+4141+4242+# -- General configuration ---------------------------------------------------
4343+4444+# Add any Sphinx extension module names here, as strings. They can be
4545+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
4646+# ones.
4747+extensions = [
4848+ 'sphinx.ext.autodoc',
4949+ 'sphinx.ext.mathjax',
5050+ 'sphinx.ext.intersphinx',
5151+ 'sphinx_rtd_theme',
5252+ 'sphinx.ext.viewcode',
5353+ 'autodoc_typehints',
5454+]
5555+5656+nitpicky = True # warn about every broken reference
5757+add_function_parentheses = False # no parentheses after function names
5858+add_module_names = False # no module names at start of classes
5959+set_type_checking_flag = False # setting to True creates issues when dealing with circular dependencies introduced for static typechecking
6060+autodoc_typehints = "none" # don't document type hints, extension 'autodoc_typehints' will take care of it
6161+6262+with open("autodoc-type-aliases.json", "r") as f:
6363+ autodoc_type_aliases = json.load(f) # load type aliases generated by make-api.py
6464+6565+intersphinx_cache_limit = -1
6666+intersphinx_timeout = 20
6767+intersphinx_mapping = {
6868+ 'python': ('https://docs.python.org/3', None),
6969+ 'multiformats': ('http://multiformats.readthedocs.io/en/latest', None)
7070+}
7171+7272+# Add any paths that contain templates here, relative to this directory.
7373+templates_path = ['_templates']
7474+7575+# List of patterns, relative to source directory, that match files and
7676+# directories to ignore when looking for source files.
7777+# This pattern also affects html_static_path and html_extra_path.
7878+exclude_patterns = [
7979+ "test"
8080+]
8181+8282+# The name of the Pygments (syntax highlighting) style to use.
8383+pygments_style = 'sphinx'
8484+8585+# -- Options for HTML output -------------------------------------------------
8686+8787+# The theme to use for HTML and HTML Help pages. See the documentation for
8888+# a list of builtin themes.
8989+#
9090+html_theme = 'sphinx_rtd_theme'
9191+9292+# Add any paths that contain custom static files (such as style sheets) here,
9393+# relative to this directory. They are copied after the builtin static files,
9494+# so a file named "default.css" will overwrite the builtin "default.css".
9595+# html_static_path = ['_static']
+17
vendor/git/dag-cbor/docs/decoding.rst
···11+Decoding
22+========
33+44+The core decoding functionality is performed by the :func:`~dag_cbor.decoding.decode` function, which decodes :obj:`bytes` into a value:
55+66+>>> import dag_cbor
77+>>> dag_cbor.decode(b'\xa2aa\x0cabfhello!')
88+{'a': 12, 'b': 'hello!'}
99+1010+A buffered binary stream (i.e. an instance of :obj:`~io.BufferedIOBase`) can be passed to the :func:`~dag_cbor.decoding.decode` function instead of a :obj:`bytes` object, in which case the contents of the stream are read in their entirety and decoded:
1111+1212+>>> stream = BytesIO(b'\xa2aa\x0cabfhello!')
1313+>>> dag_cbor.decode(stream)
1414+{'a': 12, 'b': 'hello!'}
1515+1616+The decision to read the entirety of the stream stems from the `DAG-CBOR codec <https://ipld.io/specs/codecs/dag-cbor/spec/>`_ specification, stating that encoding and decoding is only allowed on a single top-level item.
1717+However, the optional keyword argument ``allow_concat`` (default :obj:`False`) can be set to :obj:`True` to disable this behaviour and allow only part of the stream to be decoded.
+18
vendor/git/dag-cbor/docs/encoding.rst
···11+22+Encoding
33+========
44+55+The core encoding functionality is performed by the :func:`~dag_cbor.encoding.encode` function, which encods a value into a :obj:`bytes` object:
66+77+>>> import dag_cbor
88+>>> dag_cbor.encode({'a': 12, 'b': 'hello!'})
99+b'\xa2aa\x0cabfhello!'
1010+1111+A buffered binary stream (i.e. an instance of :obj:`~io.BufferedIOBase`) can be passed to the :func:`~dag_cbor.encoding.encode` function using the optional keyword argument ``stream``, in which case the encoded bytes are written to the stream and the number of bytes written is returned:
1212+1313+>>> from io import BytesIO
1414+>>> stream = BytesIO()
1515+>>> dag_cbor.encode({'a': 12, 'b': 'hello!'}, stream=stream)
1616+13
1717+>>> stream.getvalue()
1818+b'\xa2aa\x0cabfhello!'
+67
vendor/git/dag-cbor/docs/getting-started.rst
···11+Getting Started
22+===============
33+44+This is a fully compliant Python implementation of the `DAG-CBOR codec <https://ipld.io/specs/codecs/dag-cbor/spec/>`_, a subset of the `Concise Binary Object Representation (CBOR) <https://cbor.io/>`_ supporting the `IPLD Data Model <https://ipld.io/docs/data-model/>`_ and enforcing a unique (strict) encoded representation of items.
55+66+77+Installation
88+------------
99+1010+You can install the latest release from `PyPI <https://pypi.org/project/dag-cbor/>`_ as follows:
1111+1212+.. code-block:: console
1313+1414+ $ pip install --upgrade dag-cbor
1515+1616+GitHub repo: https://github.com/hashberg-io/dag-cbor
1717+1818+1919+Basic Usage
2020+-----------
2121+2222+The core functionality of the library is performed by the :func:`~dag_cbor.encoding.encode` and :func:`~dag_cbor.decoding.decode` functions:
2323+2424+>>> import dag_cbor
2525+>>> dag_cbor.encode({'a': 12, 'b': 'hello!'})
2626+b'\xa2aa\x0cabfhello!'
2727+>>> dag_cbor.decode(b'\xa2aa\x0cabfhello!')
2828+{'a': 12, 'b': 'hello!'}
2929+3030+The :mod:`~dag_cbor.ipld` module contains utility types and functions pertaining to the `IPLD Data Model <https://ipld.io/docs/data-model/>`_.
3131+The :mod:`~dag_cbor.random` module contains functions to generate random data compatible with DAG-CBOR encoding.
3232+3333+3434+The DAG-CBOR codec
3535+------------------
3636+3737+The `DAG-CBOR codec <https://ipld.io/specs/codecs/dag-cbor/spec/>`_ is a restriction of the `CBOR codec <https://cbor.io/>`_, enforcing additional conventions:
3838+3939+- The only tag (major type 6) allowed is the CID tag 42, to be encoded as a two bytes head ``0xd82a``
4040+ (``0xd8`` is ``0b110_11000``, which means "major type 6 (``0b110``, i.e. 6) with 1 byte of argument (``0b11000``, i.e. 24)",
4141+ while `0x2a` is the number 42).
4242+- Integers (major types 0 and 1) must be encoded using the minimum possible number of bytes.
4343+- Lengths for major types 2, 3, 4 and 5 must be encoded in the data item head using the minimum possible number of bytes.
4444+- Map keys must be strings (major type 3) and must be unique.
4545+- Map keys must be sorted ascendingly, first by increasing length and then by lexicographic ordering of their utf-8 encoded bytes (cf. `strictness <https://ipld.io/specs/codecs/dag-cbor/spec/#strictness>`_).
4646+- Indefinite-length items (bytes, strings, lists or maps) are not allowed.
4747+- The "break" token is not allowed.
4848+- The only major type 7 items allowed are 64-bit floats (minor 27) and the simple values `true` (minor 20),
4949+ `false` (minor 21) and `null` (minor 22).
5050+- The special float values ``NaN``, ``Infinity`` and ``-Infinity`` are not allowed.
5151+- Encoding and decoding is only allowed on a single top-level item: back-to-back concatenated items at the top level
5252+ are not allowed.
5353+5454+Because the CBOR codec can encode/decode all data handled by the DAG-CBOR codec, we use an established CBOR implementation as the reference when testing, namely the `cbor2 <https://github.com/agronholm/cbor2>`_ package (with the exception of CID data, which is not natively handled by cbor2).
5555+5656+5757+Multiformats Config
5858+-------------------
5959+6060+Please note that :mod:`dag_cbor` internally imports `multiformats <https://github.com/hashberg-io/multiformats>`_: if you'd like to initialise multiformats
6161+with a custom selection of multicodecs/multihashes, you should call ``multiformats_config.enable()`` **before** you import :mod:`dag_cbor` (see the `multiformats docs <https://multiformats.readthedocs.io/en/latest/getting-started.html>`_ for further details):
6262+6363+.. code-block:: python
6464+6565+ import multiformats_config
6666+ multiformats_config.enable(codecs=["sha1", 0x29], bases=["base64url", "9"])
6767+ import dag_cbor # internally imports multiformats
+27
vendor/git/dag-cbor/docs/index.rst
···11+22+dag-cbor: A Python implementation of the DAG-CBOR codec
33+=======================================================
44+55+This is a fully compliant Python implementation of the `DAG-CBOR codec <https://ipld.io/specs/codecs/dag-cbor/spec/>`_, a subset of the `Concise Binary Object Representation (CBOR) <https://cbor.io/>`_ supporting the `IPLD Data Model <https://ipld.io/docs/data-model/>`_ and enforcing a unique (strict) encoded representation of items.
66+77+GitHub repo: https://github.com/hashberg-io/dag-cbor
88+99+1010+.. toctree::
1111+ :maxdepth: 3
1212+ :caption: Contents
1313+1414+ getting-started
1515+ encoding
1616+ decoding
1717+ random
1818+1919+.. include:: api-toc.rst
2020+2121+2222+Indices and tables
2323+==================
2424+2525+* :ref:`genindex`
2626+* :ref:`modindex`
2727+* :ref:`search`
+4
vendor/git/dag-cbor/docs/make-api-clean-html.bat
···11+call make api
22+call make clean
33+call make html
44+@pause
···11+"""
22+ A script to generate .rst files for API documentation.
33+"""
44+55+import glob
66+import importlib
77+import inspect
88+import json
99+import os
1010+import pkgutil
1111+from typing import Dict, List, Optional, Tuple
1212+import sys
1313+1414+from typing_validation import validate
1515+1616+def _list_package_contents(pkg_name: str) -> List[str]:
1717+ modules = [pkg_name]
1818+ for submod in pkgutil.iter_modules([pkg_name.replace(".", "/")]):
1919+ submod_fullname = pkg_name+"."+submod.name
2020+ if submod.ispkg:
2121+ for subsubmod_name in _list_package_contents(submod_fullname):
2222+ modules.append(subsubmod_name)
2323+ else:
2424+ modules.append(submod_fullname)
2525+ return modules
2626+2727+def make_apidocs() -> None:
2828+ """
2929+ A script to generate .rst files for API documentation.
3030+ """
3131+ err_msg = """Expected a 'make-api.json' file, with the following structure:
3232+{
3333+ "pkg_name": str,
3434+ "apidocs_folder": str,
3535+ "pkg_path": str,
3636+ "toc_filename": str,
3737+ "type_alias_dict_filename": Optional[str],
3838+ "include_members": Dict[str, List[str]],
3939+ "type_aliases": Dict[str, List[str]],
4040+ "exclude_members": Dict[str, List[str]],
4141+ "exclude_modules": List[str],
4242+ "member_fullnames": Dict[str, Dict[str, str]],
4343+ "special_class_members": Dict[str, List[str]],
4444+}
4545+4646+Set "toc_filename" to null to avoid generating a table of contents file.
4747+4848+"""
4949+ try:
5050+ with open("make-api.json", "r") as f:
5151+ config = json.load(f)
5252+ pkg_name = config.get("pkg_name", None)
5353+ validate(pkg_name, str)
5454+ pkg_path = config.get("pkg_path", None)
5555+ validate(pkg_path, str)
5656+ apidocs_folder = config.get("apidocs_folder", None)
5757+ validate(apidocs_folder, str)
5858+ toc_filename = config.get("toc_filename", None)
5959+ validate(toc_filename, str)
6060+ type_alias_dict_filename = config.get("type_alias_dict_filename", None)
6161+ validate(type_alias_dict_filename, Optional[str])
6262+ include_members = config.get("include_members", {})
6363+ validate(include_members, Dict[str, List[str]])
6464+ type_aliases = config.get("type_aliases", {})
6565+ validate(type_aliases, Dict[str, List[str]])
6666+ exclude_members = config.get("exclude_members", {})
6767+ validate(exclude_members, Dict[str, List[str]])
6868+ include_modules = config.get("include_modules", [])
6969+ validate(include_modules, List[str])
7070+ exclude_modules = config.get("exclude_modules", [])
7171+ validate(exclude_modules, List[str])
7272+ member_fullnames = config.get("member_fullnames", {})
7373+ validate(member_fullnames, Dict[str, Dict[str, str]])
7474+ special_class_members = config.get("special_class_members", {})
7575+ validate(special_class_members, Dict[str, List[str]])
7676+ except FileNotFoundError:
7777+ print(err_msg)
7878+ sys.exit(1)
7979+ except TypeError:
8080+ print(err_msg)
8181+ sys.exit(1)
8282+ for mod_name, type_alias_members in type_aliases.items():
8383+ if mod_name not in include_members:
8484+ include_members[mod_name] = []
8585+ include_members[mod_name].extend(type_alias_members)
8686+8787+ cwd = os.getcwd()
8888+ os.chdir(pkg_path)
8989+ sys.path = [os.getcwd()]+sys.path
9090+ modules = _list_package_contents(pkg_name)
9191+ modules_dict = {
9292+ mod_name: importlib.import_module(mod_name)
9393+ for mod_name in modules
9494+ }
9595+ for mod_name in include_modules:
9696+ if mod_name not in modules_dict:
9797+ modules_dict[mod_name] = importlib.import_module(mod_name)
9898+ os.chdir(cwd)
9999+100100+ print(f"Removing all docfiles from {apidocs_folder}/")
101101+ for apidoc_file in glob.glob(f"{apidocs_folder}/*.rst"):
102102+ print(f" {apidoc_file}")
103103+ os.remove(apidoc_file)
104104+ print()
105105+106106+ type_alias_fullnames: dict[str, str] = {}
107107+108108+ print("Pre-processing type aliases:")
109109+ for mod_name, mod_type_aliases in type_aliases.items():
110110+ if mod_name in exclude_modules:
111111+ continue
112112+ for member_name in mod_type_aliases:
113113+ member_fullname = f"{mod_name}.{member_name}"
114114+ if member_name in type_alias_fullnames:
115115+ print(f" WARNING! Skipping type alias {member_name} -> {member_fullname}")
116116+ print(f" Existing type alias {member_name} -> {type_alias_fullnames[member_name]}")
117117+ else:
118118+ type_alias_fullnames[member_name] = member_fullname
119119+ print(f" {member_name} -> {member_fullname}")
120120+ print()
121121+122122+ for mod_name, mod in modules_dict.items():
123123+ if mod_name in exclude_modules:
124124+ continue
125125+ filename = f"{apidocs_folder}/{mod_name}.rst"
126126+ print(f"Writing API docfile {filename}")
127127+ lines: List[str] = [
128128+ mod_name,
129129+ "="*len(mod_name),
130130+ "",
131131+ f".. automodule:: {mod_name}",
132132+ ""
133133+ ]
134134+ mod__all__ = getattr(mod, "__all__", [])
135135+ reexported_members: List[Tuple[str, str]] = []
136136+ for member_name in sorted(name for name in dir(mod)):
137137+ to_include = mod_name in include_members and member_name in include_members[mod_name]
138138+ to_exclude = mod_name in exclude_members and member_name in exclude_members[mod_name]
139139+ if to_exclude:
140140+ continue
141141+ if member_name.startswith("_") and not to_include:
142142+ continue
143143+ member = getattr(mod, member_name)
144144+ member_module = inspect.getmodule(member)
145145+ member_module_name = member_module.__name__ if member_module is not None else None
146146+ imported_member = member_module is not None and member_module != mod
147147+ if mod_name in include_members and member_name in include_members[mod_name]:
148148+ imported_member = False
149149+ if member_name in type_alias_fullnames:
150150+ member_fullname = type_alias_fullnames[member_name]
151151+ elif mod_name in member_fullnames and member_name in member_fullnames[mod_name]:
152152+ member_fullname = member_fullnames[mod_name][member_name]
153153+ elif imported_member:
154154+ if inspect.ismodule(member):
155155+ member_fullname = member_module_name or ""
156156+ else:
157157+ member_fullname = f"{member_module_name}.{member_name}"
158158+ else:
159159+ member_fullname = f"{mod_name}.{member_name}"
160160+ member_kind = "data"
161161+ if inspect.isclass(member):
162162+ member_kind = "class"
163163+ elif inspect.isfunction(member):
164164+ member_kind = "function"
165165+ elif inspect.ismodule(member):
166166+ member_kind = "module"
167167+ if not imported_member:
168168+ member_lines: List[str] = []
169169+ member_lines = [
170170+ member_name,
171171+ "-"*len(member_name),
172172+ "",
173173+ f".. auto{member_kind}:: {member_fullname}",
174174+ ]
175175+ if member_kind == "class":
176176+ member_lines.append(" :show-inheritance:")
177177+ member_lines.append(" :members:")
178178+ if member_fullname in special_class_members and special_class_members[member_fullname]:
179179+ member_lines.append(f" :special-members: {', '.join(special_class_members[member_fullname])}")
180180+ member_lines.append("")
181181+ if member_name in type_alias_fullnames:
182182+ print(f" {member_kind} {member_name} -> {type_alias_fullnames[member_name]} (type alias)")
183183+ else:
184184+ print(f" {member_kind} {member_name}")
185185+ lines.extend(member_lines)
186186+ elif member_name in mod__all__:
187187+ reexported_members.append((member_fullname, member_kind))
188188+ if reexported_members:
189189+ reexported_members_header = f"{mod_name}.__all__"
190190+ print(f" {reexported_members_header}:")
191191+ lines.extend([
192192+ reexported_members_header,
193193+ "-"*len(reexported_members_header),
194194+ "",
195195+ "The following members were explicitly reexported using ``__all__``:",
196196+ "",
197197+ ])
198198+ refkinds = {
199199+ "data": "obj",
200200+ "function": "func",
201201+ "class": "class",
202202+ "module": "mod"
203203+ }
204204+ for member_fullname, member_kind in reexported_members:
205205+ refkind = f":py:{refkinds[member_kind]}:"
206206+ lines.append(f" - {refkind}`{member_fullname}`")
207207+ print(f" {member_kind} {member_fullname}")
208208+ lines.append("")
209209+ with open(filename, "w") as f:
210210+ f.write("\n".join(lines))
211211+ print("")
212212+213213+ toctable_lines = [
214214+ ".. toctree::",
215215+ " :maxdepth: 2",
216216+ " :caption: API Documentation",
217217+ ""
218218+ ]
219219+ print(f"Writing TOC for API docfiles at {toc_filename}")
220220+ for mod_name in modules_dict:
221221+ if mod_name in exclude_modules:
222222+ continue
223223+ line = f" {apidocs_folder}/{mod_name}"
224224+ toctable_lines.append(line)
225225+ print(line)
226226+ toctable_lines.append("")
227227+ print()
228228+229229+ with open(toc_filename, "w") as f:
230230+ f.write("\n".join(toctable_lines))
231231+232232+ if type_alias_dict_filename is not None:
233233+ print(f"Writing type alias dictionary: {type_alias_dict_filename}")
234234+ for name, fullname in type_alias_fullnames.items():
235235+ print(f" {name} -> {fullname}")
236236+ print()
237237+ with open(type_alias_dict_filename, "w") as f:
238238+ json.dump(type_alias_fullnames, f, indent=4)
239239+240240+if __name__ == "__main__":
241241+ make_apidocs()
+39
vendor/git/dag-cbor/docs/make.bat
···11+@ECHO OFF
22+33+pushd %~dp0
44+55+REM Command file for Sphinx documentation
66+77+if "%SPHINXBUILD%" == "" (
88+ set SPHINXBUILD=sphinx-build
99+)
1010+set SOURCEDIR=.
1111+set BUILDDIR=_build
1212+1313+if "%1" == "" goto help
1414+if "%1" == "api" goto api
1515+1616+%SPHINXBUILD% >NUL 2>NUL
1717+if errorlevel 9009 (
1818+ echo.
1919+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
2020+ echo.installed, then set the SPHINXBUILD environment variable to point
2121+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
2222+ echo.may add the Sphinx directory to PATH.
2323+ echo.
2424+ echo.If you don't have Sphinx installed, grab it from
2525+ echo.https://www.sphinx-doc.org/
2626+ exit /b 1
2727+)
2828+2929+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
3030+goto end
3131+3232+:help
3333+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
3434+3535+:api
3636+python make-api.py
3737+3838+:end
3939+popd
+84
vendor/git/dag-cbor/docs/random.rst
···11+Random DAG-CBOR Data
22+====================
33+44+The module :mod:`~dag_cbor.random` contains a set of functions to generate random DAG-CBOR data.
55+The functions are named ``rand_X``, where ``X`` is one of:
66+77+- :obj:`int` for uniformly distributed integers
88+- :obj:`float` for uniformly distributed floats, with fixed decimals
99+- :obj:`bytes` for byte-strings of uniformly distributed length, with uniformly distributed bytes
1010+- :obj:`str` for strings of uniformly distributed length, with uniformly distributed codepoints (all valid UTF-8 strings, by rejection sampling)
1111+- :obj:`bool` for :obj:`False` or :obj:`True` (50% each)
1212+- ``bool_none`` for :obj:`False`, :obj:`True` or :obj:`None` (33.3% each)
1313+- :obj:`list` for lists of uniformly distributed length, with random elements of any type
1414+- :obj:`dict` for dictionaries of uniformly distributed length, with distinct random string keys and random values of any type
1515+- `cid` for CID data (instance of :obj:`~multiformats.cid.CID` from the `multiformats <https://github.com/hashberg-io/multiformats>`_ library)
1616+1717+1818+Generating random values
1919+------------------------
2020+2121+The function call ``rand_X(n)`` returns an iterator yielding a stream of ``n`` random values of type ``X``, e.g.:
2222+2323+>>> import pprint
2424+>>> import dag_cbor
2525+>>> kwargs = dict(min_codepoint=0x41, max_codepoint=0x5a, include_cid=False)
2626+>>> with dag_cbor.random.options(**kwargs):
2727+... for d in dag_cbor.random.rand_dict(3):
2828+... pprint.pp(d)
2929+...
3030+{'BIQPMZ': b'\x85\x1f\x07/\xcc\x00\xfc\xaa',
3131+ 'EJEYDTZI': {},
3232+ 'PLSG': {'G': 'JFG',
3333+ 'HZE': -61.278,
3434+ 'JWDRKRGZ': b'-',
3535+ 'OCCKQPDJ': True,
3636+ 'SJOCTZMK': False},
3737+ 'PRDLN': 39.129,
3838+ 'TUGRP': None,
3939+ 'WZTEJDXC': -69.933}
4040+{'GHAXI': 39.12,
4141+ 'PVUWZLC': 4.523,
4242+ 'TDPSU': 'TVCADUGT',
4343+ 'ZHGVSNSI': [-57, 9, -78.312]}
4444+{'': 11, 'B': True, 'FWD': {}, 'GXZBVAR': 'BTDWMGI', 'TDICHC': 87}
4545+4646+The function call ``rand_X()``, without the positional argument ``n``, instead yields an infinite stream of random values.
4747+4848+4949+Random generation options
5050+-------------------------
5151+5252+The :func:`dag_cbor.random.options` context manager is used to set options temporarily, within the scope of a ``with`` directive.
5353+In the snippet below, we set string characters to be uppercase alphabetic (codepoints `0x41`-`0x5a`) and we excluded CID values from being generated:
5454+5555+.. code-block:: python
5656+5757+ kwargs = dict(min_codepoint=0x41, max_codepoint=0x5a, include_cid=False)
5858+ with dag_cbor.random.options(**kwargs):
5959+ ...
6060+6161+Options can be permanently set with :func:`~dag_cbor.random.set_options` and reset with :func:`~dag_cbor.random.reset_options`.
6262+A read-only view on options can be obtained from :func:`~dag_cbor.random.get_options`, and a read-only view on default options can be obtained from :func:`~dag_cbor.random.default_options`:
6363+6464+>>> import pprint
6565+>>> import dag_cbor
6666+>>> pprint.pp(dag_cbor.random.default_options())
6767+mappingproxy({'min_int': -100,
6868+ 'max_int': 100,
6969+ 'min_bytes': 0,
7070+ 'max_bytes': 8,
7171+ 'min_chars': 0,
7272+ 'max_chars': 8,
7373+ 'min_codepoint': 33,
7474+ 'max_codepoint': 126,
7575+ 'min_len': 0,
7676+ 'max_len': 8,
7777+ 'max_nesting': 2,
7878+ 'canonical': True,
7979+ 'min_float': -100.0,
8080+ 'max_float': 100.0,
8181+ 'float_decimals': 3,
8282+ 'include_cid': True})
8383+8484+See :func:`~dag_cbor.random.set_options` for a description of the individual options.
···11+22+[MASTER]
33+44+# A comma-separated list of package or module names from where C extensions may
55+# be loaded. Extensions are loading into the active Python interpreter and may
66+# run arbitrary code.
77+extension-pkg-whitelist=
88+99+# Specify a score threshold to be exceeded before program exits with error.
1010+fail-under=10
1111+1212+# Add files or directories to the blacklist. They should be base names, not
1313+# paths.
1414+ignore=CVS
1515+1616+# Add files or directories matching the regex patterns to the blacklist. The
1717+# regex matches against base names, not paths.
1818+ignore-patterns=
1919+2020+# Python code to execute, usually for sys.path manipulation such as
2121+# pygtk.require().
2222+#init-hook=
2323+2424+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
2525+# number of processors available to use.
2626+jobs=0
2727+2828+# Control the amount of potential inferred values when inferring a single
2929+# object. This can help the performance when dealing with large functions or
3030+# complex, nested conditions.
3131+limit-inference-results=100
3232+3333+# List of plugins (as comma separated values of python module names) to load,
3434+# usually to register additional checkers.
3535+load-plugins=
3636+3737+# Pickle collected data for later comparisons.
3838+persistent=yes
3939+4040+# When enabled, pylint would attempt to guess common misconfiguration and emit
4141+# user-friendly hints instead of false-positive error messages.
4242+suggestion-mode=yes
4343+4444+# Allow loading of arbitrary C extensions. Extensions are imported into the
4545+# active Python interpreter and may run arbitrary code.
4646+unsafe-load-any-extension=no
4747+4848+4949+[MESSAGES CONTROL]
5050+5151+# Only show warnings with the listed confidence levels. Leave empty to show
5252+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
5353+confidence=
5454+5555+# Disable the message, report, category or checker with the given id(s). You
5656+# can either give multiple identifiers separated by comma (,) or put this
5757+# option multiple times (only on the command line, not in the configuration
5858+# file where it should appear only once). You can also use "--disable=all" to
5959+# disable everything first and then reenable specific checks. For example, if
6060+# you want to run only the similarities checker, you can use "--disable=all
6161+# --enable=similarities". If you want to run only the classes checker, but have
6262+# no Warning level messages displayed, use "--disable=all --enable=classes
6363+# --disable=W".
6464+disable=print-statement,
6565+ parameter-unpacking,
6666+ unpacking-in-except,
6767+ old-raise-syntax,
6868+ backtick,
6969+ long-suffix,
7070+ old-ne-operator,
7171+ old-octal-literal,
7272+ import-star-module-level,
7373+ non-ascii-bytes-literal,
7474+ raw-checker-failed,
7575+ bad-inline-option,
7676+ locally-disabled,
7777+ file-ignored,
7878+ suppressed-message,
7979+ useless-suppression,
8080+ deprecated-pragma,
8181+ use-symbolic-message-instead,
8282+ apply-builtin,
8383+ basestring-builtin,
8484+ buffer-builtin,
8585+ cmp-builtin,
8686+ coerce-builtin,
8787+ execfile-builtin,
8888+ file-builtin,
8989+ long-builtin,
9090+ raw_input-builtin,
9191+ reduce-builtin,
9292+ standarderror-builtin,
9393+ unicode-builtin,
9494+ xrange-builtin,
9595+ coerce-method,
9696+ delslice-method,
9797+ getslice-method,
9898+ setslice-method,
9999+ no-absolute-import,
100100+ old-division,
101101+ dict-iter-method,
102102+ dict-view-method,
103103+ next-method-called,
104104+ metaclass-assignment,
105105+ indexing-exception,
106106+ raising-string,
107107+ reload-builtin,
108108+ oct-method,
109109+ hex-method,
110110+ nonzero-method,
111111+ cmp-method,
112112+ input-builtin,
113113+ round-builtin,
114114+ intern-builtin,
115115+ unichr-builtin,
116116+ map-builtin-not-iterating,
117117+ zip-builtin-not-iterating,
118118+ range-builtin-not-iterating,
119119+ filter-builtin-not-iterating,
120120+ using-cmp-argument,
121121+ eq-without-hash,
122122+ div-method,
123123+ idiv-method,
124124+ rdiv-method,
125125+ exception-message-attribute,
126126+ invalid-str-codec,
127127+ sys-max-int,
128128+ bad-python3-import,
129129+ deprecated-string-function,
130130+ deprecated-str-translate-call,
131131+ deprecated-itertools-function,
132132+ deprecated-types-field,
133133+ next-method-defined,
134134+ dict-items-not-iterating,
135135+ dict-keys-not-iterating,
136136+ dict-values-not-iterating,
137137+ deprecated-operator-function,
138138+ deprecated-urllib-function,
139139+ xreadlines-attribute,
140140+ deprecated-sys-function,
141141+ exception-escape,
142142+ comprehension-escape
143143+144144+# Enable the message, report, category or checker with the given id(s). You can
145145+# either give multiple identifier separated by comma (,) or put this option
146146+# multiple time (only on the command line, not in the configuration file where
147147+# it should appear only once). See also the "--disable" option for examples.
148148+enable=c-extension-no-member
149149+150150+151151+[REPORTS]
152152+153153+# Python expression which should return a score less than or equal to 10. You
154154+# have access to the variables 'error', 'warning', 'refactor', and 'convention'
155155+# which contain the number of messages in each category, as well as 'statement'
156156+# which is the total number of statements analyzed. This score is used by the
157157+# global evaluation report (RP0004).
158158+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
159159+160160+# Template used to display messages. This is a python new-style format string
161161+# used to format the message information. See doc for all details.
162162+#msg-template=
163163+164164+# Set the output format. Available formats are text, parseable, colorized, json
165165+# and msvs (visual studio). You can also give a reporter class, e.g.
166166+# mypackage.mymodule.MyReporterClass.
167167+output-format=text
168168+169169+# Tells whether to display a full report or only the messages.
170170+reports=no
171171+172172+# Activate the evaluation score.
173173+score=yes
174174+175175+176176+[REFACTORING]
177177+178178+# Maximum number of nested blocks for function / method body
179179+max-nested-blocks=5
180180+181181+# Complete name of functions that never returns. When checking for
182182+# inconsistent-return-statements if a never returning function is called then
183183+# it will be considered as an explicit return statement and no message will be
184184+# printed.
185185+never-returning-functions=sys.exit
186186+187187+188188+[BASIC]
189189+190190+# Naming style matching correct argument names.
191191+argument-naming-style=snake_case
192192+193193+# Regular expression matching correct argument names. Overrides argument-
194194+# naming-style.
195195+#argument-rgx=
196196+197197+# Naming style matching correct attribute names.
198198+attr-naming-style=snake_case
199199+200200+# Regular expression matching correct attribute names. Overrides attr-naming-
201201+# style.
202202+#attr-rgx=
203203+204204+# Bad variable names which should always be refused, separated by a comma.
205205+bad-names=foo,
206206+ bar,
207207+ baz,
208208+ toto,
209209+ tutu,
210210+ tata
211211+212212+# Bad variable names regexes, separated by a comma. If names match any regex,
213213+# they will always be refused
214214+bad-names-rgxs=
215215+216216+# Naming style matching correct class attribute names.
217217+class-attribute-naming-style=any
218218+219219+# Regular expression matching correct class attribute names. Overrides class-
220220+# attribute-naming-style.
221221+#class-attribute-rgx=
222222+223223+# Naming style matching correct class names.
224224+class-naming-style=PascalCase
225225+226226+# Regular expression matching correct class names. Overrides class-naming-
227227+# style.
228228+#class-rgx=
229229+230230+# Naming style matching correct constant names.
231231+const-naming-style=UPPER_CASE
232232+233233+# Regular expression matching correct constant names. Overrides const-naming-
234234+# style.
235235+#const-rgx=
236236+237237+# Minimum line length for functions/classes that require docstrings, shorter
238238+# ones are exempt.
239239+docstring-min-length=-1
240240+241241+# Naming style matching correct function names.
242242+function-naming-style=snake_case
243243+244244+# Regular expression matching correct function names. Overrides function-
245245+# naming-style.
246246+#function-rgx=
247247+248248+# Good variable names which should always be accepted, separated by a comma.
249249+good-names=i,
250250+ j,
251251+ k,
252252+ ex,
253253+ Run,
254254+ _
255255+256256+# Good variable names regexes, separated by a comma. If names match any regex,
257257+# they will always be accepted
258258+good-names-rgxs=
259259+260260+# Include a hint for the correct naming format with invalid-name.
261261+include-naming-hint=no
262262+263263+# Naming style matching correct inline iteration names.
264264+inlinevar-naming-style=any
265265+266266+# Regular expression matching correct inline iteration names. Overrides
267267+# inlinevar-naming-style.
268268+#inlinevar-rgx=
269269+270270+# Naming style matching correct method names.
271271+method-naming-style=snake_case
272272+273273+# Regular expression matching correct method names. Overrides method-naming-
274274+# style.
275275+#method-rgx=
276276+277277+# Naming style matching correct module names.
278278+module-naming-style=snake_case
279279+280280+# Regular expression matching correct module names. Overrides module-naming-
281281+# style.
282282+#module-rgx=
283283+284284+# Colon-delimited sets of names that determine each other's naming style when
285285+# the name regexes allow several styles.
286286+name-group=
287287+288288+# Regular expression which should only match function or class names that do
289289+# not require a docstring.
290290+no-docstring-rgx=^_
291291+292292+# List of decorators that produce properties, such as abc.abstractproperty. Add
293293+# to this list to register other decorators that produce valid properties.
294294+# These decorators are taken in consideration only for invalid-name.
295295+property-classes=abc.abstractproperty
296296+297297+# Naming style matching correct variable names.
298298+variable-naming-style=snake_case
299299+300300+# Regular expression matching correct variable names. Overrides variable-
301301+# naming-style.
302302+#variable-rgx=
303303+304304+305305+[FORMAT]
306306+307307+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
308308+expected-line-ending-format=
309309+310310+# Regexp for a line that is allowed to be longer than the limit.
311311+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
312312+313313+# Number of spaces of indent required inside a hanging or continued line.
314314+indent-after-paren=4
315315+316316+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
317317+# tab).
318318+indent-string=' '
319319+320320+# Maximum number of characters on a single line.
321321+max-line-length=100
322322+323323+# Maximum number of lines in a module.
324324+max-module-lines=1000
325325+326326+# List of optional constructs for which whitespace checking is disabled. `dict-
327327+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
328328+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
329329+# `empty-line` allows space-only lines.
330330+no-space-check=trailing-comma,
331331+ dict-separator
332332+333333+# Allow the body of a class to be on the same line as the declaration if body
334334+# contains single statement.
335335+single-line-class-stmt=no
336336+337337+# Allow the body of an if to be on the same line as the test if there is no
338338+# else.
339339+single-line-if-stmt=no
340340+341341+342342+[LOGGING]
343343+344344+# The type of string formatting that logging methods do. `old` means using %
345345+# formatting, `new` is for `{}` formatting.
346346+logging-format-style=old
347347+348348+# Logging modules to check that the string format arguments are in logging
349349+# function parameter format.
350350+logging-modules=logging
351351+352352+353353+[MISCELLANEOUS]
354354+355355+# List of note tags to take in consideration, separated by a comma.
356356+notes=FIXME,
357357+ XXX,
358358+ TODO
359359+360360+# Regular expression of note tags to take in consideration.
361361+#notes-rgx=
362362+363363+364364+[SIMILARITIES]
365365+366366+# Ignore comments when computing similarities.
367367+ignore-comments=yes
368368+369369+# Ignore docstrings when computing similarities.
370370+ignore-docstrings=yes
371371+372372+# Ignore imports when computing similarities.
373373+ignore-imports=no
374374+375375+# Minimum lines number of a similarity.
376376+min-similarity-lines=4
377377+378378+379379+[SPELLING]
380380+381381+# Limits count of emitted suggestions for spelling mistakes.
382382+max-spelling-suggestions=4
383383+384384+# Spelling dictionary name. Available dictionaries: none. To make it work,
385385+# install the python-enchant package.
386386+spelling-dict=
387387+388388+# List of comma separated words that should not be checked.
389389+spelling-ignore-words=
390390+391391+# A path to a file that contains the private dictionary; one word per line.
392392+spelling-private-dict-file=
393393+394394+# Tells whether to store unknown words to the private dictionary (see the
395395+# --spelling-private-dict-file option) instead of raising a message.
396396+spelling-store-unknown-words=no
397397+398398+399399+[STRING]
400400+401401+# This flag controls whether inconsistent-quotes generates a warning when the
402402+# character used as a quote delimiter is used inconsistently within a module.
403403+check-quote-consistency=no
404404+405405+# This flag controls whether the implicit-str-concat should generate a warning
406406+# on implicit string concatenation in sequences defined over several lines.
407407+check-str-concat-over-line-jumps=no
408408+409409+410410+[TYPECHECK]
411411+412412+# List of decorators that produce context managers, such as
413413+# contextlib.contextmanager. Add to this list to register other decorators that
414414+# produce valid context managers.
415415+contextmanager-decorators=contextlib.contextmanager
416416+417417+# List of members which are set dynamically and missed by pylint inference
418418+# system, and so shouldn't trigger E1101 when accessed. Python regular
419419+# expressions are accepted.
420420+generated-members=
421421+422422+# Tells whether missing members accessed in mixin class should be ignored. A
423423+# mixin class is detected if its name ends with "mixin" (case insensitive).
424424+ignore-mixin-members=yes
425425+426426+# Tells whether to warn about missing members when the owner of the attribute
427427+# is inferred to be None.
428428+ignore-none=yes
429429+430430+# This flag controls whether pylint should warn about no-member and similar
431431+# checks whenever an opaque object is returned when inferring. The inference
432432+# can return multiple potential results while evaluating a Python object, but
433433+# some branches might not be evaluated, which results in partial inference. In
434434+# that case, it might be useful to still emit no-member and other checks for
435435+# the rest of the inferred objects.
436436+ignore-on-opaque-inference=yes
437437+438438+# List of class names for which member attributes should not be checked (useful
439439+# for classes with dynamically set attributes). This supports the use of
440440+# qualified names.
441441+ignored-classes=optparse.Values,thread._local,_thread._local
442442+443443+# List of module names for which member attributes should not be checked
444444+# (useful for modules/projects where namespaces are manipulated during runtime
445445+# and thus existing member attributes cannot be deduced by static analysis). It
446446+# supports qualified module names, as well as Unix pattern matching.
447447+ignored-modules=
448448+449449+# Show a hint with possible names when a member name was not found. The aspect
450450+# of finding the hint is based on edit distance.
451451+missing-member-hint=yes
452452+453453+# The minimum edit distance a name should have in order to be considered a
454454+# similar match for a missing member name.
455455+missing-member-hint-distance=1
456456+457457+# The total number of similar names that should be taken in consideration when
458458+# showing a hint for a missing member.
459459+missing-member-max-choices=1
460460+461461+# List of decorators that change the signature of a decorated function.
462462+signature-mutators=
463463+464464+465465+[VARIABLES]
466466+467467+# List of additional names supposed to be defined in builtins. Remember that
468468+# you should avoid defining new builtins when possible.
469469+additional-builtins=
470470+471471+# Tells whether unused global variables should be treated as a violation.
472472+allow-global-unused-variables=yes
473473+474474+# List of strings which can identify a callback function by name. A callback
475475+# name must start or end with one of those strings.
476476+callbacks=cb_,
477477+ _cb
478478+479479+# A regular expression matching the name of dummy variables (i.e. expected to
480480+# not be used).
481481+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
482482+483483+# Argument names that match this expression will be ignored. Default to name
484484+# with leading underscore.
485485+ignored-argument-names=_.*|^ignored_|^unused_
486486+487487+# Tells whether we should check for unused import in __init__ files.
488488+init-import=no
489489+490490+# List of qualified module names which can have objects that can redefine
491491+# builtins.
492492+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
493493+494494+495495+[CLASSES]
496496+497497+# List of method names used to declare (i.e. assign) instance attributes.
498498+defining-attr-methods=__init__,
499499+ __new__,
500500+ setUp,
501501+ __post_init__
502502+503503+# List of member names, which should be excluded from the protected access
504504+# warning.
505505+exclude-protected=_asdict,
506506+ _fields,
507507+ _replace,
508508+ _source,
509509+ _make
510510+511511+# List of valid names for the first argument in a class method.
512512+valid-classmethod-first-arg=cls
513513+514514+# List of valid names for the first argument in a metaclass class method.
515515+valid-metaclass-classmethod-first-arg=cls
516516+517517+518518+[DESIGN]
519519+520520+# Maximum number of arguments for function / method.
521521+max-args=5
522522+523523+# Maximum number of attributes for a class (see R0902).
524524+max-attributes=7
525525+526526+# Maximum number of boolean expressions in an if statement (see R0916).
527527+max-bool-expr=5
528528+529529+# Maximum number of branch for function / method body.
530530+max-branches=12
531531+532532+# Maximum number of locals for function / method body.
533533+max-locals=15
534534+535535+# Maximum number of parents for a class (see R0901).
536536+max-parents=7
537537+538538+# Maximum number of public methods for a class (see R0904).
539539+max-public-methods=20
540540+541541+# Maximum number of return / yield for function / method body.
542542+max-returns=6
543543+544544+# Maximum number of statements in function / method body.
545545+max-statements=50
546546+547547+# Minimum number of public methods for a class (see R0903).
548548+min-public-methods=2
549549+550550+551551+[IMPORTS]
552552+553553+# List of modules that can be imported at any level, not just the top level
554554+# one.
555555+allow-any-import-level=
556556+557557+# Allow wildcard imports from modules that define __all__.
558558+allow-wildcard-with-all=no
559559+560560+# Analyse import fallback blocks. This can be used to support both Python 2 and
561561+# 3 compatible code, which means that the block might have code that exists
562562+# only in one or another interpreter, leading to false positives when analysed.
563563+analyse-fallback-blocks=no
564564+565565+# Deprecated modules which should not be used, separated by a comma.
566566+deprecated-modules=optparse,tkinter.tix
567567+568568+# Create a graph of external dependencies in the given file (report RP0402 must
569569+# not be disabled).
570570+ext-import-graph=
571571+572572+# Create a graph of every (i.e. internal and external) dependencies in the
573573+# given file (report RP0402 must not be disabled).
574574+import-graph=
575575+576576+# Create a graph of internal dependencies in the given file (report RP0402 must
577577+# not be disabled).
578578+int-import-graph=
579579+580580+# Force import order to recognize a module as part of the standard
581581+# compatibility libraries.
582582+known-standard-library=
583583+584584+# Force import order to recognize a module as part of a third party library.
585585+known-third-party=enchant
586586+587587+# Couples of modules and preferred modules, separated by a comma.
588588+preferred-modules=
589589+590590+591591+[EXCEPTIONS]
592592+593593+# Exceptions that will emit a warning when being caught. Defaults to
594594+# "BaseException, Exception".
595595+overgeneral-exceptions=BaseException,
596596+ Exception
597597+598598+C:\Users\Stefa\Documents\git\hashberg-io\quetz>
···11+"""
22+ Tests on encoding data using `dag_cbor` vs encoding data using `cbor2`.
33+"""
44+# pylint: disable = global-statement
55+66+import cbor2 # type: ignore
77+88+from dag_cbor import encode
99+from dag_cbor.random import rand_list, rand_dict, rand_int, rand_bytes, rand_str, rand_bool_none, rand_float, rand_cid, options
1010+1111+nsamples = 1000
1212+1313+def test_int() -> None:
1414+ """
1515+ Encodes random `int` samples with `dag_cbor.encoding.encode`,
1616+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
1717+ """
1818+ test_data = rand_int(nsamples)
1919+ for i, x in enumerate(test_data):
2020+ error_msg = f"failed at #{i} = {repr(x)}"
2121+ assert cbor2.dumps(x) == encode(x), error_msg
2222+2323+def test_special_int() -> None:
2424+ """
2525+ Encodes specially crafted `int` samples with `dag_cbor.encoding.encode`,
2626+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
2727+ """
2828+ exponents = [8, 16, 32, 26]
2929+ special_data = [2**e for e in exponents]
3030+ special_data += [x-1 for x in special_data]
3131+ special_data += [-x for x in special_data]
3232+ for i, x in enumerate(special_data):
3333+ error_msg = f"failed at #{i} = {repr(x)}"
3434+ assert cbor2.dumps(x) == encode(x), error_msg
3535+3636+def test_bytes() -> None:
3737+ """
3838+ Encodes random `bytes` samples with `dag_cbor.encoding.encode`,
3939+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
4040+ """
4141+ test_data = rand_bytes(nsamples)
4242+ for i, x in enumerate(test_data):
4343+ error_msg = f"failed at #{i} = {repr(x)}"
4444+ assert cbor2.dumps(x) == encode(x), error_msg
4545+4646+def test_str() -> None:
4747+ """
4848+ Encodes random `str` samples with `dag_cbor.encoding.encode`,
4949+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
5050+ """
5151+ test_data = rand_str(nsamples)
5252+ for i, x in enumerate(test_data):
5353+ error_msg = f"failed at #{i} = {repr(x)}"
5454+ assert cbor2.dumps(x) == encode(x), error_msg
5555+5656+def test_bool_none() -> None:
5757+ """
5858+ Encodes random `Optional[bool]` or samples with `dag_cbor.encoding.encode`,
5959+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
6060+ """
6161+ test_data = rand_bool_none(nsamples)
6262+ for i, x in enumerate(test_data):
6363+ error_msg = f"failed at #{i} = {repr(x)}"
6464+ assert cbor2.dumps(x) == encode(x), error_msg
6565+6666+def test_float() -> None:
6767+ """
6868+ Encodes random `float` samples with `dag_cbor.encoding.encode`,
6969+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
7070+ """
7171+ test_data = rand_float(nsamples)
7272+ for i, x in enumerate(test_data):
7373+ error_msg = f"failed at #{i} = {repr(x)}"
7474+ assert cbor2.dumps(x) == encode(x), error_msg
7575+7676+def test_list() -> None:
7777+ """
7878+ Encodes random `list` samples with `dag_cbor.encoding.encode`,
7979+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
8080+ """
8181+ with options(include_cid=False):
8282+ test_data = rand_list(nsamples)
8383+ for i, x in enumerate(test_data):
8484+ error_msg = f"failed at #{i} = {repr(x)}"
8585+ assert cbor2.dumps(x) == encode(x), error_msg
8686+8787+def test_dict() -> None:
8888+ """
8989+ Encodes random `dict` samples with `dag_cbor.encoding.encode`,
9090+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
9191+ """
9292+ with options(include_cid=False):
9393+ test_data = rand_dict(nsamples)
9494+ for i, x in enumerate(test_data):
9595+ error_msg = f"failed at #{i} = {repr(x)}"
9696+ assert cbor2.dumps(x) == encode(x), error_msg
9797+9898+9999+def test_dict_noncanonical() -> None:
100100+ """
101101+ Encodes a dict given in noncanonical order and tests if it is encoded in canonical order.
102102+ from the specs (https://ipld.io/specs/codecs/dag-cbor/spec/#strictness):
103103+104104+ If two keys have different lengths, the shorter one sorts earlier;
105105+ If two keys have the same length, the one with the lower value in (byte-wise) lexical order sorts earlier.
106106+ """
107107+ test_data = {"bar123": 5, "zap": 7, "abc432": 9}
108108+ assert list(cbor2.loads(encode(test_data))) == ["zap", "abc432", "bar123"]
109109+110110+111111+def test_cid() -> None:
112112+ """
113113+ Encodes random CID samples with `dag_cbor.encoding.encode`,
114114+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
115115+ """
116116+ test_data = rand_cid(nsamples)
117117+ for i, x in enumerate(test_data):
118118+ error_msg = f"failed at #{i} = {repr(x)}"
119119+ assert cbor2.dumps(cbor2.CBORTag(42, b"\0" + bytes(x))) == encode(x), error_msg
···11+"""
22+ Tests on encoding data using `dag_cbor` and decoding back using `cbor2`.
33+"""
44+# pylint: disable = global-statement
55+66+from dag_cbor import encode, decode
77+from dag_cbor.random import rand_list, rand_dict, rand_int, rand_bytes, rand_str, rand_bool_none, rand_float, rand_cid, options
88+99+import pytest
1010+1111+nsamples = 1000
1212+1313+def test_int() -> None:
1414+ """
1515+ Encodes random `int` samples with `dag_cbor.encoding.encode`,
1616+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
1717+ """
1818+ test_data = rand_int(nsamples)
1919+ for i, x in enumerate(test_data):
2020+ error_msg = f"failed at #{i} = {repr(x)}"
2121+ assert x == decode(encode(x)), error_msg
2222+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
2323+2424+def test_special_int() -> None:
2525+ """
2626+ Encodes specially crafted `int` samples with `dag_cbor.encoding.encode`,
2727+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
2828+ """
2929+ exponents = [8, 16, 32, 26]
3030+ special_data = [2**e for e in exponents]
3131+ special_data += [x-1 for x in special_data]
3232+ special_data += [-x for x in special_data]
3333+ for i, x in enumerate(special_data):
3434+ error_msg = f"failed at #{i} = {repr(x)}"
3535+ assert x == decode(encode(x)), error_msg
3636+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
3737+3838+def test_bytes() -> None:
3939+ """
4040+ Encodes random `bytes` samples with `dag_cbor.encoding.encode`,
4141+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
4242+ """
4343+ test_data = rand_bytes(nsamples)
4444+ for i, x in enumerate(test_data):
4545+ error_msg = f"failed at #{i} = {repr(x)}"
4646+ assert x == decode(encode(x)), error_msg
4747+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
4848+4949+def test_str() -> None:
5050+ """
5151+ Encodes random `str` samples with `dag_cbor.encoding.encode`,
5252+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
5353+ """
5454+ test_data = rand_str(nsamples)
5555+ for i, x in enumerate(test_data):
5656+ error_msg = f"failed at #{i} = {repr(x)}"
5757+ assert x == decode(encode(x)), error_msg
5858+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
5959+6060+def test_bool_none() -> None:
6161+ """
6262+ Encodes random `Optional[bool]` or samples with `dag_cbor.encoding.encode`,
6363+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
6464+ """
6565+ test_data = rand_bool_none(nsamples)
6666+ for i, x in enumerate(test_data):
6767+ error_msg = f"failed at #{i} = {repr(x)}"
6868+ assert x == decode(encode(x)), error_msg
6969+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
7070+7171+def test_float() -> None:
7272+ """
7373+ Encodes random `float` samples with `dag_cbor.encoding.encode`,
7474+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
7575+ """
7676+ test_data = rand_float(nsamples)
7777+ for i, x in enumerate(test_data):
7878+ error_msg = f"failed at #{i} = {repr(x)}"
7979+ assert x == decode(encode(x)), error_msg
8080+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
8181+8282+def test_list() -> None:
8383+ """
8484+ Encodes random `list` samples with `dag_cbor.encoding.encode`,
8585+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
8686+ """
8787+ with options(include_cid=False):
8888+ test_data = rand_list(nsamples)
8989+ for i, x in enumerate(test_data):
9090+ error_msg = f"failed at #{i} = {repr(x)}"
9191+ assert x == decode(encode(x)), error_msg
9292+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
9393+9494+@pytest.mark.parametrize("canonical", [True, False])
9595+def test_dict(canonical: bool) -> None:
9696+ """
9797+ Encodes random `dict` samples with `dag_cbor.encoding.encode`,
9898+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
9999+ """
100100+ with options(include_cid=False, canonical=canonical):
101101+ test_data = rand_dict(nsamples)
102102+ for i, x in enumerate(test_data):
103103+ error_msg = f"failed at #{i} = {repr(x)}"
104104+ assert x == decode(encode(x)), error_msg
105105+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
106106+107107+def test_cid() -> None:
108108+ """
109109+ Encodes random CID samples with `dag_cbor.encoding.encode`,
110110+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
111111+ """
112112+ test_data = rand_cid(nsamples)
113113+ for i, x in enumerate(test_data):
114114+ error_msg = f"failed at #{i} = {repr(x)}"
115115+ assert x == decode(encode(x)), error_msg
116116+ assert x == decode(encode(x, include_multicodec=True), require_multicodec=True), error_msg
···11+"""
22+ Tests on encoding data using `dag_cbor` and decoding back using `dag_cbor`.
33+"""
44+# pylint: disable = global-statement
55+66+import cbor2.decoder as cbor2 # type: ignore
77+88+from multiformats import CID
99+1010+from dag_cbor import encode, decode
1111+from dag_cbor.random import rand_list, rand_dict, rand_int, rand_bytes, rand_str, rand_bool_none, rand_float, rand_cid, options
1212+1313+nsamples = 1000
1414+1515+def test_int() -> None:
1616+ """
1717+ Encodes random `int` samples with `dag_cbor.encoding.encode`,
1818+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
1919+ """
2020+ test_data = rand_int(nsamples)
2121+ for i, x in enumerate(test_data):
2222+ error_msg = f"failed at #{i} = {repr(x)}"
2323+ encoded_data = encode(x)
2424+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
2525+2626+def test_special_int() -> None:
2727+ """
2828+ Encodes specially crafted `int` samples with `dag_cbor.encoding.encode`,
2929+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
3030+ """
3131+ exponents = [8, 16, 32, 26]
3232+ special_data = [2**e for e in exponents]
3333+ special_data += [x-1 for x in special_data]
3434+ special_data += [-x for x in special_data]
3535+ for i, x in enumerate(special_data):
3636+ error_msg = f"failed at #{i} = {repr(x)}"
3737+ encoded_data = encode(x)
3838+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
3939+4040+def test_bytes() -> None:
4141+ """
4242+ Encodes random `bytes` samples with `dag_cbor.encoding.encode`,
4343+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
4444+ """
4545+ test_data = rand_bytes(nsamples)
4646+ for i, x in enumerate(test_data):
4747+ error_msg = f"failed at #{i} = {repr(x)}"
4848+ encoded_data = encode(x)
4949+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
5050+5151+def test_str() -> None:
5252+ """
5353+ Encodes random `str` samples with `dag_cbor.encoding.encode`,
5454+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
5555+ """
5656+ test_data = rand_str(nsamples)
5757+ for i, x in enumerate(test_data):
5858+ error_msg = f"failed at #{i} = {repr(x)}"
5959+ encoded_data = encode(x)
6060+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
6161+6262+def test_bool_none() -> None:
6363+ """
6464+ Encodes random `Optional[bool]` or samples with `dag_cbor.encoding.encode`,
6565+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
6666+ """
6767+ test_data = rand_bool_none(nsamples)
6868+ for i, x in enumerate(test_data):
6969+ error_msg = f"failed at #{i} = {repr(x)}"
7070+ encoded_data = encode(x)
7171+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
7272+7373+def test_float() -> None:
7474+ """
7575+ Encodes random `float` samples with `dag_cbor.encoding.encode`,
7676+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
7777+ """
7878+ test_data = rand_float(nsamples)
7979+ for i, x in enumerate(test_data):
8080+ error_msg = f"failed at #{i} = {repr(x)}"
8181+ encoded_data = encode(x)
8282+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
8383+8484+def test_list() -> None:
8585+ """
8686+ Encodes random `list` samples with `dag_cbor.encoding.encode`,
8787+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
8888+ """
8989+ with options(include_cid=False):
9090+ test_data = rand_list(nsamples)
9191+ for i, x in enumerate(test_data):
9292+ error_msg = f"failed at #{i} = {repr(x)}"
9393+ encoded_data = encode(x)
9494+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
9595+9696+def test_dict() -> None:
9797+ """
9898+ Encodes random `dict` samples with `dag_cbor.encoding.encode`,
9999+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
100100+ """
101101+ with options(include_cid=False):
102102+ test_data = rand_dict(nsamples)
103103+ for i, x in enumerate(test_data):
104104+ error_msg = f"failed at #{i} = {repr(x)}"
105105+ encoded_data = encode(x)
106106+ assert decode(encoded_data) == cbor2.loads(encoded_data), error_msg
107107+108108+def test_cid() -> None:
109109+ """
110110+ Encodes random CID samples with `dag_cbor.encoding.encode`,
111111+ encodes them with `cbor2.encoder.dumps` and checks that the two encodings match.
112112+ """
113113+ test_data = rand_cid(nsamples)
114114+ for i, x in enumerate(test_data):
115115+ error_msg = f"failed at #{i} = {repr(x)}"
116116+ encoded_data = encode(x)
117117+ decoded_data = decode(encoded_data)
118118+ assert isinstance(decoded_data, CID)
119119+ assert cbor2.CBORTag(42, b"\0" + bytes(decoded_data)) == cbor2.loads(encoded_data), error_msg
···11+"""
22+ Tests on number of bytes written to streams in encoding and read from streams in decoding,
33+ as well as tests on decoding concatenated data.
44+"""
55+# pylint: disable = global-statement
66+77+from io import BytesIO
88+from dag_cbor import encode, decode
99+from dag_cbor.ipld import IPLDKind
1010+from dag_cbor.random import rand_data
1111+1212+nsamples = 1000
1313+nconcat = 3
1414+1515+class BytesReadCounter:
1616+ """ Counter for bytes read while decoding. """
1717+ _num_bytes_read: int = 0
1818+ def __call__(self, value: IPLDKind, num_bytes_read: int) -> None:
1919+ self._num_bytes_read += num_bytes_read
2020+ def __int__(self) -> int:
2121+ return self._num_bytes_read
2222+2323+def test_decode_concat_length() -> None:
2424+ """
2525+ Encodes random item samples with `dag_cbor.encoding.encode`, then concatenates the bytes of three items.
2626+ Decodes with `dag_cbor.decoding.decode` allowing concatenation and checks that the correct number of bytes
2727+ are read for each encoded item.
2828+ """
2929+ test_data = rand_data(nconcat*nsamples)
3030+ for i in range(nsamples):
3131+ items = [next(test_data) for j in range(nconcat)]
3232+ encoded_items = [encode(x) for x in items]
3333+ stream = BytesIO(b''.join(encoded_items))
3434+ for j in range(nconcat):
3535+ x = items[j]
3636+ bytes_read_cnt = BytesReadCounter()
3737+ decode(stream, allow_concat=True, callback=bytes_read_cnt)
3838+ error_msg = f"failed at #{i}:{j} = {repr(x)}"
3939+ assert len(encoded_items[j]) == int(bytes_read_cnt), error_msg
4040+ error_msg = f"failed at #{i}"
4141+ assert len(stream.read()) == 0, error_msg
4242+4343+def test_encode_length() -> None:
4444+ """
4545+ Encodes random item samples with `dag_cbor.encoding.encode` to a stream,
4646+ then checks that the number of bytes written is the one returned by `encode`.
4747+ """
4848+ test_data = rand_data(nsamples)
4949+ for i, x in enumerate(test_data):
5050+ error_msg = f"failed at #{i} = {repr(x)}"
5151+ stream = BytesIO()
5252+ num_bytes_written: int = encode(x, stream=stream)
5353+ assert len(stream.getvalue()) == num_bytes_written, error_msg
+35
vendor/git/dag-cbor/test/test_04_link_coding.py
···11+"""
22+ Tests on the specifics of DAG-CBOR Link encoding.
33+"""
44+55+# pylint: disable = global-statement
66+77+import cbor2
88+99+from dag_cbor import encode, decode
1010+from dag_cbor.decoding.err import DAGCBORDecodingError
1111+from dag_cbor.random import rand_cid, options
1212+1313+import pytest
1414+1515+nsamples = 1000
1616+1717+def test_decoding_requires_multibase_prefix() -> None:
1818+ """
1919+ Checks that the decoder fails if the identity multibase prefix (0x00) is not
2020+ present in the DAG-CBOR representation.
2121+ """
2222+ test_data = rand_cid(nsamples)
2323+ for i, x in enumerate(test_data):
2424+ with pytest.raises(DAGCBORDecodingError):
2525+ decode(cbor2.dumps(cbor2.CBORTag(42, bytes(x))))
2626+2727+def test_encoding_produces_multibase_prefix() -> None:
2828+ """
2929+ Checks that the encoder includes the identity multibase prefix (0x00) in the
3030+ DAG-CBOR representation.
3131+ """
3232+ test_data = rand_cid(nsamples)
3333+ for i, x in enumerate(test_data):
3434+ rtdata = cbor2.loads(encode(x))
3535+ assert rtdata.value[0] == 0