diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 000000000..4e2737b80 --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,5 @@ +# frozen_string_literal: true +source "https://rubygems.org" + +gem "webrick" +gem "github-pages", "~> 226", group: :jekyll_plugins diff --git a/docs/_config.yml b/docs/_config.yml index f8b905314..68ef1203c 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,6 +1,12 @@ theme: jekyll-theme-minimal +google_analytics: G-G896Q7VERJ + defaults: + - scope: + path: "" + values: + layout: default - scope: path: developers values: diff --git a/docs/_layouts/dev_guide.html b/docs/_layouts/dev_guide.html index 6b13aa2ae..0010fa1ae 100644 --- a/docs/_layouts/dev_guide.html +++ b/docs/_layouts/dev_guide.html @@ -66,6 +66,8 @@

{{ site.title | default: site.github.repo Style guide
Tools +
+ Debug documentation

{% if site.github.is_project_page %} diff --git a/docs/developers/debug_docs.md b/docs/developers/debug_docs.md new file mode 100644 index 000000000..e98f8bd5f --- /dev/null +++ b/docs/developers/debug_docs.md @@ -0,0 +1,53 @@ +# How to setup environment for previewing changes to documentation + + + +The pytype documentation is in markdown format. + +github uses [jekyll](https://jekyllrb.com/docs/) to render these pages. + +## Prerequisites + +Install/update ruby and bundler + +```shell +ruby -v # should be greater than 3.0.0 +``` + +If it doesn't exist or is too old + +```shell +sudo apt-get install ruby-full +``` + +Add path to your .bashrc + +```shell +echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc +echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc +echo 'export PATH="$HOME/gems/bin:$PATH"' >> ~/.bashrc +source ~/.bashrc +``` + +Install packages required for jekyll + +```shell +gem install jekyll bundler webrick +gem update jekyll +bundle install +``` + +## Start jekyll locally + +```shell +cd docs # you'll need to be in the pytype/docs directory + +bundle exec jekyll serve --watch +``` + +The `--watch` flag forces jekyll to look for changes to your source files and +reload the server if it detects any changes. + +You can view your webpages by navigating to +[http://localhost:4000](http://localhost:4000) like +[http://localhost:4000/developers/index.html](http://localhost:4000/developers/index.html) diff --git a/pytype/abstract/function.py b/pytype/abstract/function.py index 7760cffc2..9885c10f3 100644 --- a/pytype/abstract/function.py +++ b/pytype/abstract/function.py @@ -902,7 +902,7 @@ def match_all_args(ctx, node, func, args): else: raise AssertionError( f"Mismatched parameter {arg_name} not found in passed_args" - ) from e + ) from e else: # This is not an InvalidParameters error. raise diff --git a/pytype/ast/debug.py b/pytype/ast/debug.py index 54f1e0149..27e073d83 100644 --- a/pytype/ast/debug.py +++ b/pytype/ast/debug.py @@ -44,7 +44,7 @@ def _format(node, level=0): elif isinstance(node, list): lines = ["["] lines.extend(indent * (level + 2) + _format(x, level + 2) + "," - for x in node) + for x in node) if len(lines) > 1: lines.append(indent * (level + 1) + "]") else: diff --git a/pytype/errors.py b/pytype/errors.py index 1d8ff6177..634e999f1 100644 --- a/pytype/errors.py +++ b/pytype/errors.py @@ -1086,9 +1086,8 @@ def _print_params_helper(self, param_or_params): if isinstance(param_or_params, abstract.BaseValue): return self._print_as_expected_type(param_or_params) else: - return ( - f"[{', '.join(self._print_params_helper(p) for p in param_or_params)}]" - ) + return "[{}]".format( + ", ".join(self._print_params_helper(p) for p in param_or_params)) def wrong_annotation_parameter_count( self, stack, annot: abstract.BaseValue, @@ -1290,7 +1289,7 @@ def annotation_type_mismatch( # ensures that we print all of the options when 'Any' is among them. # We don't need to print this if there is only 1 unique type. print_types = {self._print_as_actual_type(v, literal=literal) - for v in binding.variable.data} + for v in binding.variable.data} if len(print_types) > 1: details += ("\nIn assignment of type: " f"{self._join_printed_types(print_types)}") diff --git a/pytype/preprocess.py b/pytype/preprocess.py index 004adcbcd..ad5b69f48 100644 --- a/pytype/preprocess.py +++ b/pytype/preprocess.py @@ -35,9 +35,9 @@ def augment_annotations(src): if visitor.annotation_lines: lines = src.split("\n") for i in visitor.annotation_lines: - # No need to preserve comments, users should never see the transformed - # source code. - line, *_ = lines[i].split("#", 1) - lines[i] = line + " = ..." + # Preserve comments, as they may be pytype directives. We don't bother to + # keep the formatting, since users never see the transformed source code. + line, mark, comment = lines[i].partition("#") + lines[i] = line + " = ..." + mark + comment src = "\n".join(lines) return src diff --git a/pytype/pyi/evaluator.py b/pytype/pyi/evaluator.py index 0825f0b68..7e57c5bb7 100644 --- a/pytype/pyi/evaluator.py +++ b/pytype/pyi/evaluator.py @@ -39,8 +39,7 @@ def _convert(node): elif isinstance(node, ast3.Set): return set(map(_convert, node.elts)) elif isinstance(node, ast3.Dict): - return {_convert(k): _convert(v) - for k, v in zip(node.keys, node.values)} + return {_convert(k): _convert(v) for k, v in zip(node.keys, node.values)} elif isinstance(node, ast3.NameConstant): return node.value elif isinstance(node, ast3.Name): diff --git a/pytype/pytd/booleq.py b/pytype/pytd/booleq.py index 6e028684c..5b8b5079a 100644 --- a/pytype/pytd/booleq.py +++ b/pytype/pytd/booleq.py @@ -454,7 +454,7 @@ def _iter_implications(self): def _get_nonfalse_values(self, var): return {value for value, implication in self.implications[var].items() - if implication is not FALSE} + if implication is not FALSE} def _get_first_approximation(self): """Get all (variable, value) combinations to consider. diff --git a/pytype/tests/test_base.py b/pytype/tests/test_base.py index 73968a438..47e12f3d1 100644 --- a/pytype/tests/test_base.py +++ b/pytype/tests/test_base.py @@ -321,7 +321,7 @@ def assertOnlyHasReturnType(self, func, t): for sig in func.signatures) self.assertEqual(t, ret, "Return type {!r} != {!r}".format(pytd_utils.Print(t), - pytd_utils.Print(ret))) + pytd_utils.Print(ret))) def assertHasReturnType(self, func, t): """Test that a given return type is present. Ignore extras.""" @@ -330,11 +330,11 @@ def assertHasReturnType(self, func, t): if isinstance(ret, pytd.UnionType): self.assertIn(t, ret.type_list, "Return type {!r} not found in {!r}".format( - pytd_utils.Print(t), pytd_utils.Print(ret))) + pytd_utils.Print(t), pytd_utils.Print(ret))) else: self.assertEqual(t, ret, "Return type {!r} != {!r}".format(pytd_utils.Print(ret), - pytd_utils.Print(t))) + pytd_utils.Print(t))) def assertHasAllReturnTypes(self, func, types): """Test that all given return types are present. Ignore extras.""" diff --git a/pytype/tests/test_disables.py b/pytype/tests/test_disables.py index fb8722b92..05c7ea871 100644 --- a/pytype/tests/test_disables.py +++ b/pytype/tests/test_disables.py @@ -210,6 +210,13 @@ def foo(x): pass c = foo(a, b.i) # pytype: disable=attribute-error # pytype: disable=wrong-arg-count """) + def test_bare_annotation(self): + self.Check(""" + from typing import AnyStr + def f(): + x: AnyStr # pytype: disable=invalid-annotation + """) + class AttributeErrorDisableTest(test_base.BaseTest): """Test attribute-error disabling.""" diff --git a/pytype/tests/test_utils.py b/pytype/tests/test_utils.py index 2dd04db7a..237de8232 100644 --- a/pytype/tests/test_utils.py +++ b/pytype/tests/test_utils.py @@ -278,7 +278,7 @@ def _format_error(line, code, mark=None): exp = _format_error(error.lineno, code, mark) actual = _format_error(error.lineno, error.name) self._fail( - f"Error does not match:\nExpected: {exp}\nActual: {actual}" + f"Error does not match:\nExpected: {exp}\nActual: {actual}" ) else: self._fail(f"Unexpected error:\n{error}") diff --git a/pytype/tools/analyze_project/pytype_runner_test.py b/pytype/tools/analyze_project/pytype_runner_test.py index a35b464a4..503966896 100644 --- a/pytype/tools/analyze_project/pytype_runner_test.py +++ b/pytype/tools/analyze_project/pytype_runner_test.py @@ -575,7 +575,7 @@ def test_cycle(self): action=Action.INFER, input='bar.py', deps=' | {} {}'.format(os.path.join(runner.pyi_dir, 'bar.pyi-1'), - os.path.join(runner.pyi_dir, 'foo.pyi-1')), + os.path.join(runner.pyi_dir, 'foo.pyi-1')), imports=os.path.join(runner.imports_dir, 'bar.imports'), module='bar')) self.assertBuildStatementMatches(body[9:], ExpectedBuildStatement( @@ -583,7 +583,7 @@ def test_cycle(self): action=Action.CHECK, input='foo.py', deps=' | {} {}'.format(os.path.join(runner.pyi_dir, 'bar.pyi'), - os.path.join(runner.pyi_dir, 'foo.pyi-1')), + os.path.join(runner.pyi_dir, 'foo.pyi-1')), imports=os.path.join(runner.imports_dir, 'foo.imports'), module='foo')) @@ -617,7 +617,7 @@ def test_cycle_with_extra_action(self): action=Action.CHECK, input='foo.py', deps=' | {} {}'.format(os.path.join(runner.pyi_dir, 'foo.pyi-1'), - os.path.join(runner.pyi_dir, 'bar.pyi-1')), + os.path.join(runner.pyi_dir, 'bar.pyi-1')), imports=os.path.join(runner.imports_dir, 'foo.imports'), module='foo'))