Skip to content

Commit 1cd7f5d

Browse files
authored
Merge branch 'master' into pandas-gradebook
2 parents 685a228 + f82dff3 commit 1cd7f5d

File tree

42 files changed

+621
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+621
-0
lines changed

python-import/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Python `import`: Advanced Techniques and Tips
2+
3+
This folder contains code and materials used in Real Python's [Python `import`: Advanced Techniques and Tips]() article.
4+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# yang.py
2+
3+
print("Hello from yang")
4+
import yin # noqa
5+
6+
number = 24
7+
8+
9+
def combine():
10+
return number + yin.number
11+
12+
13+
print(f"yin and yang combined is {combine()}")
14+
print("Goodbye from yang")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# yin.py
2+
3+
print("Hello from yin")
4+
number = 42
5+
6+
7+
def combine():
8+
import yang
9+
10+
return number + yang.number
11+
12+
13+
print("Goodbye from yin")

python-import/docreader.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# docreader.py
2+
3+
import importlib
4+
5+
module_name = input("Name of module? ")
6+
module = importlib.import_module(module_name)
7+
print(module.__doc__)

python-import/feel_young.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# feel_young.py
2+
3+
4+
def make_young(text):
5+
words = [replace_by_age(w) for w in text.split()]
6+
return " ".join(words)
7+
8+
9+
def replace_by_age(word, new_age=24, age_range=(25, 120)):
10+
if word.isdigit() and int(word) in range(*age_range):
11+
return str(new_age)
12+
return word
13+
14+
15+
if __name__ == "__main__":
16+
text = input("Tell me something: ")
17+
print(make_young(text))
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ban_importer.py
2+
3+
import sys
4+
5+
BANNED_MODULES = {"re"}
6+
7+
8+
class BanFinder:
9+
@classmethod
10+
def find_spec(cls, name, path, target=None):
11+
if name in BANNED_MODULES:
12+
raise ModuleNotFoundError(f"{name!r} is banned")
13+
14+
15+
sys.meta_path.insert(0, BanFinder)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# csv_importer.py
2+
3+
import csv
4+
import pathlib
5+
import re
6+
import sys
7+
from importlib.machinery import ModuleSpec
8+
9+
10+
class CsvImporter:
11+
def __init__(self, csv_path):
12+
"""Store path to CSV file"""
13+
self.csv_path = csv_path
14+
15+
@classmethod
16+
def find_spec(cls, name, path, target=None):
17+
"""Look for CSV file"""
18+
package, _, module_name = name.rpartition(".")
19+
csv_file_name = f"{module_name}.csv"
20+
directories = sys.path if path is None else path
21+
for directory in directories:
22+
csv_path = pathlib.Path(directory) / csv_file_name
23+
if csv_path.exists():
24+
return ModuleSpec(name, cls(csv_path))
25+
26+
def create_module(self, spec):
27+
"""Returning None uses the standard machinery for creating modules"""
28+
return None
29+
30+
def exec_module(self, module):
31+
"""Executing the module means reading the CSV file"""
32+
# Read CSV data and store as a list of rows
33+
with self.csv_path.open() as fid:
34+
rows = csv.DictReader(fid)
35+
data = list(rows)
36+
fieldnames = tuple(_identifier(f) for f in rows.fieldnames)
37+
38+
# Create a dict with each field
39+
values = zip(*(row.values() for row in data))
40+
fields = dict(zip(fieldnames, values))
41+
42+
# Add the data to the module
43+
module.__dict__.update(fields)
44+
module.__dict__["data"] = data
45+
module.__dict__["fieldnames"] = fieldnames
46+
module.__file__ = str(self.csv_path)
47+
48+
def __repr__(self):
49+
"""Nice representation of the class"""
50+
return f"{self.__class__.__name__}({str(self.csv_path)!r})"
51+
52+
53+
def _identifier(var_str):
54+
"""Create a valid identifier from a string
55+
56+
See https://stackoverflow.com/a/3305731
57+
"""
58+
return re.sub(r"\W|^(?=\d)", "_", var_str)
59+
60+
61+
# Add the CSV importer at the end of the list of finders
62+
sys.meta_path.append(CsvImporter)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# debug_importer.py
2+
3+
import sys
4+
5+
6+
class DebugFinder:
7+
@classmethod
8+
def find_spec(cls, name, path, target=None):
9+
print(f"Importing {name!r}")
10+
return None
11+
12+
13+
sys.meta_path.insert(0, DebugFinder)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name,department,birthday month
2+
John Smith,Accounting,November
3+
Erica Meyers,IT,March
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# pip_importer.py
2+
3+
from importlib import util
4+
import subprocess
5+
import sys
6+
7+
8+
class PipFinder:
9+
@classmethod
10+
def find_spec(cls, name, path, target=None):
11+
print(f"Module {name!r} not installed. Attempting to pip install")
12+
cmd = f"{sys.executable} -m pip install {name}"
13+
try:
14+
subprocess.run(cmd.split(), check=True)
15+
except subprocess.CalledProcessError:
16+
return None
17+
18+
return util.find_spec(name)
19+
20+
21+
sys.meta_path.append(PipFinder)

0 commit comments

Comments
 (0)