gyomu-python-analysis 0.2.0__py3-none-any.whl

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 (42) hide show
  1. gyomu_python_analysis/__init__.py +0 -0
  2. gyomu_python_analysis/analysis/__init__.py +0 -0
  3. gyomu_python_analysis/analysis/analyzers/__init__.py +0 -0
  4. gyomu_python_analysis/analysis/analyzers/cls.py +343 -0
  5. gyomu_python_analysis/analysis/analyzers/context.py +66 -0
  6. gyomu_python_analysis/analysis/analyzers/decorator.py +88 -0
  7. gyomu_python_analysis/analysis/analyzers/dependency.py +134 -0
  8. gyomu_python_analysis/analysis/analyzers/docstring.py +288 -0
  9. gyomu_python_analysis/analysis/analyzers/expression/__init__.py +0 -0
  10. gyomu_python_analysis/analysis/analyzers/expression/expr.py +400 -0
  11. gyomu_python_analysis/analysis/analyzers/expression/name.py +38 -0
  12. gyomu_python_analysis/analysis/analyzers/functions.py +53 -0
  13. gyomu_python_analysis/analysis/analyzers/imports.py +21 -0
  14. gyomu_python_analysis/analysis/analyzers/internal/__init__.py +0 -0
  15. gyomu_python_analysis/analysis/analyzers/internal/common.py +87 -0
  16. gyomu_python_analysis/analysis/analyzers/internal/location.py +68 -0
  17. gyomu_python_analysis/analysis/analyzers/internal/visibility.py +27 -0
  18. gyomu_python_analysis/analysis/analyzers/pydantic.py +62 -0
  19. gyomu_python_analysis/analysis/analyzers/type_alias.py +24 -0
  20. gyomu_python_analysis/analysis/analyzers/types.py +29 -0
  21. gyomu_python_analysis/analysis/analyzers/variables.py +22 -0
  22. gyomu_python_analysis/analysis/extract/__init__.py +0 -0
  23. gyomu_python_analysis/analysis/extract/symbols.py +118 -0
  24. gyomu_python_analysis/analysis/file/__init__.py +0 -0
  25. gyomu_python_analysis/analysis/file/source_file_context.py +10 -0
  26. gyomu_python_analysis/analysis/get_module.py +55 -0
  27. gyomu_python_analysis/analysis/load.py +42 -0
  28. gyomu_python_analysis/analysis/load_file_context.py +27 -0
  29. gyomu_python_analysis/analysis/load_module.py +65 -0
  30. gyomu_python_analysis/analysis/metadata.py +49 -0
  31. gyomu_python_analysis/analysis/parser/__init__.py +0 -0
  32. gyomu_python_analysis/analysis/parser/docstring.py +7 -0
  33. gyomu_python_analysis/error/__init__.py +0 -0
  34. gyomu_python_analysis/error/analysis.py +36 -0
  35. gyomu_python_analysis/error/update.py +32 -0
  36. gyomu_python_analysis/path/__init__.py +0 -0
  37. gyomu_python_analysis/path/conversion.py +25 -0
  38. gyomu_python_analysis/project/__init__.py +0 -0
  39. gyomu_python_analysis/project/context.py +18 -0
  40. gyomu_python_analysis-0.2.0.dist-info/METADATA +15 -0
  41. gyomu_python_analysis-0.2.0.dist-info/RECORD +42 -0
  42. gyomu_python_analysis-0.2.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,27 @@
1
+ from gyomu_schema.schemas.python.file_analysis import (
2
+ FileAnalysisContext,
3
+ )
4
+ from gyomu_schema.schemas.python.types import ProjectRelativePath
5
+ from returns.result import Failure, Result, Success
6
+
7
+ from gyomu_python_analysis.analysis.get_module import get_module_analysis
8
+ from gyomu_python_analysis.analysis.metadata import create_file_analysis_metadata
9
+ from gyomu_python_analysis.error.analysis import AnalysisError
10
+ from gyomu_python_analysis.project.context import ProjectContext
11
+
12
+
13
+ def load_file_analysis_context(
14
+ context: ProjectContext, file_path: ProjectRelativePath
15
+ ) -> Result[FileAnalysisContext, AnalysisError]:
16
+ module_analysis_result = get_module_analysis(context, file_path)
17
+ if isinstance(module_analysis_result, Failure):
18
+ return module_analysis_result
19
+ module_analysis = module_analysis_result.unwrap()
20
+ metadata = create_file_analysis_metadata(module_analysis)
21
+
22
+ return Success(
23
+ FileAnalysisContext(
24
+ metadata=metadata,
25
+ analysis=module_analysis,
26
+ )
27
+ )
@@ -0,0 +1,65 @@
1
+ from gyomu_schema.schemas.python.module import ModuleAnalysis
2
+ from gyomu_schema.schemas.python.types import PythonPath
3
+ from gyomu_schema.utility.returns import from_sync
4
+ from returns.result import Failure, Result
5
+
6
+ from gyomu_python_analysis.analysis.analyzers.context import initialize_symbol_context
7
+ from gyomu_python_analysis.analysis.analyzers.docstring import analyze_docstring
8
+ from gyomu_python_analysis.analysis.analyzers.internal.common import (
9
+ build_docstring_common,
10
+ )
11
+ from gyomu_python_analysis.analysis.extract.symbols import extract_symbols
12
+ from gyomu_python_analysis.analysis.load import load_module
13
+ from gyomu_python_analysis.error.analysis import AnalysisError
14
+ from gyomu_python_analysis.project.context import ProjectContext
15
+
16
+
17
+ def load_module_analysis(
18
+ context: ProjectContext, module_path: PythonPath
19
+ ) -> Result[ModuleAnalysis, AnalysisError]:
20
+ source_file_result = load_module(context, module_path)
21
+
22
+ if isinstance(source_file_result, Failure):
23
+ return source_file_result
24
+
25
+ source_file = source_file_result.unwrap()
26
+
27
+ def analyze_module() -> ModuleAnalysis:
28
+ source_full_path = context.project_root / context.source_root / source_file.path
29
+ source_lines = source_full_path.read_text(encoding="utf-8").splitlines(
30
+ keepends=True
31
+ )
32
+
33
+ symbols = extract_symbols(source_file=source_file, source_lines=source_lines)
34
+ module_name = PythonPath(source_file.module.path)
35
+ module_context = initialize_symbol_context(
36
+ module_name=module_name, name="", source_lines=source_lines
37
+ )
38
+ return ModuleAnalysis(
39
+ path=source_file.path,
40
+ module_name=module_name,
41
+ imports=symbols.imported,
42
+ symbols=symbols.symbols,
43
+ name=source_file.module.name,
44
+ docstring=(
45
+ analyze_docstring(
46
+ source_file.module.docstring,
47
+ doc_common=build_docstring_common(
48
+ source_file.module.docstring, module_context
49
+ ),
50
+ context=module_context,
51
+ )
52
+ if source_file.module.docstring is not None
53
+ else None
54
+ ),
55
+ )
56
+
57
+ return from_sync(
58
+ analyze_module,
59
+ build_error=lambda e: AnalysisError(
60
+ message="fail to analyze module",
61
+ file_path=module_path,
62
+ phase="symbol-extract",
63
+ context="gyomu_python_analysis.analysis.load_sourde_file",
64
+ ).chain(e),
65
+ )
@@ -0,0 +1,49 @@
1
+ from gyomu_schema.schemas.python.class_analysis import ClassAnalysis, InnerClassAnalysis
2
+ from gyomu_schema.schemas.python.docstring import DocstringAnalysis
3
+ from gyomu_schema.schemas.python.file_analysis import FileAnalysisMetadata
4
+ from gyomu_schema.schemas.python.module import ModuleAnalysis
5
+ from gyomu_schema.schemas.python.symbol import MemberAnalysis, SymbolAnalysis
6
+ from gyomu_schema.schemas.python.types import DeclarationIdentity
7
+
8
+
9
+ def create_file_analysis_metadata(
10
+ module_analysis: ModuleAnalysis,
11
+ ) -> FileAnalysisMetadata:
12
+ parsed_docstring: dict[DeclarationIdentity, DocstringAnalysis] = {}
13
+ symbols: dict[DeclarationIdentity, SymbolAnalysis | MemberAnalysis] = {}
14
+
15
+ for symbol in module_analysis.symbols:
16
+ symbols[symbol.identity] = symbol
17
+ if symbol.docstring is not None:
18
+ parsed_docstring[symbol.identity] = symbol.docstring
19
+
20
+ if isinstance(symbol, ClassAnalysis):
21
+ register_class_metadata(symbol, symbols, parsed_docstring)
22
+ return FileAnalysisMetadata(parsed_docstring, symbols)
23
+
24
+
25
+ def register_class_metadata(
26
+ cls: ClassAnalysis | InnerClassAnalysis,
27
+ symbols: dict[DeclarationIdentity, SymbolAnalysis | MemberAnalysis],
28
+ parsed_docstring: dict[DeclarationIdentity, DocstringAnalysis],
29
+ ) -> None:
30
+ for inner in cls.inner_classes:
31
+ symbols[inner.identity] = inner
32
+ if inner.docstring is not None:
33
+ parsed_docstring[inner.identity] = inner.docstring
34
+ register_class_metadata(inner, symbols, parsed_docstring)
35
+
36
+ for method in cls.methods:
37
+ symbols[method.identity] = method
38
+ if method.docstring is not None:
39
+ parsed_docstring[method.identity] = method.docstring
40
+
41
+ for variable in cls.variables:
42
+ symbols[variable.identity] = variable
43
+ if variable.docstring is not None:
44
+ parsed_docstring[variable.identity] = variable.docstring
45
+
46
+ for alias in cls.type_aliases:
47
+ symbols[alias.identity] = alias
48
+ if alias.docstring is not None:
49
+ parsed_docstring[alias.identity] = alias.docstring
File without changes
@@ -0,0 +1,7 @@
1
+ from typing import Protocol
2
+
3
+ from gyomu_schema.schemas.python.docstring import DocstringAnalysis
4
+
5
+
6
+ class DocstringParser(Protocol):
7
+ def parse(self, value: str) -> DocstringAnalysis: ...
File without changes
@@ -0,0 +1,36 @@
1
+ from collections.abc import Mapping
2
+ from typing import Literal
3
+
4
+ from gyomu_schema.error.base import BaseError
5
+ from gyomu_schema.schemas.python.types import PythonPath
6
+
7
+ type AnalysisPhase = Literal[
8
+ "project-load",
9
+ "source-file-load",
10
+ "export-extract",
11
+ "symbol-extract",
12
+ "jsdoc-extract",
13
+ "analysis",
14
+ "post-analysis",
15
+ ]
16
+
17
+
18
+ class AnalysisError(BaseError):
19
+ """Python Analysis error."""
20
+
21
+ def __init__(
22
+ self,
23
+ message: str,
24
+ *,
25
+ file_path: PythonPath,
26
+ phase: AnalysisPhase,
27
+ context: str | None = None,
28
+ details: Mapping[str, object] | None = None,
29
+ ) -> None:
30
+ super().__init__(
31
+ message,
32
+ context=context,
33
+ details=details,
34
+ )
35
+ self.file_path = file_path
36
+ self.phase = phase
@@ -0,0 +1,32 @@
1
+ from collections.abc import Mapping
2
+ from typing import Literal
3
+
4
+ from gyomu_schema.error.base import BaseError
5
+ from gyomu_schema.schemas.python.types import DeclarationIdentity, PythonPath
6
+
7
+ type UpdatePhase = Literal[
8
+ "context-build", "update-plan", "merge-plan", "apply-merge", "update"
9
+ ]
10
+
11
+
12
+ class UpdateError(BaseError):
13
+ """Docstring Update error."""
14
+
15
+ def __init__(
16
+ self,
17
+ message: str,
18
+ *,
19
+ file_path: PythonPath,
20
+ phase: UpdatePhase,
21
+ identity: DeclarationIdentity | None,
22
+ context: str | None = None,
23
+ details: Mapping[str, object] | None = None,
24
+ ) -> None:
25
+ super().__init__(
26
+ message,
27
+ context=context,
28
+ details=details,
29
+ )
30
+ self.file_path = file_path
31
+ self.phase = phase
32
+ self.identity = identity
File without changes
@@ -0,0 +1,25 @@
1
+ from gyomu_schema.schemas.python.types import (
2
+ ProjectRelativePath,
3
+ PythonPath,
4
+ SourceRelativePath,
5
+ )
6
+
7
+ from gyomu_python_analysis.project.context import ProjectContext
8
+
9
+
10
+ def project_relative_path_to_source_relative_path(
11
+ path: ProjectRelativePath,
12
+ context: ProjectContext,
13
+ ) -> SourceRelativePath:
14
+ return SourceRelativePath(path.relative_to(context.source_root))
15
+
16
+
17
+ def source_relative_path_to_python_path(
18
+ path: SourceRelativePath,
19
+ ) -> PythonPath:
20
+ if path.name == "__init__.py":
21
+ path = SourceRelativePath(path.parent)
22
+ else:
23
+ path = SourceRelativePath(path.with_suffix(""))
24
+
25
+ return PythonPath(".".join(path.parts))
File without changes
@@ -0,0 +1,18 @@
1
+ from dataclasses import dataclass
2
+
3
+ from griffe import GriffeLoader
4
+ from gyomu_schema.schemas.python.types import ProjectRelativePath
5
+ from gyomu_schema.schemas.types import FullPath
6
+
7
+
8
+ @dataclass
9
+ class ProjectContext:
10
+ def __init__(
11
+ self, project_root: FullPath, source_root: ProjectRelativePath
12
+ ) -> None:
13
+ self.project_root = project_root
14
+ self.source_root = source_root
15
+ search_path = project_root / source_root
16
+ self.loader = GriffeLoader(
17
+ search_paths=[search_path],
18
+ )
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.5
2
+ Name: gyomu-python-analysis
3
+ Version: 0.2.0
4
+ Summary: Gyomu Python Analysis
5
+ Requires-Python: >=3.13
6
+ Requires-Dist: docstring-parser>=0.18.0
7
+ Requires-Dist: griffelib>=2.2.0
8
+ Requires-Dist: gyomu-infra
9
+ Requires-Dist: gyomu-schema
10
+ Requires-Dist: returns>=0.29.0
11
+ Description-Content-Type: text/markdown
12
+
13
+ # gyomu-python-analysis
14
+
15
+ python analysis components for Gyomu Python.
@@ -0,0 +1,42 @@
1
+ gyomu_python_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ gyomu_python_analysis/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ gyomu_python_analysis/analysis/get_module.py,sha256=UT7soyl1JLOXgf_OhO53giaLQZn2929-ZQz01GEkbh0,2130
4
+ gyomu_python_analysis/analysis/load.py,sha256=haHAXTlzF0u43aaSaQFCTmPTZ10fmVcd4UnW2dH_KT0,1543
5
+ gyomu_python_analysis/analysis/load_file_context.py,sha256=3IG_zvKXdVADMmRE8Nah3BZjVAWcYJuNQuq2qFFfmyU,1039
6
+ gyomu_python_analysis/analysis/load_module.py,sha256=dt8m9ingFSJNidAMMUYjr84xYvNJ1GlHEKa_BnQjt00,2544
7
+ gyomu_python_analysis/analysis/metadata.py,sha256=tb9r7-sEdymVTuAikxfKFQHINUlFW4WiMNCfGkUiQeQ,2083
8
+ gyomu_python_analysis/analysis/analyzers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ gyomu_python_analysis/analysis/analyzers/cls.py,sha256=bZ2WHT3MOb6wDxQlu-Ql456T3XWiMtUI9YKje-Hdklk,10529
10
+ gyomu_python_analysis/analysis/analyzers/context.py,sha256=YmOSwQEV-C4iTNSLWn9Ojw_e4O3O-uCz1m6jRif0LY4,1716
11
+ gyomu_python_analysis/analysis/analyzers/decorator.py,sha256=dAu7Af8oVjtPOA6iZV0S8Jjn1yx_vcC7_0zQDMgiYq8,3054
12
+ gyomu_python_analysis/analysis/analyzers/dependency.py,sha256=8lU3SaIWC_SL0VOAS3o_qUQ_dmM2MAUb1SNiicuC5y0,3534
13
+ gyomu_python_analysis/analysis/analyzers/docstring.py,sha256=uJEiNNYAo82VqssAaidmrSWyfw9-YLuFaGQBJCySrC0,9387
14
+ gyomu_python_analysis/analysis/analyzers/functions.py,sha256=IevPQpoEY4h5wJEFCI5djR49hHZppIYCgTPLt-Hz0uk,2056
15
+ gyomu_python_analysis/analysis/analyzers/imports.py,sha256=zan5bRTbVmKHm7rFdVoFy5E10m0mHI_L3dM0V9Hv_9Y,703
16
+ gyomu_python_analysis/analysis/analyzers/pydantic.py,sha256=9P0C1rzx_xNEyxwo4ga3jyFVQpIHSWRF7dv0tQALI18,1945
17
+ gyomu_python_analysis/analysis/analyzers/type_alias.py,sha256=MhPKiqRZBKFIrtSjyX5DrRD78765Hm5szyfocFJU7Tw,840
18
+ gyomu_python_analysis/analysis/analyzers/types.py,sha256=-WCNbpLwCb13rmvGe8AFW3QWZsDbT9lx-l6fAsnBZdw,1048
19
+ gyomu_python_analysis/analysis/analyzers/variables.py,sha256=fdRp9phR70XNqr1TXkIBKwCLaRRVcW2WlNx1a7uoBQQ,819
20
+ gyomu_python_analysis/analysis/analyzers/expression/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ gyomu_python_analysis/analysis/analyzers/expression/expr.py,sha256=QVnpKSXcQQWhA-IJOb9SyyGH7Cv7YdGQiE5xMgiQAaA,13307
22
+ gyomu_python_analysis/analysis/analyzers/expression/name.py,sha256=WUtb2Dd3AcXqmeUQDi3h8U3-YqO76ZdEG658TPk9ERA,1322
23
+ gyomu_python_analysis/analysis/analyzers/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ gyomu_python_analysis/analysis/analyzers/internal/common.py,sha256=dc3woHGnXoNQseR-C0jxxSkf5BG5oW9gV3B52TI5aIU,2921
25
+ gyomu_python_analysis/analysis/analyzers/internal/location.py,sha256=GmJMQxpxC8jwqbEcyOdCvmj0YVgTt_CHz7VNPJCrAZU,2053
26
+ gyomu_python_analysis/analysis/analyzers/internal/visibility.py,sha256=7oaITFrhXobsJbRq-RmLOLBEejekou9w02KkDLUWyzQ,553
27
+ gyomu_python_analysis/analysis/extract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ gyomu_python_analysis/analysis/extract/symbols.py,sha256=lQ_URwt5CIXYb-26EkZV-e7hmznhabmmkWk8X7pmseY,4238
29
+ gyomu_python_analysis/analysis/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ gyomu_python_analysis/analysis/file/source_file_context.py,sha256=wZu2iMIa2g_sWqdByy1upFTeg2t24gLneJMrMjguEn4,225
31
+ gyomu_python_analysis/analysis/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ gyomu_python_analysis/analysis/parser/docstring.py,sha256=kBDLCBFBoFkedAswEuIQKOdMl9uNmyNH9b7AWC9YjfI,190
33
+ gyomu_python_analysis/error/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ gyomu_python_analysis/error/analysis.py,sha256=V0Lk5fsaQw20S7DXGAlFACDPSJsXBpUtpES_Mp8IJdQ,821
35
+ gyomu_python_analysis/error/update.py,sha256=qWQIW7xKKA_4r25ltytcqlfOMn0QWI9uPMDDCn9JdSA,844
36
+ gyomu_python_analysis/path/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ gyomu_python_analysis/path/conversion.py,sha256=CH12LJx2X0bly7oHaHm6ivki6jizKLGvo82Vu8sVcEc,671
38
+ gyomu_python_analysis/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ gyomu_python_analysis/project/context.py,sha256=qMJDpVNCntSfEhU1J3w7kGu_5OFSTDV567-fu9BdgqQ,535
40
+ gyomu_python_analysis-0.2.0.dist-info/METADATA,sha256=-QlVODm3bqtgQ6pKXKbcVZh4bQcvE7N6xLXBUfVQNxI,389
41
+ gyomu_python_analysis-0.2.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
42
+ gyomu_python_analysis-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any