Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-10746: ctypes: Fix PEP 3118 type codes for c_long, c_bool, c_int #31

Merged
merged 1 commit into from
Aug 28, 2017

Conversation

pv
Copy link
Contributor

@pv pv commented Feb 11, 2017

Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8

The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes. The struct module format syntax also does not
allow specifying native-size non-native-endian items.

This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this.

Example of the current problem in practice:

>>> import numpy, ctypes
>>> numpy.asarray(memoryview(ctypes.c_long(42)))
/usr/lib64/python3.5/site-packages/numpy/core/numeric.py:482: RuntimeWarning: Item size computed from the PEP 3118 buffer format string does not match the actual item size.
  return array(a, dtype, copy=False, order=order)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.5/site-packages/numpy/core/numeric.py", line 482, in asarray
    return array(a, dtype, copy=False, order=order)
ValueError: setting an array element with a sequence.

https://bugs.python.org/issue10746

@the-knights-who-say-ni
Copy link

Hello, and thanks for your contribution!

I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA).

Unfortunately our records indicate you have not signed the CLA. For legal reasons we need you to sign this before we can look at your contribution. Please follow these steps to rectify the issue:

  1. Sign the PSF contributor agreement
  2. Wait at least a day and then check "Your Details" on bugs.python.org to see if your account has been marked as having signed the CLA (the delay is due to a person having to manually check your signed CLA)
  3. Reply here saying you have completed the above steps

Thanks again to your contribution and we look forward to looking at it!

@codecov
Copy link

codecov bot commented Feb 11, 2017

Codecov Report

Merging #31 into master will increase coverage by <.01%.
The diff coverage is 84.61%.

@@            Coverage Diff             @@
##           master      #31      +/-   ##
==========================================
+ Coverage   82.37%   82.37%   +<.01%     
==========================================
  Files        1427     1427              
  Lines      350948   350957       +9     
==========================================
+ Hits       289088   289114      +26     
+ Misses      61860    61843      -17

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e7ffb99...b4cf54b. Read the comment docs.

@pv
Copy link
Contributor Author

pv commented Feb 14, 2017 via email

since the endianness may need to be swapped to a non-native one
later on.
*/
char *
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be declared static.

# Since some types may be aliases to each other, look up the
# struct code based on the actual ctypes type
tp = code_map[ctypes_code][0]
struct_code = code_map[tp._type_][1][sizeof(tp)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this line. Can you show an example where tp._type_ is necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say I don't understand it either anymore. It may be leftover from refactoring.
Since the tests seem to pass, I now simplified it.

Copy link
Contributor Author

@pv pv Jun 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no, it was due to a int/long failure on windows:

======================================================================
FAIL: test_native_types (ctypes.test.test_pep3118.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\projects\cpython\lib\ctypes\test\test_pep3118.py", line 56, in test_native_types
    normalize(replace_type_codes(fmt)))
AssertionError: '<l' != '<i'
- <l
+ <i

Added explanatory comment in the test.

case 'i': pep_code = 'q'; break;
case 'I': pep_code = 'Q'; break;
#else
# error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add a non-empty error message, for example "SIZEOF_INT is not one of the expected values".

case 'l': pep_code = 'q'; break;
case 'L': pep_code = 'Q'; break;
#else
# error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

#elif SIZEOF__BOOL == 8
case '?': pep_code = 'Q'; break;
#else
# error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@pv
Copy link
Contributor Author

pv commented Jun 22, 2017

Sorry for the delay, updated the PR based on comments.

@pv pv force-pushed the bpo-10746 branch 2 times, most recently from d43d02d to eed2ee1 Compare June 22, 2017 23:02
@pv
Copy link
Contributor Author

pv commented Aug 26, 2017

ping?

@pitrou
Copy link
Member

pitrou commented Aug 26, 2017

Sorry for the delay.

#
# Example: on Windows c_long translates to '<i', not '<l'.
tp = code_map[ctypes_code][0]
struct_code = code_map[tp._type_][1][sizeof(tp)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still find this difficult to read and understand. Can't you rewrite the unit tests and the native_types array to get rid of the double indirection?

@@ -111,7 +146,11 @@ class Complete(Structure):
#
# This table contains format strings as they look on little endian
# machines. The test replaces '<' with '>' on big endian machines.
# The type codes written below are the internal ctypes type codes,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal ctypes type codes are not even documented, are they?

@pitrou
Copy link
Member

pitrou commented Aug 26, 2017

Thanks for persisting. I am not really happy about the way this hacks around the current structure of the tests. It adds a lot of complication that seems pointless given the task at hand (we're just checking a mapping, right?).

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017 via email

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017 via email

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017 via email

@pitrou
Copy link
Member

pitrou commented Aug 26, 2017

My main gripe here is that you shouldn't need code_map at all, let alone the complicated double indirection inside that table. Just add/replace whatever information is missing to native_types.

Also we don't care at all about ctypes internal code types, so the tests would be clearer if they didn't involve them.

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017 via email

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017 via email

@pitrou
Copy link
Member

pitrou commented Aug 26, 2017

You are already encoding platform-dependent information (the size mappings) in code_map? Why don't you fold that into native_types?

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017 via email

@pv
Copy link
Contributor Author

pv commented Aug 26, 2017

Ok, once more then, without magic. Is this what you wanted?

@pitrou
Copy link
Member

pitrou commented Aug 28, 2017

Thank you! :-) I find this much better. In particular, it's explicit that the exact type code does not depend only on the type size but also on whether c_int aliases c_long, for example (which is a weird oddity, but I guess it's not this PR's responsability to change that).

One additional thing: can you add a NEWS entry? We nowadays use the blurb CLI tool for that.

@pv
Copy link
Contributor Author

pv commented Aug 28, 2017

It's here: https://travis-ci.org/python/cpython/jobs/269157668
The build passes with success regardless.

@pitrou
Copy link
Member

pitrou commented Aug 28, 2017

Hmm... are you sure you updated master before rebasing?

@pv
Copy link
Contributor Author

pv commented Aug 28, 2017 via email

@pitrou
Copy link
Member

pitrou commented Aug 28, 2017

I see. Well, it passed on AppVeyor anyway, so I'm going to merge. Thanks for persisting in this!

@pitrou pitrou merged commit 07f1658 into python:master Aug 28, 2017
pv added a commit to pv/cpython that referenced this pull request Aug 30, 2017
…_int (pythonGH-31)

Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8

The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes.  The struct module format syntax also does not
allow specifying native-size non-native-endian items.

This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this.
(cherry picked from commit 07f1658)
pv added a commit to pv/cpython that referenced this pull request Aug 30, 2017
…_int (pythonGH-31)

Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8

The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes.  The struct module format syntax also does not
allow specifying native-size non-native-endian items.

This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this..
(cherry picked from commit 07f1658)
pitrou pushed a commit that referenced this pull request Aug 30, 2017
…_int (GH-31) (#3241)

Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8

The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes.  The struct module format syntax also does not
allow specifying native-size non-native-endian items.

This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this.
(cherry picked from commit 07f1658)
pitrou pushed a commit that referenced this pull request Sep 2, 2017
…_int (GH-31) (#3242)

[2.7] bpo-10746: Fix ctypes PEP 3118 type codes for c_long, c_bool, c_int (GH-31)

Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8

The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes.  The struct module format syntax also does not
allow specifying native-size non-native-endian items.

This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this..
(cherry picked from commit 07f1658)
GadgetSteve pushed a commit to GadgetSteve/cpython that referenced this pull request Sep 10, 2017
…ython#31)

Ctypes currently produces wrong pep3118 type codes for several types.
E.g. memoryview(ctypes.c_long()).format gives "<l" on 64-bit platforms,
but it should be "<q" instead for sizeof(c_long) == 8

The problem is that the '<>' endian specification in the struct syntax
also turns on the "standard size" mode, which makes type characters have
a platform-independent meaning, which does not match with the codes used
internally in ctypes.  The struct module format syntax also does not
allow specifying native-size non-native-endian items.

This commit adds a converter function that maps the internal ctypes
codes to appropriate struct module standard-size codes in the pep3118
format strings. The tests are modified to check for this.
jaraco pushed a commit that referenced this pull request Dec 2, 2022
There were cases where data["commit"]["committer"] is null.
jaraco pushed a commit to jaraco/cpython that referenced this pull request Feb 17, 2023
nanjekyejoannah added a commit to nanjekyejoannah/cpython that referenced this pull request Jul 28, 2023
31: Only warn in file init r=ltratt a=nanjekyejoannah

Fixes python#29 

Co-authored-by: Joannah Nanjekye <jnanjeky@unb.ca>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants