Skip to content

No good way to set 'PYTHONIOENCODING' when embedding python. #60333

Closed

Description

@ideasman42
mannequin
BPO 16129
Nosy @malemburg, @loewis, @ncoghlan, @vstinner, @larryhastings, @tiran, @asvetlov, @ideasman42, @skrah
Files
  • pyos_putenv.diff: patch on python 3.4 hg - 80610:618ea5612e83
  • setstdio.diff: patch...
  • setstdio.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/ncoghlan'
    closed_at = <Date 2013-11-03.12:23:10.879>
    created_at = <Date 2012-10-04.12:58:14.980>
    labels = ['type-feature', 'OS-windows']
    title = "No good way to set 'PYTHONIOENCODING' when embedding python."
    updated_at = <Date 2014-02-25.21:03:43.056>
    user = 'https://github.com/ideasman42'

    bugs.python.org fields:

    activity = <Date 2014-02-25.21:03:43.056>
    actor = 'python-dev'
    assignee = 'ncoghlan'
    closed = True
    closed_date = <Date 2013-11-03.12:23:10.879>
    closer = 'ncoghlan'
    components = ['Windows']
    creation = <Date 2012-10-04.12:58:14.980>
    creator = 'ideasman42'
    dependencies = []
    files = ['28144', '31808', '31985']
    hgrepos = []
    issue_num = 16129
    keywords = ['patch']
    message_count = 39.0
    messages = ['171938', '171941', '172054', '172073', '176514', '176515', '176516', '197894', '197903', '198023', '198864', '199153', '199255', '200120', '200122', '200123', '200124', '200125', '200137', '200138', '200139', '200140', '200141', '200142', '200145', '200146', '200177', '200249', '200250', '200251', '200252', '200254', '200255', '200257', '200259', '202002', '202007', '202017', '212210']
    nosy_count = 13.0
    nosy_names = ['lemburg', 'loewis', 'ncoghlan', 'vstinner', 'larry', 'christian.heimes', 'Arfrever', 'asvetlov', 'ideasman42', 'skrah', 'python-dev', 'Brecht.Van.Lommel', 'mont29']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue16129'
    versions = ['Python 3.4']

    Activity

    1. ideasman42 commented on Oct 4, 2012

      ideasman42mannequin
      MannequinAuthor

      note, I was asked to report this issue, posted on the py dev mailing list: see - http://code.activestate.com/lists/python-dev/118015/

      ---

      We've run into an issue recently with blender3d on ms-windows where we
      want to enforce the encoding is UTF-8 with the embedded python
      interpreter.
      (the encoding defaults to cp437).

      I naively thought setting the environment variable before calling
      Py_Initialize() would work, but the way python DLL loads, it gets its
      own environment variables that cant be modified directly [1].
      eg, _putenv("PYTHONIOENCODING=utf-8:surrogateescape");

      We had bug reports by windows users not able to export files because
      the stdout errors on printing paths with unsupported encoding. [2],[3]

      ---

      Of course we could distribute blender with a bat file launcher that
      sets env variables, or ask the user to set their env variable - but I
      dont think this is really a good option.

      I tried overriding the stderr & stdout, but this caused another bug on exiting, giving an assert in MSVCR90.DLL's write.c (called from python32_d.dll):
      _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(fh) & FOPEN), EBADF, -1);

      import sys, io
      sys.__stdout__ = sys.stdout =
      io.TextIOWrapper(io.open(sys.stdout.fileno(), "wb", -1),
      encoding='utf-8', errors='surrogateescape', newline="\n",
      line_buffering=True)
      sys.__stderr__ = sys.stderr =
      io.TextIOWrapper(io.open(sys.stderr.fileno(), "wb", -1),
      encoding='utf-8', errors='surrogateescape', newline="\n",
      line_buffering=True)

      IMHO either of these solutions would be fine.

      • have a PyOS_PutEnv() function, gettext has gettext_putenv() to
        workaround this problem.

      • manage this the same as Py_GetPythonHome(), which can be defined by
        the embedding application to override the default.

      [1] http://stackoverflow.com/questions/5153547/environment-variables-are-different-for-dll-than-exe
      [2] http://projects.blender.org/tracker/index.php?func=detail&aid=32750
      [3] http://projects.blender.org/tracker/index.php?func=detail&aid=31555

    2. vstinner commented on Oct 4, 2012

      @vstinner
      Member

      See also issue bpo-15216.

    3. malemburg commented on Oct 5, 2012

      @malemburg
      Member

      IMHO either of these solutions would be fine.

      • have a PyOS_PutEnv() function, gettext has gettext_putenv() to
        workaround this problem.

      This solution would help in many other cases as well, so adding
      such an API would certainly help more than specialized interfaces.

      • manage this the same as Py_GetPythonHome(), which can be defined by
        the embedding application to override the default.

      I think you meant Py_SetPythonHome().

      Given that the IO encoding is very important for Python 3.x, a special
      API just for setting the encoding may be useful to have as well.

      Care must be taken, though, that the encoding cannot be set after
      Py_Initialize() has been called.

      It may overall be easier to go with the PyOS_PutEnv() solution to
      not run into the problems with having to check for an initialized
      interpreter first.

      --
      Marc-Andre Lemburg
      eGenix.com

      Professional Python Services directly from the Source  (#1, Oct 05 2012)
      >>> Python Projects, Consulting and Support ...   http://www.egenix.com/
      >>> mxODBC.Zope/Plone.Database.Adapter ...       http://zope.egenix.com/
      >>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
      ________________________________________________________________________
      2012-09-27: Released eGenix PyRun 1.1.0 ...       http://egenix.com/go35
      2012-09-26: Released mxODBC.Connect 2.0.1 ...     http://egenix.com/go34
      2012-09-25: Released mxODBC 3.2.1 ...             http://egenix.com/go33
      2012-10-23: Python Meeting Duesseldorf ...                 18 days to go

      eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
      D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
      Registered at Amtsgericht Duesseldorf: HRB 46611
      http://www.egenix.com/company/contact/

    4. ideasman42 commented on Oct 5, 2012

      ideasman42mannequin
      MannequinAuthor

      Agree PyOS_PutEnv would be good since its not restricted to string encoding and resolves the problem of not being able to control env vars for an embedded interpreter in general.

      Having ways to change encoding is good too but a bit outside the scope of this report and possibly not the best solution either since its possible (through unlikely), that you need to set the encoding at the very start of python initialization- rather than site & builtin modules loads.

    5. ideasman42 commented on Nov 28, 2012

      ideasman42mannequin
      MannequinAuthor

      patch attached, simply wraps putenv()

    6. tiran commented on Nov 28, 2012

      @tiran
      Member

      At first glance your proposed fix looks like an easy hack to get around the issue. However it's not going to work properly. Embedded Python interpreters should isolate themselves from the user's environment. When Py_IgnoreEnvironmentFlag is enabled, Py_GETENV() always returns NULL.

      IMHO we can't get around Py_GetIOEncoding(), Py_SetIOEncoding() and Py_IOEncoding.

    7. ncoghlan commented on Nov 28, 2012

      @ncoghlan
      Contributor

      Claiming this one, mainly because I want people to largely leave the already hairy initialisation process alone until we get a chance to discuss it at the language summit next year.

      I plan to write up a comprehensive overview of the initialisation sequence before then, because we need to be figuring out how to *delete* code here, instead of adding even more.

    8. self-assigned this
      on Nov 28, 2012
    9. BrechtVanLommel commented on Sep 16, 2013

      BrechtVanLommelmannequin
      Mannequin

      With the language summit passed some time ago, is there now a more clear picture of how this would fit in the initialisation process?

      Any idea of what a proper implementation would look like, or is the message still to wait?

    10. ncoghlan commented on Sep 16, 2013

      @ncoghlan
      Contributor

      The gory details of the current startup situation are in PEP-432. However, the comprehensive solution described in that PEP isn't going to make it into Python 3.4, so a simpler interim fix would be worthwhile.

      Since Blender is designed to support building against the system Python, the trick of forcing Python to link to an alternate implementation of a function won't work.

      Inspired by http://docs.python.org/3/c-api/init.html#Py_SetPath, I suggest offering an API like:

      int Py_SetStandardStreamEncoding(char *encoding, char *errors)
      {
          if (Py_IsInitialized()) {
              return -1;
          }
          Py_StandardStreamEncoding = _PyMem_Strdup(encoding);
          Py_StandardStreamErrors = _PyMem_Strdup(errors);
      }

      The initstdio function in pythonrun.c would then be updated to use the specified Py_StandardStreamEncoding and Py_StandardStreamErrors if they weren't NULL (since that would indicate an embedding application had called SetStandardStreamEncoding).

    11. removed their assignment
      on Sep 16, 2013
    12. mont29 commented on Sep 18, 2013

      mont29mannequin
      Mannequin

      Hi,

      Decided to give it a try and implement suggested Py_SetStandardStreamEncoding, see attached patch.

      A quick test with Blender under Linux (with an ASCII console) seems to work OK, unfortunatly I do not have Windows to test it where it really matters...

      That's my first piece of code ever written for Python, I hope it does not contain too much obvious errors!

    13. mont29 commented on Oct 2, 2013

      mont29mannequin
      Mannequin

      No one to check the patch? It’s rather small, should not take much time… And we really need a solution for this issue, so better to try to get this settled before 3.4 freeze! ;)

    14. 18 remaining items

    15. ncoghlan commented on Oct 18, 2013

      @ncoghlan
      Contributor

      I dealt with the comments folks made here and on python-dev regarding the docs and the limited API, as well as the fact it isn't safe to call PyErr_NoMemory() when this function fails.

      However, I still haven't been able to reproduce the failure seen on the buildbots. It isn't a simple cross-test interference problem, as I tried the randomization seed from the Ubuntu log and that still passed for me. I'm still trying the seed from Stefan's FreeBSD system, but I expect that will be clean here as well.

    16. ncoghlan commented on Oct 18, 2013

      @ncoghlan
      Contributor

      (As expected, the original FreeBSD randomization seed passed here without any problems)

      Before I disabled the test completely, I did a run with full error diffs enabled.

      Here's the FreeBSD log with full diffs:
      http://buildbot.python.org/all/builders/AMD64%20FreeBSD%2010.0%203.x/builds/580/steps/test/logs/stdio

      This indicates both "{0.stdout.encoding}" and "{0.stdout.encoding}" produced the string "None" in the formatting operation that creates the expected output.

      The Ubuntu run exhibits the same behaviour:
      http://buildbot.python.org/all/builders/AMD64%20Ubuntu%20LTS%203.x/builds/2717/steps/test/logs/stdio

      Note that on both symptoms, the later run passes without a problem, and (aside from the full diff being enabled the second time), the symptoms were identical (further pushing against a cross-test compatibility problem).

      And the full gory list of failed logs with this error and the full diffs:
      http://buildbot.python.org/all/builders/AMD64%20OpenIndiana%203.x/builds/6502/steps/test/logs/stdio
      http://buildbot.python.org/all/builders/AMD64%20Snow%20Leop%203.x/builds/170/steps/test/logs/stdio
      http://buildbot.python.org/all/builders/x86%20Gentoo%20Non-Debug%203.x/builds/5175/steps/test/logs/stdio
      http://buildbot.python.org/all/builders/AMD64%20FreeBSD%209.0%203.x/builds/5508/steps/test/logs/stdio
      http://buildbot.python.org/all/builders/x86%20Ubuntu%20Shared%203.x/builds/8767/steps/test/logs/stdio

      I couldn't find a full diff failure for this one, but this log has the truncated diff:
      http://buildbot.python.org/all/builders/PPC64%20PowerLinux%203.x/builds/861/steps/test/logs/stdio

    17. skrah commented on Oct 18, 2013

      skrahmannequin
      Mannequin

      A test order problem is indeed unlikely: I ran the tests as the buildbot user
      with the same random seed and they passed. Let's blame the buildbot software. ;)

    18. ncoghlan commented on Oct 18, 2013

      @ncoghlan
      Contributor

      Larry - I'm kinda stumped on this one. I'm not sure how to debug the failure on the buildbots, because, as Victor said, sys.stdout/err having an encoding attribute of None *isn't* supposed to happen, so the test should be fine as it stands. And nobody has been able to reproduce the problem on a direct run.

      It's probably OK to leave the test disabled for the alpha (since even the failures show that *this* feature was working correctly, it was the test case itself that was breaking).

      While I just noticed my RHEL buildbot hit the failure as well, Stefan's inability to reproduce the problem on his FreeBSD system suggests that isn't likely to help: http://buildbot.python.org/all/builders/x86%20RHEL%206%203.x/builds/2871/steps/test/logs/stdio

      (And /facepalm moment, I just realised all my testing tonight has been pointless, because I forgot to remove the skip decorator from the offending test...)

    19. ncoghlan commented on Oct 18, 2013

      @ncoghlan
      Contributor

      Ah, that got it:

      LC_ALL=C ./python -m test -W test_capi

      => boom :)

      And, of course it's a StringIO object at that point...

    20. python-dev commented on Oct 18, 2013

      python-devmannequin
      Mannequin

      New changeset 4af20969c592 by Nick Coghlan in branch 'default':
      Issue bpo-16129: this should appease the buildbots
      http://hg.python.org/cpython/rev/4af20969c592

    21. ncoghlan commented on Oct 18, 2013

      @ncoghlan
      Contributor

      So, does that mean "asked the release manager for a ruling" is the buildbot debugging equivalent of "threatened it with tech support?" :)

    22. ncoghlan commented on Nov 3, 2013

      @ncoghlan
      Contributor

      Bastien, did you get a chance to try embedding Python 3.4a4 in Blender yet? If that works for you, we can mark this one as closed.

    23. mont29 commented on Nov 3, 2013

      mont29mannequin
      Mannequin

      Wow… Good thing you remind me that. Just tested it here (linux with ASCII terminal), works perfectly. Thanks again for all the integration work, Nick!

    24. ncoghlan commented on Nov 3, 2013

      @ncoghlan
      Contributor

      Excellent!

      Zachary Ware got the embedding tests running and passing on Windows in bpo-19439 (previously they were only executed on *nix systems), so Python 3.4 should resolve this problem on all platforms.

    25. python-dev commented on Feb 25, 2014

      python-devmannequin
      Mannequin

      New changeset 4cd620d8c3f6 by R David Murray in branch 'default':
      whatsnew: DynanicClassAttribute (bpo-19030), Py_SetStandardStreamEncoding (bpo-16129)
      http://hg.python.org/cpython/rev/4cd620d8c3f6

    26. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions