3

I want to write a script that will execute on Linux and Solaris. Most of the logic will be identical on both OS, therefore I write just one script. But because some deployed structure will differ (file locations, file formats, syntax of commands), a couple of functions will be different on the two platforms.

This could be dealt with like

if 'linux' in sys.platform:
    result = do_stuff_linux()
if 'sun' in sys.platform:
    result = do_stuff_solaris()
more_stuf(result)
...

However it seems to cumbersome and unelegant to sprinkle these ifs throughout the code. Also I could register functions in some dict and then call functions via the dict. Probably a little nicer.

Any better ideas on how this could be done?

Isaac
  • 810
  • 2
  • 13
  • 31
  • calling them via dictionary will be better – Aditya Apr 21 '17 at 10:52
  • 1
    Assuming the functions both serve the same purpose, you could also put them in OS-specific modules and `import` the appropriate set of functions using an `if` statement. The drawback is that you would need to ensure the signatures (function names, input arguments and output) match. – Kendas Apr 21 '17 at 11:00
  • @Kendas I like that approach, seems most elegant to me. The drawback for me is that I would need to ship more than one file. Maybe that is not such a big deal though, I need to think about it. – Isaac Apr 21 '17 at 11:16
  • I'm working on an answer that addresses that last problem, hang on – Kendas Apr 21 '17 at 11:20

2 Answers2

7

Solution 1:

You create separate files for each of the functions you need to duplicate and import the right one:

import sys
if 'linux' in sys.platform:
    from .linux import prepare, cook
elif 'sun' in sys.platform:
    from .sun import prepare, cook
else:
    raise RuntimeError("Unsupported operating system: {}".format(sys.platform))

dinner = prepare('pork')
drink_wine()
result = cook(dinner)

Solution 1.5:

If you need to keep everything in a single file, or just don't like the conditional import, you can always just create aliases for the functions like so:

import sys

def prepare_linux(ingredient):
    ...

def prepare_sun(ingredient):
    ...

def cook_linux(meal):
    ...

def cook_sun(meal):
    ...

if 'linux' in sys.platform:
    prepare = prepare_linux
    cook = cook_linux
elif 'sun' in sys.platform:
    prepare = prepare_sun
    cook = cook_sun
else:
    raise RuntimeError("Unsupported operating system: {}".format(sys.platform))

dinner = prepare('chicken')
drink_wine()
result = cook(dinner)
Kendas
  • 1,963
  • 13
  • 20
  • I like that. And with some more python magic, one could probably even get rid of the if/elif in the alias defintion. I will post back if I come up with something. – Isaac Apr 21 '17 at 11:34
  • 1
    According to [this](http://stackoverflow.com/questions/2933470/how-do-i-call-setattr-on-the-current-module), you could try to use `sys.modules['__main__']`, but really that seems to be more like cleverness for cleverness' sake, unless you have a truly massive amount of duplicated functions. At that point, you might consider the module approach. – Kendas Apr 21 '17 at 11:46
  • Great answer! How would this work for Windows or Mac? – krose Jan 06 '21 at 16:56
  • 1
    @Chaky31 - Try looking at the documentation of [`sys.platform`](https://docs.python.org/3/library/sys.html#sys.platform) for examples of possible values. There are values for Mac and Windows in there as well. – Kendas Jan 07 '21 at 06:32
1

You can do it like this:

if 'linux' in sys.platform:
    def do_stuff():
        result = # do linux stuff
        more_stuff(result)
elif 'sun' in sys.platform:
    def do_stuff():
        result = # do solaris stuff
        more_stuff(result)

And then simply call do_stuff().

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149