auto-coder 0.1.259__py3-none-any.whl → 0.1.261__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 auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/METADATA +1 -1
- {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/RECORD +36 -27
- autocoder/agent/auto_review_commit.py +51 -24
- autocoder/auto_coder.py +24 -1
- autocoder/chat_auto_coder.py +377 -399
- autocoder/chat_auto_coder_lang.py +20 -0
- autocoder/commands/__init__.py +0 -0
- autocoder/commands/auto_command.py +1174 -0
- autocoder/commands/tools.py +533 -0
- autocoder/common/__init__.py +8 -0
- autocoder/common/auto_coder_lang.py +61 -8
- autocoder/common/auto_configure.py +304 -0
- autocoder/common/code_auto_merge.py +2 -2
- autocoder/common/code_auto_merge_diff.py +2 -2
- autocoder/common/code_auto_merge_editblock.py +2 -2
- autocoder/common/code_auto_merge_strict_diff.py +2 -2
- autocoder/common/code_modification_ranker.py +8 -7
- autocoder/common/command_completer.py +557 -0
- autocoder/common/conf_validator.py +245 -0
- autocoder/common/conversation_pruner.py +131 -0
- autocoder/common/git_utils.py +82 -1
- autocoder/common/index_import_export.py +101 -0
- autocoder/common/result_manager.py +115 -0
- autocoder/common/shells.py +22 -6
- autocoder/common/utils_code_auto_generate.py +2 -2
- autocoder/dispacher/actions/action.py +45 -4
- autocoder/dispacher/actions/plugins/action_regex_project.py +13 -1
- autocoder/index/filter/quick_filter.py +22 -7
- autocoder/utils/auto_coder_utils/chat_stream_out.py +13 -6
- autocoder/utils/project_structure.py +15 -0
- autocoder/utils/thread_utils.py +4 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/top_level.txt +0 -0
autocoder/common/shells.py
CHANGED
|
@@ -9,6 +9,8 @@ from rich.panel import Panel
|
|
|
9
9
|
from rich.text import Text
|
|
10
10
|
from rich.live import Live
|
|
11
11
|
|
|
12
|
+
from autocoder.common.result_manager import ResultManager
|
|
13
|
+
|
|
12
14
|
def get_terminal_name() -> str:
|
|
13
15
|
"""
|
|
14
16
|
获取当前终端名称(自动适配 Windows/Linux/Mac)
|
|
@@ -139,6 +141,7 @@ def execute_shell_command(command: str):
|
|
|
139
141
|
encoding (str, optional): Override default encoding. Defaults to None.
|
|
140
142
|
"""
|
|
141
143
|
console = Console()
|
|
144
|
+
result_manager = ResultManager()
|
|
142
145
|
try:
|
|
143
146
|
# Get terminal encoding
|
|
144
147
|
encoding = get_terminal_encoding()
|
|
@@ -199,7 +202,13 @@ def execute_shell_command(command: str):
|
|
|
199
202
|
output.append(safe_decode(remaining_out, encoding))
|
|
200
203
|
if remaining_err:
|
|
201
204
|
output.append(f"ERROR: {safe_decode(remaining_err, encoding)}")
|
|
202
|
-
|
|
205
|
+
|
|
206
|
+
result_manager.add_result(content="\n".join(output),meta={
|
|
207
|
+
"action": "execute_shell_command",
|
|
208
|
+
"input": {
|
|
209
|
+
"command": command
|
|
210
|
+
}
|
|
211
|
+
})
|
|
203
212
|
# Show final output
|
|
204
213
|
console.print(
|
|
205
214
|
Panel(
|
|
@@ -210,16 +219,23 @@ def execute_shell_command(command: str):
|
|
|
210
219
|
)
|
|
211
220
|
)
|
|
212
221
|
|
|
213
|
-
if process.returncode != 0:
|
|
214
|
-
console.print(
|
|
215
|
-
f"[bold red]Command failed with code {process.returncode}[/bold red]"
|
|
216
|
-
)
|
|
217
|
-
|
|
218
222
|
except FileNotFoundError:
|
|
223
|
+
result_manager.add_result(content=f"[bold red]Command not found:[/bold red] [yellow]{command}[/yellow]",meta={
|
|
224
|
+
"action": "execute_shell_command",
|
|
225
|
+
"input": {
|
|
226
|
+
"command": command
|
|
227
|
+
}
|
|
228
|
+
})
|
|
219
229
|
console.print(
|
|
220
230
|
f"[bold red]Command not found:[/bold red] [yellow]{command}[/yellow]"
|
|
221
231
|
)
|
|
222
232
|
except Exception as e:
|
|
233
|
+
result_manager.add_result(content=f"[bold red]Unexpected error:[/bold red] [yellow]{str(e)}[/yellow]",meta={
|
|
234
|
+
"action": "execute_shell_command",
|
|
235
|
+
"input": {
|
|
236
|
+
"command": command
|
|
237
|
+
}
|
|
238
|
+
})
|
|
223
239
|
console.print(
|
|
224
240
|
f"[bold red]Unexpected error:[/bold red] [yellow]{str(e)}[/yellow]"
|
|
225
241
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from byzerllm import ByzerLLM,SimpleByzerLLM
|
|
2
|
-
from typing import Generator, List, Any, Union
|
|
2
|
+
from typing import Generator, List, Any, Union, Optional, Callable
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
from loguru import logger
|
|
5
5
|
|
|
@@ -41,7 +41,7 @@ def chat_with_continue(llm: Union[ByzerLLM,SimpleByzerLLM], conversations: List[
|
|
|
41
41
|
def stream_chat_with_continue(
|
|
42
42
|
llm: Union[ByzerLLM, SimpleByzerLLM],
|
|
43
43
|
conversations: List[dict],
|
|
44
|
-
llm_config: dict
|
|
44
|
+
llm_config: dict
|
|
45
45
|
) -> Generator[Any, None, None]:
|
|
46
46
|
"""
|
|
47
47
|
流式处理并继续生成内容,直到完成。
|
|
@@ -29,6 +29,7 @@ from autocoder.common.printer import Printer
|
|
|
29
29
|
from autocoder.utils.llms import get_llm_names
|
|
30
30
|
from autocoder.privacy.model_filter import ModelPathFilter
|
|
31
31
|
from autocoder.common import SourceCodeList
|
|
32
|
+
from autocoder.common.global_cancel import global_cancel
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class BaseAction:
|
|
@@ -106,6 +107,10 @@ class ActionTSProject(BaseAction):
|
|
|
106
107
|
f"Content(send to model) is {content_length} tokens, which is larger than the maximum input length {self.args.model_max_input_length}"
|
|
107
108
|
)
|
|
108
109
|
|
|
110
|
+
if global_cancel.requested:
|
|
111
|
+
printer = Printer()
|
|
112
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
113
|
+
|
|
109
114
|
if args.execute:
|
|
110
115
|
self.printer.print_in_terminal("code_generation_start")
|
|
111
116
|
start_time = time.time()
|
|
@@ -145,8 +150,14 @@ class ActionTSProject(BaseAction):
|
|
|
145
150
|
input_cost=input_tokens_cost,
|
|
146
151
|
output_cost=generated_tokens_cost,
|
|
147
152
|
speed=round(speed, 2),
|
|
148
|
-
model_names=model_names
|
|
153
|
+
model_names=model_names,
|
|
154
|
+
sampling_count=len(generate_result.contents)
|
|
149
155
|
)
|
|
156
|
+
|
|
157
|
+
if global_cancel.requested:
|
|
158
|
+
printer = Printer()
|
|
159
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
160
|
+
|
|
150
161
|
merge_result = None
|
|
151
162
|
if args.execute and args.auto_merge:
|
|
152
163
|
self.printer.print_in_terminal("code_merge_start")
|
|
@@ -206,6 +217,10 @@ class ActionPyScriptProject(BaseAction):
|
|
|
206
217
|
|
|
207
218
|
def process_content(self, source_code_list: SourceCodeList):
|
|
208
219
|
args = self.args
|
|
220
|
+
if global_cancel.requested:
|
|
221
|
+
printer = Printer()
|
|
222
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
223
|
+
|
|
209
224
|
if args.execute:
|
|
210
225
|
self.printer.print_in_terminal("code_generation_start")
|
|
211
226
|
start_time = time.time()
|
|
@@ -245,8 +260,14 @@ class ActionPyScriptProject(BaseAction):
|
|
|
245
260
|
input_cost=input_tokens_cost,
|
|
246
261
|
output_cost=generated_tokens_cost,
|
|
247
262
|
speed=round(speed, 2),
|
|
248
|
-
model_names=model_names
|
|
263
|
+
model_names=model_names,
|
|
264
|
+
sampling_count=len(generate_result.contents)
|
|
249
265
|
)
|
|
266
|
+
|
|
267
|
+
if global_cancel.requested:
|
|
268
|
+
printer = Printer()
|
|
269
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
270
|
+
|
|
250
271
|
merge_result = None
|
|
251
272
|
if args.execute and args.auto_merge:
|
|
252
273
|
self.printer.print_in_terminal("code_merge_start")
|
|
@@ -329,6 +350,10 @@ class ActionPyProject(BaseAction):
|
|
|
329
350
|
content_length=content_length,
|
|
330
351
|
max_length=self.args.model_max_input_length
|
|
331
352
|
)
|
|
353
|
+
|
|
354
|
+
if global_cancel.requested:
|
|
355
|
+
printer = Printer()
|
|
356
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
332
357
|
|
|
333
358
|
if args.execute:
|
|
334
359
|
self.printer.print_in_terminal("code_generation_start")
|
|
@@ -370,8 +395,14 @@ class ActionPyProject(BaseAction):
|
|
|
370
395
|
input_cost=input_tokens_cost,
|
|
371
396
|
output_cost=generated_tokens_cost,
|
|
372
397
|
speed=round(speed, 2),
|
|
373
|
-
model_names=model_names
|
|
398
|
+
model_names=model_names,
|
|
399
|
+
sampling_count=len(generate_result.contents)
|
|
374
400
|
)
|
|
401
|
+
|
|
402
|
+
if global_cancel.requested:
|
|
403
|
+
printer = Printer()
|
|
404
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
405
|
+
|
|
375
406
|
merge_result = None
|
|
376
407
|
if args.execute and args.auto_merge:
|
|
377
408
|
self.printer.print_in_terminal("code_merge_start")
|
|
@@ -446,6 +477,10 @@ class ActionSuffixProject(BaseAction):
|
|
|
446
477
|
f"Content(send to model) is {content_length} tokens, which is larger than the maximum input length {self.args.model_max_input_length}"
|
|
447
478
|
)
|
|
448
479
|
|
|
480
|
+
if global_cancel.requested:
|
|
481
|
+
printer = Printer()
|
|
482
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
483
|
+
|
|
449
484
|
if args.execute:
|
|
450
485
|
self.printer.print_in_terminal("code_generation_start")
|
|
451
486
|
start_time = time.time()
|
|
@@ -485,8 +520,14 @@ class ActionSuffixProject(BaseAction):
|
|
|
485
520
|
input_cost=input_tokens_cost,
|
|
486
521
|
output_cost=generated_tokens_cost,
|
|
487
522
|
speed=round(speed, 2),
|
|
488
|
-
model_names=model_names
|
|
523
|
+
model_names=model_names,
|
|
524
|
+
sampling_count=len(generate_result.contents)
|
|
489
525
|
)
|
|
526
|
+
|
|
527
|
+
if global_cancel.requested:
|
|
528
|
+
printer = Printer()
|
|
529
|
+
raise Exception(printer.get_message_from_key("generation_cancelled") )
|
|
530
|
+
|
|
490
531
|
merge_result = None
|
|
491
532
|
if args.execute and args.auto_merge:
|
|
492
533
|
self.printer.print_in_terminal("code_merge_start")
|
|
@@ -16,6 +16,7 @@ from autocoder.common.printer import Printer
|
|
|
16
16
|
import time
|
|
17
17
|
from autocoder.utils.llms import get_llm_names
|
|
18
18
|
from autocoder.common import SourceCodeList
|
|
19
|
+
from autocoder.common.global_cancel import global_cancel
|
|
19
20
|
from loguru import logger
|
|
20
21
|
class ActionRegexProject:
|
|
21
22
|
def __init__(
|
|
@@ -61,6 +62,11 @@ class ActionRegexProject:
|
|
|
61
62
|
content = content[: self.args.model_max_input_length]
|
|
62
63
|
|
|
63
64
|
start_time = time.time()
|
|
65
|
+
|
|
66
|
+
if global_cancel.requested:
|
|
67
|
+
printer = Printer()
|
|
68
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
69
|
+
|
|
64
70
|
if args.execute:
|
|
65
71
|
self.printer.print_in_terminal("code_generation_start")
|
|
66
72
|
|
|
@@ -100,8 +106,14 @@ class ActionRegexProject:
|
|
|
100
106
|
input_cost=input_tokens_cost,
|
|
101
107
|
output_cost=generated_tokens_cost,
|
|
102
108
|
speed=round(speed, 2),
|
|
103
|
-
model_names=model_names
|
|
109
|
+
model_names=model_names,
|
|
110
|
+
sampling_count=len(generate_result.contents)
|
|
104
111
|
)
|
|
112
|
+
|
|
113
|
+
if global_cancel.requested:
|
|
114
|
+
printer = Printer()
|
|
115
|
+
raise Exception(printer.get_message_from_key("generation_cancelled"))
|
|
116
|
+
|
|
105
117
|
merge_result = None
|
|
106
118
|
if args.execute and args.auto_merge:
|
|
107
119
|
self.printer.print_in_terminal("code_merge_start")
|
|
@@ -19,6 +19,7 @@ from concurrent.futures import ThreadPoolExecutor
|
|
|
19
19
|
from byzerllm import MetaHolder
|
|
20
20
|
|
|
21
21
|
from autocoder.utils.llms import get_llm_names, get_model_info
|
|
22
|
+
from loguru import logger
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def get_file_path(file_path):
|
|
@@ -229,7 +230,8 @@ class QuickFilter():
|
|
|
229
230
|
{{ content }}
|
|
230
231
|
</index>
|
|
231
232
|
|
|
232
|
-
索引文件包含文件序号(##[]括起来的部分),文件路径,文件符号信息等。
|
|
233
|
+
索引文件包含文件序号(##[]括起来的部分),文件路径,文件符号信息等。
|
|
234
|
+
|
|
233
235
|
下面是用户的查询需求:
|
|
234
236
|
|
|
235
237
|
<query>
|
|
@@ -248,16 +250,18 @@ class QuickFilter():
|
|
|
248
250
|
}
|
|
249
251
|
```
|
|
250
252
|
|
|
251
|
-
特别注意
|
|
252
|
-
1. 如果用户的query里 @文件 或者
|
|
253
|
+
特别注意
|
|
254
|
+
1. 如果用户的query里 @文件 或者 @@符号,那么被@的文件或者@@的符号必须要返回,并且尝试通过索引文件诸如导入语句等信息找到这些文件依赖的其他文件,再分析这些文件是否需要提供才能满足后续编码。
|
|
253
255
|
2. 如果 query 里是一段历史对话,那么对话里的内容提及的文件路径必须要返回。
|
|
254
|
-
3.
|
|
256
|
+
3. 想想,如果是你需要修改代码,然后满足这个需求,根据索引文件,你希望查看哪些文件,修改哪些文件,然后返回这些文件。
|
|
257
|
+
4. 返回的 json格式数据不允许有注释
|
|
255
258
|
'''
|
|
259
|
+
|
|
256
260
|
file_meta_str = "\n".join(
|
|
257
261
|
[f"##[{index}]{item.module_name}\n{item.symbols}" for index, item in enumerate(file_meta_list)])
|
|
258
262
|
context = {
|
|
259
263
|
"content": file_meta_str,
|
|
260
|
-
"query": query
|
|
264
|
+
"query": query
|
|
261
265
|
}
|
|
262
266
|
return context
|
|
263
267
|
|
|
@@ -308,13 +312,22 @@ class QuickFilter():
|
|
|
308
312
|
{}
|
|
309
313
|
)
|
|
310
314
|
|
|
315
|
+
def extract_file_number_list(content: str) -> str:
|
|
316
|
+
try:
|
|
317
|
+
v = to_model(content, FileNumberList)
|
|
318
|
+
return "\n".join([index_items[file_number].module_name for file_number in v.file_list])
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(f"Error extracting file number list: {e}")
|
|
321
|
+
return content
|
|
322
|
+
|
|
311
323
|
# 获取完整响应
|
|
312
324
|
full_response, last_meta = stream_out(
|
|
313
325
|
stream_generator,
|
|
314
326
|
model_name=model_name,
|
|
315
327
|
title=self.printer.get_message_from_key_with_format(
|
|
316
328
|
"quick_filter_title", model_name=model_name),
|
|
317
|
-
args=self.args
|
|
329
|
+
args=self.args,
|
|
330
|
+
display_func=extract_file_number_list
|
|
318
331
|
)
|
|
319
332
|
# 解析结果
|
|
320
333
|
file_number_list = to_model(full_response, FileNumberList)
|
|
@@ -335,6 +348,7 @@ class QuickFilter():
|
|
|
335
348
|
# 四舍五入到4位小数
|
|
336
349
|
total_input_cost = round(total_input_cost, 4)
|
|
337
350
|
total_output_cost = round(total_output_cost, 4)
|
|
351
|
+
speed = last_meta.generated_tokens_count / (end_time - start_time)
|
|
338
352
|
|
|
339
353
|
# 打印 token 统计信息和成本
|
|
340
354
|
self.printer.print_in_terminal(
|
|
@@ -345,7 +359,8 @@ class QuickFilter():
|
|
|
345
359
|
output_tokens=last_meta.generated_tokens_count,
|
|
346
360
|
input_cost=total_input_cost,
|
|
347
361
|
output_cost=total_output_cost,
|
|
348
|
-
model_names=model_name
|
|
362
|
+
model_names=model_name,
|
|
363
|
+
speed=f"{speed:.2f}"
|
|
349
364
|
)
|
|
350
365
|
|
|
351
366
|
except Exception as e:
|
|
@@ -6,7 +6,7 @@ from rich.markdown import Markdown
|
|
|
6
6
|
from rich.layout import Layout
|
|
7
7
|
from threading import Thread, Lock
|
|
8
8
|
from queue import Queue, Empty
|
|
9
|
-
from typing import Generator, List, Dict, Any, Optional, Tuple,
|
|
9
|
+
from typing import Generator, List, Dict, Any, Optional, Tuple, Callable
|
|
10
10
|
from autocoder.utils.request_queue import RequestValue, RequestOption, StreamValue
|
|
11
11
|
from autocoder.utils.request_queue import request_queue
|
|
12
12
|
import time
|
|
@@ -148,7 +148,9 @@ def stream_out(
|
|
|
148
148
|
console: Optional[Console] = None,
|
|
149
149
|
model_name: Optional[str] = None,
|
|
150
150
|
title: Optional[str] = None,
|
|
151
|
-
|
|
151
|
+
final_title: Optional[str] = None,
|
|
152
|
+
args: Optional[AutoCoderArgs] = None,
|
|
153
|
+
display_func: Optional[Callable] = None
|
|
152
154
|
) -> Tuple[str, Optional[SingleOutputMeta]]:
|
|
153
155
|
"""
|
|
154
156
|
处理流式输出事件并在终端中展示
|
|
@@ -179,6 +181,7 @@ def stream_out(
|
|
|
179
181
|
assistant_response = ""
|
|
180
182
|
last_meta = None
|
|
181
183
|
panel_title = title if title is not None else f"Response[ {model_name} ]"
|
|
184
|
+
final_panel_title = final_title if final_title is not None else title
|
|
182
185
|
first_token_time = 0.0
|
|
183
186
|
first_token_time_start = time.time()
|
|
184
187
|
try:
|
|
@@ -250,8 +253,8 @@ def stream_out(
|
|
|
250
253
|
value=StreamValue(value=[content]),
|
|
251
254
|
status=RequestOption.RUNNING,
|
|
252
255
|
),
|
|
253
|
-
)
|
|
254
|
-
|
|
256
|
+
)
|
|
257
|
+
|
|
255
258
|
live.update(
|
|
256
259
|
Panel(
|
|
257
260
|
Markdown(display_content),
|
|
@@ -266,10 +269,14 @@ def stream_out(
|
|
|
266
269
|
lines_buffer.append(current_line)
|
|
267
270
|
|
|
268
271
|
# 最终显示结果
|
|
272
|
+
final_display_content = assistant_response
|
|
273
|
+
if display_func:
|
|
274
|
+
final_display_content = display_func(assistant_response)
|
|
275
|
+
|
|
269
276
|
live.update(
|
|
270
277
|
Panel(
|
|
271
|
-
Markdown(
|
|
272
|
-
title=f"
|
|
278
|
+
Markdown(final_display_content),
|
|
279
|
+
title=f"{final_panel_title}",
|
|
273
280
|
border_style="blue"
|
|
274
281
|
)
|
|
275
282
|
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from autocoder.pyproject import PyProject
|
|
2
|
+
from autocoder.tsproject import TSProject
|
|
3
|
+
from autocoder.suffixproject import SuffixProject
|
|
4
|
+
from autocoder.common import AutoCoderArgs
|
|
5
|
+
import byzerllm
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
def get_project_structure(args:AutoCoderArgs, llm:Union[byzerllm.ByzerLLM, byzerllm.SimpleByzerLLM]):
|
|
9
|
+
if args.project_type == "ts":
|
|
10
|
+
pp = TSProject(args=args, llm=llm)
|
|
11
|
+
elif args.project_type == "py":
|
|
12
|
+
pp = PyProject(args=args, llm=llm)
|
|
13
|
+
else:
|
|
14
|
+
pp = SuffixProject(args=args, llm=llm, file_filter=None)
|
|
15
|
+
return pp.get_tree_like_directory_structure()
|
autocoder/utils/thread_utils.py
CHANGED
|
@@ -176,6 +176,7 @@ def run_in_raw_thread():
|
|
|
176
176
|
exception = []
|
|
177
177
|
def worker():
|
|
178
178
|
try:
|
|
179
|
+
# global_cancel.reset()
|
|
179
180
|
ret = func(*args, **kwargs)
|
|
180
181
|
result.append(ret)
|
|
181
182
|
global_cancel.reset()
|
|
@@ -196,6 +197,9 @@ def run_in_raw_thread():
|
|
|
196
197
|
except KeyboardInterrupt:
|
|
197
198
|
global_cancel.set()
|
|
198
199
|
raise KeyboardInterrupt("Task was cancelled by user")
|
|
200
|
+
except Exception as e:
|
|
201
|
+
global_cancel.reset()
|
|
202
|
+
raise
|
|
199
203
|
|
|
200
204
|
return wrapper
|
|
201
205
|
return decorator
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.261"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|