Skip to content

Implementation of the PEP 538: coerce C locale to C.utf-8 #72367

Closed

Description

@JanNiklasHasse
BPO 28180
Nosy @malemburg, @warsaw, @ronaldoussoren, @ncoghlan, @vstinner, @ned-deily, @mcepl, @ezio-melotti, @bitdancer, @methane, @4kir4, @xdegaye, @yan12125, @Vgr255
PRs
  • bpo-28180: Implementation for PEP 538 #659
  • bpo-28180: assume UTF-8 for Mac OS X PEP 538 tests #2130
  • bpo-28180: Fix test_capi.test_forced_io_encoding() #2155
  • bpo-28180: Standard stream & FS encoding differ on Mac OS X #2208
  • bpo-28180: Fix the implementation of PEP 538 on Android #4334
  • Dependencies
  • bpo-30565: PEP 538: silence locale coercion and compatibility warnings by default?
  • bpo-30635: Leak in test_c_locale_coercion
  • bpo-30647: CODESET error on AMD64 FreeBSD 10.x Shared 3.x caused by the PEP 538
  • Files
  • fedora-cpython-force-c-utf-8.diff: Downstream patch currently proposed for Fedora 26
  • fedora-cpython-PYTHONALLOWCLOCALE.diff: Draft Fedora 26 patch as at 2016-12-18
  • pep538_coerce_legacy_c_locale.diff: Initial patch for PEP 538 (targeting 3.7)
  • pep538_coerce_legacy_c_locale_v2.diff: Add test cases for handling of unknown locales
  • pep538-check-click.sh: Utility script to check click's behaviour in a PEP 538 patched CPython
  • pep538_coerce_legacy_c_locale_v3.diff: Refactor PEP 538 test cases to cover no locale setting, C locale, POSIX locale and unknown locale
  • android_setlocale.patch
  • pep538_coerce_legacy_c_locale.patch: Ufinished attempt to port this patch to Python 3.4
  • 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 2018-03-29.01:23:38.218>
    created_at = <Date 2016-09-16.11:17:02.590>
    labels = ['type-bug', '3.7', 'expert-unicode']
    title = 'Implementation of the PEP 538: coerce C locale to C.utf-8'
    updated_at = <Date 2020-03-22.16:25:00.648>
    user = 'https://bugs.python.org/JanNiklasHasse'

    bugs.python.org fields:

    activity = <Date 2020-03-22.16:25:00.648>
    actor = 'mcepl'
    assignee = 'ncoghlan'
    closed = True
    closed_date = <Date 2018-03-29.01:23:38.218>
    closer = 'ncoghlan'
    components = ['Unicode']
    creation = <Date 2016-09-16.11:17:02.590>
    creator = 'Jan Niklas Hasse'
    dependencies = ['30565', '30635', '30647']
    files = ['45907', '45951', '46059', '46121', '46190', '46205', '46329', '48991']
    hgrepos = []
    issue_num = 28180
    keywords = ['patch']
    message_count = 89.0
    messages = ['276693', '276694', '276707', '276709', '276722', '276729', '277273', '277274', '282964', '282965', '282970', '282971', '282972', '282977', '282978', '282984', '283244', '283408', '283409', '283469', '283471', '283482', '283495', '283515', '283543', '283732', '284150', '284170', '284176', '284537', '284605', '284620', '284621', '284631', '284641', '284647', '284697', '284716', '284718', '284719', '284720', '284722', '284725', '284729', '284736', '284742', '284747', '284764', '284782', '284794', '284795', '284799', '284882', '284884', '284886', '284887', '284900', '284908', '284943', '284952', '285735', '286001', '289002', '289534', '295121', '295683', '295688', '295698', '295710', '295713', '295722', '295871', '295872', '295875', '295885', '295913', '295914', '296064', '296075', '296077', '305850', '306108', '314627', '364740', '364760', '364767', '364770', '364804', '364810']
    nosy_count = 16.0
    nosy_names = ['lemburg', 'barry', 'ronaldoussoren', 'ncoghlan', 'vstinner', 'ned.deily', 'mcepl', 'ezio.melotti', 'r.david.murray', 'methane', 'akira', 'Sworddragon', 'xdegaye', 'yan12125', 'abarry', 'Jan Niklas Hasse']
    pr_nums = ['659', '2130', '2155', '2208', '4334']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue28180'
    versions = ['Python 3.7']

    Activity

    1. JanNiklasHasse commented on Sep 16, 2016

      JanNiklasHassemannequin
      MannequinAuthor

      Working with Docker I often end up with an environment where the locale isn't correctly set. In these cases it would be great if sys.getfilesystemencoding() could default to 'utf-8' instead of 'ascii', as it's the encoding of the future and ascii is a subset of it anyway.

      Related: http://bugs.python.org/issue19846

    2. Vgr255 commented on Sep 16, 2016

      Vgr255mannequin
      Mannequin

      This is a duplicate of bpo-27781.

    3. vstinner commented on Sep 16, 2016

      @vstinner
      Member

      This is a duplicate of bpo-27781.

      bpo-27781 is specific to Windows. I'm not sure that it's the base in this issue. So I reopen the issue.

      @jan Niklas Hasse: What is your OS?

      I proposed to add "-X utf8" command line option for UNIX to force utf8 encoding. Would it work for you?

    4. JanNiklasHasse commented on Sep 16, 2016

      JanNiklasHassemannequin
      MannequinAuthor

      Unfortunately no, as this would mean I'll have to change all my python invocations in my scripts and it wouldn't work for executable files with

      #!/usr/bin/env python3

      would it?

    5. bitdancer commented on Sep 16, 2016

      @bitdancer
      Member

      I thought we "fixed" this by using surrogate escape when the locale was ASCII? We certainly have discussed changing the default and posix and so far have decided not to (someday that will change...is this someday already?)

    6. vstinner commented on Sep 16, 2016

      @vstinner
      Member

      is this someday already?)

      Not yet :-)

    7. JanNiklasHasse commented on Sep 23, 2016

      JanNiklasHassemannequin
      MannequinAuthor

      Why not?

    8. methane commented on Sep 23, 2016

      @methane
      Member

      I want locale free Python which behaves like on C.UTF-8 locale.
      (stdio encoding, preferred encoding, weekday in _strptime._strptime,
      and more maybe)

      But Python 3.6 is feature freeze already >_<;;

    9. ncoghlan commented on Dec 12, 2016

      @ncoghlan
      Contributor

      I think we're genuinely getting to the point now where the majority of "LANG=C" cases are misconfigurations rather than intended behaviour. We're also to the point where:

      • on Mac OS X, binary system interfaces have been handled as UTF-8 by default since 3.0
      • on Windows, as of 3.6, the OS native binary system interfaces are now bypassed entirely in favour of transcoding from UTF-8 to UTF-16-LE

      So I think for Python 3.7 it makes sense to do the following on other *nix systems:

      • very early in CPython startup (even before argument processing), if the detected locale is "C", force it to "C.UTF-8" if possible, and print a warning either way
      • add a PYTHONKEEPASCIILOCALE environment variable to turn that behaviour off

      I do think we actually want to *change* the C level locale in the process though, as otherwise we can expect to see weird interactions where CPython and extension modules disagree about the default text encoding.

    10. ncoghlan commented on Dec 12, 2016

      @ncoghlan
      Contributor

      Note also that if we say we're going to do this for 3.7, *and* go ahead and implement it, then distros may be more inclined to incorporate the same behavioural changes into distro-provided releases of 3.6, providing real world testing of the concept before we make it the default behaviour.

    11. 80 remaining items

    12. mcepl commented on Mar 21, 2020

      mceplmannequin
      Mannequin

      Python 3.4 is no longer supported upstream. Python 3 got tons of Unicode fixes between Python 3.4 and Python 3.8.

      Of course, I know that, but I just didn’t want to throw all my effort away, when I spent some hours on making it. And I guess, there may be somebody else who cares for 3.4 (ehm, RHEL-7 has 3.3, doesn’t it?).

    13. vstinner commented on Mar 21, 2020

      @vstinner
      Member

      RHEL 7.7 and RHEL 8 provides Python 3.6. PEP-538 was implemented in Python 3.7. PEP-538 feature was backported in RHEL 7.7 and RHEL 8 Python 3.6.

    14. ncoghlan commented on Mar 22, 2020

      @ncoghlan
      Contributor

      The test cases for locale coercion *not* triggering still assume that bpo-19977, using surrogateescape on the standard streams in the POSIX locale, has been implemented (since that was implemented in Python 3.5).

      Hence the various test cases complaining that they found "ascii:strict" (Py 3.4 behaviour without bpo-19977) where they expected "ascii:surrogateescape" (the Py 3.5+ behaviour *with* bpo-19977).

      To get a PEP-538 backport to work as intended on 3.4, you'd need to backport that earlier IO stream error handling change as well.

    15. mcepl commented on Mar 22, 2020

      mceplmannequin
      Mannequin

      Thank you very much for the hint. Do I have to include the patch for bpo-19977 only (that would be easy), or also all twelve PRs for bpo-29240 (that would probably broke my will to do it)?

    16. transferred this issue fromon Apr 10, 2022
    17. calestyo commented on May 29, 2022

      @calestyo
      Contributor

      Not sure whether this is the appropriate place to mention/ask... but it seems that with this chance it's impossible to get the original environment Python was invoked with, or is there?
      This in turn may however be important for e.g. wrapper programs, which would want to invoke other programs with the exact original locale they were invoked themselves.

    18. methane commented on May 29, 2022

      @methane
      Member

      You can set PYTHONCOERCECLOCALE=0 to disable coercion.

    19. calestyo commented on May 29, 2022

      @calestyo
      Contributor

      Yes, but that just shifts the problem. Then one wouldn't know whether PYTHONCOERCECLOCALE was meant to be part of the real original environment, or whether it was just there to not mess around with that.

    20. methane commented on May 29, 2022

      @methane
      Member

      What is the real use case for it?
      locale affects many programs, but PYTHONCOERCELOCALE affects only Python. I don't think it is real problem for most users.

      If it is really your problem, you can disable the coercion by default by building your Python with --with-c-locale-coercion option.

    21. calestyo commented on May 29, 2022

      @calestyo
      Contributor

      Take any program that shall be written in Python and which works just as a wrapper around some other program, with the specific intention that the environment is passed on exactly to that program. Just as an example, a wrapper-program that adds numbers to lines... or maybe counts characters in the stdout of the program.

      The program the wrapper calls may even be another Python program... at that point it should become quite clear that it's apparently not possible to get that behaviour.
      Either one does nothing respectively e.g. explicitly wants to run in a C local environment and does env -i LC_CTYPE=C python3 wrapper.py command or so... then Python would do the coercion and command wouldn't see the original environment.
      Same if one does env -i python3 in which case, as per POSIX, command should fall back to the “implementation-defined default locale”, but Python would override this to C.UTF-8.

      If one disables that behaviour with PYTHONCOERCELOCALE one cannot know whether this was meant (just) for the wrapper script in order to not do the coercion, or whether it was meant for command.
      Or take something where command is something executed via ssh, LC_CTYPE is often configured to be forwarded via that, so one may not wish to have that set by Python, OTOH, one may again execute a remote Python command and may not want to have PYTHONCOERCELOCALE in the environment either, unless it's really meant for the remote.

    22. calestyo commented on May 29, 2022

      @calestyo
      Contributor

      but PYTHONCOERCELOCALE affects only Python

      Oh and, as unlikely as it is, there is no guarantee for that, at all. Changing the built-options doesn't really help either, as no real-world Python will have that.

      The problem here really is that one seems to have no way to either get/restore the true original local (directly or indirectly).

    23. methane commented on May 29, 2022

      @methane
      Member

      I understand theorical problem. What I am asking for is how this issue affects to users in real world.
      Please give us more concrete use cases.

      And this issue is not good place for this discussion. Please move to discuss.python.org.

    24. calestyo commented on May 29, 2022

      @calestyo
      Contributor

      Well I wouldn't call it a theoretical(only) problem. There is a clear use-case described along with several examples (i.e. any program who wants to serve as a transparent wrapper)... which I think speaks for itself.
      At least I wouldn't know how to "prove" validity of the use case any further - that feels a bit as if division by 834756387465723672348394923 would fail any I'd need to prove why on earth anyone could ever want to divide by exactly that.

      However, I don't think any further discussion is really needed, at least not from my side,... I've simply used C now which is as good for me and does the job well enough.

      As said, in the original post, I've just noted that this makes it impossible to get the original environment (except when using hacks)... and wanted to bring that to attention.

      Whether Python wants to support that is up to that. A simple solution would perhaps be to provide something like a os.original_environment or so, which would solve the same problem should any other modifications done in the future.

    25. ncoghlan commented on Jun 3, 2022

      @ncoghlan
      Contributor

      Wrapper program or no, setting 7-bit ASCII as the text encoding was deemed an unsupported system configuration error in 2018 when this PEP was accepted and implemented, and is still seen that way now. Given the availability of UTF-8 as an alternative, there's no good reason to run English-only systems any more. Hence the platform compatibility guidelines in PEP 11 being updated when these encoding related PEPs were accepted.

      That said, setting PYTHON_PRECOERCION_LOCALE in the environment when the coercion triggers would be straightforward, so I'd personally be +0 on providing that as a debugging aid, even though I'd advise wrapper script authors to resist the temptation to revert the coercion (all the wrapper scripts in the standard library intentionally leave the coerced locale in place)

    26. ncoghlan commented on Jun 3, 2022

      @ncoghlan
      Contributor

      Note: any such a feature request should be filed as a new issue, and while I'd be happy to review a PR for such an addition, I wouldn't write it myself.

    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