kodit 0.2.2__py3-none-any.whl → 0.2.3__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.

Potentially problematic release.


This version of kodit might be problematic. Click here for more details.

@@ -6,26 +6,22 @@ system, database operations (via SourceRepository), and provides a clean API for
6
6
  source management.
7
7
  """
8
8
 
9
- import mimetypes
10
- import shutil
11
- import tempfile
12
- from datetime import UTC, datetime
13
- from hashlib import sha256
9
+ from datetime import datetime
14
10
  from pathlib import Path
15
11
 
16
- import aiofiles
17
- import git
18
12
  import pydantic
19
13
  import structlog
20
- from tqdm import tqdm
21
14
 
22
15
  from kodit.source.git import is_valid_clone_target
23
- from kodit.source.ignore import IgnorePatterns
24
- from kodit.source.source_models import (
25
- Author,
26
- File,
27
- Source,
28
- SourceType,
16
+ from kodit.source.source_factories import (
17
+ FolderFileMetadataExtractor,
18
+ FolderSourceFactory,
19
+ FolderWorkingCopyProvider,
20
+ GitAuthorExtractor,
21
+ GitFileMetadataExtractor,
22
+ GitSourceFactory,
23
+ GitWorkingCopyProvider,
24
+ NoOpAuthorExtractor,
29
25
  )
30
26
  from kodit.source.source_repository import SourceRepository
31
27
 
@@ -69,6 +65,32 @@ class SourceService:
69
65
  self.repository = repository
70
66
  self.log = structlog.get_logger(__name__)
71
67
 
68
+ # Initialize factories
69
+ self._setup_factories()
70
+
71
+ def _setup_factories(self) -> None:
72
+ # Git-specific dependencies
73
+ git_working_copy = GitWorkingCopyProvider(self.clone_dir)
74
+ git_metadata_extractor = GitFileMetadataExtractor()
75
+ git_author_extractor = GitAuthorExtractor(self.repository)
76
+ self.git_factory = GitSourceFactory(
77
+ working_copy=git_working_copy,
78
+ metadata_extractor=git_metadata_extractor,
79
+ author_extractor=git_author_extractor,
80
+ repository=self.repository,
81
+ )
82
+
83
+ # Folder-specific dependencies
84
+ folder_working_copy = FolderWorkingCopyProvider(self.clone_dir)
85
+ folder_metadata_extractor = FolderFileMetadataExtractor()
86
+ no_op_author_extractor = NoOpAuthorExtractor()
87
+ self.folder_factory = FolderSourceFactory(
88
+ working_copy=folder_working_copy,
89
+ metadata_extractor=folder_metadata_extractor,
90
+ author_extractor=no_op_author_extractor,
91
+ repository=self.repository,
92
+ )
93
+
72
94
  async def get(self, source_id: int) -> SourceView:
73
95
  """Get a source by ID.
74
96
 
@@ -92,137 +114,13 @@ class SourceService:
92
114
  """Create a new source from a URI or path."""
93
115
  # If it's possible to clone it, then do so
94
116
  if is_valid_clone_target(uri_or_path_like):
95
- return await self._create_git_source(uri_or_path_like)
96
-
117
+ source = await self.git_factory.create(uri_or_path_like)
97
118
  # Otherwise just treat it as a directory
98
- if Path(uri_or_path_like).is_dir():
99
- return await self._create_folder_source(Path(uri_or_path_like))
100
-
101
- msg = f"Unsupported source: {uri_or_path_like}"
102
- raise ValueError(msg)
103
-
104
- async def _create_folder_source(self, directory: Path) -> SourceView:
105
- """Create a folder source.
106
-
107
- Args:
108
- directory: The path to the local directory.
109
-
110
- Raises:
111
- ValueError: If the folder doesn't exist.
112
- SourceAlreadyExistsError: If the folder is already added.
113
-
114
- """
115
- # Resolve the directory to an absolute path
116
- directory = directory.expanduser().resolve()
117
-
118
- source = await self.repository.get_source_by_uri(directory.as_uri())
119
- if source:
120
- self.log.info("Source already exists, reusing...", source_id=source.id)
119
+ elif Path(uri_or_path_like).is_dir():
120
+ source = await self.folder_factory.create(uri_or_path_like)
121
121
  else:
122
- # Check if the folder exists
123
- if not directory.exists():
124
- msg = f"Folder does not exist: {directory}"
125
- raise ValueError(msg)
126
-
127
- # Check if the folder is already added
128
- if await self.repository.get_source_by_uri(directory.as_uri()):
129
- msg = f"Directory already added: {directory}"
130
- raise ValueError(msg)
131
-
132
- # Clone into a local directory
133
- clone_path = self.clone_dir / directory.as_posix().replace("/", "_")
134
- clone_path.mkdir(parents=True, exist_ok=True)
135
-
136
- # Copy all files recursively, preserving directory structure, ignoring
137
- # hidden files
138
- shutil.copytree(
139
- directory,
140
- clone_path,
141
- ignore=shutil.ignore_patterns(".*"),
142
- dirs_exist_ok=True,
143
- )
144
-
145
- source = await self.repository.create_source(
146
- Source(
147
- uri=directory.as_uri(),
148
- cloned_path=str(clone_path),
149
- source_type=SourceType.FOLDER,
150
- ),
151
- )
152
-
153
- # Add all files to the source
154
- # Count total files for progress bar
155
- file_count = sum(1 for _ in clone_path.rglob("*") if _.is_file())
156
-
157
- # Process each file in the source directory
158
- for path in tqdm(clone_path.rglob("*"), total=file_count, leave=False):
159
- await self._process_file(source, path.absolute())
160
-
161
- return SourceView(
162
- id=source.id,
163
- uri=source.uri,
164
- cloned_path=Path(source.cloned_path),
165
- created_at=source.created_at,
166
- num_files=await self.repository.num_files_for_source(source.id),
167
- )
168
-
169
- async def _create_git_source(self, uri: str) -> SourceView:
170
- """Create a git source.
171
-
172
- Args:
173
- uri: The URI of the git repository.
174
-
175
- Raises:
176
- ValueError: If the repository cloning fails.
177
-
178
- """
179
- self.log.debug("Normalising git uri", uri=uri)
180
- with tempfile.TemporaryDirectory() as temp_dir:
181
- git.Repo.clone_from(uri, temp_dir)
182
- remote = git.Repo(temp_dir).remote()
183
- uri = remote.url
184
-
185
- self.log.debug("Checking if source already exists", uri=uri)
186
- source = await self.repository.get_source_by_uri(uri)
187
-
188
- if source:
189
- self.log.info("Source already exists, reusing...", source_id=source.id)
190
- else:
191
- # Create a unique directory name for the clone
192
- clone_path = self.clone_dir / uri.replace("/", "_").replace(":", "_")
193
- clone_path.mkdir(parents=True, exist_ok=True)
194
-
195
- try:
196
- self.log.info("Cloning repository", uri=uri, clone_path=str(clone_path))
197
- git.Repo.clone_from(uri, clone_path)
198
- except git.GitCommandError as e:
199
- if "already exists and is not an empty directory" in str(e):
200
- self.log.info("Repository already exists, reusing...", uri=uri)
201
- else:
202
- msg = f"Failed to clone repository: {e}"
203
- raise ValueError(msg) from e
204
-
205
- self.log.debug("Creating source", uri=uri, clone_path=str(clone_path))
206
- source = await self.repository.create_source(
207
- Source(
208
- uri=uri,
209
- cloned_path=str(clone_path),
210
- source_type=SourceType.GIT,
211
- ),
212
- )
213
-
214
- # Get the ignore patterns for this source
215
- ignore_patterns = IgnorePatterns(clone_path)
216
-
217
- # Get all files that are not ignored
218
- files = [
219
- f for f in clone_path.rglob("*") if not ignore_patterns.should_ignore(f)
220
- ]
221
-
222
- # Process each file in the source directory
223
- self.log.info("Inspecting files", source_id=source.id, num_files=len(files))
224
- for path in tqdm(files, total=len(files), leave=False):
225
- await self._process_file(source, path.absolute())
122
+ msg = f"Unsupported source: {uri_or_path_like}"
123
+ raise ValueError(msg)
226
124
 
227
125
  return SourceView(
228
126
  id=source.id,
@@ -232,81 +130,6 @@ class SourceService:
232
130
  num_files=await self.repository.num_files_for_source(source.id),
233
131
  )
234
132
 
235
- async def _process_file(
236
- self,
237
- source: Source,
238
- cloned_file: Path,
239
- ) -> None:
240
- """Process a single file for indexing."""
241
- if not cloned_file.is_file():
242
- return
243
-
244
- # If this file exists in a git repository, pull out the file's metadata
245
- authors: list[Author] = []
246
- first_modified_at: datetime | None = None
247
- last_modified_at: datetime | None = None
248
- if source.type == SourceType.GIT:
249
- # Get the git repository
250
- git_repo = git.Repo(source.cloned_path)
251
-
252
- # Get the last commit that touched this file
253
- commits = list(
254
- git_repo.iter_commits(
255
- paths=str(cloned_file),
256
- all=True,
257
- )
258
- )
259
- if len(commits) > 0:
260
- last_modified_at = commits[0].committed_datetime
261
- first_modified_at = commits[-1].committed_datetime
262
-
263
- # Get the file's blame
264
- blames = git_repo.blame("HEAD", str(cloned_file))
265
-
266
- # Extract the blame's authors
267
- actors = [
268
- commit.author
269
- for blame in blames or []
270
- for commit in blame
271
- if isinstance(commit, git.Commit)
272
- ]
273
-
274
- # Get or create the authors in the database
275
- for actor in actors:
276
- if actor.name or actor.email:
277
- author = await self.repository.get_or_create_author(
278
- actor.name or "", actor.email or ""
279
- )
280
- authors.append(author)
281
-
282
- # Create the file record
283
- async with aiofiles.open(cloned_file, "rb") as f:
284
- content = await f.read()
285
- mime_type = mimetypes.guess_type(cloned_file)
286
- sha = sha256(content).hexdigest()
287
-
288
- # Create file record
289
- file = File(
290
- created_at=first_modified_at or datetime.now(UTC),
291
- updated_at=last_modified_at or datetime.now(UTC),
292
- source_id=source.id,
293
- cloned_path=str(cloned_file),
294
- mime_type=mime_type[0]
295
- if mime_type and mime_type[0]
296
- else "application/octet-stream",
297
- uri=cloned_file.as_uri(),
298
- sha256=sha,
299
- size_bytes=len(content),
300
- )
301
-
302
- await self.repository.create_file(file)
303
-
304
- # Create mapping of authors to the file
305
- for author in authors:
306
- await self.repository.get_or_create_author_file_mapping(
307
- author_id=author.id, file_id=file.id
308
- )
309
-
310
133
  async def list_sources(self) -> list[SourceView]:
311
134
  """List all available sources.
312
135
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kodit
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Code indexing for better AI code generation
5
5
  Project-URL: Homepage, https://docs.helixml.tech/kodit/
6
6
  Project-URL: Documentation, https://docs.helixml.tech/kodit/
@@ -37,9 +37,9 @@ Requires-Dist: httpx-retries>=0.3.2
37
37
  Requires-Dist: httpx>=0.28.1
38
38
  Requires-Dist: openai>=1.82.0
39
39
  Requires-Dist: pathspec>=0.12.1
40
- Requires-Dist: posthog>=4.0.1
41
40
  Requires-Dist: pydantic-settings>=2.9.1
42
41
  Requires-Dist: pytable-formatter>=0.1.1
42
+ Requires-Dist: rudder-sdk-python>=2.1.4
43
43
  Requires-Dist: sentence-transformers>=4.1.0
44
44
  Requires-Dist: sqlalchemy[asyncio]>=2.0.40
45
45
  Requires-Dist: structlog>=25.3.0
@@ -1,11 +1,11 @@
1
1
  kodit/.gitignore,sha256=ztkjgRwL9Uud1OEi36hGQeDGk3OLK1NfDEO8YqGYy8o,11
2
2
  kodit/__init__.py,sha256=aEKHYninUq1yh6jaNfvJBYg-6fenpN132nJt1UU6Jxs,59
3
- kodit/_version.py,sha256=OjGGK5TcHVG44Y62aAqeJH4CskkZoY9ydbHOtCDew50,511
4
- kodit/app.py,sha256=Mr5BFHOHx5zppwjC4XPWVvHjwgl1yrKbUjTWXKubJQM,891
5
- kodit/cli.py,sha256=i7eEt0FdIQGEfXKFte-8fBcZZGE8BPXBp40aGwJDQGI,11323
3
+ kodit/_version.py,sha256=wD8hnA5gV5UmPkQnpT3xR6V2csgj9K5NEADogbLK79M,511
4
+ kodit/app.py,sha256=qKBWJ0VNSY_M6G3VFfAQ0133q5bnS99cUFD0p396taw,1032
5
+ kodit/cli.py,sha256=wKFXGUMX-fDLooaK-3po2TBpNNRBwgSD7BRbUddg-_M,11562
6
6
  kodit/config.py,sha256=3yh7hfLSILjZK_qJMhcExwRcrWJ0b5Eb1JjjOvMPJZo,4146
7
7
  kodit/database.py,sha256=WB1KpVxUYPgiJGU0gJa2hqytYB8wJEJ5z3WayhWzNMU,2403
8
- kodit/log.py,sha256=HU1OmuxO4FcVw61k4WW7Y4WM7BrDaeplw1PcBHhuIZY,5434
8
+ kodit/log.py,sha256=sHPHYetlMcKTor2VaFLMyao1_fZ_xhuzqXCAt5F5UMU,8575
9
9
  kodit/mcp.py,sha256=QruyPskWB0_x59pkfj5BBeXuR13GMny5TAZEa2j4U9s,5752
10
10
  kodit/middleware.py,sha256=I6FOkqG9-8RH5kR1-0ZoQWfE4qLCB8lZYv8H_OCH29o,2714
11
11
  kodit/bm25/__init__.py,sha256=j8zyriNWhbwE5Lbybzg1hQAhANlU9mKHWw4beeUR6og,19
@@ -14,19 +14,19 @@ kodit/bm25/keyword_search_service.py,sha256=aBbWQKgQmi2re3EIHdXFS00n7Wj3b2D0pZsL
14
14
  kodit/bm25/local_bm25.py,sha256=nokrd_xAeqXi3m68X5P1R5KBhRRB1E2L_J6Zgm26PCg,3869
15
15
  kodit/bm25/vectorchord_bm25.py,sha256=0p_FgliaoevB8GLSmzWnV3zUjdcWgCgOKIpLURr7Qfo,6549
16
16
  kodit/embedding/__init__.py,sha256=h9NXzDA1r-K23nvBajBV-RJzHJN0p3UJ7UQsmdnOoRw,24
17
- kodit/embedding/embedding_factory.py,sha256=UbrTl3NEqBBH3ecvRG7vGW5wuvUMbWJEWbAAFALOGqs,2141
17
+ kodit/embedding/embedding_factory.py,sha256=-WuXNleQ_mqdw1E4TczjtOawNeaXKAiDPFqN_XX7Mmg,2419
18
18
  kodit/embedding/embedding_models.py,sha256=rN90vSs86dYiqoawcp8E9jtwY31JoJXYfaDlsJK7uqc,656
19
19
  kodit/embedding/embedding_repository.py,sha256=-ux3scpBzel8c0pMH9fNOEsSXFIzl-IfgaWrkTb1szo,6907
20
20
  kodit/embedding/local_vector_search_service.py,sha256=dgMi8hQNUbYEgHnEYmLIpon4yLduoNUpu7k7VP6sOHI,2042
21
21
  kodit/embedding/vector_search_service.py,sha256=pQJ129QjGrAWOXzqkywmgtDRpy8_gtzYgkivyqF9Vrs,1009
22
22
  kodit/embedding/vectorchord_vector_search_service.py,sha256=TKNR3HgWHwwWtJ1SsvSaj_BXLJ_uw6Bdr_tpaePMeAA,5383
23
23
  kodit/embedding/embedding_provider/__init__.py,sha256=h9NXzDA1r-K23nvBajBV-RJzHJN0p3UJ7UQsmdnOoRw,24
24
- kodit/embedding/embedding_provider/embedding_provider.py,sha256=IC7fZaZ_ze-DxpxKfK44pRDwHWUQhVIqVKKQ3alO5Qc,1882
24
+ kodit/embedding/embedding_provider/embedding_provider.py,sha256=T6AKMWwzEJ1vDe-cEIg-qxdjhUEZ0PKs9YqQMWaLaQ0,1928
25
25
  kodit/embedding/embedding_provider/hash_embedding_provider.py,sha256=nAhlhh8j8PqqCCbhVl26Y8ntFBm2vJBCtB4X04g5Wwg,2638
26
26
  kodit/embedding/embedding_provider/local_embedding_provider.py,sha256=WP8lw6XG7v1_5Mw4_rhIOETooYRsxhkwmFaXCqCouQU,1977
27
27
  kodit/embedding/embedding_provider/openai_embedding_provider.py,sha256=-phz5FKYM_tI3Q4_3SPzjzIOK3k92Uk52TAOTmoVoWI,2722
28
28
  kodit/enrichment/__init__.py,sha256=vBEolHpKaHUhfINX0dSGyAPlvgpLNAer9YzFtdvCB24,18
29
- kodit/enrichment/enrichment_factory.py,sha256=JbWFNciB6Yf79SFVjG9UhLgCcrXZ1rIJrenU8QmNLBE,1411
29
+ kodit/enrichment/enrichment_factory.py,sha256=AAzvxgjo-FQU5aAm9Zla4DAwUMKGrcw8mQwJsMhIsHY,1566
30
30
  kodit/enrichment/enrichment_service.py,sha256=87Sd3gGbEMJYb_wVrHG8L1yGIZmQNR7foUS4_y94azI,977
31
31
  kodit/enrichment/enrichment_provider/__init__.py,sha256=klf8iuLVWX4iRz-DZQauFFNAoJC5CByczh48TBZPW-o,27
32
32
  kodit/enrichment/enrichment_provider/enrichment_provider.py,sha256=E0H5rq3OENM0yYbA8K_3nSnj5lUHCpoIOqpWLo-2MVU,413
@@ -36,14 +36,14 @@ kodit/indexing/__init__.py,sha256=cPyi2Iej3G1JFWlWr7X80_UrsMaTu5W5rBwgif1B3xo,75
36
36
  kodit/indexing/fusion.py,sha256=TZb4fPAedXdEUXzwzOofW98QIOymdbclBOP1KOijuEk,1674
37
37
  kodit/indexing/indexing_models.py,sha256=6NX9HVcj6Pu9ePwHC7n-PWSyAgukpJq0nCNmUIigtbo,1282
38
38
  kodit/indexing/indexing_repository.py,sha256=dqOS0pxKM6bUjMXWqYukAK8XdiD36OnskFASgZRXRQM,6955
39
- kodit/indexing/indexing_service.py,sha256=79BZ4yaSJqADkivzjsq1bDCBtbfWikVRC7Fjlp1HmZw,10885
39
+ kodit/indexing/indexing_service.py,sha256=3hW7vbFyabLEkLU-PRoGR49yVLewANdOKlye4GhR-tw,11467
40
40
  kodit/migrations/README,sha256=ISVtAOvqvKk_5ThM5ioJE-lMkvf9IbknFUFVU_vPma4,58
41
41
  kodit/migrations/__init__.py,sha256=lP5MuwlyWRMO6UcDWnQcQ3G-GYHcFb6rl9gYPHJ1sjo,40
42
42
  kodit/migrations/env.py,sha256=w1M7OZh-ZeR2dPHS0ByXAUxQjfZQ8xIzMseWuzLDTWw,2469
43
43
  kodit/migrations/script.py.mako,sha256=zWziKtiwYKEWuwPV_HBNHwa9LCT45_bi01-uSNFaOOE,703
44
- kodit/migrations/versions/42e836b21102_add_authors.py,sha256=KmXlHb_y8bIa_ABNU67zZi13r0DAfHA9G8tjQNkdITM,2638
45
44
  kodit/migrations/versions/7c3bbc2ab32b_add_embeddings_table.py,sha256=-61qol9PfQKILCDQRA5jEaats9aGZs9Wdtp-j-38SF4,1644
46
45
  kodit/migrations/versions/85155663351e_initial.py,sha256=Cg7zlF871o9ShV5rQMQ1v7hRV7fI59veDY9cjtTrs-8,3306
46
+ kodit/migrations/versions/9e53ea8bb3b0_add_authors.py,sha256=a32Zm8KUQyiiLkjKNPYdaJDgjW6VsV-GhaLnPnK_fpI,3884
47
47
  kodit/migrations/versions/__init__.py,sha256=9-lHzptItTzq_fomdIRBegQNm4Znx6pVjwD4MiqRIdo,36
48
48
  kodit/migrations/versions/c3f5137d30f5_index_all_the_things.py,sha256=rI8LmjF-I2OMxZ2nOIF_NRmqOLXe45hL_iz_nx97DTQ,1680
49
49
  kodit/snippets/__init__.py,sha256=-2coNoCRjTixU9KcP6alpmt7zqf37tCRWH3D7FPJ8dg,48
@@ -58,13 +58,14 @@ kodit/snippets/languages/typescript.scm,sha256=U-ujbbv4tylbUBj9wuhL-e5cW6hmgPCNs
58
58
  kodit/source/__init__.py,sha256=1NTZyPdjThVQpZO1Mp1ColVsS7sqYanOVLqnoqV9Ipo,83
59
59
  kodit/source/git.py,sha256=CpNczc06SbxpzfQKq76lZFzuol10ZJvTRSzeXW9DFUs,363
60
60
  kodit/source/ignore.py,sha256=W7cuIrYlgfu3S1qyoIepXe8PqYmtFv61Tt5RO8cbZbg,1701
61
- kodit/source/source_models.py,sha256=lCaaoukLlMHuRWJBuYM2nkNKGtFASgbk7ZXq8kp4H5c,3519
62
- kodit/source/source_repository.py,sha256=4L-W0uE4LOB9LQlefk5f2sgHlsJjj8t33USPxU0na40,4448
63
- kodit/source/source_service.py,sha256=v-lY-7tsNFCyXo9yCUo7Q00NOWYKGiDB_M2-Hr8hp3U,11391
61
+ kodit/source/source_factories.py,sha256=qTjKBKu62vynHUxf3-lgxQCoj1nGn8aI9ExFUWNk5B8,11678
62
+ kodit/source/source_models.py,sha256=XlgrY2dlpJkOFZQjrwMGwebAcwQ4rSfjshvCrHKA18Q,3916
63
+ kodit/source/source_repository.py,sha256=eme0C3pRqwFZ1ZSbqq4Z6SV9CC6AvRmiOjy3eHQoEN0,5443
64
+ kodit/source/source_service.py,sha256=E1KPG7TrorqdreJVHxZPx8CVLncOxGEvZ5uDQ6yZugo,5050
64
65
  kodit/util/__init__.py,sha256=bPu6CtqDWCRGU7VgW2_aiQrCBi8G89FS6k1PjvDajJ0,37
65
66
  kodit/util/spinner.py,sha256=R9bzrHtBiIH6IfLbmsIVHL53s8vg-tqW4lwGGALu4dw,1932
66
- kodit-0.2.2.dist-info/METADATA,sha256=UU1curOx-XMql_IiXty-eoz-MJrd5QdlzfCj7ZoSzhg,5857
67
- kodit-0.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
68
- kodit-0.2.2.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
69
- kodit-0.2.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
70
- kodit-0.2.2.dist-info/RECORD,,
67
+ kodit-0.2.3.dist-info/METADATA,sha256=ccZ0bl5PCGFNC30XSr-4ljL-JrkTgTfYlqZUlUPYba8,5867
68
+ kodit-0.2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
69
+ kodit-0.2.3.dist-info/entry_points.txt,sha256=hoTn-1aKyTItjnY91fnO-rV5uaWQLQ-Vi7V5et2IbHY,40
70
+ kodit-0.2.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
71
+ kodit-0.2.3.dist-info/RECORD,,
@@ -1,64 +0,0 @@
1
- # ruff: noqa
2
- """add authors
3
-
4
- Revision ID: 42e836b21102
5
- Revises: c3f5137d30f5
6
- Create Date: 2025-06-13 14:48:50.152940
7
-
8
- """
9
-
10
- from typing import Sequence, Union
11
-
12
- from alembic import op
13
- import sqlalchemy as sa
14
-
15
-
16
- # revision identifiers, used by Alembic.
17
- revision: str = '42e836b21102'
18
- down_revision: Union[str, None] = 'c3f5137d30f5'
19
- branch_labels: Union[str, Sequence[str], None] = None
20
- depends_on: Union[str, Sequence[str], None] = None
21
-
22
-
23
- def upgrade() -> None:
24
- """Upgrade schema."""
25
- # ### commands auto generated by Alembic - please adjust! ###
26
- op.create_table('authors',
27
- sa.Column('name', sa.String(length=255), nullable=False),
28
- sa.Column('email', sa.String(length=255), nullable=False),
29
- sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
30
- sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
31
- sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
32
- sa.PrimaryKeyConstraint('id')
33
- )
34
- op.create_index(op.f('ix_authors_email'), 'authors', ['email'], unique=True)
35
- op.create_index(op.f('ix_authors_name'), 'authors', ['name'], unique=True)
36
- op.create_table('author_file_mappings',
37
- sa.Column('author_id', sa.Integer(), nullable=False),
38
- sa.Column('file_id', sa.Integer(), nullable=False),
39
- sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
40
- sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
41
- sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
42
- sa.ForeignKeyConstraint(['author_id'], ['authors.id'], ),
43
- sa.ForeignKeyConstraint(['file_id'], ['files.id'], ),
44
- sa.PrimaryKeyConstraint('id')
45
- )
46
- op.add_column('files', sa.Column('extension', sa.String(length=255), nullable=False))
47
- op.create_index(op.f('ix_files_extension'), 'files', ['extension'], unique=False)
48
- op.add_column('sources', sa.Column('type', sa.Enum('UNKNOWN', 'FOLDER', 'GIT', name='sourcetype'), nullable=False))
49
- op.create_index(op.f('ix_sources_type'), 'sources', ['type'], unique=False)
50
- # ### end Alembic commands ###
51
-
52
-
53
- def downgrade() -> None:
54
- """Downgrade schema."""
55
- # ### commands auto generated by Alembic - please adjust! ###
56
- op.drop_index(op.f('ix_sources_type'), table_name='sources')
57
- op.drop_column('sources', 'type')
58
- op.drop_index(op.f('ix_files_extension'), table_name='files')
59
- op.drop_column('files', 'extension')
60
- op.drop_table('author_file_mappings')
61
- op.drop_index(op.f('ix_authors_name'), table_name='authors')
62
- op.drop_index(op.f('ix_authors_email'), table_name='authors')
63
- op.drop_table('authors')
64
- # ### end Alembic commands ###
File without changes