gyomu-concept 0.5.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. gyomu_concept-0.5.0/.gitignore +29 -0
  2. gyomu_concept-0.5.0/PKG-INFO +24 -0
  3. gyomu_concept-0.5.0/README.md +3 -0
  4. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/pyproject.toml +38 -0
  5. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/__init__.py +0 -0
  6. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/common/__init__.py +0 -0
  7. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/common/result.py +19 -0
  8. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/order/__init__.py +2 -0
  9. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/order/model.py +11 -0
  10. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/order/repository.py +18 -0
  11. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/order/service.py +11 -0
  12. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/user/__init__.py +2 -0
  13. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/user/model.py +8 -0
  14. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/user/repository.py +13 -0
  15. gyomu_concept-0.5.0/concept_test_support/fixtures/directory/src/service/user/service.py +11 -0
  16. gyomu_concept-0.5.0/concept_test_support/helpers.py +38 -0
  17. gyomu_concept-0.5.0/pyproject.toml +40 -0
  18. gyomu_concept-0.5.0/src/gyomu_concept/__init__.py +0 -0
  19. gyomu_concept-0.5.0/src/gyomu_concept/directory/build.py +34 -0
  20. gyomu_concept-0.5.0/src/gyomu_concept/directory/internal/build.py +168 -0
  21. gyomu_concept-0.5.0/src/gyomu_concept/directory/internal/file_summary.py +90 -0
  22. gyomu_concept-0.5.0/src/gyomu_concept/directory/internal/load.py +27 -0
  23. gyomu_concept-0.5.0/src/gyomu_concept/directory/internal/path.py +21 -0
  24. gyomu_concept-0.5.0/src/gyomu_concept/directory/internal/process.py +26 -0
  25. gyomu_concept-0.5.0/src/gyomu_concept/directory/internal/save.py +28 -0
  26. gyomu_concept-0.5.0/src/gyomu_concept/directory/types.py +16 -0
  27. gyomu_concept-0.5.0/src/gyomu_concept/error/concept.py +38 -0
  28. gyomu_concept-0.5.0/tests/integration/__init__.py +0 -0
  29. gyomu_concept-0.5.0/tests/integration/directory/__init__.py +0 -0
  30. gyomu_concept-0.5.0/tests/integration/directory/test_build.py +71 -0
  31. gyomu_concept-0.5.0/tests/unit/__init__.py +0 -0
  32. gyomu_concept-0.5.0/tests/unit/directory/__init__.py +0 -0
  33. gyomu_concept-0.5.0/tests/unit/directory/internal/__init__.py +0 -0
  34. gyomu_concept-0.5.0/tests/unit/directory/internal/test_build.py +432 -0
  35. gyomu_concept-0.5.0/tests/unit/directory/internal/test_file_summary.py +200 -0
  36. gyomu_concept-0.5.0/tests/unit/directory/internal/test_load.py +150 -0
  37. gyomu_concept-0.5.0/tests/unit/directory/internal/test_process.py +118 -0
  38. gyomu_concept-0.5.0/tests/unit/directory/internal/test_save.py +103 -0
  39. gyomu_concept-0.5.0/tests/unit/directory/test_build.py +197 -0
@@ -0,0 +1,29 @@
1
+ venv/
2
+ .idea/
3
+
4
+ /build/
5
+ /dist/
6
+ /src/gyomu.egg-info/
7
+ /.coverage
8
+ /htmlcov/
9
+ __pycache__/
10
+ *.py[cod]
11
+
12
+ .env
13
+ .env.*
14
+ !.env.example
15
+
16
+ .mypy_cache/
17
+ .ruff_cache/
18
+ htmlcov/
19
+ *.egg-info/
20
+ log/
21
+
22
+
23
+ # gyomu ai related
24
+ **/.gyomu/cache
25
+ **/.gyomu/snapshot
26
+ **/.gyomu/checkpoint
27
+
28
+ # snapshot
29
+ __snapshots__
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.5
2
+ Name: gyomu-concept
3
+ Version: 0.5.0
4
+ Summary: Gyomu Concept
5
+ Author: Yoshihisa Matsumoto
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Software Development :: Libraries
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Requires-Python: >=3.13
15
+ Requires-Dist: gyomu-ai-compiler
16
+ Requires-Dist: gyomu-infra
17
+ Requires-Dist: gyomu-python-analysis
18
+ Requires-Dist: gyomu-schema
19
+ Requires-Dist: returns
20
+ Description-Content-Type: text/markdown
21
+
22
+ # gyomu-concept
23
+
24
+ concept components for Gyomu Python.
@@ -0,0 +1,3 @@
1
+ # gyomu-concept
2
+
3
+ concept components for Gyomu Python.
@@ -0,0 +1,38 @@
1
+ [project]
2
+ name = "directory-concept-fixture"
3
+ version = "1.0"
4
+ description = "Gyomu Test Fixture"
5
+ requires-python = ">=3.13"
6
+ dependencies = [
7
+ "pydantic"
8
+ ]
9
+ license = "MIT"
10
+
11
+ [build-system]
12
+ requires = ["hatchling"]
13
+ build-backend = "hatchling.build"
14
+
15
+
16
+ [tool.ruff]
17
+ target-version = "py313"
18
+ line-length = 88
19
+ exclude = [
20
+ "packages/infra/src/gyomu_infra/db/model/generated",
21
+ "packages/python_analysis/python_analysis_test_support/fixtures",
22
+ "packages/python_analysis/experiments",
23
+ "version",
24
+ "docs"
25
+ ]
26
+
27
+ [tool.ruff.lint]
28
+ select = [
29
+ "E",
30
+ "F",
31
+ "I",
32
+ "UP",
33
+ "B",
34
+ "SIM"
35
+ ]
36
+
37
+ [tool.ruff.format]
38
+ quote-style = "double"
@@ -0,0 +1,19 @@
1
+ # result.py
2
+ from dataclasses import dataclass
3
+ from typing import Generic, TypeVar
4
+
5
+ T = TypeVar("T")
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class Result(Generic[T]):
10
+ value: T | None
11
+ error: str | None
12
+
13
+ @classmethod
14
+ def success(cls, value: T) -> "Result[T]":
15
+ return cls(value=value, error=None)
16
+
17
+ @classmethod
18
+ def failure(cls, error: str) -> "Result[T]":
19
+ return cls(value=None, error=error)
@@ -0,0 +1,2 @@
1
+ # service/order/__init__.py
2
+ """Order management services."""
@@ -0,0 +1,11 @@
1
+ # model.py
2
+ from dataclasses import dataclass
3
+
4
+ from service.user.model import User
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class Order:
9
+ order_id: int
10
+ user: User
11
+ amount: int
@@ -0,0 +1,18 @@
1
+ # repository.py
2
+ from service.order.model import Order
3
+ from service.user.model import User
4
+
5
+
6
+ class OrderRepository:
7
+ def find_by_id(self, order_id: int) -> Order | None:
8
+ if order_id <= 0:
9
+ return None
10
+
11
+ return Order(
12
+ order_id=order_id,
13
+ user=User(
14
+ user_id=1,
15
+ name="user-1",
16
+ ),
17
+ amount=1000,
18
+ )
@@ -0,0 +1,11 @@
1
+ # service.py
2
+ from service.order.model import Order
3
+ from service.order.repository import OrderRepository
4
+
5
+
6
+ class OrderService:
7
+ def __init__(self, repository: OrderRepository) -> None:
8
+ self._repository = repository
9
+
10
+ def find_order(self, order_id: int) -> Order | None:
11
+ return self._repository.find_by_id(order_id)
@@ -0,0 +1,2 @@
1
+ # service/user/__init__.py
2
+ """User management services."""
@@ -0,0 +1,8 @@
1
+ # model.py
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass(frozen=True)
6
+ class User:
7
+ user_id: int
8
+ name: str
@@ -0,0 +1,13 @@
1
+ # repository.py
2
+ from service.user.model import User
3
+
4
+
5
+ class UserRepository:
6
+ def find_by_id(self, user_id: int) -> User | None:
7
+ if user_id <= 0:
8
+ return None
9
+
10
+ return User(
11
+ user_id=user_id,
12
+ name=f"user-{user_id}",
13
+ )
@@ -0,0 +1,11 @@
1
+ # service.py
2
+ from service.user.model import User
3
+ from service.user.repository import UserRepository
4
+
5
+
6
+ class UserService:
7
+ def __init__(self, repository: UserRepository) -> None:
8
+ self._repository = repository
9
+
10
+ def find_user(self, user_id: int) -> User | None:
11
+ return self._repository.find_by_id(user_id)
@@ -0,0 +1,38 @@
1
+ from difflib import unified_diff
2
+ from pathlib import Path
3
+
4
+ from gyomu_python_analysis.analysis.initialize import initialize_project_context
5
+ from gyomu_python_analysis.project.context import ProjectContext
6
+ from gyomu_schema.schemas.python.types import (
7
+ ProjectRelativePath,
8
+ )
9
+ from gyomu_schema.schemas.types import FullPath
10
+
11
+ FIXTURES_ROOT = FullPath(Path(__file__).parent / "fixtures")
12
+
13
+
14
+ def assert_text_file_equals(
15
+ root_path: Path, source_path: Path, expected_path: Path
16
+ ) -> None:
17
+ actual_path = root_path / source_path
18
+ expected_path = root_path / expected_path
19
+ actual = actual_path.read_text(encoding="utf-8")
20
+ expected = expected_path.read_text(encoding="utf-8")
21
+
22
+ diff = "".join(
23
+ unified_diff(
24
+ expected.splitlines(keepends=True),
25
+ actual.splitlines(keepends=True),
26
+ fromfile=str(expected_path),
27
+ tofile=str(actual_path),
28
+ )
29
+ )
30
+
31
+ assert actual == expected, f"\n{diff}"
32
+
33
+
34
+ def _create_directory_project_context() -> ProjectContext:
35
+ return initialize_project_context(
36
+ project_root=FIXTURES_ROOT / "directory",
37
+ source_root=ProjectRelativePath(Path("src")),
38
+ ).unwrap()
@@ -0,0 +1,40 @@
1
+ [project]
2
+ name = "gyomu-concept"
3
+ dynamic = ["version"]
4
+ description = "Gyomu Concept"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "gyomu-schema",
9
+ "gyomu-infra",
10
+ "gyomu-python-analysis",
11
+ "gyomu-ai-compiler",
12
+ "returns",
13
+ ]
14
+ license = "MIT"
15
+ authors = [
16
+ { name = "Yoshihisa Matsumoto" },
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Intended Audience :: Developers",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ ]
27
+
28
+ [build-system]
29
+ requires = ["hatchling"]
30
+ build-backend = "hatchling.build"
31
+
32
+
33
+ [tool.uv.sources]
34
+ gyomu-schema = { workspace = true }
35
+ gyomu-infra = { workspace = true }
36
+ gyomu-python-analysis = { workspace = true }
37
+ gyomu-ai-compiler = {workspace = true}
38
+
39
+ [tool.hatch.version]
40
+ path = "../../version/__about__.py"
File without changes
@@ -0,0 +1,34 @@
1
+ from gyomu_concept.directory.internal.build import build_directory_concept_from_path
2
+ from gyomu_concept.directory.types import BuildRootResult
3
+ from gyomu_concept.error.concept import ConceptError
4
+ from gyomu_python_analysis.project.context import ProjectContext
5
+ from gyomu_schema.option.concept import ConceptOption
6
+ from gyomu_schema.schemas.concept.directory.concept import DirectoryConcept
7
+ from gyomu_schema.schemas.types import FullPath
8
+ from returns.result import Failure, Result, Success
9
+
10
+
11
+ async def build_directory_concept(
12
+ context: ProjectContext, option: ConceptOption | None = None
13
+ ) -> Result[BuildRootResult, ConceptError]:
14
+ root_path_items: tuple[FullPath, ...] = (
15
+ (FullPath(context.project_root / option.target_folder),)
16
+ if option is not None and option.target_folder is not None
17
+ else tuple(
18
+ FullPath(context.project_root / root) for root in context.package_roots
19
+ )
20
+ )
21
+ is_changed = False
22
+ concepts: list[DirectoryConcept] = []
23
+ for root_path in root_path_items:
24
+ result = await build_directory_concept_from_path(context, root_path, option)
25
+ if isinstance(result, Failure):
26
+ return result
27
+
28
+ item_result = result.unwrap()
29
+ concepts.append(item_result.concept)
30
+
31
+ if item_result.changed:
32
+ is_changed = True
33
+
34
+ return Success(BuildRootResult(concepts=tuple(concepts), changed=is_changed))
@@ -0,0 +1,168 @@
1
+ from gyomu_concept.directory.internal.file_summary import build_file_summary_record
2
+ from gyomu_concept.directory.internal.load import load_directory_concept
3
+ from gyomu_concept.directory.internal.process import process_directory_concept
4
+ from gyomu_concept.directory.internal.save import save_directory_concept
5
+ from gyomu_concept.directory.types import BuildResult
6
+ from gyomu_concept.error.concept import ConceptError
7
+ from gyomu_python_analysis.analysis.load_file_context import load_file_analysis_context
8
+ from gyomu_python_analysis.project.context import ProjectContext
9
+ from gyomu_schema.option.concept import ConceptOption
10
+ from gyomu_schema.schemas.concept.directory.input import (
11
+ DirectoryConceptInput,
12
+ SubDirectoryInput,
13
+ )
14
+ from gyomu_schema.schemas.python.types import (
15
+ DirectoryRelativePath,
16
+ ProjectRelativePath,
17
+ )
18
+ from gyomu_schema.schemas.types import FullPath
19
+ from returns.result import Failure, Result, Success
20
+
21
+
22
+ async def build_directory_concept_from_path(
23
+ context: ProjectContext,
24
+ target_directory: FullPath,
25
+ option: ConceptOption | None = None,
26
+ ) -> Result[BuildResult, ConceptError]:
27
+ target_directory_relative_path = ProjectRelativePath(
28
+ target_directory.relative_to(context.project_root)
29
+ )
30
+
31
+ entries = sorted(
32
+ target_directory.iterdir(),
33
+ key=lambda path: path.name,
34
+ )
35
+
36
+ folders = [path for path in entries if path.is_dir()]
37
+
38
+ files = [
39
+ path
40
+ for path in entries
41
+ if path.is_file()
42
+ and ProjectRelativePath(path.relative_to(context.project_root))
43
+ in context.included_files
44
+ ]
45
+
46
+ is_changed = _is_directory_changed(
47
+ target_directory_relative_path=target_directory_relative_path,
48
+ option=option,
49
+ )
50
+
51
+ if not is_changed:
52
+ loaded = load_directory_concept(
53
+ context=context,
54
+ target_directory=target_directory_relative_path,
55
+ option=option,
56
+ )
57
+
58
+ if isinstance(loaded, Success):
59
+ concept = loaded.unwrap()
60
+
61
+ if concept is not None:
62
+ return Success(
63
+ BuildResult(
64
+ concept=concept,
65
+ changed=False,
66
+ )
67
+ )
68
+
69
+ directory_concepts: list[SubDirectoryInput] = []
70
+
71
+ for folder in folders:
72
+ directory_result = await build_directory_concept_from_path(
73
+ context=context,
74
+ target_directory=folder,
75
+ option=option,
76
+ )
77
+
78
+ if isinstance(directory_result, Failure):
79
+ return directory_result
80
+
81
+ build_result = directory_result.unwrap()
82
+
83
+ if build_result.changed:
84
+ is_changed = True
85
+
86
+ directory_concepts.append(
87
+ SubDirectoryInput(
88
+ path=DirectoryRelativePath(folder.relative_to(target_directory)),
89
+ concept=build_result.concept,
90
+ )
91
+ )
92
+
93
+ file_summaries = []
94
+
95
+ for file in files:
96
+ file_relative_path = ProjectRelativePath(file.relative_to(context.project_root))
97
+
98
+ file_result = load_file_analysis_context(
99
+ context=context,
100
+ file_path=file_relative_path,
101
+ )
102
+
103
+ if isinstance(file_result, Failure):
104
+ return Failure(
105
+ ConceptError(
106
+ message="fail to load file analysis context",
107
+ file_path=file_relative_path,
108
+ package_name=context.config.name,
109
+ phase="directory-summary",
110
+ identity=None,
111
+ ).chain(file_result.failure())
112
+ )
113
+
114
+ file_summaries.append(
115
+ build_file_summary_record(
116
+ project_context=context,
117
+ file_context=file_result.unwrap(),
118
+ )
119
+ )
120
+
121
+ input_context = DirectoryConceptInput(
122
+ files=tuple(file_summaries),
123
+ sub_directories=tuple(directory_concepts),
124
+ )
125
+
126
+ generated = await process_directory_concept(
127
+ package_name=context.config.name,
128
+ target_directory=target_directory_relative_path,
129
+ concept=input_context,
130
+ )
131
+
132
+ if isinstance(generated, Failure):
133
+ return generated
134
+
135
+ concept = generated.unwrap()
136
+
137
+ saved = save_directory_concept(
138
+ context=context,
139
+ target_directory=target_directory_relative_path,
140
+ concept=concept,
141
+ option=option,
142
+ )
143
+
144
+ if isinstance(saved, Failure):
145
+ return saved
146
+
147
+ return Success(
148
+ BuildResult(
149
+ concept=concept,
150
+ changed=is_changed,
151
+ )
152
+ )
153
+
154
+
155
+ def _is_directory_changed(
156
+ target_directory_relative_path: ProjectRelativePath,
157
+ option: ConceptOption | None,
158
+ ) -> bool:
159
+ if option is None or option.changed_files is None:
160
+ return False
161
+
162
+ return any(
163
+ changed_file.project_relative_path == target_directory_relative_path
164
+ or changed_file.project_relative_path.is_relative_to(
165
+ target_directory_relative_path
166
+ )
167
+ for changed_file in option.changed_files
168
+ )
@@ -0,0 +1,90 @@
1
+ from gyomu_python_analysis.path.conversion import (
2
+ source_relative_path_to_project_relative_path,
3
+ )
4
+ from gyomu_python_analysis.project.context import ProjectContext
5
+ from gyomu_schema.schemas.concept.file_summary import (
6
+ DependencySummary,
7
+ FileSummary,
8
+ PublicDeclarationSummary,
9
+ )
10
+ from gyomu_schema.schemas.python.dependency import ImportedSymbolDependency
11
+ from gyomu_schema.schemas.python.file_analysis import FileAnalysisContext
12
+ from gyomu_schema.schemas.python.symbol import SymbolAnalysis
13
+ from gyomu_schema.schemas.python.symbol_base import DeclarationKind
14
+ from gyomu_schema.schemas.python.visibility import Visibility
15
+
16
+
17
+ def build_file_summary_record(
18
+ project_context: ProjectContext, file_context: FileAnalysisContext
19
+ ) -> FileSummary:
20
+ package_name = file_context.analysis.module_name.split(".")[0]
21
+ return FileSummary(
22
+ path=source_relative_path_to_project_relative_path(
23
+ path=file_context.analysis.path, context=project_context
24
+ ),
25
+ exports=tuple(
26
+ [
27
+ _build_export_summary(item)
28
+ for item in file_context.analysis.symbols
29
+ if item.visibility == Visibility.PUBLIC
30
+ ]
31
+ ),
32
+ dependencies=_aggregate_dependencies(
33
+ file_context=file_context, package_name=package_name
34
+ ),
35
+ )
36
+
37
+
38
+ def _build_export_summary(item: SymbolAnalysis) -> PublicDeclarationSummary:
39
+ summary = ""
40
+ if (
41
+ item.docstring is not None
42
+ and item.docstring.summary is not None
43
+ and item.docstring.summary != ""
44
+ ):
45
+ summary = item.docstring.summary
46
+ elif (
47
+ item.kind == DeclarationKind.VARIABLE
48
+ and item.pydantic is not None
49
+ and item.pydantic.description is not None
50
+ ):
51
+ summary = item.pydantic.description
52
+ return PublicDeclarationSummary(
53
+ symbol=item.identity.symbol_id, kind=item.kind, summary=summary
54
+ )
55
+
56
+
57
+ def _aggregate_dependencies(
58
+ file_context: FileAnalysisContext, package_name: str
59
+ ) -> tuple[DependencySummary, ...]:
60
+ dependencies = [
61
+ dependency.target
62
+ for symbol in file_context.analysis.symbols
63
+ for dependency in symbol.dependencies
64
+ if isinstance(dependency.target, ImportedSymbolDependency)
65
+ ]
66
+
67
+ summaries = {
68
+ (
69
+ summary.target,
70
+ summary.external,
71
+ ): summary
72
+ for dependency in dependencies
73
+ for summary in [
74
+ _build_dependency_summary(
75
+ import_item=dependency,
76
+ package_name=package_name,
77
+ )
78
+ ]
79
+ }
80
+
81
+ return tuple(summaries.values())
82
+
83
+
84
+ def _build_dependency_summary(
85
+ import_item: ImportedSymbolDependency, package_name: str
86
+ ) -> DependencySummary:
87
+ return DependencySummary(
88
+ target=import_item.symbol_id,
89
+ external=not import_item.symbol_id.startswith(package_name),
90
+ )
@@ -0,0 +1,27 @@
1
+ from gyomu_concept.directory.internal.path import get_directory_concept_path
2
+ from gyomu_concept.error.concept import ConceptError
3
+ from gyomu_infra.filesystem.file_io import read_json
4
+ from gyomu_python_analysis.project.context import ProjectContext
5
+ from gyomu_schema.option.concept import ConceptOption
6
+ from gyomu_schema.schemas.concept.directory.concept import DirectoryConcept
7
+ from gyomu_schema.schemas.python.types import ProjectRelativePath
8
+ from returns.result import Result, Success
9
+
10
+
11
+ def load_directory_concept(
12
+ context: ProjectContext,
13
+ target_directory: ProjectRelativePath,
14
+ option: ConceptOption | None = None,
15
+ ) -> Result[DirectoryConcept | None, ConceptError]:
16
+ concept_full_path = get_directory_concept_path(context, target_directory, option)
17
+ if not concept_full_path.exists():
18
+ return Success(None)
19
+ return read_json(path=concept_full_path, model_type=DirectoryConcept).alt(
20
+ lambda error: ConceptError(
21
+ message="fail to load Directory Concept",
22
+ file_path=target_directory,
23
+ package_name=context.config.name,
24
+ phase="directory-summary",
25
+ identity=None,
26
+ ).chain(error)
27
+ )
@@ -0,0 +1,21 @@
1
+ from gyomu_python_analysis.project.context import ProjectContext
2
+ from gyomu_schema.option.concept import ConceptOption
3
+ from gyomu_schema.schemas.python.types import ProjectRelativePath
4
+ from gyomu_schema.schemas.types import FullPath
5
+
6
+
7
+ def get_directory_concept_path(
8
+ context: ProjectContext,
9
+ target_directory: ProjectRelativePath,
10
+ option: ConceptOption | None = None,
11
+ ) -> FullPath:
12
+ return FullPath(
13
+ context.project_root
14
+ / (
15
+ "cache"
16
+ if option and option.action and option.action.write_to_temp_folder
17
+ else "concept"
18
+ )
19
+ / target_directory
20
+ / "$Directory.json"
21
+ )
@@ -0,0 +1,26 @@
1
+ from gyomu_ai_compiler.pipelines.directory_concept.executor.generate import (
2
+ generate_directory_concept,
3
+ )
4
+ from gyomu_concept.error.concept import ConceptError
5
+ from gyomu_schema.schemas.concept.directory.concept import DirectoryConcept
6
+ from gyomu_schema.schemas.concept.directory.input import DirectoryConceptInput
7
+ from gyomu_schema.schemas.python.types import ProjectRelativePath
8
+ from returns.result import Result
9
+
10
+
11
+ async def process_directory_concept(
12
+ package_name: str,
13
+ target_directory: ProjectRelativePath,
14
+ concept: DirectoryConceptInput,
15
+ ) -> Result[DirectoryConcept, ConceptError]:
16
+ result = await generate_directory_concept(context=concept)
17
+ return result.alt(
18
+ lambda error: ConceptError(
19
+ message="fail to generate Directory Concept",
20
+ file_path=target_directory,
21
+ package_name=package_name,
22
+ phase="directory-summary",
23
+ identity=None,
24
+ details=vars(concept),
25
+ ).chain(error)
26
+ )