Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-ini2toml for openSUSE:Factory
checked in at 2024-05-05 12:10:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ini2toml (Old)
and /work/SRC/openSUSE:Factory/.python-ini2toml.new.1880 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ini2toml"
Sun May 5 12:10:27 2024 rev:10 rq:1171769 version:0.14
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ini2toml/python-ini2toml.changes
2024-03-21 17:00:29.824498110 +0100
+++
/work/SRC/openSUSE:Factory/.python-ini2toml.new.1880/python-ini2toml.changes
2024-05-05 12:10:33.839395439 +0200
@@ -1,0 +2,17 @@
+Fri May 3 07:41:22 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 0.14:
+ * Introduce LiteTranslator and FullTranslator as convenience
+ classes for more deterministic behaviour, :pr:`95`.
+ * setuptools plugin: Fix ValueError when setup.cfg contains
+ [options.packages.find] but also lists [options] packages =
+ ... explicitly as a list of package names, :issue:`93`.
+ * Fix ValueError when setup.cfg contains
+ [options.packages.find] but also lists [options] packages =
+ ... explicitly as a list of package names, :issue:`93`.
+ * pytest plugin: Remove comments when converting addopts with
+ multi-line values, :issue:`98`.
+ * Remove comments when converting addopts with multi-line
+ values, :issue:`98`.
+
+-------------------------------------------------------------------
Old:
----
ini2toml-0.13.tar.gz
New:
----
ini2toml-0.14.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-ini2toml.spec ++++++
--- /var/tmp/diff_new_pack.ZlgmL8/_old 2024-05-05 12:10:35.583458557 +0200
+++ /var/tmp/diff_new_pack.ZlgmL8/_new 2024-05-05 12:10:35.587458701 +0200
@@ -50,7 +50,7 @@
%define skip_python2 1
Name: python-ini2toml%{psuffix}
-Version: 0.13
+Version: 0.14
Release: 0
Summary: Automatic conversion of .ini/cfg files to TOML equivalents
License: MPL-2.0
@@ -157,6 +157,8 @@
%if %{with test}
%check
%if %{without all} && %{without full}
+rm -v src/ini2toml/drivers/configupdater.py
+rm -v src/ini2toml/drivers/full_toml.py
ignoretests=(
--ignore tests/test_examples.py
--ignore tests/test_transformations.py
++++++ ini2toml-0.13.tar.gz -> ini2toml-0.14.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/.cirrus.yml
new/ini2toml-0.14/.cirrus.yml
--- old/ini2toml-0.13/.cirrus.yml 2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/.cirrus.yml 2024-04-20 21:23:26.000000000 +0200
@@ -99,8 +99,7 @@
- name: test (Linux - 3.11)
container: {image: "python:3.11-bullseye"}
- name: test (Linux - 3.12)
- container: {image: "python:3.12-rc-bullseye"}
- allow_failures: true # Experimental
+ container: {image: "python:3.12-bullseye"}
install_script:
- python -m pip install --upgrade pip tox pipx
<<: *test-template
@@ -124,7 +123,7 @@
freebsd_task:
name: test (freebsd - 3.9)
- freebsd_instance: {image_family: freebsd-13-1}
+ freebsd_instance: {image_family: freebsd-14-0}
install_script:
- pkg remove -y python lang/python
- pkg install -y git python39 py39-pip py39-gdbm py39-sqlite3 py39-tox
py39-pipx py39-tomli
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/.pre-commit-config.yaml
new/ini2toml-0.14/.pre-commit-config.yaml
--- old/ini2toml-0.13/.pre-commit-config.yaml 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/.pre-commit-config.yaml 2024-04-20 21:23:26.000000000
+0200
@@ -2,7 +2,7 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: v4.6.0
hooks:
- id: trailing-whitespace
exclude: 'test_(.*)\.py$'
@@ -19,7 +19,7 @@
args: ['--fix=lf']
- repo: https://github.com/PyCQA/autoflake
- rev: v2.2.1
+ rev: v2.3.1
hooks:
- id: autoflake
args: [
@@ -29,12 +29,12 @@
]
- repo: https://github.com/PyCQA/isort
- rev: 5.12.0
+ rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/psf/black
- rev: 23.9.1
+ rev: 24.4.0
hooks:
- id: black
language_version: python3
@@ -51,13 +51,13 @@
- id: codespell # See setup.cfg for args
- repo: https://github.com/PyCQA/flake8
- rev: 6.1.0
+ rev: 7.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear>=23.2.13]
- repo: https://github.com/asottile/pyupgrade
- rev: v3.15.0
+ rev: v3.15.2
hooks:
- id: pyupgrade
args:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/CHANGELOG.rst
new/ini2toml-0.14/CHANGELOG.rst
--- old/ini2toml-0.13/CHANGELOG.rst 2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/CHANGELOG.rst 2024-04-20 21:23:26.000000000 +0200
@@ -2,6 +2,21 @@
Changelog
=========
+Version 0.14
+============
+
+* Introduce ``LiteTranslator`` and ``FullTranslator`` as
+ convenience classes for more deterministic behaviour, :pr:`95`.
+* ``setuptools`` plugin:
+
+ * Fix ``ValueError`` when ``setup.cfg`` contains ``[options.packages.find]``
+ but also lists ``[options] packages = ...`` explicitly as a list of package
+ names, :issue:`93`.
+
+* ``pytest`` plugin:
+
+ * Remove comments when converting ``addopts`` with multi-line values,
:issue:`98`.
+
Version 0.13
============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/CONTRIBUTING.rst
new/ini2toml-0.14/CONTRIBUTING.rst
--- old/ini2toml-0.13/CONTRIBUTING.rst 2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/CONTRIBUTING.rst 2024-04-20 21:23:26.000000000 +0200
@@ -77,9 +77,9 @@
==================
Understanding how the project works
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------------
-If you have a change in mind, please have a look in our :doc:`dev-guide`.
+If you have a change in mind, please have a look in our :doc:`/dev-guide`.
It explains the main aspects of the project and provide a brief overview on how
it is organised and how to implement :ref:`plugins`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/PKG-INFO new/ini2toml-0.14/PKG-INFO
--- old/ini2toml-0.13/PKG-INFO 2023-10-23 14:17:02.442848400 +0200
+++ new/ini2toml-0.14/PKG-INFO 2024-04-20 21:24:34.163375100 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: ini2toml
-Version: 0.13
+Version: 0.14
Summary: Automatically conversion of .ini/.cfg files to TOML equivalents
Home-page: https://github.com/abravalheri/ini2toml/
Author: Anderson Bravalheri
@@ -138,9 +138,86 @@
To do so, don't forget to add it to your `virtual environment`_ or specify it
as a
`project dependency`_.
+Note that the class ``Translator`` will try to guess which flavour to use based
+on the available installed dependencies. If you need something more
+deterministic, consider using ``LiteTranslator`` and ``FullTranslator``,
+or explicitly specifying the ``ini_loads_fn`` and ``toml_dumps_fn`` keyword
+arguments in the constructor.
+
More details about ``ini2toml`` and its Python API can be found in `our docs`_.
+Limitations
+===========
+
+``ini2toml`` will try its best to create good quality translations from
+``.ini/.cfg`` into ``.toml`` files. However the tool comes with a set of
+well known limitations:
+
+* Although ``ini2toml`` attempts to keep the same order/sequence as the
original
+ information was written, sometimes that is not compatible with the TOML
+ syntax, and things end up moving around a bit.
+
+* ``ini2toml`` uses `ConfigParser`_ + `tomli-w`_ for implementing the *"lite"*
flavour
+ and `ConfigUpdater`_ + `tomlkit`_ for implementing the *"full"* flavour.
+ Therefore it inherits the limitations from those libraries (please check
+ their documentation for more information). For example:
+
+ * `ConfigUpdater`_, will have trouble to parse interpolations and the related
+ escaping sequence (``%%``) (in this respect, it behaves more similarly to
+ ``RawConfigParser`` than ``ConfigParser``).
+
+ * `tomli-w`_ is not very flexible regarding formatting and will have trouble
+ with multi-line strings.
+
+* ``ini2toml`` *expects the input to be valid* and will not perform extensive
+ checks on the provided document. If something in the output is not working
as you would
+ expect, it might be a good idea to check the input.
+
+* ``.ini/.cfg`` files are used in a plethora of use cases and it is impossible
+ to cover all of them in a single code base. Even when considering
+ ``setup.cfg``, there are many packages that define different sections in the
+ document in addition to the basic definition by ``setuptools``.
+ Because of that ``ini2toml``, adopts a "best-effort" approach, that might not
+ correspond to what you expect. If that is the case please consider
+ contributing or creating your own `plugin`_.
+
+* The translation procedure analyse only the given input. If the original
+ ``.ini/.cfg`` file contains references to other files, or behaves differently
+ depending on the existence/presence of other files and directories, the
+ translation will not take that into consideration.
+
+Therefore it is recommended to double check the output and fix any
+problems before using the ``.toml`` files in production.
+
+
+Can ``ini2toml`` also translate ``setup.py`` into ``pyproject.toml``?
+=====================================================================
+
+Working with ``.py`` files is not in the scope of the ``ini2toml`` project,
+and therefore this feature is not implemented.
+
+However, you can probably find some tools on PyPI to translate from
+``setup.py`` into ``setup.cfg``, like `setup-py-upgrade`_ and
+`setuptools-py2cfg`_ [#untested]_.
+
+Once you have ``setup.cfg``, you can use ``ini2toml`` [#setuppy]_.
+
+.. [#untested] Such tools are neither maintained by this project,
+ nor tested for integration by ``ini2toml``.
+ It is best to try some of them out and find the one that works for you.
+ Manual corrections might be needed.
+
+.. [#setuppy] Please note that ``setup.py`` is a very dynamic
+ format and that not everything can be represented in ``setup.cfg`` or
+ ``pyproject.toml``. Indeed, the `setuptools' docs`_ explicitly say that
+ ``setup.py`` can be used in tandem with ``pyproject.toml``: ideally all the
+ declarative metadata goes to ``pyproject.toml``, but you can keep the
+ dynamic bits in ``setup.py``.
+ Remember: ``setup.py`` is a perfectly valid and non deprecated
configuration file;
+ what is deprecated is running it as a CLI tool, i.e. ``python setup.py
...``.
+
+
.. _pyscaffold-notes:
.. tip::
@@ -167,8 +244,14 @@
.. _ini_cfg:
https://docs.python.org/3/library/configparser.html#supported-ini-file-structure
.. _our docs: https://ini2toml.readthedocs.io
.. _PEP 621: https://www.python.org/dev/peps/pep-0621/
-.. _pipx: https://pypa.github.io/pipx/
+.. _pipx: https://pipx.pypa.io/stable/
.. _project dependency:
https://packaging.python.org/tutorials/managing-dependencies/
+.. _plugin: https://ini2toml.readthedocs.io/en/latest/dev-guide.html#plugins
+.. _setup-py-upgrade: https://pypi.org/project/setup-cfg-fmt/
+.. _setuptools-py2cfg: https://pypi.org/project/setuptools-py2cfg/
+.. _setuptools' docs:
https://setuptools.pypa.io/en/latest/userguide/quickstart.html#setuppy-discouraged
.. _TOML: https://toml.io/en/
.. _TOML library: https://github.com/sdispater/tomlkit
+.. _tomli-w: https://pypi.org/project/tomli-w/
+.. _tomlkit: https://tomlkit.readthedocs.io/en/latest/
.. _virtual environment:
https://realpython.com/python-virtual-environments-a-primer/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/README.rst new/ini2toml-0.14/README.rst
--- old/ini2toml-0.13/README.rst 2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/README.rst 2024-04-20 21:23:26.000000000 +0200
@@ -93,9 +93,86 @@
To do so, don't forget to add it to your `virtual environment`_ or specify it
as a
`project dependency`_.
+Note that the class ``Translator`` will try to guess which flavour to use based
+on the available installed dependencies. If you need something more
+deterministic, consider using ``LiteTranslator`` and ``FullTranslator``,
+or explicitly specifying the ``ini_loads_fn`` and ``toml_dumps_fn`` keyword
+arguments in the constructor.
+
More details about ``ini2toml`` and its Python API can be found in `our docs`_.
+Limitations
+===========
+
+``ini2toml`` will try its best to create good quality translations from
+``.ini/.cfg`` into ``.toml`` files. However the tool comes with a set of
+well known limitations:
+
+* Although ``ini2toml`` attempts to keep the same order/sequence as the
original
+ information was written, sometimes that is not compatible with the TOML
+ syntax, and things end up moving around a bit.
+
+* ``ini2toml`` uses `ConfigParser`_ + `tomli-w`_ for implementing the *"lite"*
flavour
+ and `ConfigUpdater`_ + `tomlkit`_ for implementing the *"full"* flavour.
+ Therefore it inherits the limitations from those libraries (please check
+ their documentation for more information). For example:
+
+ * `ConfigUpdater`_, will have trouble to parse interpolations and the related
+ escaping sequence (``%%``) (in this respect, it behaves more similarly to
+ ``RawConfigParser`` than ``ConfigParser``).
+
+ * `tomli-w`_ is not very flexible regarding formatting and will have trouble
+ with multi-line strings.
+
+* ``ini2toml`` *expects the input to be valid* and will not perform extensive
+ checks on the provided document. If something in the output is not working
as you would
+ expect, it might be a good idea to check the input.
+
+* ``.ini/.cfg`` files are used in a plethora of use cases and it is impossible
+ to cover all of them in a single code base. Even when considering
+ ``setup.cfg``, there are many packages that define different sections in the
+ document in addition to the basic definition by ``setuptools``.
+ Because of that ``ini2toml``, adopts a "best-effort" approach, that might not
+ correspond to what you expect. If that is the case please consider
+ contributing or creating your own `plugin`_.
+
+* The translation procedure analyse only the given input. If the original
+ ``.ini/.cfg`` file contains references to other files, or behaves differently
+ depending on the existence/presence of other files and directories, the
+ translation will not take that into consideration.
+
+Therefore it is recommended to double check the output and fix any
+problems before using the ``.toml`` files in production.
+
+
+Can ``ini2toml`` also translate ``setup.py`` into ``pyproject.toml``?
+=====================================================================
+
+Working with ``.py`` files is not in the scope of the ``ini2toml`` project,
+and therefore this feature is not implemented.
+
+However, you can probably find some tools on PyPI to translate from
+``setup.py`` into ``setup.cfg``, like `setup-py-upgrade`_ and
+`setuptools-py2cfg`_ [#untested]_.
+
+Once you have ``setup.cfg``, you can use ``ini2toml`` [#setuppy]_.
+
+.. [#untested] Such tools are neither maintained by this project,
+ nor tested for integration by ``ini2toml``.
+ It is best to try some of them out and find the one that works for you.
+ Manual corrections might be needed.
+
+.. [#setuppy] Please note that ``setup.py`` is a very dynamic
+ format and that not everything can be represented in ``setup.cfg`` or
+ ``pyproject.toml``. Indeed, the `setuptools' docs`_ explicitly say that
+ ``setup.py`` can be used in tandem with ``pyproject.toml``: ideally all the
+ declarative metadata goes to ``pyproject.toml``, but you can keep the
+ dynamic bits in ``setup.py``.
+ Remember: ``setup.py`` is a perfectly valid and non deprecated
configuration file;
+ what is deprecated is running it as a CLI tool, i.e. ``python setup.py
...``.
+
+
.. _pyscaffold-notes:
.. tip::
@@ -122,8 +199,14 @@
.. _ini_cfg:
https://docs.python.org/3/library/configparser.html#supported-ini-file-structure
.. _our docs: https://ini2toml.readthedocs.io
.. _PEP 621: https://www.python.org/dev/peps/pep-0621/
-.. _pipx: https://pypa.github.io/pipx/
+.. _pipx: https://pipx.pypa.io/stable/
.. _project dependency:
https://packaging.python.org/tutorials/managing-dependencies/
+.. _plugin: https://ini2toml.readthedocs.io/en/latest/dev-guide.html#plugins
+.. _setup-py-upgrade: https://pypi.org/project/setup-cfg-fmt/
+.. _setuptools-py2cfg: https://pypi.org/project/setuptools-py2cfg/
+.. _setuptools' docs:
https://setuptools.pypa.io/en/latest/userguide/quickstart.html#setuppy-discouraged
.. _TOML: https://toml.io/en/
.. _TOML library: https://github.com/sdispater/tomlkit
+.. _tomli-w: https://pypi.org/project/tomli-w/
+.. _tomlkit: https://tomlkit.readthedocs.io/en/latest/
.. _virtual environment:
https://realpython.com/python-virtual-environments-a-primer/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/docs/conf.py
new/ini2toml-0.14/docs/conf.py
--- old/ini2toml-0.13/docs/conf.py 2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/docs/conf.py 2024-04-20 21:23:26.000000000 +0200
@@ -18,41 +18,16 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.join(__location__))
sys.path.insert(0, os.path.join(__location__, "../src"))
-# -- Run sphinx-apidoc -------------------------------------------------------
-# This hack is necessary since RTD does not issue `sphinx-apidoc` before
running
-# `sphinx-build -b html . _build/html`. See Issue:
-# https://github.com/readthedocs/readthedocs.org/issues/1139
-# DON'T FORGET: Check the box "Install your project inside a virtualenv using
-# setup.py install" in the RTD Advanced Settings.
-# Additionally it helps us to avoid running apidoc manually
+# -- Automatically generated content ------------------------------------------
-try: # for Sphinx >= 1.7
- from sphinx.ext import apidoc
-except ImportError:
- from sphinx import apidoc
+import public_api_docs
output_dir = os.path.join(__location__, "api")
module_dir = os.path.join(__location__, "../src/ini2toml")
-try:
- shutil.rmtree(output_dir)
-except FileNotFoundError:
- pass
-
-try:
- import sphinx
-
- cmd_line = f"sphinx-apidoc --implicit-namespaces -f -o {output_dir}
{module_dir}"
-
- args = cmd_line.split(" ")
- if tuple(sphinx.__version__.split(".")) >= ("1", "7"):
- # This is a rudimentary parse_version to avoid external dependencies
- args = args[1:]
-
- apidoc.main(args)
-except Exception as e:
- print("Running `sphinx-apidoc` failed!\n{}".format(e))
+public_api_docs.gen_stubs(module_dir, output_dir)
# -- General configuration ---------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/docs/dev-guide.rst
new/ini2toml-0.14/docs/dev-guide.rst
--- old/ini2toml-0.13/docs/dev-guide.rst 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/docs/dev-guide.rst 2024-04-20 21:23:26.000000000
+0200
@@ -96,8 +96,7 @@
.. code-block:: python
- def text_process(file_contents: str) -> str:
- ...
+ def text_process(file_contents: str) -> str: ...
.. important:: All processors are called in sequence, so the output of one is
@@ -119,8 +118,7 @@
.. code-block:: python
- def intermediate_process(intermediate: IntermediateRepr) ->
IntermediateRepr:
- ...
+ def intermediate_process(intermediate: IntermediateRepr) ->
IntermediateRepr: ...
:class:`~ini2toml.intermediate_repr.IntermediateRepr` is a special kind of
Python object with characteristics of both :obj:`dict` and :obj:`list`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/docs/public_api_docs.py
new/ini2toml-0.14/docs/public_api_docs.py
--- old/ini2toml-0.13/docs/public_api_docs.py 1970-01-01 01:00:00.000000000
+0100
+++ new/ini2toml-0.14/docs/public_api_docs.py 2024-04-20 21:23:26.000000000
+0200
@@ -0,0 +1,77 @@
+import shutil
+from pathlib import Path
+
+TOC_TEMPLATE = """
+Module Reference
+================
+
+.. toctree::
+ :glob:
+ :maxdepth: 2
+
+ ini2toml.api
+ ini2toml.errors
+ ini2toml.types
+
+.. toctree::
+ :maxdepth: 1
+
+ ini2toml.transformations
+
+.. toctree::
+ :caption: Plugins
+ :glob:
+ :maxdepth: 1
+
+ plugins/*
+"""
+
+MODULE_TEMPLATE = """
+``{name}``
+~~{underline}~~
+
+.. automodule:: {name}
+ :members:{_members}
+ :undoc-members:
+ :show-inheritance:
+"""
+
+
+def gen_stubs(module_dir: str, output_dir: str):
+ try_rmtree(output_dir) # Always start fresh
+ Path(output_dir, "plugins").mkdir(parents=True, exist_ok=True)
+ for module in iter_public():
+ text = module_template(module)
+ Path(output_dir, f"{module}.rst").write_text(text, encoding="utf-8")
+ for module in iter_plugins(module_dir):
+ text = module_template(module, "activate")
+ Path(output_dir, f"plugins/{module}.rst").write_text(text,
encoding="utf-8")
+ Path(output_dir, "modules.rst").write_text(TOC_TEMPLATE, encoding="utf-8")
+
+
+def iter_public():
+ lines = (x.strip() for x in TOC_TEMPLATE.splitlines())
+ return (x for x in lines if x.startswith("ini2toml."))
+
+
+def iter_plugins(module_dir: str):
+ return (
+ f'ini2toml.plugins.{path.with_suffix("").name}'
+ for path in Path(module_dir, "plugins").iterdir()
+ if path.is_file()
+ and path.name not in {".", "..", "__init__.py"}
+ and not path.name.startswith("_")
+ )
+
+
+def try_rmtree(target_dir: str):
+ try:
+ shutil.rmtree(target_dir)
+ except FileNotFoundError:
+ pass
+
+
+def module_template(name: str, *members: str) -> str:
+ underline = "~" * len(name)
+ _members = (" " + ", ".join(members)) if members else ""
+ return MODULE_TEMPLATE.format(name=name, underline=underline,
_members=_members)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/setup.cfg new/ini2toml-0.14/setup.cfg
--- old/ini2toml-0.13/setup.cfg 2023-10-23 14:17:02.446848400 +0200
+++ new/ini2toml-0.14/setup.cfg 2024-04-20 21:24:34.163375100 +0200
@@ -75,12 +75,12 @@
[tool:pytest]
addopts =
- --cov ini2toml --cov-report term-missing -vv
+ --cov ini2toml --cov-report term-missing -vv --doctest-modules
norecursedirs =
dist
build
.tox
-testpaths = tests
+testpaths = src tests
[devpi:upload]
no_vcs = 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/setup.py new/ini2toml-0.14/setup.py
--- old/ini2toml-0.13/setup.py 2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/setup.py 2024-04-20 21:23:26.000000000 +0200
@@ -6,6 +6,7 @@
PyScaffold helps you to put up the scaffold of your new Python project.
Learn more under: https://pyscaffold.org/
"""
+
from setuptools import setup
if __name__ == "__main__":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/api.py
new/ini2toml-0.14/src/ini2toml/api.py
--- old/ini2toml-0.13/src/ini2toml/api.py 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/src/ini2toml/api.py 2024-04-20 21:23:26.000000000
+0200
@@ -13,13 +13,17 @@
for checking `structural polymorphism`_ during static analysis).
These should be preferred when writing type hints and signatures.
-Plugin authors can also rely on the functions exported by
-:mod:`~ini2toml.transformations`.
+Plugin authors can also use functions exported by
:mod:`~ini2toml.transformations`.
.. _structural polymorphism: https://www.python.org/dev/peps/pep-0544/
"""
-from . import errors, transformations, types
+
from .base_translator import BaseTranslator
-from .translator import Translator
+from .translator import FullTranslator, LiteTranslator, Translator
-__all__ = ["BaseTranslator", "Translator", "errors", "types",
"transformations"]
+__all__ = [
+ "BaseTranslator",
+ "FullTranslator",
+ "LiteTranslator",
+ "Translator",
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/base_translator.py
new/ini2toml-0.14/src/ini2toml/base_translator.py
--- old/ini2toml-0.13/src/ini2toml/base_translator.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/base_translator.py 2024-04-20
21:23:26.000000000 +0200
@@ -18,7 +18,7 @@
class BaseTranslator(Generic[T]):
"""Translator object that follows the public API defined in
- :class:`ini2toml.types.Translator`. See :doc:`dev-guide` for a quick
explanation of
+ :class:`ini2toml.types.Translator`. See :doc:`/dev-guide` for a quick
explanation of
concepts such as plugins, profiles, profile augmentations, etc.
Arguments
@@ -68,7 +68,8 @@
Tip
---
- Most of the times the usage of :class:`~ini2toml.translator.Translator` is
preferred
+ Most of the times the usage of :class:`~ini2toml.translator.Translator`
+ (or its deterministic variants ``LiteTranslator``, ``FullTranslator``) is
preferred
over :class:`~ini2toml.base_translator.BaseTranslator` (unless you are
vendoring
``ini2toml`` and wants to reduce the number of files included in your
project).
"""
@@ -121,7 +122,7 @@
help_text: str = "",
):
"""Register a profile augmentation function to be called after the
- profile is selected and before the actual translation (see
:doc:`dev-guide`).
+ profile is selected and before the actual translation (see
:doc:`/dev-guide`).
"""
name = (name or fn.__name__).strip()
InvalidAugmentationName.check(name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/drivers/full_toml.py
new/ini2toml-0.14/src/ini2toml/drivers/full_toml.py
--- old/ini2toml-0.13/src/ini2toml/drivers/full_toml.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/drivers/full_toml.py 2024-04-20
21:23:26.000000000 +0200
@@ -3,6 +3,7 @@
It makes it easy to swap between implementations for testing (by means of
search and
replace).
"""
+
from collections import UserList
from collections.abc import Mapping, MutableSequence, Sequence
from functools import singledispatch
@@ -317,8 +318,9 @@
literal = '"' in obj or "\\" in single_line
if multiline and not obj.startswith("\n"):
- # TOML will automatically strip an starting newline
- # so let's add it, since it is better for reading
+ # TOML feature: during parsing a starting newline character in a
multi-line
+ # string will be stripped away.
+ # So we are free to add it, since it is better for reading
obj = "\n" + obj
try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/drivers/lite_toml.py
new/ini2toml-0.14/src/ini2toml/drivers/lite_toml.py
--- old/ini2toml-0.13/src/ini2toml/drivers/lite_toml.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/drivers/lite_toml.py 2024-04-20
21:23:26.000000000 +0200
@@ -3,6 +3,7 @@
It makes it easy to swap between implementations for testing (by means of
search and
replace).
"""
+
try:
from tomli_w import dumps
except ImportError: # pragma: no cover
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/drivers/plain_builtins.py
new/ini2toml-0.14/src/ini2toml/drivers/plain_builtins.py
--- old/ini2toml-0.13/src/ini2toml/drivers/plain_builtins.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/drivers/plain_builtins.py 2024-04-20
21:23:26.000000000 +0200
@@ -4,6 +4,7 @@
This is **not a loss-less** process, since comments are not preserved.
"""
+
from collections.abc import Mapping, MutableMapping
from functools import singledispatch
from typing import Any, TypeVar
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/errors.py
new/ini2toml-0.14/src/ini2toml/errors.py
--- old/ini2toml-0.13/src/ini2toml/errors.py 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/src/ini2toml/errors.py 2024-04-20 21:23:26.000000000
+0200
@@ -15,6 +15,7 @@
@classmethod
def check(cls, name: str, available: List[str]):
+ """:meta private:"""
if name not in available:
raise cls(name, available)
@@ -37,6 +38,7 @@
def check(
cls, name: str, fn: Callable, registry: Mapping[str,
types.ProfileAugmentation]
):
+ """:meta private:"""
if name in registry:
raise cls(name, fn, registry[name].fn)
@@ -63,7 +65,7 @@
class InvalidCfgBlock(ValueError): # pragma: no cover -- not supposed to
happen
- """Something is wrong with the provided CFG AST, the given block is not
valid."""
+ """Something is wrong with the provided ``.ini/.cfg`` AST"""
def __init__(self, block):
super().__init__(f"{block.__class__}: {block}", {"block_object":
block})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/intermediate_repr.py
new/ini2toml-0.14/src/ini2toml/intermediate_repr.py
--- old/ini2toml-0.13/src/ini2toml/intermediate_repr.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/intermediate_repr.py 2024-04-20
21:23:26.000000000 +0200
@@ -1,6 +1,7 @@
"""Intermediate representations used by ``ini2toml`` when transforming between
the INI and TOML syntaxes.
"""
+
from collections import UserList
from enum import Enum
from itertools import chain
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/plugins/best_effort.py
new/ini2toml-0.14/src/ini2toml/plugins/best_effort.py
--- old/ini2toml-0.13/src/ini2toml/plugins/best_effort.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/plugins/best_effort.py 2024-04-20
21:23:26.000000000 +0200
@@ -7,8 +7,8 @@
M = TypeVar("M", bound=IntermediateRepr)
-SECTION_SPLITTER = re.compile(r"\.|:|\\")
-KEY_SEP = "="
+_SECTION_SPLITTER = re.compile(r"\.|:|\\")
+_KEY_SEP = "="
def activate(translator: Translator):
@@ -23,12 +23,12 @@
def __init__(
self,
- key_sep=KEY_SEP,
- section_splitter=SECTION_SPLITTER,
+ key_sep=_KEY_SEP,
+ section_splitter=_SECTION_SPLITTER,
):
self.key_sep = key_sep
self.section_splitter = section_splitter
- self.split_dict = partial(split_kv_pairs, key_sep=KEY_SEP)
+ self.split_dict = partial(split_kv_pairs, key_sep=key_sep)
def process_values(self, doc: M) -> M:
doc_items = list(doc.items())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ini2toml-0.13/src/ini2toml/plugins/profile_independent_tasks.py
new/ini2toml-0.14/src/ini2toml/plugins/profile_independent_tasks.py
--- old/ini2toml-0.13/src/ini2toml/plugins/profile_independent_tasks.py
2023-10-23 14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/plugins/profile_independent_tasks.py
2024-04-20 21:23:26.000000000 +0200
@@ -1,4 +1,5 @@
"""Profile-independent tasks implemented via *profile augmentation*."""
+
import re
from functools import wraps
from typing import Callable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/plugins/pytest.py
new/ini2toml-0.14/src/ini2toml/plugins/pytest.py
--- old/ini2toml-0.13/src/ini2toml/plugins/pytest.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/plugins/pytest.py 2024-04-20
21:23:26.000000000 +0200
@@ -1,16 +1,19 @@
#
https://docs.pytest.org/en/latest/reference/reference.html#configuration-options
#
https://docs.pytest.org/en/latest/reference/customize.html#config-file-formats
+import logging
from collections.abc import MutableMapping
from functools import partial
-from typing import TypeVar
+from typing import TypeVar, Union
-from ..transformations import coerce_scalar, split_list
-from ..types import IntermediateRepr, Translator
+from ..transformations import coerce_scalar, remove_comments, split_comment,
split_list
+from ..types import Commented, IntermediateRepr, Translator
R = TypeVar("R", bound=IntermediateRepr)
-split_spaces = partial(split_list, sep=" ")
-split_lines = partial(split_list, sep="\n")
+_logger = logging.getLogger(__name__)
+
+_split_spaces = partial(split_list, sep=" ")
+_split_lines = partial(split_list, sep="\n")
# ^ most of the list values in pytest use whitespace separators,
# but markers/filterwarnings are a special case.
@@ -60,8 +63,30 @@
if field in self.DONT_TOUCH:
continue
if field in self.LINE_SEPARATED_LIST_VALUES:
- section[field] = split_lines(section[field])
+ section[field] = _split_lines(section[field])
elif field in self.SPACE_SEPARATED_LIST_VALUES:
- section[field] = split_spaces(section[field])
+ section[field] = _split_spaces(section[field])
+ elif hasattr(self, f"_process_{field}"):
+ section[field] = getattr(self,
f"_process_{field}")(section[field])
else:
section[field] = coerce_scalar(section[field])
+
+ def _process_addopts(self, content: str) -> Union[Commented[str], str]:
+ # pytest-dev/pytest#12228: pytest maintainers recommend addopts as
string.
+ # However, it cannot handle embedded comments, so we have to strip
them.
+
+ if "\n" not in content:
+ # It is easy to handle inline comments for a single line.
+ return split_comment(content)
+
+ if "#" not in content:
+ return content
+
+ msg = (
+ "Stripping comments from `tool.pytest.ini_options.addopts`.\n"
+ "This field is recommended to be a string, however it cannot "
+ "contain embedded comments (ref: pytest-dev/pytest#12228)."
+ )
+ _logger.warning(msg)
+
+ return remove_comments(content)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ini2toml-0.13/src/ini2toml/plugins/setuptools_pep621.py
new/ini2toml-0.14/src/ini2toml/plugins/setuptools_pep621.py
--- old/ini2toml-0.13/src/ini2toml/plugins/setuptools_pep621.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/plugins/setuptools_pep621.py 2024-04-20
21:23:26.000000000 +0200
@@ -438,8 +438,13 @@
options = doc["options"]
# Abort when not using find or find_namespace
packages = options.get("packages")
+
if not isinstance(packages, Directive):
+ if "options.packages.find" in doc:
+ _ConfusingPackagesConfig.emit()
+ doc.pop("options.packages.find", None)
return doc
+
prefix = packages.kind.replace("_", "-")
# Enhancement #1: Unify find and find_namespaces, using `namespaces`
as a flag
options["packages"] = Directive("find", {"namespaces": "namespace" in
prefix})
@@ -845,3 +850,24 @@
keep1, keep2 = values1[:-1], values2[1:]
shared = values1[-1].strip().strip("\\").strip() + " " + values2[0].strip()
return Commented(keep1 + [shared] + keep2, line2.comment)
+
+
+class _ConfusingPackagesConfig(UserWarning):
+ _MSG = """Confusing configuration `[options.packages.find]`.
+
+ Original configuration sets both:
+
+ - `[options] packages = ...` as a list of named packages
+ - `[options.packages.find]`
+
+ The confusion comes from the fact that `[options.packages.find]` should be
used
+ with `[options] packages = find:` or `[options] packages =
find_namespace:`.
+
+ Conversion will ignore `[options.packages.find]`, as it cannot be written
in the
+ TOML format when `[options] packages = ...` is already given.
+ """
+ __doc__ = _MSG
+
+ @classmethod
+ def emit(cls, msg=_MSG, stacklevel=1):
+ warnings.warn(msg, category=cls, stacklevel=stacklevel + 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/transformations.py
new/ini2toml-0.14/src/ini2toml/transformations.py
--- old/ini2toml-0.13/src/ini2toml/transformations.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/transformations.py 2024-04-20
21:23:26.000000000 +0200
@@ -1,4 +1,17 @@
-"""Reusable value and type casting transformations"""
+"""
+Reusable value and type casting transformations
+
+This module is stable on a "best effort"-basis, and small backwards
incompatibilities
+can be introduced in "minor"/"patch" version bumps (it will not be considered a
+regression automatically).
+While it can be used by plugin writers, it is not intended for general public
use.
+
+.. testsetup:: *
+
+ # workaround for missing import in sphinx-doctest
+ from ini2toml.transformations import *
+"""
+
import warnings
from collections.abc import MutableMapping
from functools import reduce, wraps
@@ -45,7 +58,7 @@
For example: transforming ``"2"`` (string) into ``2`` (integer).
- The second one tries to preserve metadata (such as comments) from the
original CFG/INI
file. This kind of transformation processes a string value into an
intermediary
- representation (e.g. :obj:`Commented`, :obj:`CommentedList`,
obj:`CommentedKV`)
+ representation (e.g. :obj:`Commented`, :obj:`CommentedList`,
:obj:`CommentedKV`)
that needs to be properly handled before adding to the TOML document.
In a higher level we can also consider an ensemble of transformations that
transform an
@@ -60,15 +73,18 @@
def noop(x: T) -> T:
+ """Return the value unchanged"""
return x
def is_true(value: str) -> bool:
+ """``value in ("true", "1", "yes", "on")``"""
value = value.lower()
return value in ("true", "1", "yes", "on")
def is_false(value: str) -> bool:
+ """``value in ("false", "0", "no", "off", "none", "null", "nil")``"""
value = value.lower()
return value in ("false", "0", "no", "off", "none", "null", "nil")
@@ -79,6 +95,7 @@
def coerce_bool(value: str) -> bool:
+ """Convert the value based on :func:`~.is_true` and :func:`~.is_false`."""
if is_true(value):
return True
if is_false(value):
@@ -140,18 +157,17 @@
@overload
-def split_comment(value: str, *, comment_prefixes=CP) -> Commented[str]:
- ...
+def split_comment(value: str, *, comment_prefixes=CP) -> Commented[str]: ...
@overload
def split_comment(
value: str, coerce_fn: CoerceFn[T], comment_prefixes=CP
-) -> Commented[T]:
- ...
+) -> Commented[T]: ...
def split_comment(value, coerce_fn=noop, comment_prefixes=CP):
+ """Split a "comment suffix" from the value."""
if not isinstance(value, str):
return value
value = value.strip()
@@ -162,14 +178,15 @@
return Commented(coerce_fn(value))
if any(value.startswith(p) for p in comment_prefixes):
- return Commented(comment=_strip_comment(value, comment_prefixes))
+ return Commented(comment=_strip_prefix(value, comment_prefixes))
prefix = prefixes[0] # We can only analyse one...
value, _, cmt = value.partition(prefix)
- return Commented(coerce_fn(value.strip()), _strip_comment(cmt,
comment_prefixes))
+ return Commented(coerce_fn(value.strip()), _strip_prefix(cmt,
comment_prefixes))
def split_scalar(value: str, *, comment_prefixes=CP) -> Commented[Scalar]:
+ """Combination of :func:`~.split_comment` and :func:`~.coerce_scalar`."""
return split_comment(value, coerce_scalar, comment_prefixes)
@@ -181,8 +198,7 @@
subsplit_dangling=True,
comment_prefixes=CP,
force_multiline=False,
-) -> CommentedList[str]:
- ...
+) -> CommentedList[str]: ...
@overload
@@ -194,8 +210,7 @@
subsplit_dangling=True,
comment_prefixes=CP,
force_multiline=False,
-) -> CommentedList[T]:
- ...
+) -> CommentedList[T]: ...
@overload
@@ -206,8 +221,7 @@
subsplit_dangling=True,
comment_prefixes=CP,
force_multiline=False,
-) -> CommentedList[T]:
- ...
+) -> CommentedList[T]: ...
def split_list(
@@ -247,8 +261,7 @@
pair_sep=",",
subsplit_dangling=True,
comment_prefixes=CP,
-) -> CommentedKV[str]:
- ...
+) -> CommentedKV[str]: ...
@overload
@@ -260,8 +273,7 @@
pair_sep=",",
subsplit_dangling=True,
comment_prefixes=CP,
-) -> CommentedKV[T]:
- ...
+) -> CommentedKV[T]: ...
@overload
@@ -272,8 +284,7 @@
pair_sep=",",
subsplit_dangling=True,
comment_prefixes=CP,
-) -> CommentedKV[T]:
- ...
+) -> CommentedKV[T]: ...
def split_kv_pairs(
@@ -326,25 +337,21 @@
@overload
-def pipe(fn1: FN[S, T], fn2: FN[T, U]) -> FN[S, U]:
- ...
+def pipe(fn1: FN[S, T], fn2: FN[T, U]) -> FN[S, U]: ...
@overload
-def pipe(fn1: FN[S, T], fn2: FN[T, U], fn3: FN[U, V]) -> FN[S, V]:
- ...
+def pipe(fn1: FN[S, T], fn2: FN[T, U], fn3: FN[U, V]) -> FN[S, V]: ...
@overload
-def pipe(fn1: FN[S, T], fn2: FN[T, U], fn3: FN[U, V], fn4: FN[V, X]) -> FN[S,
X]:
- ...
+def pipe(fn1: FN[S, T], fn2: FN[T, U], fn3: FN[U, V], fn4: FN[V, X]) -> FN[S,
X]: ...
@overload
def pipe(
fn1: FN[S, T], fn2: FN[T, U], fn3: FN[U, V], fn4: FN[V, X], fn5: FN[X, Y]
-) -> FN[S, Y]:
- ...
+) -> FN[S, Y]: ...
@overload
@@ -355,8 +362,7 @@
fn4: FN[V, X],
fn5: FN[X, Y],
*fn: FN[Y, Y],
-) -> FN[S, Y]:
- ...
+) -> FN[S, Y]: ...
def pipe(*fns):
@@ -369,10 +375,44 @@
return lambda x: reduce(apply, fns, x)
+def remove_comments(text: str, comment_mark="#") -> str:
+ r"""
+ >>> remove_comments("\nhello\n#comment\nworld\n")
+ '\nhello\nworld\n'
+ >>> remove_comments("\n hello\n\nworld\n")
+ '\n hello\n\nworld\n'
+ >>> remove_comments("\nhello\n \nworld\n")
+ '\nhello\n \nworld\n'
+ """
+ lines = (_line_remove_comment(x, comment_mark) for x in text.splitlines())
+ suffix = "\n" if text.strip(" ").endswith("\n") else ""
+ return "\n".join(x for x in lines if x is not None) + suffix
+
+
# ---- Private Helpers ----
-def _strip_comment(msg: Optional[str], prefixes: Sequence[str] = CP) ->
Optional[str]:
+def _line_remove_comment(line: str, comment_mark="#") -> Optional[str]:
+ """
+ >>> print(_line_remove_comment(" # hello world"))
+ None
+ >>> _line_remove_comment(" abc # hello world")
+ ' abc'
+ >>> _line_remove_comment(" ")
+ ' '
+ >>> _line_remove_comment("")
+ ''
+ """
+ if comment_mark not in line:
+ # Keep empty lines intentionally added by the user
+ return line
+ if line.strip().startswith(comment_mark):
+ # Remove empty lines that were just inserted as a replacement for
comments
+ return None
+ return line.partition(comment_mark)[0].rstrip()
+
+
+def _strip_prefix(msg: Optional[str], prefixes: Sequence[str] = CP) ->
Optional[str]:
if not msg:
return None
return remove_prefixes(msg, prefixes)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/translator.py
new/ini2toml-0.14/src/ini2toml/translator.py
--- old/ini2toml-0.13/src/ini2toml/translator.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml/translator.py 2024-04-20
21:23:26.000000000 +0200
@@ -8,6 +8,10 @@
_logger = logging.getLogger(__name__)
+# TODO: Once MyPy/other type checkers handle ``partial`` and ``partialmethod``
+# we probably can use them to simply the implementations in this module.
+
+
class Translator(BaseTranslator[str]):
"""``Translator`` is the main public Python API exposed by the
``ini2toml``,
to convert strings representing ``.ini/.cfg`` files into the ``TOML``
syntax.
@@ -20,6 +24,8 @@
while ``BaseTranslator`` requires the user to explicitly set these
parameters.
For most of the users ``Translator`` is recommended over
``BaseTranslator``.
+ Most of the times ``Translator`` (or its deterministic variants
``LiteTranslator``,
+ ``FullTranslator``) is recommended over ``BaseTranslator``.
See :class:`~ini2toml.base_translator.BaseTranslator` for a description of
the
instantiation parameters.
@@ -67,3 +73,73 @@
raise
return convert
+
+
+class LiteTranslator(Translator):
+ """Similar to ``Translator``, but instead of trying to figure out
``ini_loads_fn``
+ and ``toml_dumps_fn`` is will always try to use the ``lite`` flavour
+ (ignoring comments).
+ """
+
+ def __init__(
+ self,
+ plugins: Optional[Sequence[types.Plugin]] = None,
+ profiles: Sequence[types.Profile] = (),
+ profile_augmentations: Sequence[types.ProfileAugmentation] = (),
+ ini_parser_opts: Mapping = EMPTY,
+ ini_loads_fn: Optional[types.IniLoadsFn] = None,
+ toml_dumps_fn: Optional[types.TomlDumpsFn] = None,
+ ):
+ if ini_loads_fn:
+ parse = ini_loads_fn
+ else:
+ from .drivers.configparser import parse
+
+ if toml_dumps_fn:
+ convert = toml_dumps_fn
+ else:
+ from .drivers.lite_toml import convert
+
+ super().__init__(
+ ini_loads_fn=parse,
+ toml_dumps_fn=convert,
+ plugins=plugins,
+ ini_parser_opts=ini_parser_opts,
+ profiles=profiles,
+ profile_augmentations=profile_augmentations,
+ )
+
+
+class FullTranslator(Translator):
+ """Similar to ``Translator``, but instead of trying to figure out
``ini_loads_fn``
+ and ``toml_dumps_fn`` is will always try to use the ``full`` flavour
+ (best effort to maintain comments).
+ """
+
+ def __init__(
+ self,
+ plugins: Optional[Sequence[types.Plugin]] = None,
+ profiles: Sequence[types.Profile] = (),
+ profile_augmentations: Sequence[types.ProfileAugmentation] = (),
+ ini_parser_opts: Mapping = EMPTY,
+ ini_loads_fn: Optional[types.IniLoadsFn] = None,
+ toml_dumps_fn: Optional[types.TomlDumpsFn] = None,
+ ):
+ if ini_loads_fn:
+ parse = ini_loads_fn
+ else:
+ from .drivers.configupdater import parse
+
+ if toml_dumps_fn:
+ convert = toml_dumps_fn
+ else:
+ from .drivers.full_toml import convert
+
+ super().__init__(
+ ini_loads_fn=parse,
+ toml_dumps_fn=convert,
+ plugins=plugins,
+ ini_parser_opts=ini_parser_opts,
+ profiles=profiles,
+ profile_augmentations=profile_augmentations,
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml/types.py
new/ini2toml-0.14/src/ini2toml/types.py
--- old/ini2toml-0.13/src/ini2toml/types.py 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/src/ini2toml/types.py 2024-04-20 21:23:26.000000000
+0200
@@ -43,6 +43,8 @@
class CLIChoice(Protocol):
+ """:meta private:"""
+
name: str
help_text: str
@@ -60,14 +62,14 @@
name: str
help_text: str
- def fn(self, profile: Profile):
- ...
+ def fn(self, profile: Profile): ...
def is_active(self, explicitly_active: Optional[bool] = None) -> bool:
"""``explicitly_active`` is a tree-state variable: ``True`` if the user
explicitly asked for the augmentation, ``False`` if the user
explicitly denied
the augmentation, or ``None`` otherwise.
"""
+ ...
class Translator(Protocol):
@@ -75,6 +77,7 @@
"""Create and register (and return) a translation :class:`Profile`
(or return a previously registered one) (see :ref:`core-concepts`).
"""
+ ...
def augment_profiles(
self,
@@ -89,6 +92,7 @@
strings), ``name`` is taken from ``fn.__name__`` and ``help_text`` is
taken from
``fn.__doc__`` (docstring).
"""
+ ...
Plugin = Callable[[Translator], None]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml.egg-info/PKG-INFO
new/ini2toml-0.14/src/ini2toml.egg-info/PKG-INFO
--- old/ini2toml-0.13/src/ini2toml.egg-info/PKG-INFO 2023-10-23
14:17:02.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml.egg-info/PKG-INFO 2024-04-20
21:24:34.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: ini2toml
-Version: 0.13
+Version: 0.14
Summary: Automatically conversion of .ini/.cfg files to TOML equivalents
Home-page: https://github.com/abravalheri/ini2toml/
Author: Anderson Bravalheri
@@ -138,9 +138,86 @@
To do so, don't forget to add it to your `virtual environment`_ or specify it
as a
`project dependency`_.
+Note that the class ``Translator`` will try to guess which flavour to use based
+on the available installed dependencies. If you need something more
+deterministic, consider using ``LiteTranslator`` and ``FullTranslator``,
+or explicitly specifying the ``ini_loads_fn`` and ``toml_dumps_fn`` keyword
+arguments in the constructor.
+
More details about ``ini2toml`` and its Python API can be found in `our docs`_.
+Limitations
+===========
+
+``ini2toml`` will try its best to create good quality translations from
+``.ini/.cfg`` into ``.toml`` files. However the tool comes with a set of
+well known limitations:
+
+* Although ``ini2toml`` attempts to keep the same order/sequence as the
original
+ information was written, sometimes that is not compatible with the TOML
+ syntax, and things end up moving around a bit.
+
+* ``ini2toml`` uses `ConfigParser`_ + `tomli-w`_ for implementing the *"lite"*
flavour
+ and `ConfigUpdater`_ + `tomlkit`_ for implementing the *"full"* flavour.
+ Therefore it inherits the limitations from those libraries (please check
+ their documentation for more information). For example:
+
+ * `ConfigUpdater`_, will have trouble to parse interpolations and the related
+ escaping sequence (``%%``) (in this respect, it behaves more similarly to
+ ``RawConfigParser`` than ``ConfigParser``).
+
+ * `tomli-w`_ is not very flexible regarding formatting and will have trouble
+ with multi-line strings.
+
+* ``ini2toml`` *expects the input to be valid* and will not perform extensive
+ checks on the provided document. If something in the output is not working
as you would
+ expect, it might be a good idea to check the input.
+
+* ``.ini/.cfg`` files are used in a plethora of use cases and it is impossible
+ to cover all of them in a single code base. Even when considering
+ ``setup.cfg``, there are many packages that define different sections in the
+ document in addition to the basic definition by ``setuptools``.
+ Because of that ``ini2toml``, adopts a "best-effort" approach, that might not
+ correspond to what you expect. If that is the case please consider
+ contributing or creating your own `plugin`_.
+
+* The translation procedure analyse only the given input. If the original
+ ``.ini/.cfg`` file contains references to other files, or behaves differently
+ depending on the existence/presence of other files and directories, the
+ translation will not take that into consideration.
+
+Therefore it is recommended to double check the output and fix any
+problems before using the ``.toml`` files in production.
+
+
+Can ``ini2toml`` also translate ``setup.py`` into ``pyproject.toml``?
+=====================================================================
+
+Working with ``.py`` files is not in the scope of the ``ini2toml`` project,
+and therefore this feature is not implemented.
+
+However, you can probably find some tools on PyPI to translate from
+``setup.py`` into ``setup.cfg``, like `setup-py-upgrade`_ and
+`setuptools-py2cfg`_ [#untested]_.
+
+Once you have ``setup.cfg``, you can use ``ini2toml`` [#setuppy]_.
+
+.. [#untested] Such tools are neither maintained by this project,
+ nor tested for integration by ``ini2toml``.
+ It is best to try some of them out and find the one that works for you.
+ Manual corrections might be needed.
+
+.. [#setuppy] Please note that ``setup.py`` is a very dynamic
+ format and that not everything can be represented in ``setup.cfg`` or
+ ``pyproject.toml``. Indeed, the `setuptools' docs`_ explicitly say that
+ ``setup.py`` can be used in tandem with ``pyproject.toml``: ideally all the
+ declarative metadata goes to ``pyproject.toml``, but you can keep the
+ dynamic bits in ``setup.py``.
+ Remember: ``setup.py`` is a perfectly valid and non deprecated
configuration file;
+ what is deprecated is running it as a CLI tool, i.e. ``python setup.py
...``.
+
+
.. _pyscaffold-notes:
.. tip::
@@ -167,8 +244,14 @@
.. _ini_cfg:
https://docs.python.org/3/library/configparser.html#supported-ini-file-structure
.. _our docs: https://ini2toml.readthedocs.io
.. _PEP 621: https://www.python.org/dev/peps/pep-0621/
-.. _pipx: https://pypa.github.io/pipx/
+.. _pipx: https://pipx.pypa.io/stable/
.. _project dependency:
https://packaging.python.org/tutorials/managing-dependencies/
+.. _plugin: https://ini2toml.readthedocs.io/en/latest/dev-guide.html#plugins
+.. _setup-py-upgrade: https://pypi.org/project/setup-cfg-fmt/
+.. _setuptools-py2cfg: https://pypi.org/project/setuptools-py2cfg/
+.. _setuptools' docs:
https://setuptools.pypa.io/en/latest/userguide/quickstart.html#setuppy-discouraged
.. _TOML: https://toml.io/en/
.. _TOML library: https://github.com/sdispater/tomlkit
+.. _tomli-w: https://pypi.org/project/tomli-w/
+.. _tomlkit: https://tomlkit.readthedocs.io/en/latest/
.. _virtual environment:
https://realpython.com/python-virtual-environments-a-primer/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/src/ini2toml.egg-info/SOURCES.txt
new/ini2toml-0.14/src/ini2toml.egg-info/SOURCES.txt
--- old/ini2toml-0.13/src/ini2toml.egg-info/SOURCES.txt 2023-10-23
14:17:02.000000000 +0200
+++ new/ini2toml-0.14/src/ini2toml.egg-info/SOURCES.txt 2024-04-20
21:24:34.000000000 +0200
@@ -24,6 +24,7 @@
docs/dev-guide.rst
docs/index.rst
docs/license.rst
+docs/public_api_docs.py
docs/readme.rst
docs/requirements.txt
docs/setuptools_pep621.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/tests/examples/pyscaffold/setup.cfg
new/ini2toml-0.14/tests/examples/pyscaffold/setup.cfg
--- old/ini2toml-0.13/tests/examples/pyscaffold/setup.cfg 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/tests/examples/pyscaffold/setup.cfg 2024-04-20
21:23:26.000000000 +0200
@@ -117,9 +117,8 @@
# in order to write a coverage file that can be read by Jenkins.
# CAUTION: --cov flags may prohibit setting breakpoints while debugging.
# Comment those flags to avoid this pytest issue.
-addopts =
- --cov pyscaffold --cov-config .coveragerc --cov-report term-missing
- --verbose
+addopts = --cov pyscaffold --cov-config .coveragerc --cov-report term-missing
+ --verbose
# In order to use xdist, the developer can add, for example, the following
# arguments:
# --dist=load --numprocesses=auto
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/tests/plugins/test_pytest.py
new/ini2toml-0.14/tests/plugins/test_pytest.py
--- old/ini2toml-0.13/tests/plugins/test_pytest.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/tests/plugins/test_pytest.py 2024-04-20
21:23:26.000000000 +0200
@@ -1,54 +1,77 @@
from textwrap import dedent
+import pytest
import tomli
from ini2toml.drivers import full_toml, lite_toml
-from ini2toml.plugins import pytest
-from ini2toml.translator import Translator
+from ini2toml.plugins.pytest import activate
+from ini2toml.translator import FullTranslator
+EXAMPLES = {
+ "simple": {
+ "example": """\
+ [pytest]
+ minversion = 6.0
+ addopts = -ra -q --cov ini2toml
+ testpaths = tests
+ python_files = test_*.py check_*.py example_*.py
+ required_plugins = pytest-django>=3.0.0,<4.0.0 pytest-html
pytest-xdist>=1.0.0
+ norecursedirs =
+ dist
+ build
+ .tox
+ filterwarnings=
+ error
+ ignore:Please use `dok_matrix` from the `scipy\\.sparse`
namespace, the `scipy\\.sparse\\.dok` namespace is
deprecated.:DeprecationWarning
+ """, # noqa
+ "expected": """\
+ [pytest]
+ [pytest.ini_options]
+ minversion = "6.0"
+ addopts = "-ra -q --cov ini2toml"
+ testpaths = ["tests"]
+ python_files = ["test_*.py", "check_*.py", "example_*.py"]
+ required_plugins = ["pytest-django>=3.0.0,<4.0.0", "pytest-html",
"pytest-xdist>=1.0.0"]
+ norecursedirs = [
+ "dist",
+ "build",
+ ".tox",
+ ]
+ filterwarnings = [
+ "error",
+ 'ignore:Please use `dok_matrix` from the `scipy\\.sparse`
namespace, the `scipy\\.sparse\\.dok` namespace is
deprecated.:DeprecationWarning',
+ ]
+ """, # noqa
+ },
+ "multiline-addopts": {
+ "example": """\
+ [pytest]
+ addopts = -ra -q
+ # comment
+ --cov ini2toml
+ """,
+ "expected": '''\
+ [pytest.ini_options]
+ addopts = """
+ -ra -q
+ --cov ini2toml"""
+ ''',
+ },
+}
-def test_pytest():
- example = """\
- [pytest]
- minversion = 6.0
- addopts = -ra -q --cov ini2toml
- testpaths = tests
- python_files = test_*.py check_*.py example_*.py
- required_plugins = pytest-django>=3.0.0,<4.0.0 pytest-html
pytest-xdist>=1.0.0
- norecursedirs =
- dist
- build
- .tox
- filterwarnings=
- error
- ignore:Please use `dok_matrix` from the `scipy\\.sparse` namespace,
the `scipy\\.sparse\\.dok` namespace is deprecated.:DeprecationWarning
- """ # noqa
- expected = """\
- [pytest]
- [pytest.ini_options]
- minversion = "6.0"
- addopts = "-ra -q --cov ini2toml"
- testpaths = ["tests"]
- python_files = ["test_*.py", "check_*.py", "example_*.py"]
- required_plugins = ["pytest-django>=3.0.0,<4.0.0", "pytest-html",
"pytest-xdist>=1.0.0"]
- norecursedirs = [
- "dist",
- "build",
- ".tox",
- ]
- filterwarnings = [
- "error",
- 'ignore:Please use `dok_matrix` from the `scipy\\.sparse` namespace,
the `scipy\\.sparse\\.dok` namespace is deprecated.:DeprecationWarning',
- ]
- """ # noqa
- for convert in (lite_toml.convert, full_toml.convert):
- translator = Translator(plugins=[pytest.activate],
toml_dumps_fn=convert)
- out = translator.translate(dedent(example), "pytest.ini").strip()
- expected = dedent(expected).strip()
- print("expected=\n" + expected + "\n***")
- print("out=\n" + out)
- try:
- assert expected in out
- except AssertionError:
- # At least the Python-equivalents when parsing should be the same
- assert tomli.loads(expected) == tomli.loads(out)
+
[email protected]("example_name", EXAMPLES.keys())
[email protected]("convert", [full_toml.convert, lite_toml.convert])
+def test_pytest(example_name, convert):
+ example = EXAMPLES[example_name]["example"]
+ expected = EXAMPLES[example_name]["expected"]
+ translator = FullTranslator(plugins=[activate], toml_dumps_fn=convert)
+ out = translator.translate(dedent(example), "pytest.ini").strip()
+ expected = dedent(expected).strip()
+ print("expected=\n" + expected + "\n***")
+ print("out=\n" + out)
+ try:
+ assert expected in out
+ except AssertionError:
+ # At least the Python-equivalents when parsing should be the same
+ assert tomli.loads(expected) == tomli.loads(out)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ini2toml-0.13/tests/plugins/test_setuptools_pep621.py
new/ini2toml-0.14/tests/plugins/test_setuptools_pep621.py
--- old/ini2toml-0.13/tests/plugins/test_setuptools_pep621.py 2023-10-23
14:15:48.000000000 +0200
+++ new/ini2toml-0.14/tests/plugins/test_setuptools_pep621.py 2024-04-20
21:23:26.000000000 +0200
@@ -2,7 +2,12 @@
import tomli
from ini2toml.plugins.profile_independent_tasks import
remove_empty_table_headers
-from ini2toml.plugins.setuptools_pep621 import Directive, SetuptoolsPEP621,
activate
+from ini2toml.plugins.setuptools_pep621 import (
+ Directive,
+ SetuptoolsPEP621,
+ _ConfusingPackagesConfig,
+ activate,
+)
from ini2toml.translator import Translator
@@ -738,3 +743,37 @@
print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
print(doc)
assert convert(doc) == expected_convert_directives
+
+
+# ----
+
+# Example taken from https://github.com/aio-libs/aiohttp/
+# In general, you should either list packages explicit or use find,
+# but some configs change and `options.packages.find` is left behind
+example_explicit_packages_with_find = """\
+[options]
+packages = aiohttp
+[options.packages.find]
+exclude =
+ examples
+"""
+
+# In those cases, `ini2toml` should remove `[options.packages.find]`
+# And warn about it
+expected_explicit_packages_with_find = """\
+[tool.setuptools]
+packages = ["aiohttp"]
+"""
+
+
+def test_explicit_packages_with_find(plugin, parse, convert):
+ doc = parse(example_explicit_packages_with_find)
+ print(doc)
+ doc = plugin.apply_value_processing(doc)
+ print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
+ with pytest.warns(_ConfusingPackagesConfig,
match="[options.packages.find]"):
+ doc = plugin.handle_packages_find(doc)
+ doc.rename("options", ("tool", "setuptools"))
+ print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
+ print(doc)
+ assert convert(doc) == expected_explicit_packages_with_find
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/tests/test_examples.py
new/ini2toml-0.14/tests/test_examples.py
--- old/ini2toml-0.13/tests/test_examples.py 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/tests/test_examples.py 2024-04-20 21:23:26.000000000
+0200
@@ -9,7 +9,7 @@
from ini2toml import cli
from ini2toml.drivers import configparser, full_toml, lite_toml
-from ini2toml.translator import Translator
+from ini2toml.translator import FullTranslator, LiteTranslator
def examples():
@@ -39,7 +39,7 @@
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
@pytest.mark.parametrize(("original", "expected"), list(examples()))
def test_examples_api(original, expected, validate):
- translator = Translator()
+ translator = FullTranslator()
available_profiles = list(translator.profiles.keys())
profile = cli.guess_profile(None, original, available_profiles)
orig = Path(original)
@@ -71,7 +71,7 @@
@pytest.mark.parametrize(("original", "expected"), list(examples()))
def test_examples_api_lite(original, expected, validate):
opts = {"ini_loads_fn": configparser.parse, "toml_dumps_fn":
lite_toml.convert}
- translator = Translator(**opts)
+ translator = LiteTranslator(**opts)
available_profiles = list(translator.profiles.keys())
profile = cli.guess_profile(None, original, available_profiles)
# We cannot compare "flake8" sections (currently not handled)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ini2toml-0.13/tests/test_translator.py
new/ini2toml-0.14/tests/test_translator.py
--- old/ini2toml-0.13/tests/test_translator.py 2023-10-23 14:15:48.000000000
+0200
+++ new/ini2toml-0.14/tests/test_translator.py 2024-04-20 21:23:26.000000000
+0200
@@ -5,7 +5,7 @@
from ini2toml.errors import UndefinedProfile
from ini2toml.plugins import profile_independent_tasks
from ini2toml.profile import Profile, ProfileAugmentation
-from ini2toml.translator import Translator
+from ini2toml.translator import FullTranslator, LiteTranslator, Translator
def test_simple_example():
@@ -139,3 +139,31 @@
]
translator = Translator(plugins=plugins)
assert len(translator.plugins) == 1
+
+
+minimal_example = """\
+# comment
+
+[section1]
+option1 = value
+option2 = value # option comments are considered part of the value
+"""
+
+
+def test_lite_translator():
+ parser_opts = {"inline_comment_prefixes": ["#"]}
+ translator = LiteTranslator(plugins=[], ini_parser_opts=parser_opts)
+ # ensure profile exists
+ translator["simple"]
+ out = translator.translate(dedent(minimal_example), "simple")
+ assert "# comment" not in out
+ assert "part of the value" not in out
+
+
+def test_full_translator():
+ translator = FullTranslator(plugins=[])
+ # ensure profile exists
+ translator["simple"]
+ out = translator.translate(dedent(minimal_example), "simple")
+ assert "# comment" in out
+ assert "part of the value" in out