diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..63ad98eb --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,23 @@ +# .readthedocs.yml +# Read the Docs configuration file +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.12" + +python: + install: + - requirements: docs/requirements.txt + - method: pip + path: . + +sphinx: + configuration: docs/source/conf.py + +# Optionally, set the documentation type +# formats: +# - html +# - pdf +# - epub diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 673b32c8..cd436889 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -232,7 +232,7 @@ For more information to debug `pytest` test suites see ## Running GitHub actions locally using `act` With `docker` (or `podman`) installed, [act](https://github.com/nektos/act) can be used to run -the CI jobs configured in [.actrc](.actrc): +the CI jobs configured in [`.actrc`](https://github.com/xenserver/python-libs/blob/master/.actrc): - `act` uses `docker` (also mimicked by `podman-docker`) to run GitHub actions locally - While `act` does not use the same GitHub runner images, they are similar. diff --git a/DOCUMENTING.md b/DOCUMENTING.md new file mode 100644 index 00000000..9d21bb8d --- /dev/null +++ b/DOCUMENTING.md @@ -0,0 +1,57 @@ +# Documenting using Sphinx + +This project uses **Google style docstrings** for Python code documentation. These docstrings are compatible with Sphinx (with the `sphinx.ext.napoleon` extension) and other documentation tools. + +## Why Google Style Docstrings? + +- Clear, readable format +- Widely supported by documentation generators +- Easy to maintain + +## Example Google Style Docstring + +```python +def add(a: int, b: int) -> int: + """Add two integers. + + Args: + a (int): First integer. + b (int): Second integer. + + Returns: + int: The sum of `a` and `b`. + + Raises: + ValueError: If either argument is not an integer. + """ + if not isinstance(a, int) or not isinstance(b, int): + raise ValueError("Arguments must be integers.") + return a + b +``` + +## Steps to Document Your Code + +1. **Write Google style docstrings** for all public modules, classes, and functions. +2. **Include sections** such as `Args`, `Returns`, `Raises`, and `Examples` as needed. +3. **Keep docstrings concise and informative.** + +## Benefits of using Sphinx + +- Supports docstring formats – such as Google-style, NumPy-style, and reST. +- Autodoc extension – can automatically extract documentation from Python docstrings. +- Integration with Read the Docs – makes it easy to publish and host documentation online. +- Theme support – like Read the Docs theme or the modern Furo theme. + +## Building the documentation + +```bash +pip install -r docs/requirements.txt +make -C docs html +``` + +Open `docs/html/index.html` in a web browser. + +## References + +- [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) +- [Sphinx Napoleon Documentation](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html) diff --git a/README-Unicode.md b/README-Unicode.md index f38b93ae..3f21dff9 100644 --- a/README-Unicode.md +++ b/README-Unicode.md @@ -1,4 +1,4 @@ -# Python3 Unicode migration in the XCP package +# Unicode migration ## Problem @@ -79,7 +79,7 @@ When this is known to be the case, `encoding="iso-8859-1` could be tried (not te With the locale set to C (XAPI plugins have that), Python's default mode changes between 3.6 and 3.7: -```py +```sh for i in 3.{6,7,10,11};do echo -n "3.$i: "; LC_ALL=C python3.$i -c 'import locale,sys;print(locale.getpreferredencoding())';done 3.6: ANSI_X3.4-1968 @@ -90,9 +90,12 @@ for i in 3.{6,7,10,11};do echo -n "3.$i: "; This has the effect that in Python 3.6, the default codec for XAPI plugins is `ascii`: -```py +```sh for i in 2.7 3.{6,7};do echo "$i:"; LC_ALL=C python$i -c 'open("/usr/share/hwdata/pci.ids").read()';done +``` + +``` 2.7: 3.6: Traceback (most recent call last): @@ -111,54 +114,18 @@ While Python 3.7 and newer use UTF-8 mode by default, it does not set up an erro As it happens, some older tools output ISO-8859-1 characters hard-coded and these aren't valid UTF-8 sequences, and even newer Python versions need error handlers to not fail: -```py +```sh echo -e "\0262" # ISO-8859-1 for: "²" python3 -c 'open(".text").read()' +``` + +``` Traceback (most recent call last): File "", line 1, in File "", line 322, in decode UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 0: invalid start byte ``` -```py -pylint -d all -e unspecified-encoding --msg-template="{path} line {line} in {obj}()" xcp/ tests/ -************* Module xcp.accessor -xcp/accessor.py line 165 in MountingAccessor.writeFile() -xcp/accessor.py line 240 in FileAccessor.writeFile() -************* Module xcp.bootloader -xcp/bootloader.py line 111 in Bootloader.readExtLinux() -xcp/bootloader.py line 219 in Bootloader.readGrub() -xcp/bootloader.py line 335 in Bootloader.readGrub2() -xcp/bootloader.py line 465 in Bootloader.writeExtLinux() -xcp/bootloader.py line 507 in Bootloader.writeGrub() -xcp/bootloader.py line 541 in Bootloader.writeGrub2() -************* Module xcp.cmd -xcp/cmd.py line 67 in OutputCache.fileContents() -************* Module xcp.dom0 -xcp/dom0.py line 85 in default_memory() -************* Module xcp.environ -xcp/environ.py line 48 in readInventory() -************* Module xcp.logger -xcp/logger.py line 51 in openLog() -************* Module xcp.net.ifrename.dynamic -xcp/net/ifrename/dynamic.py line 95 in DynamicRules.load_and_parse() -xcp/net/ifrename/dynamic.py line 292 in DynamicRules.save() -************* Module xcp.net.ifrename.static -xcp/net/ifrename/static.py line 118 in StaticRules.load_and_parse() -xcp/net/ifrename/static.py line 330 in StaticRules.save() -************* Module tests.test_biosdevname -tests/test_biosdevname.py line 30 in TestDeviceNames.test() -tests/test_biosdevname.py line 32 in TestDeviceNames.test() -************* Module tests.test_bootloader -tests/test_bootloader.py line 32 in TestLinuxBootloader.setUp() -tests/test_bootloader.py line 34 in TestLinuxBootloader.setUp() -tests/test_bootloader.py line 36 in TestLinuxBootloader.setUp() -tests/test_bootloader.py line 38 in TestLinuxBootloader.setUp() -************* Module tests.test_pci -tests/test_pci.py line 96 in TestPCIIds.test_videoclass_by_mock_calls() -tests/test_pci.py line 110 in TestPCIIds.mock_lspci_using_open_testfile() -``` - Of course, `xcp/net/ifrename` won't be affected but it would be good to fix the warning for them as well in an intelligent way. See the proposal for that below. diff --git a/README.md b/README.md index ee12582e..7189f780 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ open a recent workflow run the latest and scroll down until you see the tables! ## Installation and setup of the development environment -For the installation of the general development dependencies, visit [CONTRIBUTING.md](CONTRIBUTING.md) +For the installation of the general development dependencies, visit [CONTRIBUTING.md] ## Static analysis using mypy, pylint, pyright and pytype @@ -112,7 +112,7 @@ As proof, these examples show how the comment below triggers the checks: mypy: -```py +```sh $ mypy xcp/xmlunwrap.py xcp/xmlunwrap.py:31: error: Name "Element" is not defined xcp/xmlunwrap.py:38: error: Incompatible return value type (got "bytes", expected "str") @@ -120,7 +120,7 @@ xcp/xmlunwrap.py:38: error: Incompatible return value type (got "bytes", expecte pyright (used by VS Code by default): -```py +```sh $ pyright xcp/xmlunwrap.py|sed "s|$PWD/||" ... pyright 1.1.295 @@ -141,7 +141,7 @@ See for the context of this e ## Guidelines Charset encoding/string handling: -See [README-Unicode.md](README-Unicode.md) for details on Unicode support. +See [README-Unicode.md] for details on Unicode support. ## Users @@ -174,7 +174,7 @@ See [README-Unicode.md](README-Unicode.md) for details on Unicode support. Verification: -```ps +```py # rpm -qf $(grep -r import /usr/libexec/ /usr/bin /etc/xapi.d/ /opt/xensource/|grep xcp|cut -d: -f1|grep -v Binary) --qf '%{name}\n'|sort -u|tee xcp-python-libs-importers.txt host-upgrade-plugin interface-rename diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..e37b355b --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +sphinx +sphinx-autodoc-typehints +furo +myst_parser \ No newline at end of file diff --git a/docs/source/accessor.rst b/docs/source/accessor.rst new file mode 100644 index 00000000..0c700e53 --- /dev/null +++ b/docs/source/accessor.rst @@ -0,0 +1,7 @@ +xcp.accessor +============= + +.. automodule:: xcp.accessor + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst new file mode 100644 index 00000000..b73023df --- /dev/null +++ b/docs/source/bootloader.rst @@ -0,0 +1,7 @@ +xcp.bootloader +============== + +.. automodule:: xcp.bootloader + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/cmd.rst b/docs/source/cmd.rst new file mode 100644 index 00000000..2342f05e --- /dev/null +++ b/docs/source/cmd.rst @@ -0,0 +1,7 @@ +xcp.cmd +======= + +.. automodule:: xcp.cmd + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/compat.rst b/docs/source/compat.rst new file mode 100644 index 00000000..708684c0 --- /dev/null +++ b/docs/source/compat.rst @@ -0,0 +1,7 @@ +xcp.compat +========== + +.. automodule:: xcp.compat + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..cfcdc4e4 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,57 @@ +# Configuration file for the Sphinx documentation builder. +# -- Path setup ------------------------------------------------------------- +import logging +import os +import sys + +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# Add project root to sys.path for autodoc to find xcp modules and it allows +# to {include} the toplevel README.md files from their wrapper files here. +sys.path.insert(0, os.path.abspath("../..")) + +# Add stubs directory to sys.path for stubs (xcp/bootloader.py needs a branding.py) +sys.path.insert(0, os.path.abspath("../../stubs")) + +# +# To support Markdown-based documentation, Sphinx can use MyST-Parser. +# MyST-Parser is a Docutils bridge to markdown-it-py, a Python package +# for parsing the CommonMark Markdown flavor. +# See https://myst-parser.readthedocs.io/en/latest/ for details. +# Set the log level of markdown-it log categories to INFO to disable DEBUG +# logging and prevent flooding the logs with many 1000s of DEBUG messages: +# +logging.getLogger("markdown_it.rules_block").setLevel(logging.INFO) +logging.getLogger("markdown_it.rules_inline").setLevel(logging.INFO) +logging.getLogger("markdown_it").setLevel(logging.INFO) + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "python-libs" +copyright = "2025, Citrix Inc." +author = "Citrix Inc." +from datetime import datetime + +release = datetime.now().strftime("%Y.%m.%d-%H%M") + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.githubpages", + "myst_parser", +] + +templates_path = ["_templates"] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "furo" +html_static_path = ["_static"] diff --git a/docs/source/cpiofile.rst b/docs/source/cpiofile.rst new file mode 100644 index 00000000..05790d87 --- /dev/null +++ b/docs/source/cpiofile.rst @@ -0,0 +1,7 @@ +xcp.cpiofile +============ + +.. automodule:: xcp.cpiofile + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/dmv.rst b/docs/source/dmv.rst new file mode 100644 index 00000000..89fc998d --- /dev/null +++ b/docs/source/dmv.rst @@ -0,0 +1,7 @@ +xcp.dmv +======= + +.. automodule:: xcp.dmv + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/dom0.rst b/docs/source/dom0.rst new file mode 100644 index 00000000..3f17076b --- /dev/null +++ b/docs/source/dom0.rst @@ -0,0 +1,7 @@ +xcp.dom0 +======== + +.. automodule:: xcp.dom0 + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/environ.rst b/docs/source/environ.rst new file mode 100644 index 00000000..9d9c15f6 --- /dev/null +++ b/docs/source/environ.rst @@ -0,0 +1,7 @@ +xcp.environ +=========== + +.. automodule:: xcp.environ + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/include-toplevel-CONTRIBUTING.md b/docs/source/include-toplevel-CONTRIBUTING.md new file mode 100644 index 00000000..b007eebc --- /dev/null +++ b/docs/source/include-toplevel-CONTRIBUTING.md @@ -0,0 +1,2 @@ +```{include} ../../CONTRIBUTING.md +:parser: myst \ No newline at end of file diff --git a/docs/source/include-toplevel-DOCUMENTING.md b/docs/source/include-toplevel-DOCUMENTING.md new file mode 100644 index 00000000..e56d3fb9 --- /dev/null +++ b/docs/source/include-toplevel-DOCUMENTING.md @@ -0,0 +1,2 @@ +```{include} ../../DOCUMENTING.md +:parser: myst \ No newline at end of file diff --git a/docs/source/include-toplevel-README-Unicode.md b/docs/source/include-toplevel-README-Unicode.md new file mode 100644 index 00000000..a64fb4f2 --- /dev/null +++ b/docs/source/include-toplevel-README-Unicode.md @@ -0,0 +1,2 @@ +```{include} ../../README-Unicode.md +:parser: myst \ No newline at end of file diff --git a/docs/source/include-toplevel-README.md b/docs/source/include-toplevel-README.md new file mode 100644 index 00000000..6c5b587c --- /dev/null +++ b/docs/source/include-toplevel-README.md @@ -0,0 +1,2 @@ +```{include} ../../README.md +:parser: myst \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..c4c3da95 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,40 @@ +.. python-libs documentation master file, created by + sphinx-quickstart on Tue Aug 26 19:05:28 2025. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +python-libs documentation +========================= + +.. toctree:: + :maxdepth: 2 + :caption: Project Documentation + + include-toplevel-README.md + include-toplevel-CONTRIBUTING.md + include-toplevel-DOCUMENTING.md + include-toplevel-README-Unicode.md + +.. toctree:: + :maxdepth: 2 + :caption: XCP Python Modules + + accessor + bootloader + cmd + compat + cpiofile + dmv + dom0 + environ + logger + mount + pci + repository + version + xmlunwrap + +Welcome to the python-libs documentation! + +Each module is documented in its own section. Select a module from the menu to view its API documentation. + diff --git a/docs/source/logger.rst b/docs/source/logger.rst new file mode 100644 index 00000000..8bfdded3 --- /dev/null +++ b/docs/source/logger.rst @@ -0,0 +1,7 @@ +xcp.logger +========== + +.. automodule:: xcp.logger + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/modules.txt b/docs/source/modules.txt new file mode 100644 index 00000000..58fc64aa --- /dev/null +++ b/docs/source/modules.txt @@ -0,0 +1,14 @@ +xcp.accessor +xcp.bootloader +xcp.cmd +xcp.compat +xcp.cpiofile +xcp.dmv +xcp.dom0 +xcp.environ +xcp.logger +xcp.mount +xcp.pci +xcp.repository +xcp.version +xcp.xmlunwrap diff --git a/docs/source/mount.rst b/docs/source/mount.rst new file mode 100644 index 00000000..40237016 --- /dev/null +++ b/docs/source/mount.rst @@ -0,0 +1,7 @@ +xcp.mount +========= + +.. automodule:: xcp.mount + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/pci.rst b/docs/source/pci.rst new file mode 100644 index 00000000..9c99db22 --- /dev/null +++ b/docs/source/pci.rst @@ -0,0 +1,7 @@ +xcp.pci +======= + +.. automodule:: xcp.pci + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/repository.rst b/docs/source/repository.rst new file mode 100644 index 00000000..7e4915a0 --- /dev/null +++ b/docs/source/repository.rst @@ -0,0 +1,7 @@ +xcp.repository +============== + +.. automodule:: xcp.repository + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/version.rst b/docs/source/version.rst new file mode 100644 index 00000000..af9ca1fe --- /dev/null +++ b/docs/source/version.rst @@ -0,0 +1,7 @@ +xcp.version +=========== + +.. automodule:: xcp.version + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/xmlunwrap.rst b/docs/source/xmlunwrap.rst new file mode 100644 index 00000000..abedbc31 --- /dev/null +++ b/docs/source/xmlunwrap.rst @@ -0,0 +1,7 @@ +xcp.xmlunwrap +============= + +.. automodule:: xcp.xmlunwrap + :members: + :undoc-members: + :show-inheritance: diff --git a/xcp/accessor.py b/xcp/accessor.py index afdb643d..bed4e80f 100644 --- a/xcp/accessor.py +++ b/xcp/accessor.py @@ -440,13 +440,15 @@ def createAccessor(baseAddress, *args): For all Accessors, the 1st arg after the address is type bool for ro (readonly flag) The DeviceAccessor accepts a 3rd argument: a List[] of filesystem names - Examples: + Example usage:: + accessor = createAccessor("http://example.com", True) accessor = createAccessor("dev://example.com", True, ['iso9660', 'ext3']) if not accessor: fatal() else: accessor.read() + """ url_parts = urllib.parse.urlsplit(baseAddress, allow_fragments=False) diff --git a/xcp/cpiofile.py b/xcp/cpiofile.py index ff8f5c7c..cc98d2d0 100644 --- a/xcp/cpiofile.py +++ b/xcp/cpiofile.py @@ -925,13 +925,13 @@ class CpioFile(six.Iterator): def __init__(self, name=None, mode="r", fileobj=None): # type:(str | None, str, Optional[IO[bytes] | GzipFile | _Stream]) -> None - """Open an (uncompressed) cpio archive `name'. `mode' is either 'r' to - read from an existing archive, 'a' to append data to an existing - file or 'w' to create a new file overwriting an existing one. `mode' - defaults to 'r'. - If `fileobj' is given, it is used for reading or writing data. If it - can be determined, `mode' is overridden by `fileobj's mode. - `fileobj' is not closed, when CpioFile is closed. + """Open an (uncompressed) cpio archive `name'. `mode` is either `r` to + read from an existing archive, `a` to append data to an existing + file or `w` to create a new file overwriting an existing one. `mode` + defaults to `r`. + If `fileobj` is given, it is used for reading or writing data. If it + can be determined, `mode` is overridden by `fileobj`'s mode. + `fileobj` is not closed, when CpioFile is closed. """ if len(mode) > 1 or mode not in "raw": raise ValueError("mode must be 'r', 'a' or 'w'") @@ -1003,26 +1003,27 @@ def open(cls, name=None, mode="r", fileobj=None, bufsize=20*512): an appropriate CpioFile class. mode: - 'r' or 'r:*' open for reading with transparent compression - 'r:' open for reading exclusively uncompressed - 'r:gz' open for reading with gzip compression - 'r:bz2' open for reading with bzip2 compression - 'r:xz' open for reading with xz compression - 'a' or 'a:' open for appending - 'w' or 'w:' open for writing without compression - 'w:gz' open for writing with gzip compression - 'w:bz2' open for writing with bzip2 compression - 'w:xz' open for writing with xz compression - - 'r|*' open a stream of cpio blocks with transparent compression - 'r|' open an uncompressed stream of cpio blocks for reading - 'r|gz' open a gzip compressed stream of cpio blocks - 'r|bz2' open a bzip2 compressed stream of cpio blocks - 'r|xz' open a xz compressed stream of cpio blocks - 'w|' open an uncompressed stream for writing - 'w|gz' open a gzip compressed stream for writing - 'w|bz2' open a bzip2 compressed stream for writing - 'w|xz' open a xz compressed stream for writing + + - ``r`` or ``r:*`` open for reading with transparent compression + - ``r:`` open for reading exclusively uncompressed + - ``r:gz`` open for reading with gzip compression + - ``r:bz2`` open for reading with bzip2 compression + - ``r:xz`` open for reading with xz compression + - ``a`` or ``a:`` open for appending + - ``w`` or ``w:`` open for writing without compression + - ``w:gz`` open for writing with gzip compression + - ``w:bz2`` open for writing with bzip2 compression + - ``w:xz`` open for writing with xz compression + + - ``r|*`` open a stream of cpio blocks with transparent compression + - ``r|`` open an uncompressed stream of cpio blocks for reading + - ``r|gz`` open a gzip compressed stream of cpio blocks + - ``r|bz2`` open a bzip2 compressed stream of cpio blocks + - ``r|xz`` open a xz compressed stream of cpio blocks + - ``w|`` open an uncompressed stream for writing + - ``w|gz`` open a gzip compressed stream for writing + - ``w|bz2`` open a bzip2 compressed stream for writing + - ``w|xz`` open a xz compressed stream for writing """ if not name and not fileobj: @@ -1182,9 +1183,9 @@ def close(self): def getmember(self, name): # type:(str | bytes) -> CpioInfo - """Return a CpioInfo object for member `name'. If `name' can not be + """Return a CpioInfo object for member `name`. If `name` can not be found in the archive, KeyError is raised. If a member occurs more - than once in the archive, its last occurence is assumed to be the + than once in the archive, its last occurrence is assumed to be the most up-to-date version. """ cpioinfo = self._getmember(name) @@ -1210,10 +1211,10 @@ def getnames(self): return [cpioinfo.name for cpioinfo in self.getmembers()] def getcpioinfo(self, name=None, arcname=None, fileobj=None): - """Create a CpioInfo object for either the file `name' or the file - object `fileobj' (using os.fstat on its file descriptor). You can + """Create a CpioInfo object for either the file `name` or the file + object `fileobj` (using os.fstat on its file descriptor). You can modify some of the CpioInfo's attributes before you add it using - addfile(). If given, `arcname' specifies an alternative name for the + addfile(). If given, `arcname` specifies an alternative name for the file in the archive. """ self._check("aw") @@ -1274,8 +1275,8 @@ def getcpioinfo(self, name=None, arcname=None, fileobj=None): return cpioinfo def list(self, verbose=True): - """Print a table of contents to sys.stdout. If `verbose' is False, only - the names of the members are printed. If it is True, an `ls -l'-like + """Print a table of contents to sys.stdout. If `verbose` is False, only + the names of the members are printed. If it is True, an `ls -l`-like output is produced. """ self._check() @@ -1300,11 +1301,11 @@ def list(self, verbose=True): print() def add(self, name, arcname=None, recursive=True): - """Add the file `name' to the archive. `name' may be any type of file - (directory, fifo, symbolic link, etc.). If given, `arcname' + """Add the file `name` to the archive. `name` may be any type of file + (directory, fifo, symbolic link, etc.). If given, `arcname` specifies an alternative name for the file in the archive. Directories are added recursively by default. This can be avoided by - setting `recursive' to False. + setting `recursive` to False. """ self._check("aw") @@ -1351,10 +1352,10 @@ def add(self, name, arcname=None, recursive=True): self.addfile(cpioinfo) def addfile(self, cpioinfo, fileobj=None): - """Add the CpioInfo object `cpioinfo' to the archive. If `fileobj' is + """Add the CpioInfo object `cpioinfo` to the archive. If `fileobj` is given, cpioinfo.size bytes are read from it and added to the archive. You can create CpioInfo objects using getcpioinfo(). - On Windows platforms, `fileobj' should always be opened with mode + On Windows platforms, `fileobj` should always be opened with mode 'rb' to avoid irritation about the file size. """ self._check("aw") @@ -1389,8 +1390,8 @@ def addfile(self, cpioinfo, fileobj=None): def extractall(self, path=".", members=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the + directories afterwards. `path` specifies a different directory + to extract to. `members` is optional and must be a subset of the list returned by getmembers(). """ directories = [] @@ -1430,8 +1431,8 @@ def extractall(self, path=".", members=None): def extract(self, member, path=""): """Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately - as possible. `member' may be a filename or a CpioInfo object. You can - specify a different directory using `path'. + as possible. `member` may be a filename or a CpioInfo object. You can + specify a different directory using `path`. """ self._check("r") @@ -1462,10 +1463,10 @@ def extract(self, member, path=""): def extractfile(self, member): # type:(CpioInfo | str | bytes) -> ExFileObject | None - """Extract a member from the archive as a file object. `member' may be - a filename or a CpioInfo object. If `member' is a regular file, a - file-like object is returned. If `member' is a link, a file-like - object is constructed from the link's target. If `member' is none of + """Extract a member from the archive as a file object. `member` may be + a filename or a CpioInfo object. If `member` is a regular file, a + file-like object is returned. If `member` is a link, a file-like + object is constructed from the link's target. If `member` is none of the above, None is returned. The file-like object is read-only and provides the following methods: read(), readline(), readlines(), seek() and tell()