Created
August 20, 2024 18:22
-
-
Save abadger/a260d656344217307ca0282d2ac501b2 to your computer and use it in GitHub Desktop.
Parsing "docstrings" for class attributes.
This file contains 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
#!/usr/bin/python3 -tt | |
import ast | |
import inspect | |
# Define the classes from your code | |
class MyField(): | |
""" | |
That's my field | |
""" | |
def __init__(self, value=None): | |
self.value = value | |
class KindOfModel(): | |
""" | |
My docstring title | |
Docstring body | |
""" | |
field1 = MyField("hooray") | |
""" | |
Whatever field in the KindOfModel. | |
""" | |
class MyModel(KindOfModel): | |
field2 = MyField("boom") | |
""" | |
chick-a-lacka | |
""" | |
def get_source(filename): | |
with open(filename) as f: | |
return f.read() | |
# Function to retrieve attribute-level docstrings | |
def get_attribute_docstrings(source): | |
# Parse the source code into an AST | |
tree = ast.parse(source) | |
# Find the class definition in the AST | |
models = {} | |
for node in ast.walk(tree): | |
### TODO: Need to look at whether this is a subclass of Model | |
# Will we need to import the code to make this work? | |
if isinstance(node, ast.ClassDef): | |
models[node.name] = {} | |
# Iterate over all the class body elements | |
for sub_node in node.body: | |
# Check if the sub_node is an assignment (i.e., a field definition) | |
if isinstance(sub_node, ast.Assign): | |
for target in sub_node.targets: | |
### TODO: do we have any specific attributes to filter out? | |
if isinstance(target, ast.Name): | |
# Look for the following Expr node which contains the docstring | |
models[node.name][target.id] = "" | |
next_node_index = node.body.index(sub_node) + 1 | |
if next_node_index < len(node.body): | |
next_node = node.body[next_node_index] | |
if isinstance(next_node, ast.Expr) and isinstance(next_node.value, ast.Str): | |
models[node.name][target.id] = next_node.value.s | |
return models | |
# Retrieve the class and field docstrings | |
def get_class_and_field_docstrings(cls): | |
with open(__file__) as f: | |
source = f.read() | |
models = get_attribute_docstrings(source) | |
for model_name, attributes in models.items(): | |
print("=== {} ===".format(model_name)) | |
for attr_name, docstring in attributes.items(): | |
print("Attribute {}.{}: {}".format(model_name, attr_name, docstring)) | |
# Get docstrings for KindOfModel | |
get_class_and_field_docstrings(MyModel) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output:
But what we want is for
MyModel
to include bothfield1
andfield2