This topic describes log printing, error handling, built-in modules, custom modules, and calls to external commands in Python runtime environments.

Background information

Function Compute supports the following Python runtime environments:

  • Python 2.7 ( runtime = python2.7 )
  • Python 3.6 ( runtime = python3 )

Print logs

The data that a function prints to stdout will be collected and stored in a Logstore that you specify when you create a service. The logs can be printed in the following ways:

  • Use the logging module. In this way, each log contains information such as the time, request ID, and log level.
    import logging
    
    def my_handler(event, context):     
        logger = logging.getLogger()     
        logger.info('hello world')     
        return 'done'

    After the preceding code is executed, the following log is output:

    message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [INFO]   hello world
    Note We recommend that you use the logging module to print logs, because the log can automatically contain the request ID, which facilitates locating the corresponding logs when an error occurs.
  • Directly run print to output the original content to the log.
    def my_handler(event, context):      
        print 'hello world'      
        return 'done'

    After the preceding code is executed, the following log is output:

    message:hello world

Handle errors

If an error occurs when a Function Compute instance is executing a function, the Function Compute instance captures the error and returns the information about the error. The following code shows an example of this process.

def my_handler(event, context):   
    raise Exception('something is wrong')

The response that is received after the function is called is as follows:

{    
    "errorMessage": "something is wrong",    
    "errorType": "Exception",    
    "stackTrace": [       
        [            
            "File \"/code/index.py\"",           
            "line 2",            
            "in my_handler",            
            "raise Exception('something is wrong')"        
        ]    
    ]
}

When an error occurs, the HTTP header in the response of the call contains X-Fc-Error-Type: UnhandledInvocationError. For more information about error types in Function Compute, see Error handling.

Use built-in modules

In addition to standard Python modules, Python runtime environments for Function Compute provide common modules that you can directly reference. The following table lists existing modules contained in the Python runtime environments.

Module Description References
oss2 2.6.0 OSS SDK https://github.com/aliyun/aliyun-oss-python-sdk
tablestore 4.6.0 Tablestore SDK https://github.com/aliyun/aliyun-tablestore-python-sdk
aliyun-fc2 2.1.0 Function Compute SDK https://github.com/aliyun/fc-python-sdk
aliyun-python-sdk-ecs 4.10.1 Elastic Compute Service (ECS) SDK https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-ecs
aliyun-python-sdk-vpc 3.0.2 Virtual Private Network (VPC) SDK https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-vpc
aliyun-python-sdk-rds 2.1.4 ApsaraDB for RDS SDK https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-rds
aliyun-python-sdk-kms 2.5.0 Key Management Service (KMS) SDK https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-kms
pydatahub 2.11.2 DataHub SDK https://github.com/aliyun/aliyun-datahub-sdk-python
aliyun-mns 1.1.5 Message Service https://github.com/gikoluo/aliyun-mns
aliyun-python-sdk-cdn 2.6.2 Alibaba Cloud CDN https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-cdn
aliyun-python-sdk-ram 3.0.0 Resource Access Management (RAM) https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-ram
aliyun-python-sdk-sts 3.0.0 Security Token Service (STS) https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-sts
aliyun-python-sdk-iot 7.8.0 IoT Platform https://github.com/aliyun/aliyun-openapi-python-sdk/tree/master/aliyun-python-sdk-iot
aliyun-log-python-sdk 0.6.38 Log Service (SLS) https://github.com/aliyun/aliyun-log-python-sdk
wand 0.4.4 Wand http://docs.wand-py.org/en/0.4.4/
opencv 3.3.0.10 OpenCV http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_setup/py_intro/py_intro.html
numpy 1.13.3 NumPy http://www.numpy.org/
scipy 1.0.0 SciPy https://www.scipy.org/
matplotlib 2.0.2 Matplotlib https://matplotlib.org/
scrapy 1.4.0 Scrapy https://scrapy.org/

The following code is the sample code for connecting to OSS.

import json
import oss2
def my_handler(event, context):
    evt = json.loads(event)
    creds = context.credentials
    # do not forget security_token
    auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token)
    bucket = oss2.Bucket(auth, evt['endpoint'], evt['bucket'])
    bucket.put_object(evt['objectName'], evt['message'])
    return 'success'
Notice The preceding sample code shows how to upload a file to OSS by using a security token. For other sample code for using Python-based third-party libraries, see fc-python-demo.

Use custom modules

To use a custom module, you must package the custom module and the code together and upload the package. You can manage dependencies by using the PIP Installs Python (PIP) package manager. If you use FunCraft to deploy applications, you can run the fun install command to install dependencies.

  • Method 1: Manage dependencies by using the PIP package manager.

    Perform the following steps:

    • Run the pip install -t . command to install the dependency library to the root directory of the function.
    • Package the dependency library and the code library together and upload the package.

    The following example describes how to install the pymysql library by using this method.

    1. Create a directory to store code and dependency modules.
      mkdir /tmp/code
    2. Install dependencies in the /tmp/code directory.
      cd /tmp/code
      pip install -t . PyMySQL
    3. Create a code file, such as /tmp/code/index.py, and use pymysql in the code.
      import pymysql.cursors
      # Connect to the database
      connection = pymysql.connect(host='localhost',
                                   user='user',
                                   password='passwd',
                                   db='db',
                                   charset='utf8mb4',
                                   cursorclass=pymysql.cursors.DictCursor)
      def handler(event, context):
       with connection.cursor() as cursor:
           # Read a single record
           sql = "SELECT count(*) FROM `users`"
           cursor.execute(sql)
           result = cursor.fetchone()
           print(result)
           return result
    4. Package the code and the dependencies and upload the package.

      You must package all the required files instead of only the code folders. Ensure that the function handler is in the root directory of the package.

      • In the Windows operating system, you can select all the files in the code directory of the function, right-click these files, and click Added to Zip to generate a code package.
      • In the Linux operating system, you can call the zip command to select all the files in the code directory as source files to generate a deployment code package, such as zip code.zip /home/code/*.

      After the packaging is complete, you can click the function name in the Function Compute console. On the page that appears, click the Code tab. You can select Import from OSS or Upload Zip File to upload the code package.

  • Method 2: Install dependencies by running the fun install command.

    If you use FunCraft to deploy an application, you can run the fun install command to install dependencies. For more information about how to deploy an application by using FunCraft, see Funcraft. For more information about the fun install command, see Use fun install to install third-party dependencies.

    The following example describes how to install the pymysql library by using this method.

    1. Run the following command to initialize the Funfile file in the root directory of the function:
      $ fun install init
      ? Select a runtime   
        nodejs8   
        nodejs10   
        python2.7 
      ❯ python3   
        java8   
        php7.2   
        dotnetcore2.1 
       (Move up and down to reveal more choices)
    2. After python3 is selected, a file named Funfile is generated in the current directory. Edit the content of the file.
      RUNTIME python 
      fun-install pip install PyMySQL
    3. Create a file named template.yml, such as /tmp/code/template.yml. For more information, see template.yml. The content is as follows:
      ROSTemplateFormatVersion: '2015-09-01'
      Transform: 'Aliyun::Serverless-2018-04-03'
      Resources:
      FunDemo:  
       Type: 'Aliyun::Serverless::Service' 
       pythondemo:    
         Type: 'Aliyun::Serverless::Function'   
         Properties:     
           Handler: index.handler     
           Runtime: python3     
           CodeUri: '. /'
      The meaning of the template.yml file is as follows: Declare a service named FunDemo and a function named pythondemo for the FunDemo service. Set the function handler to index.handler, set the runtime of the function to python3, and set the CodeUri property to the current directory. During application deployment, FunCraft packages the directory specified by CodeUri and uploads the package.
      • For more information about the FunDemo service, see FunDemo.
      • For more information about the pythondemo function, see pythondemo.
      • For more information about the content of the CodeUri property, see CodeUri.
      • For more configuration rules, see Serverless Application Model.
    4. Run fun install in the root directory of the function to install dependencies.
      $ fun install
      using template: template.yml
      start installing function dependencies without docker
      
      building FunDemo/pythondemoFunfile exist, 
      Fun will use container to build forcely
      Step 1/2 : FROM registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:build-1.9.4
      ---> 702c91653452
      Step 2/2 : RUN fun-install pip install PyMySQL
      ---> Using cache
      ---> 8f59062f15bb
      sha256:8f59062f15bb7a86bd59b85e3b61bd0e4ed711c536fe0cd10fdefebc78eae152
      Successfully built 8f59062f15bb
      Successfully tagged fun-cache-a6f4221c-33c8-4050-93b8-015e42396475:latest
      copying function artifact to /Users/txd123/Desktop/express
      
      Install Success
      
      
      Tips for next step
      ======================
      * Invoke Event Function: fun local invoke
      * Invoke Http Function: fun local start
      * Build Http Function: fun build
      * Deploy Resources: fun deploy
    5. Use FunCraft to deploy the application. For more information, see Overview.
      fun deploy -y

      You can view the related log if the function is executed.

      $ fun deploy -y
      using template: template.yml
      using region: cn-hangzhou
      using accountId: ***********3743using accessKeyId: ***********Ptgk
      using timeout: 60
      
      Collecting your services information, in order to caculate devlopment changes...
      
      Resources Changes(Beta version! Only FC resources changes will be displayed):
      
      ┌────────────┬──────────────────────────────┬────────┬──────────┐
      │ Resource   │ ResourceType                 │ Action │ Property │
      ├────────────┼──────────────────────────────┼────────┼──────────┤
      │            │                              │        │ Handler  │
      │            │                              │        ├──────────┤
      │ pythondemo │ Aliyun::Serverless::Function │ Add    │ Runtime  │
      │            │                              │        ├──────────┤
      │            │                              │        │ CodeUri  │
      └────────────┴──────────────────────────────┴────────┴──────────┘
      
      Waiting for service FunDemo to be deployed...      
            Waiting for function pythondemo to be deployed...              
                    Waiting for packaging function pythondemo code...              
                    The function pythondemo has been packaged. A total of 51 files were compressed and the final size was 114.35 KB
            function pythondemo deploy success
      service FunDemo deploy success

    Log on to the Function Compute console. You will find that the related service and function are created. A correct response is returned if you click the function name, click the Code tab, and click Invoke.

Run external commands

Your functions may use some tools that are not written in Python, such as executable files compiled in Shell, C ++, and Go. You can package these tools and the code together and use them in the target function by running external commands.

Notice The executable files compiled in C, C++, and Go must be compatible with the runtime environments of Function Compute. The Python runtime environments in Function Compute are as follows:
  • Linux kernel version: Linux 4.4.24-2.al7.x86_64
  • Docker base image: docker pull python:2.7 and docker pull python:3.6.

You can use FunCraft to install dependencies. For more information, see Use fun install to install third-party dependencies. The following example describes how to install mysql-python (including .so files) in the runtime environment Python 2.7.

You can run the following command in the code directory to install dependencies: fun install --runtime python2.7 --package-type pip mysql-python.

Notice
  • When you use this command for the first time, this process may take a long time because of image pulling.
  • Dependencies, including mysql.so, are installed in the .fun directory. You only need to set the CodeUri property to .fun in the template.yml file and store the code package in the fun directory.

The following code shows how to run a Shell script.

import os
import subprocess

def my_handler(event, context):    
    script_path = os.environ.get('FC_FUNC_CODE_PATH') + '/script.sh'    
    ret = subprocess.check_output(['bash', script_path])    
    return ret