Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

formatting(docstrings): fix common errors #5

Closed
wants to merge 91 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
f8837b2
initial commit
NripeshN Sep 5, 2023
f49f98c
small fix
NripeshN Sep 5, 2023
c7f30a5
ignore FunctionOrderingFormatter for now
NripeshN Sep 5, 2023
ad5d9b8
example section
NripeshN Sep 5, 2023
a3aba96
print docstring
NripeshN Sep 5, 2023
df24707
print test
NripeshN Sep 5, 2023
c12980b
revert print statements
NripeshN Sep 5, 2023
05c73cd
extract docstrings fix
NripeshN Sep 5, 2023
9858545
small fix
NripeshN Sep 5, 2023
3403a29
small fix
NripeshN Sep 5, 2023
e01eca7
small fix
NripeshN Sep 5, 2023
bfc11a7
small fix
NripeshN Sep 5, 2023
15635eb
small fix
NripeshN Sep 5, 2023
009fa64
big change
NripeshN Sep 5, 2023
be7fc1a
big fix
NripeshN Sep 5, 2023
647f6a7
Revert "big fix"
NripeshN Sep 5, 2023
112ed4a
small fix
NripeshN Sep 5, 2023
bb185b0
big changes
NripeshN Sep 5, 2023
b66bb44
small fix
NripeshN Sep 5, 2023
140d9c3
import fix
NripeshN Sep 5, 2023
beb2a4d
small changes
NripeshN Sep 6, 2023
cac6277
big changes
NripeshN Sep 6, 2023
ba5d03d
small fix
NripeshN Sep 6, 2023
14593aa
small fix
NripeshN Sep 6, 2023
a322eb0
small fix
NripeshN Sep 6, 2023
4c5dd3d
indentation fix
NripeshN Sep 6, 2023
0d2e1a3
redundant underline fix
NripeshN Sep 6, 2023
8c48996
small fix
NripeshN Sep 6, 2023
d38f2a4
small fix
NripeshN Sep 6, 2023
d1ad169
indentation issue
NripeshN Sep 6, 2023
b0d961a
small fix
NripeshN Sep 6, 2023
13e85ea
small fix
NripeshN Sep 6, 2023
05cec2d
uncomment functional ordering formatting
NripeshN Sep 6, 2023
0a51a24
Update docs_formatter.py
he11owthere Nov 22, 2023
1757b15
Update docs_formatter.py
he11owthere Nov 22, 2023
27d479e
Update docs_formatter.py
he11owthere Nov 22, 2023
9b7f3cb
Update docs_formatter.py
he11owthere Nov 22, 2023
bffe3ff
Update docs_formatter.py
he11owthere Nov 22, 2023
1588d06
original
he11owthere Nov 22, 2023
f0f4d77
Update docs_formatter.py
he11owthere Nov 22, 2023
f4fec9f
small fix
he11owthere Nov 22, 2023
a4fea43
Update docs_formatter.py
he11owthere Nov 22, 2023
90ec9b8
testing
he11owthere Nov 22, 2023
86e2ef8
testing formatter
he11owthere Nov 22, 2023
5c58a21
Update docs_formatter.py
he11owthere Nov 22, 2023
56b8f3c
Update docs_formatter.py
he11owthere Nov 22, 2023
e50c8a8
Update docs_formatter.py
he11owthere Nov 22, 2023
bb654eb
Update docs_formatter.py
he11owthere Nov 22, 2023
737d15e
Update docs_formatter.py
he11owthere Nov 22, 2023
2e05c73
Update docs_formatter.py
he11owthere Nov 22, 2023
263b162
Update docs_formatter.py
he11owthere Nov 22, 2023
5044d97
tokenization approach
he11owthere Nov 28, 2023
05e173d
Update docs_formatter.py
he11owthere Nov 28, 2023
5b99d49
Update docs_formatter.py
he11owthere Nov 28, 2023
820bb96
Update docs_formatter.py
he11owthere Nov 28, 2023
8be213c
Update docs_formatter.py
he11owthere Nov 28, 2023
6f3b35e
Update docs_formatter.py
he11owthere Nov 28, 2023
5fc13a6
Update docs_formatter.py
he11owthere Nov 28, 2023
70a84c1
Update docs_formatter.py
he11owthere Nov 28, 2023
c65ef35
Update docs_formatter.py
he11owthere Nov 28, 2023
4984ee2
Update docs_formatter.py
he11owthere Nov 28, 2023
4006d33
Update docs_formatter.py
he11owthere Nov 28, 2023
069bdbd
Update docs_formatter.py
he11owthere Nov 28, 2023
2a707fb
Update docs_formatter.py
he11owthere Nov 28, 2023
25bed81
Update docs_formatter.py
he11owthere Nov 28, 2023
e66555a
append "..."
he11owthere Nov 28, 2023
532f1c8
Update docs_formatter.py
he11owthere Nov 28, 2023
0f69d5b
Update docs_formatter.py
he11owthere Nov 28, 2023
7027ec0
Update docs_formatter.py
he11owthere Nov 28, 2023
219dc38
Update docs_formatter.py
he11owthere Nov 28, 2023
8a28533
Update docs_formatter.py
he11owthere Nov 29, 2023
38f1ffc
Update docs_formatter.py
he11owthere Nov 29, 2023
a5a6acd
Update docs_formatter.py
he11owthere Nov 29, 2023
e2c659b
Update docs_formatter.py
he11owthere Nov 29, 2023
168ba13
Update docs_formatter.py
he11owthere Nov 29, 2023
dfe0243
small fix
he11owthere Nov 29, 2023
c211afd
Update docs_formatter.py
he11owthere Nov 29, 2023
002f70b
Update docs_formatter.py
he11owthere Nov 29, 2023
1f582a5
Update docs_formatter.py
he11owthere Nov 29, 2023
ff10e0e
Update docs_formatter.py
he11owthere Nov 29, 2023
0f98a43
Update docs_formatter.py
he11owthere Nov 29, 2023
ce0b255
small fix
he11owthere Nov 29, 2023
48ed776
Update docs_formatter.py
he11owthere Nov 29, 2023
a68e93b
Update docs_formatter.py
he11owthere Nov 29, 2023
33cd752
Update docs_formatter.py
he11owthere Nov 29, 2023
60cd1c8
section name checker
he11owthere Dec 1, 2023
287b257
Update docs_formatter.py
he11owthere Dec 1, 2023
306b148
small test
he11owthere Dec 1, 2023
8ecec4c
Update docs_formatter.py
he11owthere Dec 1, 2023
a81dda1
Update docs_formatter.py
he11owthere Dec 1, 2023
da35495
working code
he11owthere Dec 1, 2023
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
6 changes: 4 additions & 2 deletions ivy_lint/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import sys
import argparse

from .formatters import FunctionOrderingFormatter
from .formatters import FunctionOrderingFormatter, DocstringFormatter

FORMATTERS = (FunctionOrderingFormatter,)
FORMATTERS = (DocstringFormatter,
FunctionOrderingFormatter,
)


def parse_args() -> argparse.Namespace:
Expand Down
1 change: 1 addition & 0 deletions ivy_lint/formatters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
from .base_docstring import BaseDocstringFormatter
from .ivy_array import IvyArrayDocstringFormatter
from .function_ordering import FunctionOrderingFormatter
from .docs_formatter import DocstringFormatter
122 changes: 122 additions & 0 deletions ivy_lint/formatters/docs_formatter.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm remembering correctly, we have the infrastructure for section manipulation already in place , you may use those.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not convinced why didn't we use the base class instead and extended it?

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import tokenize
from io import BytesIO
import re
import ast

from ivy_lint.formatters import BaseFormatter, BaseDocstringFormatter

class DocstringFormatter(BaseDocstringFormatter):
def validate_section_name(self, section_name, VALID_SECTION_NAMES):
if section_name not in VALID_SECTION_NAMES:
print(f"Invalid section name: {section_name}. Valid section names are {VALID_SECTION_NAMES}")
return False
return True

def format_docstring(self, doc):
"""Formats a single docstring."""
# Rename "Functional Examples" to "Examples" and format it without the extra newline
doc = re.sub(r'(\s*)Functional Examples\n\1-*\n?', r'\1Examples\n\1--------\n', doc)

# Ensure newline and correct indentation after "Examples" when it's already there
doc = re.sub(r'(\s*)Examples\n\1--------\s*\n+([^\n])', r'\1Examples\n\1--------\n\2', doc)

VALID_SECTION_NAMES = ["Args", "Arguments", "Attention", "Attributes", "Caution", "Danger", "Error", "Example", "Examples", "Hint", "Important",
"Keyword Args", "Keyword Arguments", "Methods", "Note", "Notes", "Other Parameters", "Parameters", "Return", "Returns",
"Raise", "Raises", "References", "See Also", "Tip", "Todo", "Warning", "Warnings", "Warn", "Warns", "Yield", "Yields"]

# Identify code blocks
lines = doc.split('\n')
is_codeblock = False
codeblock_start_lines = set() # This will store indices of lines which start a code block
lines_to_modify = set() # This will store the indices of indented lines not containing "..."
incorrect_sections = set() # This will store the indices of all the incorrect sections
prev_line = ""
is_codeblock_cont = False
lb = 0
rb = 0

for idx, line in enumerate(lines):
stripped_line = line.strip()

if stripped_line.startswith('-') and stripped_line.endswith('-'):
section_title = prev_line
if not self.validate_section_name(section_title, VALID_SECTION_NAMES):
incorrect_sections.add(idx)

if not is_codeblock and stripped_line.startswith('>>>'):
is_codeblock = True
codeblock_start_lines.add(idx)
elif is_codeblock and not is_codeblock_cont and (not stripped_line or (not stripped_line.startswith(('>>>', '...')))):
is_codeblock = False

if is_codeblock:
if stripped_line.startswith(('>>>')):
lb = rb = 0
lb += line.count('(')
rb += line.count(')')
if rb >= lb:
rb = 0
lb = 0
is_codeblock_cont = False
else:
lb = lb - rb
rb = 0
is_codeblock_cont = True
if not stripped_line.startswith(('>>>', '...')):
lines_to_modify.add(idx)
prev_line = stripped_line

# Add blank lines before code blocks
formatted_lines = []
skip = True
indentation = 0
for idx, line in enumerate(lines):
if idx in codeblock_start_lines and formatted_lines and formatted_lines[-1].strip(): # Insert blank line before code block
if not formatted_lines[-1].strip().startswith("-"):
skip = False
elif skip:
skip = False
formatted_lines.append(line)
continue
formatted_lines.append('')
if idx in lines_to_modify:
formatted_lines.append(line)
indentation = len(formatted_lines[-2]) - len(formatted_lines[-2].lstrip())
formatted_lines[-1] = (indentation * ' ') + '...' + line[indentation:]
continue
if idx in incorrect_sections: #for future purposes
pass
formatted_lines.append(line)

return '\n'.join(formatted_lines)

def format_all_docstrings(self, python_code):
"""Extracts all docstrings from the given Python code, formats them, and replaces the original ones with the formatted versions."""
replacements = {}
# Tokenize the code
tokens = tokenize.tokenize(BytesIO(python_code.encode('utf-8')).readline)
for token in tokens:
if token.type == tokenize.STRING:
original_docstring = token.string
modified_docstring = self.format_docstring(original_docstring)
formatted_docstring = self._do_format_docstring(modified_docstring)
if original_docstring != formatted_docstring: # Only add if there are changes
replacements[original_docstring] = formatted_docstring

for original, formatted in replacements.items():
python_code = python_code.replace(original, formatted, 1) # Only replace once to be safe

return python_code

def _format_file(self, filename: str) -> bool:
with open(filename, 'r') as file:
original_content = file.read()

formatted_content = self.format_all_docstrings(original_content)

if original_content != formatted_content:
with open(filename, 'w') as file:
file.write(formatted_content)
return True

return False