summaryrefslogtreecommitdiffstats
path: root/doc/source/tutorials
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 18:07:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 18:07:41 +0000
commit76926159194e180003aa78de97e5f287bf4325a5 (patch)
tree2cea7245cdc3f66355900c820c145eba90598766 /doc/source/tutorials
parentInitial commit. (diff)
downloadpython-apt-76926159194e180003aa78de97e5f287bf4325a5.tar.xz
python-apt-76926159194e180003aa78de97e5f287bf4325a5.zip
Adding upstream version 2.7.6.upstream/2.7.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/source/tutorials')
-rw-r--r--doc/source/tutorials/apt-cdrom.rst156
-rw-r--r--doc/source/tutorials/apt-get.rst46
-rw-r--r--doc/source/tutorials/contributing.rst315
-rw-r--r--doc/source/tutorials/index.rst8
4 files changed, 525 insertions, 0 deletions
diff --git a/doc/source/tutorials/apt-cdrom.rst b/doc/source/tutorials/apt-cdrom.rst
new file mode 100644
index 0000000..7e1d794
--- /dev/null
+++ b/doc/source/tutorials/apt-cdrom.rst
@@ -0,0 +1,156 @@
+Writing your own apt-cdrom
+==========================
+:Author: Julian Andres Klode <jak@debian.org>
+:Release: |release|
+:Date: |today|
+
+This article explains how to utilise python-apt to build your own clone of the
+:command:`apt-cdrom` command. To do this, we will take a look at the
+:mod:`apt.cdrom` and :mod:`apt.progress.text` modules, and we will learn how
+to use apt_pkg.parse_commandline to parse commandline arguments. The code shown
+here works on Python 2 and Python 3.
+
+Basics
+------
+The first step in building your own :command:`apt-cdrom` clone is to import the
+:mod:`apt` package, which will import :mod:`apt.cdrom` and
+:mod:`apt.progress.text`::
+
+ import apt
+
+Now we have to create a new :class:`apt.cdrom.Cdrom` object and pass to it an
+:class:`apt.progress.text.CdromProgress` object, which is responsible for
+displaying the progress and asking questions::
+
+ cdrom = apt.Cdrom(apt.progress.text.CdromProgress())
+
+Now we have to choose the action, depending on the given options on the
+command line. For now, we simply use the value of ``sys.argv[1]``::
+
+ import sys
+ if sys.argv[1] == 'add':
+ cdrom.add()
+ elif sys.argv[1] == 'ident':
+ cdrom.ident()
+
+Now we have a basic :command:`apt-cdrom` clone which can add and identify
+CD-ROMs::
+
+ import sys
+
+ import apt
+
+ cdrom = apt.Cdrom(apt.progress.text.CdromProgress())
+ if sys.argv[1] == 'add':
+ cdrom.add()
+ elif sys.argv[1] == 'ident':
+ cdrom.ident()
+
+Advanced example with command-line parsing
+-------------------------------------------
+Our example clearly misses a way to parse the commandline in a correct
+manner. Luckily, :mod:`apt_pkg` provides us with a function to do this:
+:func:`apt_pkg.parse_commandline`. To use it, we add ``import apt_pkg`` right
+after import apt::
+
+ import sys
+
+ import apt_pkg
+ import apt
+
+
+:func:`apt_pkg.parse_commandline` is similar to :mod:`getopt` functions, it
+takes a list of recognized options and the arguments and returns all unknown
+arguments. If it encounters an unknown argument which starts with a leading
+'-', the function raises an error indicating that the option is unknown. The
+major difference is that this function manipulates the apt configuration space.
+
+The function takes 3 arguments. The first argument is an
+:class:`apt_pkg.Configuration` object. The second argument is a list of tuples
+of the form ``(shortopt, longopt, config, type)``, whereas *shortopt* is a
+character indicating the short option name, *longopt* a string indicating the
+corresponding long option (e.g. ``"--help"``), *config* the name of the
+configuration item which should be set and *type* the type of the argument.
+
+For apt-cdrom, we can use the following statement::
+
+ arguments = apt_pkg.parse_commandline(apt_pkg.config,
+ [('h', "help", "help"),
+ ('v', "version", "version"),
+ ('d', "cdrom", "Acquire::cdrom::mount", "HasArg"),
+ ('r', "rename", "APT::CDROM::Rename"),
+ ('m', "no-mount", "APT::CDROM::NoMount"),
+ ('f', "fast", "APT::CDROM::Fast"),
+ ('n', "just-print", "APT::CDROM::NoAct"),
+ ('n', "recon", "APT::CDROM::NoAct"),
+ ('n', "no-act", "APT::CDROM::NoAct"),
+ ('a', "thorough", "APT::CDROM::Thorough"),
+ ('c', "config-file", "", "ConfigFile"),
+ ('o', "option", "", "ArbItem")], args)
+
+
+This allows us to support all options supported by apt-cdrom. The first option
+is --help. As you can see, it omits the fourth field of the tuple; which means
+it is a boolean argument. Afterwards you could use
+``apt_pkg.config.find_b("help")`` to see whether ``--help`` was specified. In
+``('d',"cdrom","Acquire::cdrom::mount","HasArg")`` the fourth field is
+``"HasArg"``. This means that the option has an argument, in this case the
+location of the mount point. ``('c',"config-file","","ConfigFile")`` shows how
+to include configuration files. This option takes a parameter which points to
+a configuration file which will be added to the configuration space.
+``('o',"option","","ArbItem")`` is yet another type of option, which allows users
+to set configuration options on the commandline.
+
+Now we have to check whether help or version is specified, and print a message
+and exit afterwards. To do this, we use :meth:`apt_pkg.Configuration.find_b`
+which returns ``True`` if the configuration option exists and evaluates to
+``True``::
+
+ if apt_pkg.config.find_b("help"):
+ print("This should be a help message")
+ sys.exit(0)
+ elif apt_pkg.config.find_b("version"):
+ print("Version blah.")
+ sys.exit(0)
+
+
+Now we are ready to create our progress object and our cdrom object. Instead
+of using :class:`apt.Cdrom` like in the first example, we will use
+:class:`apt_pkg.Cdrom` which provides a very similar interface. We could also
+use :class:`apt.Cdrom`, but `apt.Cdrom` provides options like *nomount* which
+conflict with our commandline parsing::
+
+ progress = apt.progress.text.CdromProgress()
+ cdrom = apt_pkg.Cdrom()
+
+
+Now we have to do the action requested by the user on the commandline. To see
+which option was requested, we check the list ``arguments`` which was returned
+by ``apt_pkg.parse_commandline`` above, and afterwards call ``cdrom.add`` or
+``cdrom.ident``::
+
+ if apt_pkg.config.find_b("help"):
+ print("This should be a help message")
+ sys.exit(0)
+ elif apt_pkg.config.find_b("version"):
+ print("Version blah.")
+ sys.exit(0)
+
+ if not arguments:
+ sys.stderr.write('E: No operation specified\n')
+ sys.exit(1)
+ elif arguments[0] == 'add':
+ cdrom.add(progress)
+ elif arguments[0] == 'ident':
+ cdrom.ident(progress)
+ else:
+ sys.stderr.write('E: Invalid operation %s\n' % arguments[0])
+ sys.exit(1)
+
+
+After putting all our actions into a main() function, we get a completely
+working apt-cdrom clone, which just misses useful ``--help`` and ``--version``
+options. If we add a function show_help(), we get an even more complete
+apt-cdrom clone:
+
+.. literalinclude:: ../examples/apt-cdrom.py
diff --git a/doc/source/tutorials/apt-get.rst b/doc/source/tutorials/apt-get.rst
new file mode 100644
index 0000000..26ebc3d
--- /dev/null
+++ b/doc/source/tutorials/apt-get.rst
@@ -0,0 +1,46 @@
+Doing stuff :command:`apt-get` does
+===================================
+:Author: Julian Andres Klode <jak@debian.org>
+:Release: |release|
+:Date: |today|
+
+The following article will show how you can use python-apt to do actions done
+by the :command:`apt-get` command.
+
+
+Printing the URIs of all index files
+------------------------------------
+We all now that we can print the URIs of all our index files by running a
+simple ``apt-get --print-uris update``. We can do the same. Responsible for
+the source entries is the class :class:`apt_pkg.SourceList`, which can be
+combined with an :class:`apt_pkg.Acquire` object using :meth:`get_indexes`.
+
+First of all, we have to create the objects::
+
+ acquire = apt_pkg.Acquire()
+ slist = apt_pkg.SourceList()
+
+Now we have to parse /etc/apt/sources.list and its friends, by using
+:meth:`apt_pkg.SourceList.read_main_list`::
+
+ slist.read_main_list()
+
+The **slist** object now knows about the location of the indexes. We now have
+to load those indexes into the *acquire* object by calling
+:meth:`apt_pkg.SourceList.get_indexes`::
+
+ slist.get_indexes(acquire, True)
+
+The first argument is the acquire object into which we will load these indexes,
+and the second argument means that we want to fetch all indexes. Now the only
+thing left to do is iterating over the list of items and printing out their
+URIs. Luckily, there is :attr:`apt_pkg.Acquire.items` which allows us to
+iterate over the items::
+
+ for item in acquire.items:
+ print(item.desc_uri)
+
+In the end a program could look like this:
+
+.. literalinclude:: ../examples/update-print-uris.py
+
diff --git a/doc/source/tutorials/contributing.rst b/doc/source/tutorials/contributing.rst
new file mode 100644
index 0000000..33f1654
--- /dev/null
+++ b/doc/source/tutorials/contributing.rst
@@ -0,0 +1,315 @@
+Contributing to python-apt
+==========================
+:Author: Julian Andres Klode <jak@debian.org>
+:Release: |release|
+:Date: |today|
+
+Let's say you need a new feature, you can develop it, and you want to get it
+included in python-apt. Then be sure to follow the following guidelines.
+
+Available branches
+-------------------
+First of all, let's talk a bit about the git branches of python-apt. In the
+following parts, we will assume that you use git to create your changes and
+submit them.
+
+Repositories
+^^^^^^^^^^^^
+
+https://salsa.debian.org/apt-team/python-apt.git
+
+ This is the official Debian repository of python-apt.
+ You can clone it using git by doing::
+
+ git clone git://salsa.debian.org/apt-team/python-apt.git
+
+
+ All code which will be uploaded to Debian is here.
+ There are also branches for Ubuntu releases, but those may not be up-to-date.
+
+ Branch names consist of the distribution vendor, followed by a slash,
+ followed by the release of that distribution, for example: ``debian/sid``.
+
+ The current working branch is usually pointed to by ``HEAD``, it is
+ either ``debian/sid`` or ``debian/experimental``.
+
+ If both sid and experimental are active, bug fixes are either cherry-picked from
+ ``debian/experimental`` to ``debian/sid``, or a new release is cut on the sid branch
+ and then merged into experimental.
+
+ Updates to stable release branches, such as ``debian/wheezy``, are almost always
+ cherry-picked or backported from the ``debian/sid`` branch.
+
+
+.. highlight:: cpp
+
+C++ Coding style
+----------------
+This document gives coding conventions for the C++ code comprising
+the C++ extensions of Python APT. Please see the companion
+informational PEP describing style guidelines for Python code (:PEP:`8`).
+
+Note, rules are there to be broken. Two good reasons to break a
+particular rule:
+
+ (1) When applying the rule would make the code less readable, even
+ for someone who is used to reading code that follows the rules.
+
+ (2) To be consistent with surrounding code that also breaks it
+ (maybe for historic reasons) -- although this is also an
+ opportunity to clean up someone else's mess (in true XP style).
+
+This part of the document is derived from :PEP:`7` which was written by
+Guido van Rossum.
+
+
+C++ dialect
+^^^^^^^^^^^
+
+- Use ISO standard C++ (the 2011 version of the standard), headers
+ should also adhere to the 1998 version of the standard.
+
+- Use C++ style // one-line comments for single-line comments.
+
+- No compiler warnings with ``gcc -std=c++11 -Wall -Wno-write-strings``. There
+ should also be no errors with ``-pedantic`` added.
+
+
+Code lay-out
+^^^^^^^^^^^^
+
+- Use 3-space indents, in files that already use them. In new source files,
+ that were created after this rule was introduced, use 4-space indents.
+
+ At some point, the whole codebase may be converted to use only
+ 4-space indents.
+
+- No line should be longer than 79 characters. If this and the
+ previous rule together don't give you enough room to code, your
+ code is too complicated -- consider using subroutines.
+
+- No line should end in whitespace. If you think you need
+ significant trailing whitespace, think again -- somebody's
+ editor might delete it as a matter of routine.
+
+- Function definition style: function name in column 2, outermost
+ curly braces in column 1, blank line after local variable
+ declarations::
+
+ static int extra_ivars(PyTypeObject *type, PyTypeObject *base)
+ {
+ int t_size = PyType_BASICSIZE(type);
+ int b_size = PyType_BASICSIZE(base);
+
+ assert(t_size >= b_size); /* type smaller than base! */
+ ...
+ return 1;
+ }
+
+- Code structure: one space between keywords like 'if', 'for' and
+ the following left paren; no spaces inside the paren; braces as
+ shown::
+
+ if (mro != NULL) {
+ ...
+ }
+ else {
+ ...
+ }
+
+- The return statement should *not* get redundant parentheses::
+
+ return Py_None; /* correct */
+ return(Py_None); /* incorrect */
+
+- Function and macro call style: ``foo(a, b, c)`` -- no space before
+ the open paren, no spaces inside the parens, no spaces before
+ commas, one space after each comma.
+
+- Always put spaces around assignment, Boolean and comparison
+ operators. In expressions using a lot of operators, add spaces
+ around the outermost (lowest-priority) operators.
+
+- Breaking long lines: if you can, break after commas in the
+ outermost argument list. Always indent continuation lines
+ appropriately, e.g.::
+
+ PyErr_Format(PyExc_TypeError,
+ "cannot create '%.100s' instances",
+ type->tp_name);
+
+- When you break a long expression at a binary operator, the
+ operator goes at the end of the previous line, e.g.::
+
+ if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 &&
+ type->tp_dictoffset == b_size &&
+ (size_t)t_size == b_size + sizeof(PyObject *))
+ return 0; /* "Forgive" adding a __dict__ only */
+
+- Put blank lines around functions, structure definitions, and
+ major sections inside functions.
+
+- Comments go before the code they describe.
+
+- All functions and global variables should be declared static
+ unless they are to be part of a published interface
+
+
+Naming conventions
+^^^^^^^^^^^^^^^^^^
+
+- Use a ``Py`` prefix for public functions; never for static
+ functions. The ``Py_`` prefix is reserved for global service
+ routines like ``Py_FatalError``; specific groups of routines
+ (e.g. specific object type APIs) use a longer prefix,
+ e.g. ``PyString_`` for string functions.
+
+- Public functions and variables use MixedCase with underscores,
+ like this: ``PyObject_GetAttr``, ``Py_BuildValue``, ``PyExc_TypeError``.
+
+- Internal functions and variables use lowercase with underscores, like
+ this: ``hashes_get_sha1.``
+
+- Occasionally an "internal" function has to be visible to the
+ loader; we use the _Py prefix for this, e.g.: ``_PyObject_Dump``.
+
+- Macros should have a MixedCase prefix and then use upper case,
+ for example: ``PyString_AS_STRING``, ``Py_PRINT_RAW``.
+
+
+Documentation Strings
+^^^^^^^^^^^^^^^^^^^^^
+- The first line of each function docstring should be a "signature
+ line" that gives a brief synopsis of the arguments and return
+ value. For example::
+
+ PyDoc_STRVAR(myfunction__doc__,
+ "myfunction(name: str, value) -> bool\n\n"
+ "Determine whether name and value make a valid pair.");
+
+ The signature line should be formatted using the format for function
+ annotations described in :PEP:`3107`, whereas the annotations shall reflect
+ the name of the type (e.g. ``str``). The leading ``def`` and the trailing
+ ``:`` as used for function definitions must not be included.
+
+ Always include a blank line between the signature line and the
+ text of the description.
+
+ If the return value for the function is always ``None`` (because
+ there is no meaningful return value), do not include the
+ indication of the return type.
+
+- When writing multi-line docstrings, be sure to always use
+ string literal concatenation::
+
+ PyDoc_STRVAR(myfunction__doc__,
+ "myfunction(name, value) -> bool\n\n"
+ "Determine whether name and value make a valid pair.");
+
+
+Python Coding Style
+-------------------
+The coding style for all code written in python is :PEP:`8`. Exceptions from
+this rule are the documentation, where code is sometimes formatted differently
+to explain aspects.
+
+When writing code, use tools like pylint, pyflakes, pychecker and pycodestyle
+(all available from Debian/Ubuntu) to verify that your code is
+OK. Fix all the problems which seem reasonable, and mention the unfixed issues
+when asking for merge.
+
+All code must work on both Python 2 and Python 3.
+
+Submitting your patch
+---------------------
+First of all, the patch you create should be based against the most current
+branch of python-apt (debian/sid or debian/experimental). If it is a bugfix,
+you should probably use debian/sid. If you choose the wrong branch, we will
+ask you to rebase your patches against the correct one.
+
+Once you have made your change, check that it:
+
+ * conforms to :PEP:`8` (checked with pycodestyle). It should, at least not
+ introduce new errors. (and never have whitespace at end of line)
+ * produces no new errors in pychecker, pyflakes and pylint (unless you
+ can't fix them, but please tell so when requesting the merge, so it can
+ be fixed before hitting one of the main branches).
+ * does not change the behaviour of existing code in a non-compatible way.
+ * works on both Python 2 and Python 3.
+
+If your change follows all points of the checklist, you can commit it to your
+repository. (You could commit it first, and check later, and then commit the
+fixes, but commits should be logical and it makes no sense to have to commits
+for one logical unit).
+
+The changelog message should follow standard git format. At the end of the
+message, tags understood by gbp-dch and other tags may be added. An example
+commit message could be:
+
+.. code-block:: none
+
+ apt.package: Fix blah blah
+
+ Fix a small bug where foo is doing bar, but should be doing baz
+ instead.
+
+ Closes: #bugnumber
+ LP: #ubuntu-bug-number
+ Reported-By: Bug Reporter Name <email@example.com>
+
+
+Once you have made all your changes, you can run ``git format-patch``,
+specifying the upstream commit or branch you want to create patches
+against. Then you can either:
+
+* report a bug against the python-apt package, attach the patches
+ you created in the previous step, and tag it with 'patch'. It might also be
+ a good idea to prefix the bug report with '[PATCH]'.
+
+* send the patches via ``git send-email``.
+
+For larger patch series, you can also publish a git branch on a
+public repository and request it to be pulled.
+
+If you choose that approach, you may want to base your patches against
+the latest release, and not against some random commit, for the sake of
+preserving a sane git history.
+
+Be prepared to rebase such a branch, and close any bugs you fix in the
+branch by mentioning them in the commit message using a Closes or LP
+tag.
+
+
+Documentation updates
+---------------------
+If you want to update the documentation, please follow the procedure as written
+above. You can send your content in plain text, but reStructuredText is the
+preferred format. I (Julian Andres Klode) will review your patch and include
+it.
+
+.. highlight:: sh
+
+Example patch session
+----------------------
+In the following example, we edit a file, create a patch (an enhanced
+patch), and report a wishlist bug with this patch against the python-apt
+package::
+
+ user@ pc:~$ git clone git://anonscm.debian.org/apt/python-apt.git
+ user@pc:~$ cd python-apt
+ user@pc:~/python-apt$ editor FILES
+ user@pc:~/python-apt$ pycodestyle FILES # Check with pycodestyle
+ user@pc:~/python-apt$ pylint -e FILES # Check with pylint
+ user@pc:~/python-apt$ pyflakes FILES # Check with pyflakes
+ user@pc:~/python-apt$ pychecker FILES # Check with pychecker
+ user@pc:~/python-apt$ git commit -p
+ user@pc:~/python-apt$ git format-patch origin/HEAD
+ user@pc:~/python-apt$ reportbug --severity=wishlist --tag=patch --attach=<patch> ... python-apt
+
+You may also send the patches to the mailing list instead of
+reporting the bug::
+
+ user@pc:~/python-apt$ git send-email --to=deity@lists.debian.org <patches created by format-patch>
+
+You can even push your changes to your own repository and request
+a pull request.
diff --git a/doc/source/tutorials/index.rst b/doc/source/tutorials/index.rst
new file mode 100644
index 0000000..06d31c6
--- /dev/null
+++ b/doc/source/tutorials/index.rst
@@ -0,0 +1,8 @@
+Tutorials
+=========
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ *