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
2 changes: 1 addition & 1 deletion tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
snippets/whats_left_to_implement.py
snippets/whats_left_*.py
32 changes: 32 additions & 0 deletions tests/generator/not_impl_modules_footer.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@


rustpymods = list(
map(
lambda mod: mod[0],
filter(
lambda mod: (mod[1] == "" or mod[1] == ".py") and "LICENSE" not in mod[0],
map(os.path.splitext, os.listdir(libdir)),
),
)
)
rustpymods += list(sys.builtin_module_names)

rustpymods = dict(map(
lambda mod: (
mod,
set(dir(__import__(mod)))
if mod not in ("this", "antigravity")
else None,
),
rustpymods
))

for modname, cpymod in cpymods.items():
if modname in rustpymods:
rustpymod = rustpymods[modname]
if rustpymod:
for item in cpymod - rustpymod:
print(f"{modname}.{item}")
else:
print(f"{modname} (entire module)")

8 changes: 8 additions & 0 deletions tests/generator/not_impl_modules_header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# WARNING: THIS IS AN AUTOMATICALLY GENERATED FILE
# EDIT tests/not_impl_mods_gen.sh, NOT THIS FILE.
# RESULTS OF THIS TEST DEPEND ON THE CPYTHON
# VERSION AND PYTHON ENVIRONMENT USED
# TO RUN not_impl_mods_gen.py

import sys
import os
123 changes: 88 additions & 35 deletions tests/not_impl_gen.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,101 @@
objects = [
bool,
bytearray,
bytes,
complex,
dict,
float,
frozenset,
int,
list,
memoryview,
range,
set,
str,
tuple,
object,
]
# It's recommended to run this with `python3 -I not_impl_gen.py`, to make sure
# that nothing in your global Python environment interferes with what's being
# extracted here.

import pkgutil
import os
import sys

sys.path = list(
filter(
lambda path: "site-packages" not in path and "dist-packages" not in path,
sys.path,
)
)


def attr_is_not_inherited(type_, attr):
"""
returns True if type_'s attr is not inherited from any of its base classes
"""

bases = obj.__mro__[1:]
bases = type_.__mro__[1:]

return getattr(type_, attr) not in (getattr(base, attr, None) for base in bases)


def gen_methods(header, footer, output):
objects = [
bool,
bytearray,
bytes,
complex,
dict,
float,
frozenset,
int,
list,
memoryview,
range,
set,
str,
tuple,
object,
]

output.write(header.read())
output.write("expected_methods = {\n")

for obj in objects:
output.write(f" '{obj.__name__}': ({obj.__name__}, [\n")
output.write(
"\n".join(
f" {attr!r},"
for attr in dir(obj)
if attr_is_not_inherited(obj, attr)
)
)
output.write("\n ])," + ("\n" if objects[-1] == obj else "\n\n"))

output.write("}\n\n")
output.write(footer.read())


def gen_modules(header, footer, output):
output.write(header.read())

modules = dict(
map(
lambda mod: (
mod.name,
# check name b/c modules listed have side effects on import,
# e.g. printing something or opening a webpage
set(dir(__import__(mod.name)))
if mod.name not in ("this", "antigravity")
else None,
),
pkgutil.iter_modules(),
)
)

print(
f"""
cpymods = {modules!r}
libdir = {os.path.abspath("../Lib/")!r}
""",
file=output,
)

return getattr(obj, attr) not in (
getattr(base, attr, None) for base in bases)
output.write(footer.read())


header = open("generator/not_impl_header.txt")
footer = open("generator/not_impl_footer.txt")
output = open("snippets/whats_left_to_implement.py", "w")
gen_funcs = {"methods": gen_methods, "modules": gen_modules}

output.write(header.read())
output.write("expected_methods = {\n")

for obj in objects:
output.write(f" '{obj.__name__}': ({obj.__name__}, [\n")
output.write("\n".join(
f" {attr!r},"
for attr in dir(obj)
if attr_is_not_inherited(obj, attr)
))
output.write("\n ])," + ("\n" if objects[-1] == obj else "\n\n"))
for name, gen_func in gen_funcs.items():
gen_func(
header=open(f"generator/not_impl_{name}_header.txt"),
footer=open(f"generator/not_impl_{name}_footer.txt"),
output=open(f"snippets/whats_left_{name}.py", "w"),
)

output.write("}\n\n")
output.write(footer.read())
42 changes: 37 additions & 5 deletions whats_left.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
#!/bin/sh
#!/bin/bash
set -e

ALL_SECTIONS=(methods modules)

GREEN=''
BOLD=''
NC='(B'

h() {
# uppercase input
header_name=$(echo "$@" | tr "[:lower:]" "[:upper:]")
echo "$GREEN$BOLD===== $header_name =====$NC"
}

cd "$(dirname "$0")"
cd tests

python3 not_impl_gen.py
(
cd tests
# -I means isolate from environment; we don't want any pip packages to be listed
python3 -I not_impl_gen.py
)

# show the building first, so people aren't confused why it's taking so long to
# run whats_left_to_implement
cargo build --release

cd ..
if [ $# -eq 0 ]; then
sections=(${ALL_SECTIONS[@]})
else
sections=($@)
fi

cargo run -- tests/snippets/whats_left_to_implement.py
for section in "${sections[@]}"; do
section=$(echo "$section" | tr "[:upper:]" "[:lower:]")
snippet=tests/snippets/whats_left_$section.py
if ! [[ -f $snippet ]]; then
echo "Invalid section $section" >&2
continue
fi
h "$section" >&2
cargo run --release -q -- "$snippet"
done