Repository navigation
Introduce platform.vm_info (or similar) as a replacement for recently deprecated platform.java_ver. #116504
Description
Feature or enhancement
Proposal:
There exist alternative Python implementations that run on a virtual machine (vm) or a comparable middleware. The platform module currently lacks an implementation-independent API to retrieve (version-)information of an underlying vm. Examples are IronPython, Jython (3 possibly one day), RustPython. The proposal is to add a replacement for the recently deprecated function platform.java_ver under a generic name platform.vm_info that can optionally be implemented by a Python implementation. The return value of such a function would be a tuple inspired by what used to be returned by platform.java_ver.
The doc of that function states:
""" Version interface for Jython.
Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
tuple (os_name, os_version, os_arch).
Values which cannot be determined are set to the defaults
given as parameters (which all default to '').
"""IMO only the vm_info part should be returned by the propsed function platform.vm_info, hence the name. Os info should be obtainable from the os module, release should be obtainable similar to CPython's release. For vendor I do honestly not understand what the difference to vm_vendor would supposed to be.
As a consequence, I suggest the following definition:
def vm_info(vm_name='', vm_release='', vm_vendor=''):
""" Version interface for Python implementations on virtual machines.
Returns a tuple (vm_name, vm_release, vm_vendor).
Values which cannot be determined are set to the defaults
given as parameters (which all default to '').
""" Apparently, this is plainly the old java_ver refactured to the relevant subset.
This definition is merely intended as an entry point for discussion. E.g. I would be fine with a different naming etc. if as a result more use cases can be covered. E.g. I am not sure whether for RustPython the notion of a vm would be accurate, so a broader name may be suggested. Also the parameters vm_name, vm_release and vm_vendor are placed here for discussion. For Java this makes sense because there exists e.g. Java implementations by Oracle and IBM (and many more in fact), which is relevant to know besides the release version number. I am rather confident about the idea that a tuple should be returned and that a plain version number would be an insufficiently narrow information. Perhaps even more fields should be defined, e.g. the build-type of the vm.
As many maintainers of alternative Python implementations as possible should be noticed to take a look at this proposal to make sure it covers as many use cases as possible.
Note:
Most enhancements and bug fixes don’t need a PEP and can be submitted directly to the Python issue tracker. (from: PEP 1)
Given that with java_ver a special case of this proposal has already been part of Python STL for well over a decade, evidence demands the inevitable conclusion that a PEP would be an overkill for this proposal. Even if not, the discussion in this issue would be a necessary prerequisite for a PEP.
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Activity
Stewori commentedon Mar 8, 2024
@sobolevn @malemburg according to your posts in #116349 I hope this proposal addresses your API concerns. Please feel free to ping relevant devs for this discussion.
sobolevn commentedon Mar 8, 2024
I would suggest using some other name, not
vm, becauseRustPythondoesn't have a vm, it usesrustccompiler 🤔tooling_version()?Stewori commentedon Mar 8, 2024
@slozier and @BCSharp , what is your perspective on this for IronPython (please feel free to ping further IronPython devs)?
Stewori commentedon Mar 8, 2024
@sobolevn sure, the name "vm" is placed for discussion. Let's collect a couple of ideas.
Stewori commentedon Mar 8, 2024
@cfbolz @mattip @arigo pinging you just in case there is some point to make from PyPy perspective (not running on a vm, I know).
Stewori commentedon Mar 8, 2024
@jeff5 @fwierzbicki @jimbaker pinging you to make you aware.
sobolevn commentedon Mar 8, 2024
@youknowone and @coolreader18 for RustPython
JelleZijlstra commentedon Mar 8, 2024
I'd caution against using a tuple as the return value, because it will be difficult to change in the future in a backwards-compatible way. Instead I would suggest a simple object with a documented set of attributes (e.g. using
types.SimpleNamespace).Stewori commentedon Mar 8, 2024
What about a named tuple? What is the advantage of SimpleNamespace over named tuple?
@sobolevn Regarding RustPython, it occurred to me that there is
platform.python_compiler(). On Linux I get "GCC [version]" as output from CPython. Perhaps that is better suited to expose a rust compiler version and this proposal would really target vm/middleware info. Just thinking...JelleZijlstra commentedon Mar 8, 2024
Namedtuples are still tuples and therefore make it difficult to add new values. You can hack around it by adding a new property that isn't part of the tuple, but that's hacky. For a use case like this the API that tuple provides is mostly not very useful.
sobolevn commentedon Mar 9, 2024
Related discussion about deprecating
'Java'asplatform.system(): https://discuss.python.org/t/lets-deprecate-platform-system-java/48026Stewori commentedon Mar 14, 2024
Looking at https://docs.python.org/3/library/types.html#types.SimpleNamespace it appears that elements would be mutable, which should be avoided. The property should have strict read-only character, which may be a reason for using a tuple in the first place. I know, there are techniques to make class attributes read-only but that would complicate the minimalistic intention. Probably the best way is to specify that the function creates a new object every time. (It could actively set the values of a returned singleton to its supposed values. But then, if a user stores the returned object and modifies its attributes they might magically change back later, which can be a nasty side effect.) Or is there an elegant way to have
SimpleNamespacewith immutable attributes?Another advantage of tuple is that
print(platform.vm_info)would directly produce something useful.SimpleNamespaceappears to provide only a__repr__implementation, so a proper__str__would need to be added as well (AFAIK the default__str__would not provide attribute values). That's certainly doable, but again makes it a little more complicated.youknowone commentedon Mar 15, 2024
Can platform refer another implementation-depend either c-written or python-written module
_platform(or_python,_variantor any _something_good_name) and put everything CPython-specific literals in it? Then every other implementation only can write its own_platform. Here are the places RustPython hard-code its name:platform._sys_version()https://github.com/python/cpython/blob/v3.12.0/Lib/platform.py#L1113site._getuserbase()https://github.com/python/cpython/blob/v3.12.0/Lib/site.py#L278sysconfig._getuserbase()https://github.com/python/cpython/blob/v3.12.0/Lib/sysconfig.py#L124sysconfig._INSTALL_SCHEMEShttps://github.com/python/cpython/blob/v3.12.0/Lib/sysconfig.py#L156-L157test_cmd_linehttps://github.com/python/cpython/blob/v3.12.0/Lib/test/test_cmd_line.py#L370Making interface for them will be easier once we gather those variants into a single spot.
Stewori commentedon Mar 15, 2024
That would demand a bigger change in CPython than was intended with this issue (would probably be hard to convince them for such a change). That said, providing a custom version of platform is what also Jython is doing. You may be right that the path to a proper implementation-independent interface would be to collect and consider all variants but that is well beyond the ambition of this feature request.
18 remaining items
Stewori commentedon Jun 14, 2025
Thx, Marc-André, for taking a look.
Not only "about right", it precisely nails the point.
Nice thought, but it appears that the available info for most implementations is fairly limited. For Java-based Pythons there is the rich info from Java's System.properties dict, but for IronPython and browser-based Pythons there is apparently only one string available (
RuntimeInformation.FrameworkDescriptionfor .net; the user agent for browser-based Python). So, without the perspective that at least, say, three Python implementations would likely provide the API (additional info beyond one single info string), I think it's probably not sufficiently founded by demand.Repeating myself, my conclusion was that just one single plain string value is the common denominator of what existing implementations could reasonably and realistically provide. Also, I suppose providing just one single string is not asked too much, so that this would minimize the hurdle for adoption.
My proposal from #116504 (comment) still stands with the amendment that I would consider an empty string the more canonical default value for CPython rather than
None.This proposal is a chance to clarify the role of
sys.versionto refer to the actual system, rather than to a potential vm/middleware. From my Jython experience it is unrealistic that a vm would sufficiently abstract away the underlying system to successfully get away with having such info refer to the vm.jeff5 commentedon Jun 15, 2025
But that is only common in the sense that it has a single data type. It pushes the problem onto a thousand other developers to parse that string for every implementation they care about. And strings attract extra data. There have to be conventions on how that string is composed, and once you do that, you are back to tying to design a data structure, just with less effective tools than if you were to use classes.
You can see the
platformmodule has wrestled with the problem that the data necessary to describe the different implementations of Python have a structure that depends on the implementation, yet have commonalities you'd like to exploit.A false turn when describing Jython is that we have tried and failed to make Java the platform. Actually, I don't know what a "platform" is. A lot of the time it is used to mean OS. Perhaps it means a layer to supply all your most fundamental needs: no need to dig any lower. It would be lovely if Java did that, and insulated us entirely from the "real" OS, but we acknowledge it doesn't. I think
platform.system()=="Java"is therefore a bad idea, likeos.name=="Java", which we have seen make packages unusable on Jython on Windows.I think an adequate representation of platform has to have optional layers in the description. It appears the first and last are always the version of the Python language and the OS respectively, but there is sometimes one (just one?) inbetween, that could be a VM. I think it is worth attempting some structure here, even if it is just the guarantee of certain named members (if the whole layer is not
None), with others contingent on those. Or does each layer give a clue to the existence of one lower? E.g. it is Jython, so I will be able to ask (particular things) about a VM.CPython does not see a need to describe more than the top and bottom layers ... but then, what is
platform.python_compiler()? And I suppose I can ask whether I'm on the free-threading implementation somehow.Stewori commentedon Jun 15, 2025
All good and valid thoughts, Jeff, although I am not really sure what alternative you are actually proposing.
I think what truly matters is what libraries and implementors will make of this API. The interest in maintaining this feature turned out fairly low (which I don't quite understand but it is what it is), e.g. IronPython devs indicated close to zero ambition to maintain such a thing.
So, I conclude, if there is a chance for this feature at all, it has to be as simplistic as possible. A thin wrapper to a specific call to middleware API. That doesn't have to be a bad thing - aren't other functions in the module thin wrappers to system properties as well?
I agree it would be nice if more help could be provided for users to make structural sense of the provided data. But that would require more ambition from implementors which I currently don't see.
I still think that having a commonly defined way to expose an info string would be an improvement over the status quo. Perhaps the thin-wrapper-approach could be a starting point to propose a more sophisticated API in the future once the thin wrapper has been widely adopted.
We should indeed check whether such a flag has been introduced so Jython can set it to indicate free-threaded behavior.
jeff5 commentedon Jun 18, 2025
Not a positive alternative, just not keen on the idea of a string users have to parse.
A structure reflecting some easily interrogated properties doesn't seem too much to ask of the team that chose that layer. It would be the same across all JVM implementations, and different for a different VM/intermediate layer. If there's really only one thing to say (at present) about a given class of layer it could contain one attribute. I think you need to be able to inspect the layer for its type, but that could be its
__class__.CPython seems not to need such a layer, but I think it has places where the C nature is assumed and attributes can be interrogated, e.g.
sysconfigand https://docs.python.org/3/howto/free-threading-python.html#identifying-free-threaded-pythonStewori commentedon Jun 18, 2025
Standard browser API does apparently expose middleware info only through the user agent string and user agent parsing is a
messscience for itself.youknowone commentedon Jun 18, 2025
Perhaps the core of the issue is better addressed by allowing each implementation some space to add arbitrary functions to the platform module as needed.
The reason Jython and IronPython struggle to share a common interface is fundamentally because Java and .NET cannot return the same kind of information through vm_info.
In any case, users will have no way to meaningfully use the result of
platform.vm_info()without also queryingplatform.python_implementation().So why not simply leave the return type of
vm_info()undefined?If we allow Jython and IronPython the freedom to define the return format in a way that suits their respective implementations, then users can first check
platform.python_implementation()and then proceed with further logic based onvm_info().This approach may seem irresponsible at first glance, but in practice, since no user can handle vm_info() meaningfully without first checking platform.python_implementation(), I believe it causes no real issues.
jeff5 commentedon Jun 18, 2025
Let's not create another similar mess by having a string (that will surely get fatter over time).
jeff5 commentedon Jun 18, 2025
I favour this idea, although I think it would help if an attribute of the object returned, which attribute could be its Python type, would tell you what you otherwise need to work out from
platform.python_implementation(), mapping potentially several implementations to one VM type.Stewori commentedon Jun 18, 2025
That would be prevented by the convention that it has to be a thin wrapper or
name<space>versionfor cases where there is nothing conclusive to wrap (conveniently, for IronPython both cases yield the same result). An undefined return type is harder to use than a string.youknowone commentedon Jun 18, 2025
This is the opposite: it is undefined at the Python standard level but must be defined at the Python implementation level. Jython and IronPython must define their own concrete types; otherwise, it would be a disaster. A well-defined struct sequence type is much easier to work with than a simple string type. It's just defined differently by each Python implementation.
youknowone commentedon Jun 18, 2025
Probably defining the return type as a free-length tuple will encourage the VmInfo type to be struct sequence.
The return type forces not to return a single string, and the actual users of the function still can rely on the implementation-defined struct sequence.
sobolevn commentedon Jun 18, 2025
Structs / tuples are hard, because people can use
name, version = ver()and adding new fields totuplewill be a breaking change. So,dictis almost always a better choice.youknowone commentedon Jun 18, 2025
Python already has a struct sequence, which is a tuple but accessible by field names, which can prevent more mistakes than dict
This is also a lot used for *Info types
Stewori commentedon Jun 18, 2025
You would have to condition the use of the return value every time, which would diminish the advantage of a standardization approach. Asking implementations to implement custom types is over-engineering for a simple info feature and chances are that the API is just ignored by implementers and will be removed again in some years.
Perhaps there can be two functions. One returns a string under a thin wrapper convention, which is readily justified for debugging, and one that returns a dict-like object (but should not be writable). Then this can be consolidated in a couple of years depending on adoption. The latter one should have a somewhat even more optional character (although both are optional).
Can this be made read-only?
I think it might be helpful to draft anticipated example outputs as implementation recommendations for the main foreseeable frameworks/use cases:
I did this in #116504 (comment) for the thin-wrapper approach. What would a dict-like return type contain for these examples concretely? By means of an initial recommendation. Founded on an actually existing API call of the respective framework. It's not too hard to look into the API specs for these three cases: Java API, .net API, HTML5 API. I can provide links if you like.
My point is to assert that there is actually a meaningful implementation perspective.
youknowone commentedon Jun 18, 2025
Even though it is not readonly, if Python is already using it for VersionInfo, I can't say VmInfo have to be more strict than any other info functions under
sysmodule.I also agree dict has enough benefits except for the consistency.
Note: I am not a real potential provider/user of this API. The real provider/user's voice need to be more seriously accepted.