Skip to content

More improvements to stubgen #7951

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 38 commits into from
Nov 15, 2019
Merged

More improvements to stubgen #7951

merged 38 commits into from
Nov 15, 2019

Conversation

JukkaL
Copy link
Collaborator

@JukkaL JukkaL commented Nov 14, 2019

This includes many improvements to stubgen and a related mypy fix.
Here are the most useful ones:

  • Use a separate process to do introspection of modules so that we can
    recover if a module kills the current process on import, for example.
  • Export all names imported from the current package by default.
    Add --export-less stubgen flag to disable this behavior.
  • Avoid a crash in semantic analysis if there's a bad property definition
    (stubgen can generate these).
  • Fix various issues with bad Python code being generated by stubgen.
  • Ignore bad signatures in docstrings (this is still very ad-hoc, but it's a
    bit more robust now).
  • Try to find a module using sys.path if we can't import it.
  • Skip some additional modules that may be runnable since they can cause
    trouble when we try to introspect them.

This is again a big PR, but the commit history should be reasonably clean.

We can't always tell whether they are supposed to be part of a public
API, so just export all of them.

Add the `--export-less` flag to get the old behavior.
This is best effort anyway, and we can't expect docstring to
follow any strict conventions.
…alue

This also fixes an issue with generated attrs methods.
@JukkaL JukkaL requested a review from ilevkivskyi November 14, 2019 17:52
Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

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

Thanks, many nice fixes here. I have several comments/suggestions.

path = getattr(package, '__path__', None)
pkg_all = getattr(package, '__all__', None)
if pkg_all is not None:
pkg_all = list(pkg_all)
Copy link
Member

Choose a reason for hiding this comment

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

Can this cause troubles if __all__ is not valid?

subpackages=subpackages)


def worker(queue1: 'Queue[str]', queue2: 'Queue[Union[str, ModuleProperties]]') -> None:
Copy link
Member

Choose a reason for hiding this comment

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

This is very minor, but maybe call them task_queue and result_queue?


def _start(self) -> None:
self.q1 = Queue() # type: Queue[str]
self.q2 = Queue() # type: Queue[Union[ModuleProperties, str]]
Copy link
Member

Choose a reason for hiding this comment

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

Same as above, maybe call theses self.tasks and self.results? Also maybe add a short comment that str contains exception message?

if n == max_iter:
raise RuntimeError('Timeout waiting for subprocess')
try:
return self.q2.get(timeout=0.05)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe make the timeout configurable in constructor?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think that making it configurable is useful.

else:
self.fail('Unexpected definition for property "{}"'.format(first_item.func.name),
item)
deleted_items.append(i + 1)
Copy link
Member

Choose a reason for hiding this comment

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

What if the extra item is also decorated (with some unrelated decorator)? Maybe add a test for this?

mypy/stubgen.py Outdated
'__gt__',
'__ge__',
'__hash__',
'__iter__',
}
Copy link
Member

Choose a reason for hiding this comment

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

Not really important but I think all these top-level constants can be made Final.

mypy/stubgen.py Outdated
exported_names.update(sub_names)
if module:
for name in sub_names:
self.import_tracker.require_name(name)

def translate_module_name(self, module: str, relative: int) -> Tuple[str, int]:
Copy link
Member

Choose a reason for hiding this comment

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

This technically doesn't need to be a method, but up to you.

mypy/stubgen.py Outdated
@@ -1041,6 +1105,21 @@ def is_recorded_name(self, name: str) -> bool:
return self.is_top_level() and name in self._toplevel_names


def find_method_names(defs: List[Statement]) -> Set[str]:
# TODO: Traverse into nested definitions
# TODO: Overloads
Copy link
Member

Choose a reason for hiding this comment

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

There is an elif for OverloadedFuncDef is this TODO outdated?

@@ -1385,6 +1481,9 @@ def parse_options(args: List[str]) -> Options:
parser.add_argument('--include-private', action='store_true',
help="generate stubs for objects and members considered private "
"(single leading underscore and no trailing underscores)")
parser.add_argument('--export-less', action='store_true',
help=("don't implicitly export all names imported from other modules "
"in the same package"))
Copy link
Member

Choose a reason for hiding this comment

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

Maybe update the docs with the new flag? (In a separate PR if you prefer.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A good idea. I'll create a separate PR.

__all__ = ['C']

@asyncio.coroutine
def f():
Copy link
Member

Choose a reason for hiding this comment

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

Why don't we include f() in the output?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not included in __all__.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

(This is something we may want to change, but it may require the generation of an explicit __all__.)

@ilevkivskyi
Copy link
Member

(I think you noticed, but tests are still failing.)

@JukkaL JukkaL merged commit bbb192d into master Nov 15, 2019
@gvanrossum gvanrossum deleted the stubgen-fixes-final branch August 26, 2020 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants