Reliably detect Windows in Python - python

I'm working on a couple of Linux tools and need to prevent installation on Windows, since it depends on FHS and is thus rendered useless on that platform. The platform.platform function comes close but only returns a string.
Unfortunately I don't know what to search for in that string for it to yield a reliable result. Does anyone know what to search for or does anyone know of another function that I'm missing here?

>>> import platform
>>> platform.system()
'Windows'

For those that came here looking for a way to detect Cygwin from Python (as opposed to just detecting Windows), here are some example return values from os.name and platform.system on different platforms
OS/build | os.name | platform.system()
-------------+---------+-----------------------
Win32 native | nt | Windows
Win32 cygwin | posix | CYGWIN_NT-5.1*
Win64 native | nt | Windows
Win64 cygwin | posix | CYGWIN_NT-6.1-WOW64*
Linux | posix | Linux
From this point, how to distinguish between Windows native and Cygwin should be obvious although I'm not convinced this is future proof.
* version numbers are for XP and Win7 respectively, do not rely on them

On my Windows box, platform.system() returns 'Windows'.
However, I'm not sure why you'd bother. If you want to limit the platform it runs on technologically, I'd use a white-list rather than a black-list.
In fact, I wouldn't do it technologically at all since perhaps the next release of Python may have Win32/Win64 instead of Windows (for black-listing) and *nix instead of Linux (for white-listing).
My advice is to simply state what the requirements are and, if the user chooses to ignore that, that's their problem. If they ring up saying they got an error message stating "Cannot find FHS" and they admit they're running on Windows, gently point out to them that it's not a supported configuration.
Maybe your customers are smart enough to get FHS running under Windows so that your code will work. They're unlikely to appreciate what they would then consider an arbitrary limitation of your software.
This is a problem faced by software developers every day. Even huge organizations can't support every single platform and configuration out there.

>>> import os
>>> os.name
'nt'
"The name of the operating system dependent module imported. The following names have currently been registered: 'posix', 'nt', 'mac', 'os2', 'ce', 'java', 'riscos'." (c) http://docs.python.org/library/os.html#os.name
import os
if os.name == 'nt':
#yourcodehere

Try this:
import platform
if platform.system() == "Darwin":
# Don't have Windows handy, but I'd expect "Win32" or "Windows" for it
Edit: Just saw that you tried platform.platform()...platform.system() will work better for this case. Trust me, use it. Dark corners lie in platform detection.
distutils will do this too, if you ask it nicely.
You could always do something bad like os.path.exists() on a Windows file...but platform is as reliable as it gets in the Python standard library.
Edit 2: Another helpful answerer pointed out platform.system() is exactly equal to "Windows" on his Windows machine.

From help(platform)
system()
Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
An empty string is returned if the value cannot be determined.

Related

Python's platform module does not detect windows 10

I am working on Windows 10 presently and need to put some code if the platform is Windows 10. So, I checked in python docs and read about platform module. This is what the documentation says :
platform.win32_ver(release='', version='', csd='', ptype=''):
Get additional version information from the Windows Registry and return a tuple (release, version, csd, ptype) referring to OS release, version number, CSD level (service pack) and OS type (multi/single processor)
When I tried the same function on my Windows 10 machine I got below :
>>> platform.win32_ver()
('8', '6.2.9200', '', u'Multiprocessor Free')
But, I was expecting the release to be 10 instead of 8.
So, any idea if I am missing something here ?
Also, can somebody please tell me if there exists any other way to detect if the windows platform is Windows 10 ?
The problem is python uses GetVersionEx to determine the version.
As you can read here, Microsoft doesn't support this anymore and offers a different API.
However, you can always call the new API yourself, or check the registry value at HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion.
You can also use WMI to get the Win32_OperatingSystem instance.
I'd also like to note that specific version checking is generally considered a bad practice.

Python for .NET "unable to find assembly" error

I'm using CPython and I have a C# dll. I'm trying to use Python for .NET to make them talk. I can't use IronPython because I need to integrate this into an existing CPython system.
I'm completely new to Python for .NET, and I actually have very little experience with Python and no experience with C#. So please forgive me if my question seems very basic.
I'm using Python 2.7.3, and I downloaded
pythonnet-2.0-alpha2-clr2.0_131_py27_UCS2 and unzipped it into a folder named pyfornet_test, which also contains the dll I'm trying to use (called DotNet4Class.dll)
Then I run this:
import sys
import os
import clr
sys.path.append(r"C:\pyfornet_test")
clr.AddReference("DotNet4Class.dll")
Which gives me this error:
System.IO.FileNotFoundException: Unable to find assembly 'DotNet4Class.dll'.
at Python.Runtime.CLRModule.AddReference(String name) in C:\Users\Barton\Documents\Visual Studio 2008\Projects\PyShar
p\trunk\pythonnet\src\runtime\moduleobject.cs:line 375
Any advice would be much appreciated. Thank you!
One reason can be Windows was not enabling it to load from "external sources". To fix this:
Right-click on the .dll
"Properties"
Under "General", click "Unblock"
Try this (without extension .dll):
clr.AddReference(r"C:\pyfornet_test\DotNet4Class")
Is DotNet4Class.dll built against .NET 4? I assume so based on the naming of the dll.
Note the issue here: http://sourceforge.net/tracker/?func=detail&aid=3293169&group_id=162464&atid=823891
clr.AddReference fails when assembly is built with .NET 4.0 - ID: 3293169
I'd read the solution, but essentially, you need to rebuild and recompile the python for .NET project under .NET 4.
I'll also mention that projects like this, that aren't actively developed and used by lots of people, generally have subtle idiosyncrasies that make knowledge of the platform essential to work around problems such as this. It sounds like you're trying to hack this solution in without understanding much about python or .NET which is always going to be fraught with problems.
Did you try clr.FindAssembly?
import clr
import sys
assemblydir = r"C:\pyfornet_test"
assemblypath = r"C:\pyfornet_test\DotNet4Class.dll"
sys.path.append(assemblydir)
clr.FindAssembly(assemblypath)
I don't know why it works, but this code works on my computer (Python 2.7, .NET4)
I have code like this (I copied MyRightClickMenuService.dll to the same directory as my script.py). It is built against .Net 4.0.
# script.py
import clr
import os
import sys
sys.path.append(os.path.dirname(__file__))
clr.AddReference('MyRightClickMenuService')
clr.AddReference('System')
clr.AddReference('System.Security')
from MyRightClickMenuService import (
AclSecuredNamedPipeBinding,
MyMenuItem,
MyContextMenuService,
etc
)
Checklist
The folder(s) containing the DLL(s) is/are added to sys.path before loading. You may append, or sys.path.insert(0, dll_folder) to put it first on the list.
You call clr.AddReference('my_dll') without the dll extension (for my_dll.dll), after adding the folder to sys.path
The DLL Target Architecture is the same as the CPython version bitness. That is, if Architecture is x64, use 64-bit python, and if Architecture is x86, use 32-bit python. (instructions for this below)
How to check target Architecture for DLL?
I Used ILSpy (free and open source) -> Open DLL -> Check the output. Below example output.
What worked for me was to Unblock the dll file.
if u download the dll file or took it from different computer it might be blocked. So unblocked solved the issue for me.
To unblock right click on the properties if the dll file and check the Unblock box at the bottom

How to tell if rosetta is installed?

I am working on a Python script that will rely on rosetta being installed. Rosetta is a dynamic binary translator for Mac OS X which allows many PowerPC applications to run on certain Intel-based Macintosh computers without modification. Is there anyway for to check the OS to see if rosetta is there?
Haven't got rosetta installed anymore but if I recall correctly it would give some kind of usage screen if you just type translate (rosetta command line). If so, something like this should work.
if os.system("/usr/libexec/oah/translate > /dev/null 2>&1"):
print "Not installed"
else:
print "Installed"
If you are really just trying to check whether something with a PPC dependency will likely run, you could do a loose check that the running CPU type is PPC or the running OS X version >= 10.4 and < 10.7 since those are the OS X versions where Rosetta is supported and, at least on 10.6, OS X will automatically prompt the user to install Rosetta when needed if it wasn't already installed. Note that the Darwin kernel versions are different from the OS X version number, i.e 10.4 -> Darwin 8, 10.5 -> 9, etc.:
>>> import os
>>> os.uname()
('Darwin', 'kitt.local', '11.4.0', 'Darwin Kernel Version 11.4.0: Mon Apr 9 19:32:15 PDT 2012; root:xnu-1699.26.8~1/RELEASE_X86_64', 'x86_64')
>>> un = os.uname()
>>> darwin_major_version = int(os.uname()[2].split('.')[0])
>>> cputype = un[4]
>>> can_run_ppc = cputype.startswith('ppc') or (darwin_major_version > 7 and darwin_major_version < 11)
>>> can_run_ppc
False
There is no official way to get this.
Rosetta works via a program called /usr/libexec/oah/translate. Officially, this is an implementation detail which is subject to change, and therefore shouldn't be relied on. However, we know that it never did change until 10.7, when Rosetta was killed completely, so it's safe despite the caveats. Maria Zverina's answer works for that (if you add the path), and it's probably the simplest. Or, maybe, just check for the presence of such a file instead of running it.
Alternatively, Rosetta came with Intel 10.4-10.6 (earlier versions of the OS were PPC-only and didn't have Intel). Again, officially you're never supposed to rely on OS version, instead using the appropriate APIs to check for features. But in this case, there don't seem to be any appropriate APIs, so maybe this is appropriate. Except for the caveat that you don't have to install Rosetta with 10.6, so this won't detect users who turned off the checkbox. If you want to do this:
import platform
release, versioninfo, machine = platform.mac_ver()
versionbits = [int(bit) for bit in release.split('.')]
rosetta = (versionbits < (10,7) and not machine.startswith('ppc'))
(Note that this is also "bad" because on some versions platform.mac_ver() does some hacky stuff that you're not supposed to do—the right way to get the OS X version bits is to call Gestalt. But mac_ver() is part of the standard library, so at least you can rely on it doing the hacky stuff as well as possible, and it being widely tested.)
If you're not actually after Rosetta, but whether you can run PPC either natively or via Rosetta, that's even simpler. All pre-10.7 versions that don't come with Rosetta are PPC; all 10.7+ versions can't run PPC period. So, just "release < '10.7'" does it. (Again, with the caveat that 10.6 can optionally skip Rosetta install.)
Try to run:
brew config
Rosetta 2: true

run as administrator problem with py2exe

I am having this problem that we compiled our python project into an exe with py2exe and the resulting exe does not work unless it is executed as an administrator.
I wanted to ask that is this supposed to happen ?? As in there are so many applications that we can run as not an administrator so is there any way I can convert my python code to such an application ...
Thanks a lot..
It sounds like your application is attempting to write to a directory for which the basic user doesn't have access; most likely the "Program Files" directory. I believe in Vista/Win7 this is not allowed, and the standard convention is to write to the user's appdata folder, for any user data you might wish to store.
You can reliably obtain the location of this directory using the ctypes module, here's an example:
import ctypes
from ctypes import wintypes
def get_appdata_directory():
CSIDL_APPDATA = 0x001a
dll = ctypes.windll.shell32
app_data_directory = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
found = dll.SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, app_data_directory)
# FYI: if `found` is False, then it failed to locate the appdata directory
# and app_data_directory.value is empty. So you might want to add some
# code here to verify that a valid path is going to be returned.
# This would probably only happen on older versions of windows,
# but, this is just a guess as I don't have any older OSs available
# for testing. (see my note below)
return app_data_directory.value
appdata = get_appdata_directory()
print(appdata)
# outputs something such as: 'C:\Users\bob\AppData'
Note: I believe the appdata folder was introduced with WinXP/Win2k. Not sure about WinME and prior, however, I don't believe you have to worry about the administrator restrictions on these earlier OSs. If you really care to support them, you could use python's builtin platform module along with some conditionals, then simply write user data to the "Program Files" directory for the archaic versions of Windows.
I've had serious problems with getting py2exe to work. Luckily I found the excellent PyInstaller which not only works, but also creates smaller executables. I haven't ran into the problem you mention with PyInstaller so I recommend trying it.
http://www.pyinstaller.org/

How can I get the correct case when calling Python's os.getcwd()?

When I call os.getcwd() on my Mac under OS X 10.6.4 from my home directory, the path is converted to lowercase. I get
/users/myusername
instead of
/Users/myusername
On another Mac I get the correct uppercase string. How can I configure this? Is there a (hidden) Python setting?
Reason for asking:
On OS X all user directories are in "/Users". This is always uppercase. When using Mercurial, it gets sometimes confused with this strange and incorrect normalization of my current directory.
In reply to the suggested solutions:
(1)
DiskUtil says that my drive has a format of "Mac OS Extended (Journaled)". I bought my computer some month ago and it's still the original drive, never reformatted.
(2) Another python console session log:
$>>> os.system('pwd')
/Users/klaas
0
$>>> os.getcwd()"
'/users/klaas'
$>>> os.path.normcase('/Users/klaas')
'/Users/klaas'
$>>> os.chdir('/UsErS/klaas')
$>>> os.getcwd()
'/users/klaas'
$>>> os.chdir('/UsErS/klaas')
$>>> os.getcwd()
'/users/klaas'
Update 2:
Thanks for all the replies. I created a test case in Objective-C and it has the same lowercase folder name:
NSFileManager *filemgr;
NSString *currentpath;
filemgr = [NSFileManager defaultManager];
currentpath = [filemgr currentDirectoryPath];
NSLog (#"Current directory is %#", currentpath);
The "HFS plus" filesystem, which has been Apple's filesystem of choice since the days of Mac OS 8, is normally not case-sensitive.
Mac OS X version 10.4, or "Tiger" as it's more commonly known, introduced the ability to create an HFS plus filesystem which is case-sensitive.
Could one of them be using a case-sensitive FS?
The problem seems to be a problem with your particular Python install on your particular Mac. I haven't been able to turn up anyone else who has the same problem.
It's likely that your Mac has a problem with its installation of Python. AFAIK, there isn't a configuration option to make Python represent getcwd() with the proper case (this behavior should be enabled by default). If it's an option, I'd try reinstalling Python. If that doesn't work, you should report a bug to the Python bug tracker.
Two uneducated guesses:
First, apparently OSX is usually case-insensitive, which usually means case-preserving: the name of the current directory either comes from how it's capitalized on disk, or how it was capitalized when you changed into it. If you run os.system('pwd'), does it show it lowercased or not? If so, then that's what the OS is reporting and Python isn't doing anything wrong. Does it change if you os.chdir('/UsErS/username') first?
Second, there's one function that does lowercase or not selectively based on the OS: os.path.normcase. The macpath version does lowercase. I'm pretty sure os.getcwd does not automatically run the results through this; just mentioning it as a place to check.
In the end it was an issue with the Mercurial installation. I ran into it again tonight.
https://www.mercurial-scm.org/wiki/Download gives you different options how to install Mercurial. If I choose the first one (the Mac OS X packages) the "/Users" directory will be reported as "/users" (even when accessing it with Objective C). This can be solved by installing Mercurial via the macports option. This fixes the issue and the "/Users" directory is returned again with an uppercase "U".
Any hints why this is happening are still welcome.
But a least there is a solution.

Categories