Skip to content

Unicode conversion issue #1466

Closed
Closed

Description

@pkese

Environment

  • Pythonnet version: 3.0.0-preview2021-06-04
  • Python version: 3.8.8
  • Operating System: ubuntu 21.04
  • .NET Runtime: 5.0.300

Details

Unicode characters get lost / mangled during conversion:

scope.Exec("testStr = 'Nom 🍗';");
scope.Exec("""print("python:", testStr);""")
Console.WriteLine($"""dotnet: {scope.Get("testStr").ToString()}""");

writes

python: Nom 🍗
dotnet: Nom �

Activity

  1. pkese commented on Jun 7, 2021

    @pkese
    ContributorAuthor

    Presumably the problem is surrogate pairs.
    It seems that two-pair unicode sequences get incorrect string length - e.g. in actual letters rather than the amount of unicode characters that are required to properly encode these letters.

    scope.Exec("testStr = 'Test 💪...';");
    scope.Exec("""print("python:", testStr);""")
    Console.WriteLine($"""dotnet: {scope.Get("testStr").ToString()}""");

    results in

    python: Test 💪...
    dotnet: Test 💪..
    

    ^^^ Notice how one dot at the end of string is missing in dotnet version

  2. pkese commented on Jun 7, 2021

    @pkese
    ContributorAuthor

    Analogously, putting two unicode surrogates into string will eat two dots at the end

    python: Test 💪💪...
    dotnet: Test 💪💪.
    
  3. pkese commented on Jun 8, 2021

    @pkese
    ContributorAuthor

    It looks this problem goes in both directions:

    • when converting from dotnet, Python expects the string "foo🐼" to be 4 characters long, but we somehow create a Python object with Length 5.
    • when converting from Python to dotnet, we truncate the string as described above. In my test Add a failing test for Unicode conversion #1467, it appears that there is some sort of size mismatch and a null pointer is returned somewhere in the call stack.

    I found some hints of how Python treats unicode conversion internally https://stackoverflow.com/questions/36098984/python-3-3-c-api-and-utf-8-strings

    Using PyUnicode_DecodeUTF16 or PyUnicode_DecodeUTF16Stateful instead of PyUnicode_FromKindAndData would maybe alleviate this problem. But getting these functions imported from .dlls and getting delegates in place is probably beyond my capacity.

  4. filmor commented on Jun 8, 2021

    @filmor
    Member

    Thank you for the detailed evaluation, I'll have a look at this this weekend. We indeed treat all strings coming from .NET as UCS2 and that breaks as soon as surrogate pairs are involved.

  5. pkese commented on Jun 8, 2021

    @pkese
    ContributorAuthor

    I managed to fix the Python to dotnet path in runtime.cs: 1b6c6c0

    This fixes one side of the problem - i.e. the initial bug report.

    However the dotnet -> Python conversion issue still remains.

  6. filmor commented on Jun 8, 2021

    @filmor
    Member

    Very nice, I'll work on the other direction. The underlying issue (I think) is that C# "some str".Length that we use returns the number of Unicode code points, which may be 16 or 32 bit in UTF-16. The safest solution is likely the one you suggested, to use the UTF16-specific functions of the Python API.

  7. filmor commented on Jun 11, 2021

    @filmor
    Member

    Fixed by #1467, thank you very much :)

  8. pkese commented on Jun 11, 2021

    @pkese
    ContributorAuthor

    And thank You, @filmor, for fixing all the rest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions