简体   繁体   中英

Python AWS Lambda S3: [Errno 2] No such file or directory: 'which'

I am trying to convert the HTML file to pdf and upload it in S3 using Python 3.8 and lambda. I have created a deployment package using pdfkit but while converting to pdf, getting error "[Errno 2] No such file or directory: 'which'". The same piece of code works on my local machine with the local path.

I also tried to create a txt file in /tmp to make sure I have access and it was successfully able to create a file and from there upload to S3. Please help me here.

    s3_upload = boto3.resource('s3')
    bucket_name = 'bucket-invoice'
    html_body = '<html>Hello from test-resource</html>'
    writeFileName = 'test_invoice.pdf'
    local_file_path = '/tmp/local_pdf_file.pdf'

    print('Step 1: ' + local_file_path, html_body)
    pdfkit.from_string(html_body, local_file_path)  # <-- Getting error here

    # Write to S3:
    print('Step 2: Uploading in S3')
    s3_upload.meta.client.upload_file(local_file_path, bucket_name, writeFileName)

    print('Step 3: upload done')

Error Message:

Response:
{
  "errorMessage": "[Errno 2] No such file or directory: 'which'",
  "errorType": "FileNotFoundError",
  "stackTrace": [
    "  File \"/var/task/invoice_api.py\", line 49, in lambda_handler\n    generate_pdf_2()\n",
    "  File \"/var/task/invoice_api.py\", line 161, in generate_pdf_2\n    pdfkit.from_string(html_body, local_file_path)\n",
    "  File \"/var/task/pdfkit/api.py\", line 69, in from_string\n    r = PDFKit(input, 'string', options=options, toc=toc, cover=cover, css=css,\n",
    "  File \"/var/task/pdfkit/pdfkit.py\", line 42, in __init__\n    self.configuration = (Configuration() if configuration is None\n",
    "  File \"/var/task/pdfkit/configuration.py\", line 17, in __init__\n    self.wkhtmltopdf = subprocess.Popen(\n",
    "  File \"/var/lang/lib/python3.8/subprocess.py\", line 854, in __init__\n    self._execute_child(args, executable, preexec_fn, close_fds,\n",
    "  File \"/var/lang/lib/python3.8/subprocess.py\", line 1702, in _execute_child\n    raise child_exception_type(errno_num, err_msg, err_filename)\n"
  ]
}

If you want to include libraries which are not part of Python's standard library, such as pdfkit , you can use lambda's layers .


1. Create the zip

This is a zip which contains all the libraries you want the lambda function to use. First, create a folder called python :

$ mkdir python
$ cd python

then, install the Python libraries you need in there. You can do this either with a single library:

$ pip install --target . pdfkit

or with a list of libraries (requirements.txt)

$ pip install --target . -r requirements.txt

finally, zip up everything.

... in Bash:

$ zip -r dependencies.zip ../python

... in Powershell:

$ Compress-Archive -Path . -DestinationPath dependencies.zip

2. Create a layer

You can do this either in the AWS console or in the CLI. Follow these instructions .


3. Add the layer to the lambda function

You can do this either with the Add a layer option in the lambda page, or in the CLI. Follow these instructions .

The issue is that unless it is preconfigured pdfkit is trying to call the "which" command to figure out where the wkhtmltopdf binary is. But "which" is not available on the container running Lambda. If you look at the pdfkit code you can call the configuration object with the contents of the binary.

So for this to work, you could try the following:

 config = pdfkit.configuration(wkhtmltopdf=bytes('/opt/bin/wkhtmltopdf','utf-8')) pdf = pdfkit.from_string(html_body, local_file_path, configuration=config)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM