Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions python-import/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,16 @@

This folder contains code and materials used in Real Python's [Python `import`: Advanced Techniques and Tips](https://realpython.com/python-import/) article.

The code was tested with Python 3.15.1 and 3.14.9. Install the third-party dependencies with:

```console
$ python -m pip install PyYAML==6.0.3 matplotlib==3.11.2 colorama==0.4.6
```

The examples need Python 3.9 or later, since they use `importlib.resources.files()`.

Some examples need a bit of setup before you run them:

- **`namespace_package/`:** Start Python inside this folder and run `sys.path.extend(["third_party", "local"])` first, as the tutorial shows.
- **`population_quiz/`:** Download the UN data file described in `population_quiz/data/README.md`. Then run `python population_quiz.py` or `python -c "import population"` from inside `population_quiz/`, so that Python finds the `data` package.
- **`structure/`:** Run `python cli.py structure` from inside `structure/`, or install the project with `python -m pip install -e .` from that folder.
11 changes: 4 additions & 7 deletions python-import/hello_gui/__main__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
# hello_gui/__main__.py

import tkinter as tk
from importlib import resources
from tkinter import ttk

try:
from importlib import resources
except ImportError:
import importlib_resources as resources


class Hello(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.wm_title("Hello")
images = resources.files("hello_gui.gui_resources")

# Read image, store a reference to it, and set it as an icon
with resources.path("hello_gui.gui_resources", "logo.png") as path:
with resources.as_file(images / "logo.png") as path:
self._icon = tk.PhotoImage(file=path)
self.iconphoto(True, self._icon)

# Read image, create a button, and store a reference to the image
with resources.path("hello_gui.gui_resources", "hand.png") as path:
with resources.as_file(images / "hand.png") as path:
hand = tk.PhotoImage(file=path)
button = ttk.Button(
self,
Expand Down
2 changes: 1 addition & 1 deletion python-import/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def _import(package, plugin):

def _import_all(package):
"""Import all plugins in a package"""
files = resources.contents(package)
files = [path.name for path in resources.files(package).iterdir()]
plugins = [f[:-3] for f in files if f.endswith(".py") and f[0] != "_"]
for plugin in plugins:
_import(package, plugin)
Expand Down
2 changes: 1 addition & 1 deletion python-import/population_quiz/data/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Population Data

You should download [`WPP2019_TotalPopulationBySex.csv`](https://population.un.org/wpp/Download/Files/1_Indicators%20(Standard)/CSV_FILES/WPP2019_TotalPopulationBySex.csv) from [the UN web page](https://population.un.org/wpp/Download/Standard/CSV/). Save the CSV file in this folder.
Download [`WPP2024_TotalPopulationBySex.csv.gz`](https://population.un.org/wpp/assets/Excel%20Files/1_Indicator%20(Standard)/CSV_FILES/WPP2024_TotalPopulationBySex.csv.gz) from the UN's [World Population Prospects 2024](https://population.un.org/wpp/). Unzip it and save `WPP2024_TotalPopulationBySex.csv` in this folder.
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,28 @@

class _Population:
def __init__(self):
"""Prepare to read the population file"""
self._data = {}
"""Read the population file"""
self.data = {}
self.variant = "Medium"

@property
def data(self):
"""Read data from disk"""
if self._data: # Data has already been read, return it directly
return self._data

# Read data and store it in self._data
print(f"Reading population data for {self.variant} scenario")
with resources.open_text(
"data", "WPP2019_TotalPopulationBySex.csv"
) as fid:
csv_file = resources.files("data") / "WPP2024_TotalPopulationBySex.csv"
with csv_file.open() as fid:
rows = csv.DictReader(fid)

# Read data, filter the correct variant
for row in rows:
if int(row["LocID"]) >= 900 or row["Variant"] != self.variant:
continue

country = self._data.setdefault(row["Location"], {})
country = self.data.setdefault(row["Location"], {})
population = float(row["PopTotal"]) * 1000
country[int(row["Time"])] = round(population)
return self._data

def get_country(self, country):
"""Get population data for one country"""
country = self.data[country]
years, population = zip(*country.items(), strict=False)
data = self.data[country]
years, population = zip(*data.items())
return years, population

def plot_country(self, country):
Expand All @@ -52,5 +43,5 @@ def order_countries(self, year):
return sorted(countries, key=lambda c: countries[c], reverse=True)


# Instantiate the singleton
# Instantiate the Singleton
data = _Population()
15 changes: 5 additions & 10 deletions python-import/population_quiz/population_quiz.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@

import csv
import random

try:
from importlib import resources
except ImportError:
import importlib_resources as resources
from importlib import resources


def read_population_file(year, variant="Medium"):
"""Read population data for the given year and variant"""
population = {}

print(f"Reading population data for {year}, {variant} scenario")
with resources.open_text(
"data", "WPP2019_TotalPopulationBySex.csv"
) as fid:
csv_file = resources.files("data") / "WPP2024_TotalPopulationBySex.csv"
with csv_file.open() as fid:
rows = csv.DictReader(fid)

# Read data, filter the correct year
Expand All @@ -37,7 +32,7 @@ def run_quiz(population, num_questions, num_countries):
num_correct = 0
for q_num in range(num_questions):
print(f"\n\nQuestion {q_num + 1}:")
countries = random.sample(population.keys(), num_countries)
countries = random.sample(list(population), num_countries)
print("\n".join(f"{i}. {a}" for i, a in enumerate(countries, start=1)))

# Get user input
Expand Down Expand Up @@ -67,7 +62,7 @@ def run_quiz(population, num_questions, num_countries):

def main():
"""Read population data and run quiz"""
population = read_population_file("2020")
population = read_population_file("2024")
num_correct = run_quiz(population, num_questions=10, num_countries=3)
print(f"\nYou answered {num_correct} questions correctly")

Expand Down
10 changes: 10 additions & 0 deletions python-import/structure/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

[project]
name = "local_structure"
version = "0.1.0"

[tool.setuptools]
packages = ["structure"]
6 changes: 0 additions & 6 deletions python-import/structure/setup.cfg

This file was deleted.

5 changes: 0 additions & 5 deletions python-import/structure/setup.py

This file was deleted.

Loading