[转]Develop with Python on Ubuntu
本文转自:https://documentation.ubuntu.com/ubuntu-for-developers/tutorials/python-use/#use-python
Develop with Python on Ubuntu - Ubuntu for Developers
Develop with Python on Ubuntu
This tutorial shows how to run, check, and debug Python scripts on Ubuntu. For instructions on how to install Python and related tooling, including IDEs, debuggers, and linters, see the dedicated guide on How to set up a development environment for Python on Ubuntu. This article assumes that tooling suggested in that article has been installed.
Important
To separate the system installation of Python from your development and testing setup, only use virtual environments for installing development project dependencies and running the developed code. This guide uses the standard venv
virtual environment.
Preparing a Python virtual environment
-
(Optional) Create a directory for Python development, as well as a directory for the new project:
mkdir -p ~/python/helloworld cd ~/python/helloworld
-
Create a separate virtual environment for the new project (specifying
.venv
as the directory for it):python3 -m venv .venv
-
Activate the virtual environment by sourcing the
activate
script:source .venv/bin/activate
-
Check that the environment has been set up:
dev@ubuntu:~/python/helloworld$
which python3
/home/dev/python/helloworld/.venv/bin/python3
Note
If you attempt to install a Python package using pip
outside of a Python virtual environment, such as venv
, on an Ubuntu (Debian) system, you receive a warning that explains that you should keep the system installation of Python (installed using .deb
packages from Ubuntu repositories) separate from Python packages installed using pip
:
$ which pip
/usr/bin/pip
$ pip install -r requirements.txt
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.12/README.venv for more information.
note: If you believe this is a mistake, please contact your Python
installation or OS distribution provider. You can override this,
at the risk of breaking your Python installation or OS, by passing
--break-system-packages.
hint: See PEP 668 for the detailed specification.
Creating a basic Python program
To illustrate the installation of a dependency confined to the Python virtual environment, the following example uses the requests
library for handling HTTP requests.
-
Create a
requirements.txt
file with the list of dependencies. For example:echo "requests" > requirements.txt
-
Install the dependencies:
pip install -r requirements.txt
Checking the list of Python packages installed within the virtual environment should show output similar to this:
dev@ubuntu:~/python/helloworld$
pip list
Package Version -------- ------- certifi 2025.1.31 charset-normalizer 3.4.1 idna 3.10 pip 24.2 requests 2.32.3 urllib3 2.4.0
(The version numbers can differ based on your environment.)
-
Write a Python script that uses the installed dependency. For example, create a
helloworld.py
file with the following contents:helloworld.py
import requests def hello_world(): # Use the example HTTP response service url = "https://httpbin.org/post" # Define a custom header for the POST method header = {"Message": "Hello, world!"} try: # Send the defined header to the response service response = requests.post(url, headers=header) # Basic error handling response.raise_for_status() # Parse the response response_data = response.json() # Print the message print(response_data["headers"]["Message"]) except requests.exceptions.RequestException as e: print(f"An error occurred: {e}") if __name__ == "__main__": hello_world()
-
Executing the program should result in the message you defined and sent using the
POST
method printed to standard output:dev@ubuntu:~/python/helloworld$
python3 helloworld.py
Hello, world!
Improving Python code with the help of tooling
Use linters and formatters to improve the quality and style of your Python code to achieve consistency and better readability.
In this example, we use the Flake8 code checker and Black formatter to identify areas for improvement and automatically format code. See How to set up a development environment for Python on Ubuntu for instructions on how to install these tools.
Checking Python code with Flake8
Consider the ‘Hello, world!’ script shown in Creating a basic Python program. Let’s introduce a simple style transgression into the code:
helloworld.py
import requests
def hello_world():
# Use the example HTTP response service
url = "https://httpbin.org/post"
# Define a custom header for the POST method
header = {"Message": "Hello, world!"}
try:
# Send the defined header to the response service
response = requests.post(url, headers=header)
# Basic error handling
response.raise_for_status()
# Parse the response
response_data = response.json()
# Print the message
print(response_data["headers"]["Message"])
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
hello_world()
Running the Flake8 checker identifies the offense and informs us that it expects one more blank line on line number 27:
$ flake8 helloworld.py
helloworld.py:27:1: E305 expected 2 blank lines after class
or function definition, found 1
Reformatting Python code with Black
Running the Black formatter automatically reformats the code and fixes the problem:
$ black helloworld.py
reformatted helloworld.py
All done! ✨ 🍰 ✨
1 file reformatted.
Black is opinionated
Note that Black proceeds to reformat the code without asking for a confirmation.
Debugging Python code
To allow for the possibility of inspecting the state of the script at different points of execution, add breakpoints. In this example, we use the ipdb
debugger, which is an enhanced version of the built-in pdb
debugger.
-
Add
ipdb
to the list of dependencies:echo "ipdb" >> requirements.txt
-
Install the dependencies:
pip install -r requirements.txt
-
Add
ipdb
module import, and insert a breakpoint in the code (see line 23):helloworld.py
import requests import ipdb def hello_world(): # Use the example HTTP response service url = "https://httpbin.org/post" # Define a custom header for the POST method header = {"Message": "Hello, world!"} try: # Send the defined header to the response service response = requests.post(url, headers=header) # Basic error handling response.raise_for_status() # Parse the response response_data = response.json() # Set a breakpoint to check response data ipdb.set_trace() # Print the message print(response_data["headers"]["Message"]) except requests.exceptions.RequestException as e: print(f"An error occurred: {e}") if __name__ == "__main__": hello_world()
-
Execute the script to interact with the
ipdb
debugger:$ python3 helloworld.py > /home/rkratky/python/hw.py(26)hello_world() 25 # Print the message ---> 26 print(response_data["headers"]["Message"]) 27 ipdb> ipdb> pp response_data['headers'] {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '0', 'Host': 'httpbin.org', 'Message': 'Hello, world!', 'User-Agent': 'python-requests/2.32.3', 'X-Amzn-Trace-Id': 'Root=1-680a5186-49625c625bc31933473464b7'} ipdb> response_data['headers']['Message'] 'Hello, world!'
In the above example, we query the
response_data
variable using thepp
(pretty print) command and then by specifying theMessage
header directly.
Testing Python code with a unit test
The following example shows how to use the pytest
testing tool. First we implement a simple unit test that supplies mock data in place of querying the remote service and compares the output with the expected return value from the hello_world()
function. Then we run pytest
to perform the test.
-
Create a unit-test file,
helloworld_test.py
, with the following contents:helloworld_test.py
from helloworld import hello_world MOCK_RESPONSE_DATA = {"headers": {"Message": "Hello, world!"}} class MockResponse: def __init__(self, json_data): self.json_data = json_data def json(self): return self.json_data def raise_for_status(self): pass def test_hello_world(mocker, capsys): # Mock the requests.post method mocker.patch("requests.post", return_value=MockResponse(MOCK_RESPONSE_DATA)) # Call the function to be tested hello_world() # Get the printed output captured = capsys.readouterr() # Check that the output is as expected assert captured.out.strip() == "Hello, world!"
-
Run the unit test using
pytest
:$ pytest helloworld_test.py ================= test session starts ===================== platform linux -- Python 3.12.7, pytest-8.3.2, pluggy-1.5.0 rootdir: /home/user/python plugins: cov-5.0.0, xdist-3.6.1, mock-3.14.0, requests_mock-1.12.1, typeguard-4.3.0 collected 1 item helloworld_test.py . [100%] ==================== 1 passed in 0.01s ====================
posted on 2025-08-05 22:01 freeliver54 阅读(8) 评论(0) 收藏 举报