{"id":15717128,"url":"https://github.com/maximelemagicien/upip","last_synced_at":"2025-04-05T00:26:47.628Z","repository":{"id":250914818,"uuid":"834597476","full_name":"MaximeLeMagicien/uPip","owner":"MaximeLeMagicien","description":"Easily install any Python package as universal2 wheel, compatible with both x86_64 and arm64 architectures on macOS.","archived":false,"fork":false,"pushed_at":"2024-08-09T14:54:10.000Z","size":36,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-12T17:41:51.054Z","etag":null,"topics":["arm64","cli","intel","m1-infrastructure","macosx","python3","x86-64"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MaximeLeMagicien.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-27T18:53:43.000Z","updated_at":"2025-02-18T00:59:32.000Z","dependencies_parsed_at":"2024-10-24T13:40:06.319Z","dependency_job_id":"023c3161-86bf-4306-9e4c-d28cd93dbdbd","html_url":"https://github.com/MaximeLeMagicien/uPip","commit_stats":null,"previous_names":["maximelemagicien/upip"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaximeLeMagicien%2FuPip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaximeLeMagicien%2FuPip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaximeLeMagicien%2FuPip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaximeLeMagicien%2FuPip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MaximeLeMagicien","download_url":"https://codeload.github.com/MaximeLeMagicien/uPip/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247268612,"owners_count":20911160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arm64","cli","intel","m1-infrastructure","macosx","python3","x86-64"],"created_at":"2024-10-03T21:48:50.110Z","updated_at":"2025-04-05T00:26:47.596Z","avatar_url":"https://github.com/MaximeLeMagicien.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# README\n\n## universalPip\n#### Universal Package Installer for Python\n\n[![PyPI](https://img.shields.io/pypi/v/universalPip)](https://pypi.org/project/universalPip/)\n[![downloads](https://static.pepy.tech/badge/universalPip/month)](https://pepy.tech/project/universalPip)\n\n## Table of contents\n- [Description](#description)\n- [Story](#story)\n- [Note about universal wheels](#note-about-universal-wheels)\n- [Note about packaging](#important-note-about-packaging)\n- [`uPip`'s installation logic](#uPips-installation-logic)\n- [Uninstall packages](#how-to-uninstall-packages-installed-by-uPip)\n- [Install the CLI](#installation)\n- [Usage](#usage)\n    - [Install a package](#install-a-package)\n    - [Create `universal2` wheel](#create-an-universal2-wheel)\n    - [Check if a package is universal](#check-if-a-package-is-universal)\n    - [Show default stored wheel directory](#show-default-stored-wheel-directory)\n    - [Invoke pip](#invoke-pip)\n    - [`uPip`'s version](#printing-uPips-version)\n    - [Print documentation](#print-documentation)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Changelog\nYou can view the complete changelog [here](https://github.com/MaximeLeMagicien/uPip/blob/main/Changelog.md).\n\n\u003chr\u003e\n\n### Description\nThe `universalPip` package (called `uPip` in this document) is a Python package which completes the `pip` command line tool provided with any standard Python3 installation. `uPip`'s main goal is to provide an easy way to install any python package in `universal2` binary mode, which is compatible with any macOS installation.\n\n### Story\nAs you probably know, Apple recently stopped using `intel chips` as their processor for new macs. They released in September 2020 their own chip called the `M1`. Unfortunatly, apps built on intel chips can't run properly on M1 and newer chips. A complete app rebuild is necessary. Even if `rosetta` exists and enables the aibility to run `x86_64` apps on `M1` architecture, it is not a durable solution.\n\nDue to the fact that most people still uses `intel` architecture and want to publish apps on both architectures, developers needs to package their apps into an `universal` app bundle in order to run their app on any mac installation.\n\nThose changes had an huge impact on Python packages. In fact, all binary files (with `.so` extension) needed to be recompiled on newer macs with M1 chips to extend compatibility. This is why packages with binary dependencies now provides two different wheels: the first one `macosx_10_X_x86_64.whl` for `intel` macs and `macosx_11_0_arm64.whl` for `M1` macs and newer. See [below](#important-note-about-packaging) for more information.\n\nIn order to compile applications in universal mode, with `pyinstaller` for example; installed wheels in the Python environment need to have both architectures inside their `.so` binaries files. Usually these wheel distributions are named like this: `macosx_11_0_universal2.whl` (See [here](#note-about-universal-wheels) for more information about compiling `universal2` applications using `pyinstaller`). \u003cu\u003eUnfortunatly, some packages do not provide these kind of wheels but only seperarated wheels for each architecture.\u003c/u\u003e \n\n`uPip`'s story starts here: knowing all the facts mentionned above, the Python Package Index needed a new package to easily install any Python package in `universal2` mode. \u003cu\u003e`uPip` has `pip`'s same capabilities but adds a layer of verification when installing a package. If no `universal2` distribution wheel exists in the package repository, it will download each architecture wheel and fusionnate their wheels to create an `universal2` distribution and then install it.\u003c/u\u003e Read [installation logic](#uPips-installation-logic) for further information.\n\n### Note about universal wheels\n`uPip`'s main goal is to handle the case where no `universal2` wheel distribution is provided for a package release. But not all packages needs an `universal2` wheel. In fact, if a package (like this one) doesn't have any binary dependencies, it often has only one release named `py3-none-any.whl` which means that all package's logic is coded in Python only and is compatible with any installation. So, even on `arm64` or `x86_64` mac architectures, those packages will work normally. See [installation logic](#uPips-installation-logic) for more information.\n\n### Important note about packaging\nEven if compiling universal app bundles for both `x86_64` and `arm64` architectures is possible, universal applications are way heavier in terms of size than separated architecture applications. For instance, a small app packaged with `pyinstaller` for `x86_64` only has a 50 MB size whereas the same application compiled in `universal2` mode has a 250 MB size.\u003cbr\u003e\u003cb\u003eTake this warning in consideration when compiling bigger applications because their final size can either double or triple!\u003c/b\u003e\n\nIn order to compile an universal bundle on macOS with PyInstaller, you need to have all your project's requirements and dependencies installed in `universal2` mode and set inside your `.spec` file the target architecture to `universal2`. Read [pyinstaller's documentation](https://pyinstaller.org/en/stable/feature-notes.html#macos-multi-arch-support) for more information.\n\n### `uPip`'s Installation logic\nWhen installing a package, `uPip` will follow this logic: \n- First, check if an `universal2.whl` exists for the given release version.\n    - If such a release exists, downloads it and installs it\n- If no `universal2.whl` distribution exists, checks if a distribution `p3-none-any.whl` exists, meaning that the current packages has no platform specific dependencies.\n    - If such a release exists, downloads it and installs it\n- If neither `universal2.whl` and `p3-none-any.whl` distribution exists, downloads both `macos_10_X_x86_64.whl` and `macosx_11_0_arm64.whl` wheels to fuse them into `macosx_11_0_universal2.whl` and then installs the created wheel.\n\nWhen the universal2 wheel is installed, `uPip` checks the newly installed package's dependencies to also update them if they are not in universal2 mode. The same logic applies for processing package's dependencies as described above.\n\n### How to uninstall packages installed by `uPip`?\nThere is no specific tool to uninstall packages installed by `uPip`. You can use `pip` directly to uninstall any package installed by `uPip` as you would normally do for a normal package. Or you can [invoke pip from `uPip`](#invoke-pip) to be sure to call the same python version as the one used by `uPip`.\n\n### Installation\nTo install the `uPip` package, you can use the following command:\n\n```shell\n$ pip install universalPip\n```\nTo verify the installation, call the `uPip` CLI from the terminal:\n```shell\n$ uPip\n```\nIf the CLI is correctly installed, the documentation should show up.\n\n### Usage\n#### Install a package \n\u003chr\u003e\nOnce installed, you can use the `uPip` package to install other Python packages. Here's an example:\n\n\u003cbr\u003eLet's say we want to install [mzdata2mat](https://github.com/MaximeLeMagicien/mzdata2mat), a package aimed to convert `.mzData.xml` files into `.mat` files. Here is the command to install the package:\n\n```shell\n$ uPip --install mzdata2mat\n```\nThe installation will be performed into the `site-packages` of the python installation which downloaded `uPip` inside the `wheels` folder.\u003cbr\u003e\n\nAdditionnaly, you can add `--version` tag to specify a release version to install. Command would be: \n```shell\n$ uPip --install mzdata2mat --version \"1.0.0\"\n```\nIf no version is specified, the latest one will be used.\n\u003chr\u003e\n\n#### Create an universal2 wheel\nIf you just want to create a wheel without installing it, use the following command:\n```shell\n$ uPip --makeU mzdata2mat\n```\nSame logic for the `--version` tag, either specify it to create an `universal2` wheel or don't specify it and the latest version available will be used.\n\nAll created wheels are stored inside `uPip`'s install directory in the `site-packages` of the python installation in a folder called `wheels`. If you want to specify a custom path use the following command:\n```shell\n$ uPip --makeU mzdata2mat --destination \"path/to/folder\"\n```\n\nIf `--destination` is not provided, default path will be used.\n\u003chr\u003e\n\n#### Check if a package is universal\nTo avoid installing twice a package already in `universal2` mode, you can use the verification process of `uPip` by using this command:\n```shell\n$ uPip --checkU mzdata2mat\n```\nThis command will verify if all `.so` files inside `mzdata2mat` package are in fat mode with both `arm64` and `x86_64` architectures inside.\n\u003chr\u003e\n\n#### Show default stored wheel directory\nYou can show where is located the `wheels` directory by using this command:\n```shell\n$ uPip --showPath\n```\nThis will print the default save location.\n\u003chr\u003e\n\n#### Invoke `pip`\nYou can trigger pip from `uPip` CLI by adding this parameter to the command: `--pip`.\nHere is an example:\n```shell\n$ uPip --pip \"show mzdata2mat\"\n```\nOne main advantage to use `uPip` to call `pip` is to be sure to call the same python version of pip as the one used to run `uPip`. For instance, it could be useful to run pip like this in order to uninstall packages.\n\n\u003chr\u003e\n\n#### Printing `uPip`'s version\nTo show `uPip`'s version use the following command:\n```shell\n$ uPip --V\n```\n\n\u003chr\u003e\n\n#### Print documentation\nAs a normal package, to print `uPip`'s documentation in the terminal use the following command:\n```shell\n$ uPip -h\n```\nor simply:\n```shell\n$ uPip\n```\nIn fact, if there is no parameters provided with `uPip`'s call, documentation is printed by default.\n### Contributing\nContributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the [GitHub repository](https://github.com/MaximeLeMagicien/uPip).\n\n### License\nThis package is licensed under the MIT License. See the [LICENSE](https://github.com/MaximeLeMagicien/uPip/blob/main/LICENSE) file for more details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaximelemagicien%2Fupip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaximelemagicien%2Fupip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaximelemagicien%2Fupip/lists"}