the `core.publish_string()` API function (was: Recent commit activity)

Guenter Milde via Docutils-develop <[email protected]>
Newsgroups gmane.text.docutils.devel
Message-ID <[email protected]>
Dear Adam, dear Docutils developers,

On 2022-11-13, Adam Turner wrote:

>> * `output-encoding`__ is a *general* setting defined as
>>   "The text encoding for output". This raises the expectation that all
>>   Docutils output "has" the specified encoding
...
>> * The behaviour of `publish_string()` has been stable for many years.
>>   Long-time users are familiar with it and expect it to remain stable.

> There are 1283 projects published on PyPI that depend on Docutils. I
> have gone through each of these projects, there are 35 (2.7%) that use
> the ``docutils.core.publish_string`` function.

> Of those:

> * 8 set ``'output_encoding': 'unicode'``, so would be unaffected by the
> eventual change to return strings. (traitsui, odoo-tools, CodeChat,
> benchmarkstt, pyfda, pyretis, anna, resplendent)
> * 14 use the "UTF-8" encoding and call ``.decode()`` straight after, so
> would have to refactor but want to use Python strings.
> (Orange-Canvas-Core, galaxy-util, vb2py, gluetool, madgui, pydoc-fork,
> ScopeSim, bluewhale-canvas-core, rstdoc, galaxy-lib,
> orange-canvas-core-ml, meditor, jarn.viewdoc, formiko)
> * 4 are agnostic to output type, as they pass the output of
> ``publish_string`` straight into ``BeautifulSoup()`` or
> ``xml.etree.ElementTree.fromstring``, both of which accept either bytes
> or str. (doc-warden, testimony, pyLanguagetool, turq)

Good news for Docutils: we are not alone. 
"xml.etree" also uses:

"string" or "string constant"
  as a superordinate term for a sequence of characters, either
  encoded (`bytes`) or as Unicode code points (`str`).

"unicode" 
   as a pseudo-encoding name for "no encoding" (i.e. "return as
   `str` instance").

Maybe we can agree with the etree team on a compatible terminology and way
forward.

> * 3 use custom writers or the document tree, and don't use the returned
> output (pydoctor, restview, fairy-slipper)
> * 2 are broken by calling ``str()`` on a bytes instance without an
> ``encoding`` argument. (prettyqt, cornice_sphinx)
> * 1 ignores output and just uses the call to check it doesn't raise any
> exceptions (rstcheck-core)
> * 3 expect ``bytes`` and could use the proposed ``publish_bytes()``
>   function (awscli, bugrest, quorachallenge)

One more, `pyreport`_, is currently unmaintained and Python2 only...

.. _pyreport: https://github.com/joblib/pyreport

There may be more use cases in unpublished packages/modules/scripts
or helper scripts in non-Python projects.

> I am happy to work with the ~17 (14 + 3) that would be affected to help
> them to refactor, should we agree on a way forwards.

I am quite confident that we will find a consensus.

I would still want to revert the FutureWarnings until there is a stable
alternative in place.

> Out of interest, none used an ``output_encoding`` setting other than
> "unicode" or "utf-8".

Did you also check the configuration files?
Docutils also defaults to "output_encoding: utf-8" but allows users to
change this to any valid encoding via settings_spec or settings_overrides
or in a configuration file.
(Just checked: publish_string() respects the "output_encoding" set in a
docutils.conf file.)

> I would be content to delay the switch-over of return type from
> ``publish_string`` to Docutils 1.0 or 2.0 should more time be needed,
> but I suppose I see the other scenarios as sub-optimal for the
> long-term in one way or another -- e.g. ``publish_str_instance`` is
> unweidly to use regularly, and using e.g. ``publish_str`` instead would
> be confusing when ``publish_string`` still exists.

OTOH, `publish_string()` vs. `publish_bytes()` mismatch: one uses a
Python3 datatype name while the other an overloaded general term.

>>>> Regarding the "core.publish_string()" function, I see three possibilities:

>>>> Alternatives forward:

>>>> 1. [Revert to Docutils 0.19 behaviour, with clearer documentation].

>>>> 2. Add a new boolean argument: "encode".

>>>> 3. Deprecate "publish_string()" in favour of new, separate
        "publish_str()" and "publish_bytes()" functions.

During the transition period, editors with name completion will show both
`publish_str()` and `publish_string()` in the expansion list and coders
will likely look up the docstring for the difference.


>> If the documentation is clear about possible return values (and even
>> more after adding type hints) users should be able to live with the
>> unfortunate naming.

> Unfortunatley as far as I am aware type hints are unable to code for a
> setting within a dictionary affecting the return type of the function.
> I agree the documentation should be made clearer.

Type hints should support documenting the fact that a function accepts or
returns any of a set of data types (e.g. "`int` or `str`", "`int` or
`float`", or "`str` or `bytes`"). The details/conditions should be given
in the docstring.


>> OTOH, I see a use-case for a convenience function returning a `str`
>> instance also in cases where an "intended encoding" of the output is
>> given in the "output-encoding" setting. This way, a program using this
>> function can export a HTML, XML or LaTeX with an encoding declaration
>> as `str` instance, post-process and finally encode it before handing
>> it to storage or a non-Python processor.

> Yes, this is my general view too -- I see ``publish_string`` as a
> function to be called from other Python programmes.

>> If we are going to change the core API functionality regarding the
>> convenience function(s) to publish the output as `str` or `bytes`
>> instance, then we should:

>> * do not start this in the middle of a major refactoring of the test suite
>>   (where it is hard to spot the changes in expected output from
>>   "cosmetic" changes in the test code).

> I agree with this, in retrospect it was a poor choice.

>> * do it in a "quasi static" manner: both, old and the new behaviour must
>>   be accessible over a sequence of two or more stable releases.

> This of course makes sense.

>> This means that if we want to introduce an explicit `publish_bytes()`
>> convenience function, a corresponding `BytesOutput` class is
>> appropriate.

> OK, though it seems this is dependent on the outcome of the
> ``publish_string`` decision.

Maybe we can also directly support `str` as `destination_class` value in
core.Publisher and publish_programmatically().

The whole problem looks like a candidate for one more enhancement proposal ;)

Günter



_______________________________________________
Docutils-develop mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/docutils-develop

Please use "Reply All" to reply to the list.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.