Created
April 17, 2023 10:11
-
-
Save Kludex/9087acb5af2a940bd3fcefce96799412 to your computer and use it in GitHub Desktop.
Scripts used to generate the list of objects on https://github.com/pydantic/pydantic/pull/5480
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import importlib | |
import pkgutil | |
def get_public_objects(package_name, parent_module=""): | |
objects = [] | |
full_package_name = ( | |
parent_module + "." + package_name if parent_module else package_name | |
) | |
package = importlib.import_module(full_package_name) | |
for obj_name in getattr(package, "__all__", []): | |
objects.append(full_package_name + "." + obj_name) | |
for _, module_name, is_pkg in pkgutil.iter_modules(package.__path__): | |
if module_name.startswith("_"): # Skip private modules | |
continue | |
module_path = full_package_name + "." + module_name | |
if is_pkg: | |
objects.extend( | |
get_public_objects(module_name, parent_module=full_package_name) | |
) | |
else: | |
module = importlib.import_module(module_path) | |
for obj_name in getattr(module, "__all__", []): | |
objects.append(module_path + "." + obj_name) | |
return objects | |
# Example usage: | |
packages = ["pydantic"] | |
try: | |
import pydantic_extra_types | |
packages.append("pydantic_extra_types") | |
except ImportError: | |
pass | |
try: | |
import pydantic_settings | |
packages.append("pydantic_settings") | |
except ImportError: | |
pass | |
for package_name in packages: | |
public_objects = get_public_objects(package_name) | |
for obj in public_objects: | |
print(obj) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Find the difference between pydantic v1 and v2.""" | |
import contextlib | |
import os | |
import subprocess | |
import tempfile | |
import venv | |
from typing import Iterator, Literal | |
from rich.console import Console | |
console = Console() | |
@contextlib.contextmanager | |
def create_python_exe() -> Iterator[str]: | |
"""Create a python executable. | |
Returns: | |
The path to the python executable. | |
""" | |
with tempfile.TemporaryDirectory() as temp_dir: | |
venv_path = os.path.join(temp_dir, "venv") | |
venv.create(venv_path, with_pip=True) | |
python_exe = os.path.join(venv_path, "bin", "python") | |
yield python_exe | |
def collect_python_objects(version: Literal["v1", "v2"]) -> set[str]: | |
"""Collect all objects from pydantic. | |
Args: | |
version (Literal["v1", "v2"]): The version of pydantic to install. | |
Returns: | |
set[str]: A set of tuples containing the object name and the module | |
name. | |
""" | |
with create_python_exe() as python_exe: | |
subprocess_args = [python_exe, "-m", "pip", "install"] | |
if version == "v2": | |
subprocess_args.extend( | |
[ | |
"--pre", | |
"git+https://github.com/pydantic/pydantic-extra-types", | |
# "git+https://github.com/pydantic/pydantic-settings", | |
] | |
) | |
subprocess_args.extend(["pydantic", "stdlib-list", "mypy"]) | |
subprocess.run(subprocess_args) | |
result = subprocess.run([python_exe, "collect.py"], capture_output=True) | |
return {dotted_path.decode() for dotted_path in result.stdout.splitlines()} | |
def list_moved(result_v1: set[str], result_v2: set[str]) -> None: | |
"""List all objects that have been moved from v1 to v2. | |
Args: | |
result_v1 (set[str]): The objects from v1. | |
result_v2 (set[str]): The objects from v2. | |
""" | |
moved: dict[str, str] = {} | |
for dotted_path_v1 in result_v1: | |
module_v1, obj_v1 = dotted_path_v1.rsplit(".", 1) | |
found_on_v2 = False | |
location: str | None = None | |
for dotted_path_v2 in result_v2: | |
module_v2, obj_v2 = dotted_path_v2.rsplit(".", 1) | |
if dotted_path_v1 == dotted_path_v2: | |
found_on_v2 = True | |
if obj_v1 == obj_v2 and module_v1 != module_v2: | |
location = dotted_path_v2 | |
if not found_on_v2 and location: | |
moved[dotted_path_v1] = location | |
console.print(f"Moved objects: {len(moved)}", style="bold") | |
console.print(moved) | |
def list_removed(result_v1: set[str], result_v2: set[str]) -> None: | |
"""List all objects that have been removed from v1 to v2. | |
Args: | |
result_v1 (set[str]): The objects from v1. | |
result_v2 (set[str]): The objects from v2. | |
""" | |
removed: set[str] = set() | |
for dotted_path_v1 in result_v1: | |
_, obj_v1 = dotted_path_v1.rsplit(".", 1) | |
found_on_v2 = False | |
for dotted_path_v2 in result_v2: | |
_, obj_v2 = dotted_path_v2.rsplit(".", 1) | |
if obj_v1 == obj_v2: | |
found_on_v2 = True | |
if not found_on_v2: | |
removed.add(dotted_path_v1) | |
console.print(f"Removed objects: {len(removed)}", style="bold") | |
# sort the removed objects | |
console.print(sorted(removed)) | |
if __name__ == "__main__": | |
result_v1 = collect_python_objects("v1") | |
result_v2 = collect_python_objects("v2") | |
# console.print(result_v1, style="red") | |
# console.print(result_v2, style="green") | |
list_moved(result_v1, result_v2) | |
list_removed(result_v1, result_v2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment