codegrapher 0.2.1__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. codegrapher-0.3.0/.gitattributes +1 -0
  2. codegrapher-0.3.0/.github/workflows/main.yaml +39 -0
  3. codegrapher-0.3.0/.github/workflows/publish.yaml +21 -0
  4. codegrapher-0.3.0/.gitignore +13 -0
  5. codegrapher-0.3.0/.readthedocs.yaml +22 -0
  6. codegrapher-0.3.0/LICENSE +16 -0
  7. codegrapher-0.3.0/Makefile +16 -0
  8. codegrapher-0.3.0/PKG-INFO +150 -0
  9. {codegrapher-0.2.1 → codegrapher-0.3.0}/README.rst +5 -5
  10. codegrapher-0.3.0/codegrapher/__init__.py +1 -0
  11. {codegrapher-0.2.1 → codegrapher-0.3.0}/codegrapher/parser.py +37 -40
  12. codegrapher-0.3.0/docs/Makefile +177 -0
  13. codegrapher-0.3.0/docs/codegrapher.rst +29 -0
  14. codegrapher-0.3.0/docs/conf.py +261 -0
  15. codegrapher-0.3.0/docs/docs-requirements.txt +3 -0
  16. codegrapher-0.3.0/docs/index.rst +25 -0
  17. codegrapher-0.3.0/docs/make.bat +242 -0
  18. codegrapher-0.3.0/docs/modules.rst +7 -0
  19. codegrapher-0.3.0/docs/readme_link.rst +3 -0
  20. codegrapher-0.3.0/pyproject.toml +53 -0
  21. codegrapher-0.3.0/setup.md +38 -0
  22. {codegrapher-0.2.1 → codegrapher-0.3.0}/tests/test_graph.py +0 -3
  23. {codegrapher-0.2.1 → codegrapher-0.3.0}/tests/test_parser.py +26 -15
  24. codegrapher-0.3.0/uv.lock +691 -0
  25. codegrapher-0.2.1/PKG-INFO +0 -16
  26. codegrapher-0.2.1/codegrapher/__init__.py +0 -1
  27. codegrapher-0.2.1/codegrapher.egg-info/PKG-INFO +0 -16
  28. codegrapher-0.2.1/codegrapher.egg-info/SOURCES.txt +0 -17
  29. codegrapher-0.2.1/codegrapher.egg-info/dependency_links.txt +0 -1
  30. codegrapher-0.2.1/codegrapher.egg-info/entry_points.txt +0 -4
  31. codegrapher-0.2.1/codegrapher.egg-info/pbr.json +0 -1
  32. codegrapher-0.2.1/codegrapher.egg-info/requires.txt +0 -2
  33. codegrapher-0.2.1/codegrapher.egg-info/top_level.txt +0 -3
  34. codegrapher-0.2.1/setup.cfg +0 -5
  35. codegrapher-0.2.1/setup.py +0 -32
  36. {codegrapher-0.2.1 → codegrapher-0.3.0}/cli/__init__.py +0 -0
  37. {codegrapher-0.2.1 → codegrapher-0.3.0}/cli/script.py +0 -0
  38. {codegrapher-0.2.1 → codegrapher-0.3.0}/codegrapher/graph.py +0 -0
  39. {codegrapher-0.2.1 → codegrapher-0.3.0}/tests/__init__.py +0 -0
@@ -0,0 +1 @@
1
+ * text=auto eol=lf
@@ -0,0 +1,39 @@
1
+ name: Codegrapher unit tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
14
+ fail-fast: false
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - name: Set up Python ${{ matrix.python-version }}
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v5
24
+ - name: Install project and dev dependencies
25
+ run: uv sync --locked --extra dev
26
+ - name: Test with pytest
27
+ run: uv run pytest tests --doctest-modules --junitxml=junit/test-results-${{ matrix.python-version }}.xml --cov --cov-report=xml --cov-report=html
28
+ - name: Upload test results
29
+ uses: actions/upload-artifact@v4
30
+ if: always()
31
+ with:
32
+ name: test-results-${{ matrix.python-version }}
33
+ path: junit/test-results-${{ matrix.python-version }}.xml
34
+ - name: Upload coverage report
35
+ uses: actions/upload-artifact@v4
36
+ if: always()
37
+ with:
38
+ name: coverage-report-${{ matrix.python-version }}
39
+ path: htmlcov/
@@ -0,0 +1,21 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: release
11
+ permissions:
12
+ id-token: write # required for OIDC trusted publishing
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - name: Install uv
17
+ uses: astral-sh/setup-uv@v5
18
+ - name: Build distribution
19
+ run: uv build
20
+ - name: Publish to PyPI
21
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ .idea/
2
+ codegrapher.egg-info
3
+ *.pyc
4
+ .coverage
5
+ cover/
6
+ dist/
7
+ docs/_build/
8
+
9
+ *.gv
10
+ *.pdf
11
+ *.png
12
+
13
+ .python-version
@@ -0,0 +1,22 @@
1
+ # .readthedocs.yaml
2
+ # Read the Docs configuration file
3
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4
+
5
+ # Required
6
+ version: 2
7
+
8
+ # Set the version of Python and other tools you might need
9
+ build:
10
+ os: ubuntu-22.04
11
+ tools:
12
+ python: "3.11"
13
+
14
+ # Build documentation in the docs/ directory with Sphinx
15
+ sphinx:
16
+ configuration: docs/conf.py
17
+
18
+ # We recommend specifying your dependencies to enable reproducible builds:
19
+ # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
20
+ # python:
21
+ # install:
22
+ # - requirements: docs/requirements.txt
@@ -0,0 +1,16 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Laura Rupprecht
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ persons to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,16 @@
1
+ .PHONY: install install-dev test build check
2
+
3
+ install:
4
+ uv sync
5
+
6
+ install-dev:
7
+ uv sync --extra dev
8
+
9
+ test:
10
+ uv run pytest
11
+
12
+ build:
13
+ uv build
14
+
15
+ check:
16
+ twine check dist/*
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: codegrapher
3
+ Version: 0.3.0
4
+ Summary: Code that graphs code
5
+ Project-URL: Homepage, https://github.com/LaurEars/codegrapher
6
+ Project-URL: Repository, https://github.com/LaurEars/codegrapher
7
+ Project-URL: Issues, https://github.com/LaurEars/codegrapher/issues
8
+ Author: Laura Rupprecht
9
+ License: The MIT License (MIT)
10
+
11
+ Copyright (c) 2026 Laura Rupprecht
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
14
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
15
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
16
+ persons to whom the Software is furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
19
+ Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
22
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ License-File: LICENSE
26
+ Keywords: ast,call-graph,code,documentation,graph,graphviz
27
+ Classifier: Development Status :: 4 - Beta
28
+ Classifier: Intended Audience :: Developers
29
+ Classifier: License :: OSI Approved :: MIT License
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: Programming Language :: Python :: 3.8
32
+ Classifier: Programming Language :: Python :: 3.9
33
+ Classifier: Programming Language :: Python :: 3.10
34
+ Classifier: Programming Language :: Python :: 3.11
35
+ Classifier: Programming Language :: Python :: 3.12
36
+ Classifier: Programming Language :: Python :: 3.13
37
+ Classifier: Topic :: Software Development :: Documentation
38
+ Requires-Python: >=3.8
39
+ Requires-Dist: click>=7.0
40
+ Requires-Dist: graphviz>=0.4.2
41
+ Provides-Extra: dev
42
+ Requires-Dist: coverage>=5.0; extra == 'dev'
43
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
44
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
45
+ Description-Content-Type: text/x-rst
46
+
47
+ codegrapher
48
+ ===========
49
+
50
+ .. image:: https://github.com/LaurEars/codegrapher/actions/workflows/main.yaml/badge.svg
51
+ :target: https://github.com/LaurEars/codegrapher/actions/workflows/main.yaml
52
+
53
+
54
+ Code that graphs code
55
+ ---------------------
56
+ Uses the python `AST <https://docs.python.org/3/library/ast.html>`_ to parse Python source code and build a call graph.
57
+
58
+
59
+ Output
60
+ ------
61
+ An example of the current output of the parser parsing itself.
62
+
63
+ .. image:: docs/codegrapher.png
64
+ :target: docs/codegrapher.png
65
+ :align: center
66
+ :width: 100 %
67
+ :alt: parser.py
68
+
69
+
70
+ Installation
71
+ ------------
72
+
73
+ .. code:: bash
74
+
75
+ pip install codegrapher
76
+
77
+
78
+ To generate graphs, `graphviz <http://www.graphviz.org/Download.php>`_ must be installed.
79
+
80
+
81
+ Usage
82
+ -----
83
+
84
+ At the command line
85
+ ~~~~~~~~~~~~~~~~~~~
86
+ To parse a file and output results to the console:
87
+
88
+ .. code:: bash
89
+
90
+ codegrapher path/to/file.py --printed
91
+
92
+
93
+ To parse a file and output results to a file:
94
+
95
+ .. code:: bash
96
+
97
+ codegrapher path/to/file.py --output output_file_name --output-type png
98
+
99
+ To analyze a directory of files, along with all files it contains:
100
+
101
+ .. code:: bash
102
+
103
+ codegrapher -r path/to/directory --output multiple_file_analysis
104
+
105
+ And if you have a list of functions that aren't useful in your graph, add it to a `.cg_ignore` file:
106
+
107
+ ::
108
+
109
+ # cg_ignore file
110
+ # all lines beginning with '#' are ignored
111
+
112
+ # every function calls this, so it's not helpful in my graph:
113
+ log_error
114
+
115
+ # I don't want to see this in my graph:
116
+ parse
117
+ lower
118
+
119
+ Then add the `--ignore` flag to your command. Using the flag `--remove-builtins` provides the same functionality
120
+ for ignoring items found in `__builtins__`.
121
+
122
+ As a Python module
123
+ ~~~~~~~~~~~~~~~~~~
124
+
125
+ To easily parse code in Python :
126
+
127
+ .. code:: python
128
+
129
+ from codegrapher.parser import FileObject
130
+
131
+ file_object = FileObject('path/to/file.py')
132
+ file_object.visit()
133
+
134
+ And then to add that code to a graph and render it (using graphviz):
135
+
136
+ .. code:: python
137
+
138
+ from codegrapher.graph import FunctionGrapher
139
+
140
+ graph = FunctionGrapher()
141
+ graph.add_file_to_graph(file_object)
142
+ graph.name = 'name.gv'
143
+ graph.format = 'png'
144
+ graph.render()
145
+
146
+ Which will produce your code as a png file, `name.gv.png`, along with a
147
+ `dot file <http://en.wikipedia.org/wiki/DOT_%28graph_description_language%29>`_ `name.gv`
148
+
149
+ More documentation for the Python module can be found at
150
+ `Read the Docs <http://codegrapher.readthedocs.org/en/latest/>`_.
@@ -1,21 +1,21 @@
1
1
  codegrapher
2
2
  ===========
3
3
 
4
- .. image:: https://travis-ci.org/LaurEars/codegrapher.svg?branch=master
5
- :target: https://travis-ci.org/LaurEars/codegrapher
4
+ .. image:: https://github.com/LaurEars/codegrapher/actions/workflows/main.yaml/badge.svg
5
+ :target: https://github.com/LaurEars/codegrapher/actions/workflows/main.yaml
6
6
 
7
7
 
8
8
  Code that graphs code
9
9
  ---------------------
10
- Uses the python `AST <https://docs.python.org/2/library/ast.html>`_ to parse Python source code and build a call graph.
10
+ Uses the python `AST <https://docs.python.org/3/library/ast.html>`_ to parse Python source code and build a call graph.
11
11
 
12
12
 
13
13
  Output
14
14
  ------
15
15
  An example of the current output of the parser parsing itself.
16
16
 
17
- .. image:: http://i.imgur.com/2VnLaL0.png
18
- :target: http://i.imgur.com/2VnLaL0.png
17
+ .. image:: docs/codegrapher.png
18
+ :target: docs/codegrapher.png
19
19
  :align: center
20
20
  :width: 100 %
21
21
  :alt: parser.py
@@ -0,0 +1 @@
1
+ __version__ = '0.3.0'
@@ -1,11 +1,11 @@
1
- import os
2
1
  import ast
3
2
  import copy
3
+ import os
4
4
  from pprint import pformat
5
5
 
6
6
 
7
- class FileObject(object):
8
- """ Class for keeping track of files.
7
+ class FileObject:
8
+ """Class for keeping track of files.
9
9
 
10
10
  Attributes:
11
11
  modules (dict): dict of current modules with `alias: module_name`, `key:value pairs`.
@@ -29,7 +29,7 @@ class FileObject(object):
29
29
  self.ignore = set()
30
30
 
31
31
  def visit(self):
32
- """ Visits all the nodes within the current file AST node.
32
+ """Visits all the nodes within the current file AST node.
33
33
 
34
34
  Updates `self.classes` for the current instance.
35
35
  """
@@ -41,13 +41,12 @@ class FileObject(object):
41
41
  self.namespace()
42
42
 
43
43
  def remove_builtins(self):
44
- """ Removes builtins from each class in a `FileObject` instance.
45
- """
44
+ """Removes builtins from each class in a `FileObject` instance."""
46
45
  for class_object in self.classes:
47
46
  class_object.remove_builtins()
48
47
 
49
48
  def add_ignore_file(self):
50
- """ Use a file `.cg_ignore` to ignore a list of functions from the call graph
49
+ """Use a file `.cg_ignore` to ignore a list of functions from the call graph
51
50
  """
52
51
  if os.path.isfile('.cg_ignore'):
53
52
  with open('.cg_ignore', 'r') as ignore_file:
@@ -56,21 +55,21 @@ class FileObject(object):
56
55
  self.ignore.add(line.strip())
57
56
 
58
57
  def ignore_functions(self):
59
- """ Ignore all functions in the current class which are present in the instance's `ignore` attribute.
58
+ """Ignore all functions in the current class which are present in the instance's `ignore` attribute.
60
59
  """
61
60
  for class_object in self.classes:
62
61
  class_object.ignore_functions(self.ignore)
63
62
 
64
63
  def namespace(self):
65
- """ Programmatically change the name of items in the call tree so they have relative path information
64
+ """Programmatically change the name of items in the call tree so they have relative path information
66
65
  """
67
66
 
68
67
  for class_object in self.classes:
69
68
  class_object.namespace(self.relative_namespace)
70
69
 
71
70
 
72
- class ClassObject(object):
73
- """ Class for keeping track of classes in code.
71
+ class ClassObject:
72
+ """Class for keeping track of classes in code.
74
73
 
75
74
  Attributes:
76
75
  modules (dict): dict of current modules with `alias: module_name`, `key:value pairs`.
@@ -90,39 +89,30 @@ class ClassObject(object):
90
89
  self.call_tree = {}
91
90
 
92
91
  def visit(self):
93
- """ Visits all the nodes within the current class AST node.
92
+ """Visits all the nodes within the current class AST node.
94
93
 
95
94
  Updates `self.functions` and `self.call_tree` for the current instance.
96
95
  """
97
96
  function_visitor = FunctionVisitor(aliases=self.aliases, modules=self.modules)
98
97
  function_visitor.visit(self.node)
99
98
  self.functions = function_visitor.functions
100
- self.call_tree = dict(((self.name, k), v) for k, v in function_visitor.calls.iteritems())
99
+ self.call_tree = dict(((self.name, k), v) for k, v in function_visitor.calls.items())
101
100
 
102
101
  def remove_builtins(self):
103
- """ For many classes, we may not want to include builtin functions in the graph.
102
+ """For many classes, we may not want to include builtin functions in the graph.
104
103
  Remove builtins from the call tree and from called functions list.
105
104
  """
106
- new_call_tree = {}
107
- for caller, call_list in self.call_tree.iteritems():
108
- new_call_list = []
109
- for call in call_list:
110
- if __builtins__.has_key(call[0]):
111
- continue
112
- else:
113
- new_call_list.append(call)
114
- new_call_tree[caller] = new_call_list
115
-
116
- self.call_tree = new_call_tree
105
+ self.call_tree = {caller: [call for call in call_list if not self.is_builtin(call[0])]
106
+ for caller, call_list in self.call_tree.items()}
117
107
 
118
108
  def ignore_functions(self, ignore_set):
119
- """ Ignores all functions matching those specified in a pre-defined ignore set.
109
+ """Ignores all functions matching those specified in a pre-defined ignore set.
120
110
 
121
111
  Args:
122
112
  ignore_set (set): Functions whose calls should be removed (ignored) in the class call tree.
123
113
  """
124
114
  new_call_tree = {}
125
- for caller, call_list in self.call_tree.iteritems():
115
+ for caller, call_list in self.call_tree.items():
126
116
  new_call_list = []
127
117
  for call in call_list:
128
118
  if call[-1] not in ignore_set:
@@ -132,7 +122,7 @@ class ClassObject(object):
132
122
  self.call_tree = new_call_tree
133
123
 
134
124
  def namespace(self, relative_namespace):
135
- """ Take the relative namespace for the class and prepend it to each item defined in the current class.
125
+ """Take the relative namespace for the class and prepend it to each item defined in the current class.
136
126
 
137
127
  Args:
138
128
  relative_namespace (string): Namespace to be prepended to each item in the call tree.
@@ -143,13 +133,20 @@ class ClassObject(object):
143
133
  self.call_tree = new_call_tree
144
134
 
145
135
  def pprint(self):
146
- """ Pretty print formatter for class object.
136
+ """Pretty print formatter for class object.
147
137
 
148
138
  Returns:
149
139
  string
150
140
  """
151
141
  return pformat(self.call_tree)
152
142
 
143
+ @staticmethod
144
+ def is_builtin(fn):
145
+ """Checks if a """
146
+ if isinstance(fn, str):
147
+ return fn in __builtins__
148
+ return False
149
+
153
150
  def __repr__(self):
154
151
  return "ClassObject {}".format(self.name)
155
152
 
@@ -158,8 +155,8 @@ class ClassObject(object):
158
155
  return "Class {}\nDefined functions: {}".format(self.name, functions)
159
156
 
160
157
 
161
- class FunctionObject(object):
162
- """ Object that stores information within a single function definition
158
+ class FunctionObject:
159
+ """Object that stores information within a single function definition
163
160
 
164
161
  attributes:
165
162
  modules: dict of current modules with `alias: module_name`, `key:value pairs`.
@@ -183,7 +180,7 @@ class FunctionObject(object):
183
180
 
184
181
  @classmethod
185
182
  def _extract_decorators(cls, node):
186
- """ Pulls out strings for each item in a decorator list on a FunctionDef node
183
+ """Pulls out strings for each item in a decorator list on a FunctionDef node
187
184
 
188
185
  Args:
189
186
  node (:mod:`ast.AST`): Node from which `decorator_list` will be extracted
@@ -200,7 +197,7 @@ class FunctionObject(object):
200
197
  return decorator_list
201
198
 
202
199
  def visit(self):
203
- """ Visits all the nodes within the current function object's AST node.
200
+ """Visits all the nodes within the current function object's AST node.
204
201
 
205
202
  Updates `self.calls`, `self.modules`, and `self.aliases` for the current instance.
206
203
  """
@@ -215,7 +212,7 @@ class FunctionObject(object):
215
212
 
216
213
 
217
214
  class CallInspector(ast.NodeVisitor):
218
- """ Within a call, a Name or Attribute will provide the function name currently in use.
215
+ """Within a call, a Name or Attribute will provide the function name currently in use.
219
216
 
220
217
  Identifies `Name` nodes, which are called as ``name(args)``, and `Attribute` nodes, which are called as
221
218
  ``object.attr(args)``
@@ -240,7 +237,7 @@ class CallInspector(ast.NodeVisitor):
240
237
 
241
238
 
242
239
  class ImportVisitor(ast.NodeVisitor):
243
- """ For import related calls, store the source modules and aliases used.
240
+ """For import related calls, store the source modules and aliases used.
244
241
  Designed to be inherited by other classes that need to know about imports in their current scope.
245
242
 
246
243
  Attributes:
@@ -267,9 +264,9 @@ class ImportVisitor(ast.NodeVisitor):
267
264
  self.aliases[asname] = item.name
268
265
  self.modules[asname] = module
269
266
 
270
-
267
+
271
268
  class CallVisitor(ImportVisitor):
272
- """ Finds all calls present in the current scope and inspect them.
269
+ """Finds all calls present in the current scope and inspect them.
273
270
 
274
271
  Attributes:
275
272
  call_names (set): set of :class:`CallInspector.identifier` items within current AST node.
@@ -327,7 +324,7 @@ class CallVisitor(ImportVisitor):
327
324
 
328
325
 
329
326
  class FunctionVisitor(ImportVisitor):
330
- """ Function definitions are where the function is defined, and the call is where the ast for that function exists.
327
+ """Function definitions are where the function is defined, and the call is where the ast for that function exists.
331
328
 
332
329
  This only looks for items that are called within the scope of a function, and associates those items
333
330
  with the function.
@@ -355,7 +352,7 @@ class FunctionVisitor(ImportVisitor):
355
352
 
356
353
 
357
354
  class FileVisitor(ImportVisitor):
358
- """ First visitor that should be called on the file level.
355
+ """First visitor that should be called on the file level.
359
356
 
360
357
  Attributes:
361
358
  classes (list): list of :class:`ClassObject` instances defined in the current file.
@@ -377,7 +374,7 @@ class FileVisitor(ImportVisitor):
377
374
  self.classes.append(new_class)
378
375
 
379
376
  def remove_builtins(self):
380
- """ Removes builtins from each class in a `FileVisitor` instance.
377
+ """Removes builtins from each class in a `FileVisitor` instance.
381
378
  """
382
379
  for class_object in self.classes:
383
380
  class_object.remove_builtins()