In this post, I illustrate how I tackled the problem of making a specific application in Python that would communicate with AWS services.
You can find the code in this repository: https://github.com/gianlucaballa/s3-file-editor
Task: Create an application that allows users to effortlessly share and modify written information such as materials, quantities, and important notes with one another.
The application needs to meet the following criteria:
- Any user should be able to open the application on a pc with a double-click.
- Upon opening the application, users should have immediate access to a simple text file for viewing, editing, and saving (structure for the text file is not necessary – a blank text file suffices).
- The user can read, modify, and save the text file for other users to use.
This application will be specifically used by building engineers to easily share information such as material to buy, quantity and similar notes regarding construction sites.
No overheads: ease of use is vital here.
Key criteria: accessibility, seamless file handling, collaboration.
----------------------------------------------------------------------------------------------------------------------
My solution:
At first, I thought about using RDS in AWS and creating a simple table with 3 columns for a MySQL database. I steered away from this solution because it would have over complicated the code for the execution of SQL commands, without producing any significant benefit.
Instead, I proceeded with the following steps:
- I created an S3 bucket in AWS using a specific user with specific permissions and credentials.
- I uploaded an empty text file with a specific name to the S3 bucket.
- I wrote a Python application using boto3*.
*(Boto3 is the official AWS SDK for Python. It provides an easy-to-use Python interface to interact with various AWS services such as S3. With Boto3, developers can programmatically manage AWS resources, automate tasks, and build applications that leverage AWS services without needing to manually configure API requests).
This solution showed to be effective and satisfied the established key criteria, as it will be demonstrated below.
----------------------------------------------------------------------------------------------------------------------
Explanation:
By sharing and analysing the Python code that I wrote for the application (see point 3. above), you can better understand the operation of the application that I designed.
The code (formatted with Black):
import boto3
import os
def download_file(bucket_name, key, local_filename):
s3 = boto3.client(
"s3",
region_name="insert_region",
aws_access_key_id="insert_id",
aws_secret_access_key="insert_secret",
)
s3.download_file(bucket_name, key, local_filename)
def upload_file(bucket_name, key, local_filename):
s3 = boto3.client(
"s3",
region_name="insert_region",
aws_access_key_id="insert_id",
aws_secret_access_key="insert_secret",
)
s3.upload_file(local_filename, bucket_name, key)
def edit_file(local_filename):
os.system(f'notepad "{local_filename}"')
def main():
bucket_name = "insert_bucket_name"
key = "insert_file_name.txt"
local_filename = "temp_file.txt"
# Download the file from S3.
download_file(bucket_name, key, local_filename)
# Allow the user to edit the file.
edit_file(local_filename)
# Upload the modified file back to S3.
upload_file(bucket_name, key, local_filename)
# Clean up the temporary file.
os.remove(local_filename)
print("Success!")
if __name__ == "__main__":
main()
import boto3
These import the "boto3" module and the "os" module. The "os" module provides a way of using the operating system dependent functionality. For example, it allows the application to execute a command in the system's shell.
def download_file(bucket_name, key, local_filename):
s3 = boto3.client(
"s3",
region_name="insert_region",
aws_access_key_id="insert_id",
aws_secret_access_key="insert_secret",
)
s3.download_file(bucket_name, key, local_filename)
This function called download_file takes 3 arguments.
Once called, it creates an S3 client object, in other words, an interface through which your Python code can communicate with Amazon S3. In order to do this, it is necessary to specify the region in which the S3 exists, the AWS access key and secret access key of the AWS user (see point 1. above).
Hardcoding keys is never a good idea because they can be seen by anyone looking at the code! I hardcoded them to test the application.
Then the download_file function downloads the file from the specified S3 bucket (bucket_name
) with the specified key/name of the file (key
) to the local file (local_filename
) on the file system using the function (usually the local file is where the file with the code is on the pc). s3.download_file(bucket_name, key, local_filename) is a specific function provided by Boto3.
def upload_file(bucket_name, key, local_filename):
s3 = boto3.client(
"s3",
region_name="insert_region",
aws_access_key_id="insert_id",
aws_secret_access_key="insert_secret",
)
s3.upload_file(local_filename, bucket_name, key)
This is a similar function but now it uploads the local file (local_filename) on the file system using the function to the specified S3 bucket (bucket_name) with the specified key/name of the file (key). s3.upload_file(local_filename, bucket_name, key) is a specific function provided by Boto3.
def edit_file(local_filename):
os.system(f'notepad "{local_filename}"')
The edit_file function opens the specified file (local_filename) in the default text editor of the system using the os.system function. Since I am testing this application in Windows, I specified "notepad" as the default text editor.
def main():
bucket_name = "insert_bucket_name"
key = "insert_file_name.txt"
local_filename = "temp_file.txt"
# Download the file from S3.
download_file(bucket_name, key, local_filename)
# Allow the user to edit the file.
edit_file(local_filename)
# Upload the modified file back to S3.
upload_file(bucket_name, key, local_filename)
# Clean up the temporary file.
os.remove(local_filename)
print("File has been updated and uploaded to S3.")
In Python, main() is a conventional name for the main entry point of a script or program. It's a function that typically contains the main logic or sequence of actions that the script should perform when executed.The purpose of defining a main() function is to encapsulate the main functionality of the script and to provide a clear starting point for the program's execution. This makes the code more modular and easier to understand, as the main logic is isolated within a specific function.
In this case, main() is used to call the functions that I defined above in a specific order (download, edit, upload), clean up the temporary file on the pc once it is uploaded to S3 (using os.remove(local_filename)) and print a message once the process is concluded. In main(), I also establish variables that will be used as arguments for the functions: the name of the S3 bucket (see point 1. above), the name of the .txt file that I initially uploaded to S3 (see point 2. above) and the local file name (temp_file.txt works fine for this).
if __name__ == "__main__":
main()
This final block ensures that the
main() function is executed only when the script is run directly, not when it's imported as a module into another script. This allows the script to be used both as a stand-alone program and as a reusable module.
Final notes:
- Ensure that the IAM user associated with the AWS credentials has the necessary permissions to access the specified S3 bucket and perform read/write operations on the objects.
- Make sure to handle sensitive information such as AWS access keys securely.
- This script is intended for educational purposes and can be modified to suit specific requirements.
----------------------------------------------------------------------------------------------------------------------
To transform the script into a clickable .exe, I can use
pyinstaller --onefile my_script_name.py
After PyInstaller finishes, it will create a "dist" directory in the script's directory, containing the executable file. This executable can be distributed to others.