niess / python-appimage

AppImage distributions of Python
https://python-appimage.readthedocs.io/en/latest/
GNU General Public License v3.0
176 stars 25 forks source link

uuid.getnode() discrepancy #65

Closed mssalvatore closed 1 year ago

mssalvatore commented 1 year ago

Description

It seems that the output of uuid.getnode() for python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage differs from Python3.11.2 in the deadsnakes ubuntu PPA.

image

To reproduce

  1. Create an Ubuntu 22.04 LXD container. (I've also reproduced this successfully on bare metal.)
  2. Follow the directions from the deadsnakes PPA to install Python3.11.2
  3. Download https://github.com/niess/python-appimage/releases/download/python3.11/python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage
  4. Launch an interpreter from the installed Python3.11.2 and run import uuid; uuid.getnode()
  5. Launch an interpreter from the Appimage and run import uuid; uuid.getnode()
  6. Compare the output
niess commented 1 year ago

Hello @mssalvatore,

thank you for reporting this. I have no idea how uuid works, but I would expect identical results, whatever the python version. My understanding is that the node uuid is specific to the system, irrespective of Python version. Isn't it?

Currently, I do get identical results on my system (Debian 11).

$ python -c "import uuid; print(uuid.getnode())"
268749057538554
$ python3 -c "import uuid; print(uuid.getnode())"
268749057538554
$ ./python3.9.16-cp39-cp39-manylinux2014_x86_64.AppImage -c "import uuid; print(uuid.getnode())"
268749057538554
$ ./python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage -c "import uuid; print(uuid.getnode())"
268749057538554

The first two calls are for system Python, and the two last are for currently released AppImages. I also tried interactively and got the same result.

Do you still have this issue?

mssalvatore commented 1 year ago

@niess Yeah, I still see it, but only on Ubuntu Jammy

Debian 11

debian@debian-11:/tmp$ python3 --version
Python 3.9.2
debian@debian-11:/tmp$ python3  -c "import uuid; print(uuid.getnode())"
95541313180
debian@debian-11:/tmp$ ./python3.9.16-cp39-cp39-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid.getnode())"
95541313180
debian@debian-11:/tmp$ ./python3.10.6-cp310-cp310-manylinux2010_x86_64.AppImage  -c "import uuid; print(uuid.getnode())"
95541313180
debian@debian-11:/tmp$ ./python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid.getnode())"
95541313180

Ubuntu Jammy 22.04

ubuntu@jammy:~$ python3 --version
Python 3.10.6
ubuntu@jammy:~$ python3  -c "import uuid; print(uuid.getnode())"
208766106016652
ubuntu@jammy:~$ ./python3.9.16-cp39-cp39-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid.getnode())"
95536465137
ubuntu@jammy:~$ ./python3.10.10-cp310-cp310-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid.getnode())"
95536465137
ubuntu@jammy:~$ ./python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid.getnode())"
95536465137
ubuntu@jammy:~$ python3.11  -c "import uuid; print(uuid.getnode())" # from deadsnakes PPA
208766106016652

Both the python3 from the official Ubuntu repository and the one from the deadsnakes repository agree. They look like they're using a different scheme.

mssalvatore commented 1 year ago

Update: The manylinux 2_28 AppImage agrees with the official Ubuntu python:

ubuntu@jammy:~$ ./python3.10.10-cp310-cp310-manylinux_2_28_x86_64.AppImage -c "import uuid; print(uuid.getnode())"
208766106016652
ubuntu@jammy:~$ python3 -c "import uuid; print(uuid.getnode())"
208766106016652

They must be built against a newer version of some library that changes this behavior.

niess commented 1 year ago

I was checking the actual implementation. This seems to be currently worked on (according to last commit, "Fix uuid.getnode").

Also, there seem to be various strategies implemented for getnode, the like _ifconfig_getnode, _ip_config_getnode, etc. Maybe the AppImage version uses a different strategy, due to something failing with the default one? Or conversely, for the Ubuntu PPA one?

A test could be to directly call the private versions of getnode and see which one corresponds to what you get in both cases.

mssalvatore commented 1 year ago

Good idea:

ubuntu@jammy:~$ ./python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid._GETTERS)"
[<function _unix_getnode at 0x7f1ef6d80d60>, <function _ip_getnode at 0x7f1ef6d809a0>, <function _ifconfig_getnode at 0x7f1ef6d80900>]
ubuntu@jammy:~$ python3.11 !*
python3.11 -c "import uuid; print(uuid._GETTERS)"
[<function _unix_getnode at 0x7f4b5d9d0680>, <function _ip_getnode at 0x7f4b5d9d0220>, <function _ifconfig_getnode at 0x7f4b5d9d0180>]
ubuntu@jammy:~$ ./python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid._unix_getnode())"
None
ubuntu@jammy:~$ python3.11 -c "import uuid; print(uuid._unix_getnode())"
208766106016652
ubuntu@jammy:~$ ./python3.11.2-cp311-cp311-manylinux2014_x86_64.AppImage  -c "import uuid; print(uuid._ip_getnode())"
95536465137

It seems that _unix_getnode() returns None for the AppImage, but not the official version. From the code, it would seem that this is because _generate_time_safe is not defined (see https://github.com/python/cpython/blob/d189e2db0bca60eba328cc31b86e62a1e2b3647a/Lib/uuid.py#L579-L588). This is controlled here.

So I guess HAVE_UUID_GENERATE_TIME_SAFE is a compile-time parameter that can affect this behavior.

niess commented 1 year ago

OK, I see. Thank you for sorting this out.

The problem is that I do not compile the Python runtime. I relocate the binaries from the Manylinux Docker images. Thus, there is little that I could do here, I am afraid.

I don't know if this is an option for you, but provided that uuid.getnode actually depends on compiler flags, your could use one of the private methods instead? In order to have a cross-compilation flags uuid.

mssalvatore commented 1 year ago

The problem is that I do not compile the Python runtime. I relocate the binaries from the Manylinux Docker images. Thus, there is little that I could do here, I am afraid.

Make sense. Thanks for looking into this with me.

You could use one of the private methods instead?

This might be our only option. Thanks!