Python and different Operating Systems - python

I am about to start a personal project using python and I will be using it on both Linux(Fedora) and Windows(Vista), Although I might as well make it work on a mac while im at it. I have found an API for the GUI that will work on all 3. The reason I am asking is because I have always heard of small differences that are easily avoided if you know about them before starting. Does anyone have any tips or suggestions that fall along these lines?

In general:
Be careful with paths. Use os.path wherever possible.
Don't assume that HOME points to the user's home/profile directory.
Avoid using things like unix-domain sockets, fifos, and other POSIX-specific stuff.
More specific stuff:
If you're using wxPython, note that there may be differences in things like which thread certain events are generated in. Don't assume that events are generated in a specific thread. If you're calling a method which triggers a GUI-event, don't assume that event-handlers have completed by the time your method returns. (And vice versa, of course.)
There are always differences in how a GUI will appear. Layouts are not always implemented in the exact same way.

Some things I've noticed in my cross platform development in Python:
OSX doesn't have a tray, so application notifications usually happen right in the dock. So if you're building a background notification service you may need a small amount of platform-specific code.
os.startfile() apparently only works on Windows. Either that or Python 2.5.1 on Leopard doesn't support it.
os.normpath() is something you might want to consider using too, just to keep your paths and volumes using the correct slash notation and volume names.
icons are dealt with in fundamentally different ways in Windows and OSX, be sure you provide icons at all the right sizes for both (16x16, 24x24, 32x32, 48x48, 64x64, 128x128 and 256x256) and be sure to read up on setting up icons with wx widgets.

You should take care of the Python version you are developing against. Especially, on a Mac, the default version of Python installed with the OS, is rather old (of course, newer versions can be installed)
Don't use the OS specific libraries
Take special care of 'special' UI elements, like taskbar icons (windows), ...
Use forward slashes when using paths, avoid C:/, /home/..., ... Use os.path to work with paths.

Some filename problems: This.File and this.file are different files on Linux, but point to the same file on Windows. Troublesome if you manage some file repository and access it from both platforms. Less frequent related problem is that of names like NUL or LPT being files on Windows.
Binary distribution code (if any) would likely use py2exe on Win, py2app on Mac and wouldn't be present on Linux.

Related

How do I drag and drop onto a (python) script on OS X?

Is there any way to configure a recent OS X system so that python scripts automatically behave as drag and drop targets? If not, what is the most light-weight way (ideally scriptable) of configuring individual scripts for this behavior?
On Windows, I can simply drag and drop files onto a python script, and a python process will be launched with the full path names of the dropped arguments available in sys.argv. Amazingly, not only does this not happen on OS X, but there doesn't seem to be any way of configuring the system to do this automatically. All the solutions I've come across involve wrapping each of my scripts in an app.
Sure, this question has been asked and answered before. But not only is every single answer I could find limited to enabling drag and drop for one script at a time (by wrapping an app around them); it seems that all answers are obsolete and/or depend on broken links. Here's a sampler:
In python, how do I drag and drop 1 or more files onto my script as arguments with absolute path? (for windows, linux, and mac)
How do I execute a shell script with selected files/folders in Finder?
How to pass path names to Python script by “dropping” files/folders over script icon
As mentioned, none of them seem to work anymore. I have OS X 10.8, Mountain Lion, and I've seen zilch that could be expected to work on later OS versions. Any up to date solutions?
PS: Conceptually this question is not necessarily limited to python: I'm pretty sure that any mechanism that would work with shell or perl scripts would also work with python. But given how hard this seems to be on OS X, I'm keeping the question specific since that's my use case, and all solutions I've seen seem to be language-specific.
Have you seen this answer? Try using Mac OS X Automator (available in current and past versions of the OS--just tested this in Yosemite). As far as "one at a time" vs "multiple", this SuperUser post about the same subject explains how to make it work for multiple files.
At the end of the day, "Drag and Drop Support" is functionality of the Windowing System and has nothing to do with Python. That said, you can build OS X GUI apps in Python, which could be another solution to this. Check out this link about GUI Applications in Python for more info.

As a beginner in Python, how should I work with installation directories?

I'm a self-taught, amateur, purely recreational programmer. I don't understand all the fancy programming lingo, and I certainly don't have any good resources, apart from this website, where I can go for help. (i.e., Please dumb it down for me!) I would imagine my question here is somewhat common, but I honestly couldn't find any answers on Google or this website, probably because I don't know the proper terminology to search for.
~~~
Having said that, I feel I have a pretty solid grasp on the basics of Python. And now, I've created an application that I'd like to share with a friend. My application accesses JPEG image files on my computer using a directory path that I've written into the code itself. However, I'd like my friend to be able to store these image files anywhere on their computer, not necessarily in the file folder that I've been using.
I assume the best way to accomplish this is to allow my friend to choose the directory path for themselves and then to write their chosen directory path to a file at a predetermined location on their computer. My application would then have that file's location prewritten into its code. This way, it would be trivially easy to open the file at the predetermined location, and then that file would point my application to my friend's chosen directory path.
1.) Are any of my intuitions here misguided? Are there better ways of doing this?
2.) If you think my general approach is a reasonable one, then is there a good/common place on the computer where applications typically store their directory paths upon installation?
Any advice - or any recommended resources - would be very much appreciated! Thanks!
Well, the standard way to do this is a lot more complicated and platform-specific:
On traditional Unix, this is pretty simple; you create a text file in some simpler format (e.g., that used by ConfigParser, named, say, ~/.myprogram.cfg, and you write a line to it that looks like image_path=/path/to/images.
On most modern Linux systems, or any other FreeDesktop/XDG-based system, you should (at least for GUI apps) instead use a special directory looked up in the environment as XDG_CONFIG_HOME, falling back to ~/.config, instead of using ~.
On Windows, the standard place to store stuff like this is the Windows Registry (e.g., by using winreg), by creating a key for your program and storing a value with name image_path and value /path/to/images there.
On Mac, the standard place to store stuff like this is in the NSUserDefaults database (e.g., by using PyObjC, which isn't part of the stdlib but does come built-in with Apple's pre-installed Python) by opening the default domain for your program and adding a value with key image_path and value… well, you probably want a Cocoa bookmark (maybe even a security-scoped one), not a path.
That probably all sounds way, way too complicated.
One option is to use a library that wraps this all up for you. If you're already using a heavy-duty framework like, say, Qt, it probably has functionality built-in to do that. Otherwise, it may take a lot of searching to find something.
A simpler alternative is to just pretend everything is like traditional Unix. That will work on Windows and Mac. It will be slightly annoying on some Windows versions that your config file will be visible in their home directory, but not a huge deal. It means you won't get some of the bonus features that Mac provides, like being able to magically follow the directory if the user moves it somewhere else on his hard drive, or remembering the settings if he reinstalls OS X and migrates his old settings, but again, usually that's fine.
In between the extremes, you can pretend everything is like Linux, using a special, and unobtrusive, location for the files on Windows and Mac just as you do there. Both platforms have APIs to look up special directories, called "application data" on Windows and "application support" on Mac. Using PyWin32 or PyObjC, respectively, these are pretty easy to look up. (For example, see this answer.) Then you just create a subdirectory there named My App on Windows, or com.mydomain.myapp on Mac, and store the file there.

Copy data from the clipboard on Linux, Mac and Windows with a single Python script

I am trying to create a script in Python that will collect data put in the clipboard by the user and preferably save it as a list or in a text file or string/array/variable to work with later on.
This should work on Linux all versions (I would assume Ubuntu), Mac OS all versions and Windows all versions. I am not sure if 32bit and 64bit systems have different ways of accessing the data at the clipboard, if they do I guess it would be safe to make this work for the 32bit versions only so people running the 64bit versions can fall back onto the 32bit version of the OS.
The tricky part, apart from this having to work on the mentioned OS, is that I would like the script to run as long as the user does not stop it and while it runs all the data copied into the clipboard by the user is being copied to a list or in a text file or string/array/variable.
Of course there is a time limit at which the user can input data into the clipboard so I was thinking of having a loop scanning the clipboard every second or every 500 milliseconds, check if the content has changed, and if it has, copy it, otherwise don't copy it.
Is there a unified way or module that does this on all different OS or would it be better to write separate scripts for this task for the various OS?
The thing is, this is part of a bigger project that I would like to make work on Linux, Mac and Windows, so having those three options covered and then use Python code that can be used across the mentioned OS for the rest of the script/project would be ideal. Am I asking too much in general from this script concerning it having to work on Linux, Mac and Windows?
The xerox library supports Linux, Mac OS X, and Windows.
Note that it's a very bad idea to perform any action in short (< a minute) intervals, because that makes modern processors wake up regularily. You may want to use the respective operating system's APIs to register a callback once the clipboard changes.
You're probably better off using a more advanced gui toolkit than Tk, but it's in the standard library, so it's available everywhere.
As a really simple example:
import Tkinter
root = Tkinter.Tk()
root.withdraw() # Hide the main window (optional)
text_in_clipboard = root.clipboard_get()
print text_in_clipboard
You could use a GUI toolkit such as Qt to get a portable clipboard API. That said it might be a little overkill to use a whole GUI toolkit just for this. (Unless, of course, you're also going to use it to make a GUI.)
That said, clipboard APIs dealing with plain text should be reasonably simple to make your own abstraction over.
For instance, on OS X you can use PyObjC (which is installed along with OS X) to get plain-text contents of a clipboard:
from AppKit import NSPasteboard
from LaunchServices import
pb = NSPasteboard.generalPasteboard()
text = pb.stringForType_(kUTTypeUTF8PlainText)
CPU architectures
A 32-bit native app on a 64-bit OS will be accessing the same clipboard as a 64-bit one. If you need to support both architectures of an OS, and aren't writing a driver, for Windows it's okay to ship a 32-bit binary; for Linux you'll likely have to do both versions; for OS X, it should be reasonably safe to ship a 64-bit version, all Macs since mid-2007 have had 64-bit CPUs and the OS support is there since Leopard. A Python script will, on Linux, probably be executed by a Python installation from the distribution package manager, whose bitness will match the system, so you don't necessarily need to worry about that.
Polling is NOT robust/reliable.
You cannot determine if data has changed (on windows anyway) without pasting it into a buffer for inspection. This requires opening the clipboard. If you do this in a loop, you're going to collide with other apps. i.e. the app where the user is copying another item onto the clipboard. This will explode with an "cannot open clipboard" or "out of memory" error. This approach will not work reliably/robustly. You need to use proper clipboard monitoring APIs in the various platforms.
I suspect it's also possible to copy clipboard in platform neutral manner using pythonnet + TextCopy library via following links:
http://pythonnet.github.io/
https://stackoverflow.com/a/51912933/2338477
(See similar problem here: Quick and easy file dialog in Python? )
But haven't tried this by myself, might need also to play around what kind of commands you run and from which console. Let me know if someone will try this, I'll update more details in here.

If I use QT For Windows, will my application run great on Linux/Mac/Windows?

I'm under the impressions that Python runs in the Triforce smoothly. A program that runs in Windows will run in Linux. Is this sentiment correct?
Having said that, if I create my application in QT For Windows, will it run flawlessly in Linux/Mac as well?
Thanks.
Yes. No. Maybe. See also: Java and "write once, run anywhere".
Filesystem layout, external utilities, anything you might do with things like dock icons, character encoding behaviors, these and more are areas you might run into some trouble.
Using Qt and Python, and strenuously avoiding anything that seems tied to Windows-specific libraries or behaviors whenever possible will make running the application on Mac and Linux much easier, but for any non-trivial application, the first time someone tries it, it will blow up in their face.
But through careful choice of frameworks and libraries, making the application work cross-platform will be much more like bug fixing than traditional "porting".
As other posters mentioned, the key issue is making sure you never touch a different non-Qt non-cross-platform API. Or really even a different non-Qt crossplatform API, if you use Qt you kind of need to commit to it, it's a comprehensive framework and for the most part sticking with Qt is easier than going to anything else. There's some nice advantages as the basic primitives in your program will work the same way all over the place. (i.e. a QString in your networking code will be the same as a QString in your interface code.) Portability-wise, if you stay within the API Qt provides you, it should work on multiple platforms.
There will be areas where you may need to call some Qt functions which provide specific cross-platform tweaks more important to some platforms than others (e.g. dock icons) and you won't immediately have a polished application on all three platforms. But in general, you should remain very close to an application that compiles and runs on all three. (Try to use qmake or a similar build system too, as the build process for Qt applications varies depending on the platform. Different flags, etc.)
There's some odd issues that come up when you mix Qt with other APIs like OpenGL, in particular the way windows locks GL contexts differs from the way OS X and Linux does, so if you intend to use OpenGL with multiple threads, try to periodically compile on the other platforms to make sure nothing is completely busted. This will also quickly point out areas where you might have inadvertently used a non-cross-platform system API.
I've used Qt with a team to build a multi-threaded 3-d multiplayer real-time networked game (read: non-trivial application that fully utilized many many areas of Qt) and we were nothing but blown away by the effectiveness of Qt's ability to support multiple platforms. (We developed on OS X while targeting Windows and I regularly made sure it still ran on Linux as well.) We encountered only a few platform specific bugs, almost all of which arose from the use of non-Qt APIs such as OpenGL. (Which should really tell you something, that OpenGL was more of a struggle to use cross platform than Qt was.)
At the end of the experience we were pleased at how little time we needed to spend dealing with platform-specific bugs. It was surprising how well we could make a GUI app for windows given almost none of the team actually used it as a primary development platform through the project.
But do test early and often. I don't think your approach of writing an entire application and then testing is a good idea. It's possible with Qt, but unlikely if you don't have experience writing portable code and/or are new to Qt.
Yes. The code that you write using Qt will work on Windows, Mac, Linux/X11, embedded Linux, Windows CE and Symbian without any change.
You can take a look here.
Generally - as long as you don't use code that is not covered by Qt classes - yes.
I have several time just recompiled applications I wrote in Linux(64bit) under Windows, and the other way arround. It works for me every time.
Depends on your needs, you might also find compiler problems, but I am sure you will know how to work around them. Other people mentioned some issues you should look for, just read the other posts in the question.
It might run well, but it will take some testing, and of course Qt only handles the GUI portability, not the myriad of other things that might cause portability problems.
Qt apps generally don't fit in very well on MacOS because they don't have Applescript support by default and don't necessarily have the right keybindings. But if you do the work to fix those issues, they work, but not nicely. On the Mac, it's far better to build a native UI. If this is an in-house app, Qt is probably OK, but if it's for sale, you won't make many sales and will create yourself some support hassles.
As the others said, everything which is done using Qt-Functionality will most likely run quite flawlessly, WHEN you dont use platform specific functionality of qt.
There isnt that much (most of it has to do with window-manager stuff) , but some things might not work on other systems.
But such things are surely mentiond in the documentation of Qt.
Still there are things which cant be done using Qt, so you will have to do that yourself using plain Python...
Yeah "Python" itself is platform-independent (well it should), but there are lots of other things involved ... well mainly the OS.
And how the OS reacts you will plainly have to findout yourself by testing the application on all target OS.
Recently i wrote an quite simple GUI-application, while it ran flawlessy on Windows, it didnt run on Linux, because on Linux Python interpreted files encoded in unicode differently than on Windows.
Additionally a small script which should return the hostname of the machine, which it did on Windows, only returned "localhost" on Linux, which was obviously not what i wanted.

Self updating py2exe/py2app application

I maintain a cross platform application, based on PyQt that runs on linux mac and windows.
The windows and mac versions are distributed using py2exe and py2app, which produces quite large bundles (~40 MB).
I would like to add an "auto update" functionality, based on patches to limit downloads size:
check for new versions on an http server
download the patches needed to update to the last version
apply the patches list and restart the application
I have some questions:
what is the preferred way to update a windows application since open files are locked and can't be overwritten ?
how do I prepare and apply the patches ? perhaps using bsdiff/pspatch ?
[update]
I made a simple class to make patches with bsdiff, which is very efficient as advertised on their site : a diff on two py2exe versions of my app (~75 MB uncompressed) produces a 44 kB patch ! Small enough for me, I will stick to this format.
The code is available in the 'update' package of pyflu, a small library of Python code.
I don't believe py2exe supports patched updates. However, if you do not bundle the entire package into a single EXE (py2exe website example - bottom of page), you can get away with smaller updates by just replacing certain files, like the EXE file, for example. This can reduce the size of your updates significantly.
You can write a separate updater app, which can be downloaded/ran from inside your application. This app may be different for every update, as the files that need to be updated may change.
Once the application launches the updater, it will need to close itself so the files can be overwritten. Once the updater is complete, you can have it reopen the application before closing itself.
I don't know about patches, but on OS X the "standard" for this with cocoa apps is Sparkle. Basically it does "appcasting". It downloads the full app each time. It might be worth looking at it for inspiration.
I imagine on OS X you can probably just download the actual part of your app bundle that contains your specific code (not the libs etc that get packaged in) and that'd be fairly small and easy to replace in the bundle.
On Windows, you'd probably be able to do a similar trick by not bundling your app into one exe - thus letting you change the one file that has actually changed.
I'd imagine your actual Python code would be much less than 40Mb, so that's probably the way to go.
As for replacing the running app, well first you need to find it's location, so you could use sys.executable to get you a starting point, then you could probably fork a child process to, kill the parent process and have the child doing the actual replacement?
I'm currently playing around with a small wxPython app and wondering about exactly this problem. I'd love to hear about what you come up with.
Also how big is you app when compressed? If it compresses well then maybe you can still afford to send the whole thing.
This is 4 years old now, but what about Esky?
Since py2exe puts all of the compiled modules of your app into a ZIP file, you could try to update this file by creating a script that updates it from a given set of files.
Then replace the remaining files that have changed (which should be few, if any).
An old post, but I thought I'd mention pyupdater with pyinstaller.
It supports Amazon and scp.
In the future, according to recent github posts, they plan to support free alternatives.

Categories

Resources