Azure Functions Core Tools with Python on Mac M1/M2 + @azure/static-web-apps-cli

Tianyi Li
7 min readJun 18, 2023

--

If you’ve been trying to use Azure Functions with Python and have run into issues because the Azure Functions core tools do not support Python on Arm64, there is a workaround available.

  1. Install the Azure Functions Core Tools
    https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash#install-the-azure-functions-core-tools
    Please note that while Azure Functions Core Tools can now be installed via npm, for this particular case, we have chosen to use Homebrew as recommended by the documentation.
Enabling Rosetta emulation, as recommended by Microsoft, is not always feasible in certain cases.

Open a terminal and use the following command to install Azure Functions Core Tools (version 4)

# brew install azure functions core tools
brew tap azure/functions
brew install azure-functions-core-tools@4

2. Install python (or make sure you have installed python)

To check your current python version

# check current Python version
python -V

You should see an output like: python 3.9.16

If you have not yet installed python, there are two ways to install python: via brew or via pyenv.

  • Using Homebrew (python 3.9 is used in this case; however you can choose any versions you like)
# Install Python
brew install python@3.9
  • Using pyenv
# install pyenv 
brew install pyenv

After successfully installing pyenv, run the following command to install the specific version of python

# install python
pyenv install 3.9

use global command to switch between different python versions

# switch python version
pyenv global 3.9

If you have any difficulties in installing python using pyenv, have a look at this article:

https://medium.com/@lizhuohang.selina/install-pyenv-on-mac-818098603cb2

Although you have both Azure Function Core Tools and Python ready, running func start under your target directory may still lead to encountering the following errors:

[2023-05-08T21:29:33.030Z] Failed to initialize worker provider for: /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python 
[2023-05-08T21:29:33.030Z] Microsoft.Azure.WebJobs.Script: Architecture Arm64 is not supported for language python.
[2023-05-08T21:29:33.409Z] Failed to initialize worker provider for: /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python
[2023-05-08T21:29:33.409Z] Microsoft.Azure.WebJobs.Script: Architecture Arm64 is not supported for language python.

To avoid encountering this error, you can refer to the official documentation, which provides instructions on how to enable the Rosetta emulator:

https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cmacos%2Ccsharp%2Cportal%2Cbash#x86-emulation-on-arm64

However, being a nonconformist, I prefer to explore uncharted territories and embrace the risks of the unknown, even if it means succumbing to the tumultuous waves of the deep blue sea. (powered by ChatGPT)

The essence of this workaround involves the following steps:

  1. install grpcio inside your python via pip
  2. replace the file cygrpc.cpython-39-darwin.so in azure-functions-core-tools@4 with the one in your python

The detailed commands are shown below:

# Install grpcio inside python3.9
pip3.9 install grpcio

Or if you are already under python 3.9 ( check your version using python -V )

# install grpcio inside python
pip install grpcio

Check if grpcio is successfully installed

#check if grpcio is installed
pip freeze

You should see an output like:
grpcio==1.54.2

Keep in mind that pip functions similarly to npm. When using pyenv in conjunction with pip, the packages will be installed within the specified Python version of your preference. If you cannot locate the packages, it is likely that you are operating under the incorrect Python version. To resolve this, utilize pyenv global {version} to switch to the appropriate version.

After the installation of grpico, the modified file of cygrpc.cpython-39-darwin.so should be ready under the following paths:

  • If you are using pyenv for python version management
/Users/{username}/.pyenv/versions/3.9.16/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-darwin.so
cygrpc.cpython-39-darwin.so from Python 3.9 installed via pyenv

In the above example, Python 3.9.16 is used as a reference. Please modify the Python version accordingly to match your environment if necessary.

  • If you are using Homebrew
/opt/homebrew/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-darwin.so

The file that needs to be replaced in Azure Functions Core Tools@4 can typically be found at the following path:

/opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python/3.9/OSX/X64/grpc/_cython/cygrpc.cpython-39-darwin.so

This path only works for Azure Functions Core Tools that is installed via Homebrew

To replace the files, you have two options: manually navigating to the respective folder locations and performing copy-paste (my recommendation), or using the following command.

  • For pyenv
# replace the file in Azure Functions Core Tools with the one from Python
cp /Users/{username}/.pyenv/versions/3.9.16/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-darwin.so /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python/3.9/OSX/X64/grpc/_cython/cygrpc.cpython-39-darwin.so
  • For Homebrew installed python
# replace the file in Azure Functions Core Tools with the one from Python
cp /opt/homebrew/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-darwin.so /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python/3.9/OSX/X64/grpc/_cython/cygrpc.cpython-39-darwin.so

Congratulations on completing the previous steps! Now, to proceed further, you will need to

  • Create a symlink for the Arm64 architecture that points to the exact same folder as the x64 architecture. (This will ensure that all the modifications made in the x64 folder are correctly applied to the Arm64 architecture as well.)
# symlink X64 to Arm64
cd /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python/3.9/OSX/
ln -s X64 Arm64
An new Arm64 folder symlink should appear under OSX folder
  • Update supportedArchitectures in the work.config.json .

To update the supportedArchitectures in the work.config.json file, follow these steps:

  1. Locate the work.config.json file in your project.
  2. Open the work.config.json file in a text editor.
  3. Add the ARM64 architecture to the supportedArchitectures section. For example:
"supportedArchitectures": ["x64", "X86", "ARM64"]

4. Save the work.config.json file.

By adding ARM64 to the supportedArchitectures array, you are specifying that the Arm64 architecture is now supported. This ensures that the modifications made for the Arm64 architecture in the respective folder (Arm64 symlink) will be recognized and utilized accordingly.

Please note that the specific location of the work.config.json file may vary depending on your project structure. Make sure to navigate to the correct directory or path mentioned in your particular project context.

The config file can be typically found here:

# work.config.json file path
/opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python

Now if you run func start , no errors occur.

In summary:

# Install Python
brew install python@3.9

# install latest azure-function-core-tools from brew
brew install azure-functions-core-tools@4

# Install grpcio inside python3.9
pip3.9 install grpcio

# copy the lib
cp /opt/homebrew/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-darwin.so /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python/3.9/OSX/X64/grpc/_cython/cygrpc.cpython-39-darwin.so

# symlink X64 to Arm64
cd /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python/3.9/OSX/
ln -s X64 Arm64

#edit the worker config to reference arm64
cd /opt/homebrew/Cellar/azure-functions-core-tools@4/4.0.5198/workers/python
#use your text editor of choice e.g. nano
nano worker.config.json
# update supportedArchitectures like so
"supportedArchitectures":["X64", "X86","ARM64"],
# save and exit

# in your function directory setup a python 3.9 venv (may not be necessary)
cd <path to azure functions code>
python3.9 -m venv .venv
source .venv/bin/activate

# start func
func start

Another interesting topic regarding the use of Azure Static Web App simulator:

Assuming you have the following project folder structure:

The config file staticwebapp.database.config.jsonfor database connection of Azure Static Web Apps has been correctly set.

And you would like to run the following command to start simulator

 swa start --data-api-location swa-db-connectionsb

It is possible that you would encounter this error:

The error message explicitly states that dataApiBuilder/0.7.6 is not executing correctly, which might be puzzling as you might not have sufficient information to understand the underlying issue.

The following is the path of the folder:

/Users/{username}/.swa/dataApiBuilder/0.7.6

The solution to the issue is straightforward, yet the underlying cause remains unidentified:

  • Go to the 0.7.6 folder, and look for the following zip file.
  • Unzip this file and use the extracted content to replace EVERYTHING under 0.7.6

Now, you should be able to start the emulator seamlessly.

If you still have strange errors, for example:

libhostfxr.dylib related issue

The solutions from the Internet would suggest you to download dotnet, however, simply run

sudo  swa start --data-api-location swa-db-connections

--

--