8000 gh-86457: Fix signature for code.replace(). by serhiy-storchaka · Pull Request #23199 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-86457: Fix signature for code.replace(). #23199

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

Merged
merged 7 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Completely override signature.
  • Loading branch information
serhiy-storchaka committed Jun 29, 2023
commit 65a165b1387347caf50a307bb8c8665512680706
12 changes: 2 additions & 10 deletions Objects/clinic/codeobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,7 @@ code_linesiterator(PyCodeObject *code, PyObject *Py_UNUSED(args))
}

/*[clinic input]
@text_signature "($self, /, **changes)"
code.replace

*
Expand Down Expand Up @@ -2002,7 +2003,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
PyObject *co_filename, PyObject *co_name,
PyObject *co_qualname, PyObject *co_linetable,
PyObject *co_exceptiontable)
/*[clinic end generated code: output=e75c48a15def18b9 input=520204253f64c415]*/
/*[clinic end generated code: output=e75c48a15def18b9 input=18e280e07846c122]*/
{
#define CHECK_INT_ARG(ARG) \
if (ARG < 0) { \
Expand Down
257 changes: 133 additions & 124 deletions Tools/clinic/clinic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2751,7 +2751,7 @@ def __init__(self,
self.py_name = py_name
self.unused = unused

if default is not unspecified and (default is not NULL or c_default == 'NULL'):
if default is not unspecified:
if (self.default_type
and default is not unknown
and not isinstance(default, self.default_type)
Expand Down Expand Up @@ -4314,6 +4314,7 @@ def reset(self) -> None:
self.indent = IndentStack()
self.kind = CALLABLE
self.coexist = False
self.forced_text_signature: str | None = None
self.parameter_continuation = ''
self.preserve_output = False

Expand Down Expand Up @@ -4448,6 +4449,11 @@ def at_coexist(self) -> None:
fail("Called @coexist twice!")
self.coexist = True

def at_text_signature(self, text_signature) -> None:
if self.forced_text_signature:
fail("Called @text_signature twice!")
self.forced_text_signature = text_signature

def parse(self, block: Block) -> None:
self.reset()
self.block = block
Expand Down Expand Up @@ -5151,142 +5157,145 @@ def format_docstring(self):
add(f.cls.name)
else:
add(f.name)
add('(')
if self.forced_text_signature:
add(self.forced_text_signature)
else:
add('(')
Copy link
Member Author

Choose a reason for hiding this comment

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

All following lines just increase indentation. GitHub is not good in showing such case.

Copy link
Contributor

Choose a reason for hiding this comment

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

For the record, I plan to refactor the signature generation into a helper function. See #107623


# populate "right_bracket_count" field for every parameter
assert parameters, "We should always have a self parameter. " + repr(f)
assert isinstance(parameters[0].converter, self_converter)
# self is always positional-only.
assert parameters[0].is_positional_only()
parameters[0].right_bracket_count = 0
positional_only = True
for p in parameters[1:]:
if not p.is_positional_only():
positional_only = False
else:
assert positional_only
if positional_only:
p.right_bracket_count = abs(p.group)
else:
# don't put any right brackets around non-positional-only parameters, ever.
p.right_bracket_count = 0

right_bracket_count = 0

def fix_right_bracket_count(desired):
nonlocal right_bracket_count
s = ''
while right_bracket_count < desired:
s += '['
right_bracket_count += 1
while right_bracket_count > desired:
s += ']'
right_bracket_count -= 1
return s

need_slash = False
added_slash = False
need_a_trailing_slash = False

# we only need a trailing slash:
# * if this is not a "docstring_only" signature
# * and if the last *shown* parameter is
# positional only
if not f.docstring_only:
for p in reversed(parameters):
if not p.converter.show_in_signature:
continue
if p.is_positional_only():
need_a_trailing_slash = True
break

# populate "right_bracket_count" field for every parameter
assert parameters, "We should always have a self parameter. " + repr(f)
assert isinstance(parameters[0].converter, self_converter)
# self is always positional-only.
assert parameters[0].is_positional_only()
parameters[0].right_bracket_count = 0
positional_only = True
for p in parameters[1:]:
if not p.is_positional_only():
positional_only = False
else:
assert positional_only
if positional_only:
p.right_bracket_count = abs(p.group)
else:
# don't put any right brackets around non-positional-only parameters, ever.
p.right_bracket_count = 0

right_bracket_count = 0

def fix_right_bracket_count(desired):
nonlocal right_bracket_count
s = ''
while right_bracket_count < desired:
s += '['
right_bracket_count += 1
while right_bracket_count > desired:
s += ']'
right_bracket_count -= 1
return s

need_slash = False
added_slash = False
need_a_trailing_slash = False
added_star = False

# we only need a trailing slash:
# * if this is not a "docstring_only" signature
# * and if the last *shown* parameter is
# positional only
if not f.docstring_only:
for p in reversed(parameters):
first_parameter = True
last_p = parameters[-1]
line_length = len(''.join(text))
indent = " " * line_length
def add_parameter(text):
nonlocal line_length
nonlocal first_parameter
if first_parameter:
s = text
first_parameter = False
else:
s = ' ' + text
if line_length + len(s) >= 72:
add('\n')
add(indent)
line_length = len(indent)
s = text
line_length += len(s)
add(s)

for p in parameters:
if not p.converter.show_in_signature:
continue
if p.is_positional_only():
need_a_trailing_slash = True
break
assert p.name

is_self = isinstance(p.converter, self_converter)
if is_self and f.docstring_only:
# this isn't a real machine-parsable signature,
# so let's not print the "self" parameter
continue

added_star = False

first_parameter = True
last_p = parameters[-1]
line_length = len(''.join(text))
indent = " " * line_length
def add_parameter(text):
nonlocal line_length
nonlocal first_parameter
if first_parameter:
s = text
first_parameter = False
else:
s = ' ' + text
if line_length + len(s) >= 72:
add('\n')
add(indent)
line_length = len(indent)
s = text
line_length += len(s)
add(s)

for p in parameters:
if not p.converter.show_in_signature:
continue
assert p.name

is_self = isinstance(p.converter, self_converter)
if is_self and f.docstring_only:
# this isn't a real machine-parsable signature,
# so let's not print the "self" parameter
continue

if p.is_positional_only():
need_slash = not f.docstring_only
elif need_slash and not (added_slash or p.is_positional_only()):
added_slash = True
add_parameter('/,')

if p.is_keyword_only() and not added_star:
added_star = True
add_parameter('*,')

p_add, p_output = text_accumulator()
p_add(fix_right_bracket_count(p.right_bracket_count))

if isinstance(p.converter, self_converter):
# annotate first parameter as being a "self".
#
# if inspect.Signature gets this function,
# and it's already bound, the self parameter
# will be stripped off.
#
# if it's not bound, it should be marked
# as positional-only.
#
# note: we don't print "self" for __init__,
# because this isn't actually the signature
# for __init__. (it can't be, __init__ doesn't
# have a docstring.) if this is an __init__
# (or __new__), then this signature is for
# calling the class to construct a new instance.
p_add('$')
if p.is_positional_only():
need_slash = not f.docstring_only
elif need_slash and not (added_slash or p.is_positional_only()):
added_slash = True
add_parameter('/,')

if p.is_keyword_only() and not added_star:
added_star = True
add_parameter('*,')

p_add, p_output = text_accumulator()
p_add(fix_right_bracket_count(p.right_bracket_count))

if isinstance(p.converter, self_converter):
# annotate first parameter as being a "self".
#
# if inspect.Signature gets this function,
# and it's already bound, the self parameter
# will be stripped off.
#
# if it's not bound, it should be marked
# as positional-only.
#
# note: we don't print "self" for __init__,
# because this isn't actually the signature
# for __init__. (it can't be, __init__ doesn't
# have a docstring.) if this is an __init__
# (or __new__), then this signature is for
# calling the class to construct a new instance.
p_add('$')

if p.is_vararg():
p_add("*")
if p.is_vararg():
p_add("*")

name = p.converter.signature_name or p.name
p_add(name)
name = p.converter.signature_name or p.name
p_add(name)

if not p.is_vararg() and p.converter.is_optional():
p_add('=')
value = p.converter.py_default
if not value:
value = repr(p.converter.default)
p_add(value)
if not p.is_vararg() and p.converter.is_optional():
p_add('=')
value = p.converter.py_default
if not value:
value = repr(p.converter.default)
p_add(value)

if (p != last_p) or need_a_trailing_slash:
p_add(',')
if (p != last_p) or need_a_trailing_slash:
p_add(',')

add_parameter(p_output())
add_parameter(p_output())

add(fix_right_bracket_count(0))
if need_a_trailing_slash:
add_parameter('/')
add(')')
add(fix_right_bracket_count(0))
if need_a_trailing_slash:
add_parameter('/')
add(')')

# PEP 8 says:
#
Expand Down
0