I'm writing a library that's dependent on file-magic, which works just fine for most platforms, but in Alpine Linux, file-magic won't work so I need to instead use the python-magic library.
Now I know how to write my own code to handle the different Python library APIs, but what I don't know how to do is to write my setup.cfg
or setup.py
to have a different requirements based on the system on which we're doing the installation.
I figured the best option would be to use the PEP 508 rules, but I can't figure out how to say "libmagic like Alpine" or something in that syntax, let alone if that would work in a package's setup.py. Indeed, I can't even figure out how to tell the difference between the architectures without installing file-magic
and watching it die :-(
Surely, there must be a best practise for this sort of thing?
After some broader understanding from Tim below, I cobbled together this hack to get it working:
def get_requirements():
"""
Alpine is problematic in how it doesn't play nice with file-magic -- a
module that appears to be the standard for most other Linux distros. As a
work-around for this, we swap out file-magic for python-magic in the Alpine
case.
"""
config = configparser.ConfigParser()
config.read("setup.cfg")
requirements = config["options"]["install_requires"].split()
os_id = None
try:
with open("/etc/os-release") as f:
os_id = [_ for _ in f.readlines() if _.startswith("ID=")][0] \
.strip() \
.replace("ID=", "")
except (FileNotFoundError, OSError, IndexError):
pass
if os_id == "alpine":
requirements[1] = "python-magic>=0.4.15"
return requirements
setuptools.setup(install_requires=get_requirements())
This allows for the declarative syntax of setup.cfg
, but tweaks the install_requires
value if the installation target is an Alpine system.
You probably want to use the platform module to try to identify the system details.
Best bet is to try and use a combo of platform.architecture()
, platform.platform()
, and platform.system()
with proper error handling and consideration of all possible return info.
Example:
I am running on Win10, here are the outputs of those functions (and one more):
>>> import platform
>>> print(platform.architecture())
('32bit', 'WindowsPE')
>>> print(platform.platform())
Windows-10-10.0.17134-SP0
>>> print(platform.processor())
Intel64 Family 6 Model 142 Stepping 10, GenuineIntel
>>> print(platform.system())
Windows
The above answer does not necessarily return the info that you want (I left out mention of any deprecated functions from the platform module).
Digging a little deeper, yields this SO result which explains that the built-in platform functions for gathering distro names are deprecated.
The official docs point in the direction of a PyPi package called distro. The distro docs on PyPi acknowledge the need for this type of info and an example usage found there looks like this:
>>> import distro
>>> distro.linux_distribution(full_distribution_name=False)
('centos', '7.1.1503', 'Core')