Compare commits
1 Commits
main
..
b874441f06
| Author | SHA1 | Date | |
|---|---|---|---|
| b874441f06 |
@@ -1,42 +1,3 @@
|
|||||||
# mrpy.nvim
|
# mrpy.nvim
|
||||||
|
|
||||||
NeoVim plugin, integrating a clickup to gitlab workflow (1 task to 1 issue to 1 merge request)
|
NeoVim plugin, integrating a clickup to gitlab workflow (1 task to 1 issue to 1 merge request)
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
### Lazy.nvim
|
|
||||||
|
|
||||||
#### From Source
|
|
||||||
|
|
||||||
```lua
|
|
||||||
return {
|
|
||||||
dir = "<path/to/cloned/repo>",
|
|
||||||
dev = true,
|
|
||||||
dependencies = {
|
|
||||||
"nvim-lua/plenary.nvim",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
### Shell Configuration
|
|
||||||
|
|
||||||
#### Environment Variables
|
|
||||||
|
|
||||||
CLICKUP_AUTH
|
|
||||||
: user api token for clickup
|
|
||||||
|
|
||||||
CLICKUP_USER_ID
|
|
||||||
: user id for clickup
|
|
||||||
|
|
||||||
CLICKUP_WORKSPACE_ID
|
|
||||||
: workspace id for clickup
|
|
||||||
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
### `:MrPy`
|
|
||||||
|
|
||||||
- start task selector of user's tasks (not done/closed)
|
|
||||||
|
|
||||||
-109
@@ -1,109 +0,0 @@
|
|||||||
from collections.abc import Iterator
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from json import loads
|
|
||||||
from pydantic import BaseModel
|
|
||||||
from requests import HTTPError, get
|
|
||||||
|
|
||||||
from .common import EnvVar, JSONDataMap, JSONData, JSONDataList, JSONDataScalar
|
|
||||||
|
|
||||||
|
|
||||||
class ClickupStatus(BaseModel):
|
|
||||||
status: str
|
|
||||||
|
|
||||||
@property
|
|
||||||
def status_symbol(self) -> str:
|
|
||||||
match self.status:
|
|
||||||
case "backlog":
|
|
||||||
return ""
|
|
||||||
case "selected for development":
|
|
||||||
return ""
|
|
||||||
case "in progress":
|
|
||||||
return ""
|
|
||||||
case "in review":
|
|
||||||
return ""
|
|
||||||
case "done":
|
|
||||||
return ""
|
|
||||||
case "closed":
|
|
||||||
return ""
|
|
||||||
case "on hold":
|
|
||||||
return ""
|
|
||||||
case _:
|
|
||||||
return self.status
|
|
||||||
|
|
||||||
|
|
||||||
class ClickupTask(BaseModel):
|
|
||||||
id: str
|
|
||||||
name: str
|
|
||||||
markdown_description: str
|
|
||||||
status: ClickupStatus
|
|
||||||
|
|
||||||
|
|
||||||
class ClickupList(BaseModel):
|
|
||||||
task_count: int
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ClickupSession:
|
|
||||||
auth_key: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"CLICKUP_AUTH",
|
|
||||||
"clickup auth token is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
workspace_id: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"CLICKUP_WORKSPACE_ID",
|
|
||||||
"clickup workspace id is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
user_id: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"CLICKUP_USER_ID",
|
|
||||||
"clickup user id is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
base_url: str = "https://api.clickup.com/api/v2"
|
|
||||||
|
|
||||||
def _get(self, endpoint: str, **query_params: str) -> JSONDataMap:
|
|
||||||
with get(
|
|
||||||
self.base_url + endpoint,
|
|
||||||
query_params,
|
|
||||||
headers={
|
|
||||||
"accept": "application/json",
|
|
||||||
"Authorization": self.auth_key,
|
|
||||||
},
|
|
||||||
) as resp:
|
|
||||||
return resp.json()
|
|
||||||
|
|
||||||
def get_tasks(self, **filters: str) -> Iterator[ClickupTask]:
|
|
||||||
pix = 0
|
|
||||||
while True:
|
|
||||||
partial_data = self._get(
|
|
||||||
f"/team/{self.workspace_id}/task",
|
|
||||||
**{
|
|
||||||
"subtasks": "true",
|
|
||||||
"include_markdown_description": "true",
|
|
||||||
"include_closed": "true",
|
|
||||||
"assignees[]": self.user_id,
|
|
||||||
"page": pix,
|
|
||||||
}
|
|
||||||
| filters,
|
|
||||||
).get("tasks", [])
|
|
||||||
pix += 1
|
|
||||||
|
|
||||||
for inst in partial_data:
|
|
||||||
yield ClickupTask.model_validate(inst)
|
|
||||||
|
|
||||||
if len(partial_data) < 100:
|
|
||||||
break
|
|
||||||
|
|
||||||
def get_task(self, task_id: str) -> ClickupTask:
|
|
||||||
return ClickupTask.model_validate(
|
|
||||||
self._get(
|
|
||||||
f"/task/{task_id}",
|
|
||||||
include_markdown_description="true",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_list(self, list_id: str) -> ClickupList:
|
|
||||||
return ClickupList.model_validate(self._get(f"/list/{list_id}"))
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from os import environ
|
|
||||||
from typing import TypeAlias
|
|
||||||
|
|
||||||
|
|
||||||
JSONDataScalar: TypeAlias = str | None | float | bool
|
|
||||||
JSONDataList: TypeAlias = list["JSONDataScalar | JSONDataMap | JSONDataList"]
|
|
||||||
JSONDataMap: TypeAlias = dict[str, "JSONDataScalar | JSONDataList | JSONDataMap"]
|
|
||||||
JSONData: TypeAlias = "JSONDataMap | JSONDataList"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class EnvVar:
|
|
||||||
"""
|
|
||||||
Environment Variable fetcher for use in dataclass ``field(default_factory=...)``
|
|
||||||
|
|
||||||
>>> @dataclass
|
|
||||||
>>> class SomeDataclass:
|
|
||||||
... field_name: str = field(default_factory=EnvVar("SOME_VAR_NAME", "err msg"))
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
var_name: str
|
|
||||||
err_msg: str = ""
|
|
||||||
|
|
||||||
def __call__(self) -> str:
|
|
||||||
try:
|
|
||||||
return environ[self.var_name]
|
|
||||||
except KeyError as e:
|
|
||||||
e.add_note(self.err_msg)
|
|
||||||
raise
|
|
||||||
-133
@@ -1,133 +0,0 @@
|
|||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
from requests import get
|
|
||||||
from requests.compat import quote
|
|
||||||
|
|
||||||
from eta.common import EnvVar, JSONDataMap
|
|
||||||
|
|
||||||
|
|
||||||
class GitlabProject(BaseModel):
|
|
||||||
name: str
|
|
||||||
name_with_namespace: str
|
|
||||||
path_with_namespace: str
|
|
||||||
web_url: str
|
|
||||||
id: int
|
|
||||||
|
|
||||||
issues: list["GitlabIssue"] = Field(default_factory=list, init=False)
|
|
||||||
merge_requests: list["GitlabMergeRequest"] = Field(default_factory=list, init=False)
|
|
||||||
|
|
||||||
|
|
||||||
class GitlabMilestone(BaseModel):
|
|
||||||
id: int
|
|
||||||
title: str
|
|
||||||
state: str
|
|
||||||
|
|
||||||
|
|
||||||
class GitlabIssue(BaseModel):
|
|
||||||
title: str
|
|
||||||
description: str | None
|
|
||||||
id: int
|
|
||||||
project_id: int
|
|
||||||
iid: int
|
|
||||||
state: str
|
|
||||||
labels: list[str]
|
|
||||||
milestone: GitlabMilestone | None
|
|
||||||
# web_url: str
|
|
||||||
|
|
||||||
|
|
||||||
class GitlabMergeRequest(BaseModel):
|
|
||||||
id: int
|
|
||||||
iid: int
|
|
||||||
description: str | None
|
|
||||||
draft: bool
|
|
||||||
labels: list[str]
|
|
||||||
milestone: GitlabMilestone | None
|
|
||||||
source_branch: str
|
|
||||||
state: str
|
|
||||||
target_branch: str
|
|
||||||
project_id: int
|
|
||||||
title: str
|
|
||||||
web_url: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class GitlabSession:
|
|
||||||
auth_key: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"GITLAB_AUTH",
|
|
||||||
"gitlab auth token is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
base_url: str = "https://git.extoll.de/api/v4"
|
|
||||||
|
|
||||||
def _get(self, endpoint: str, **query_params: str) -> JSONDataMap:
|
|
||||||
with get(
|
|
||||||
self.base_url + endpoint,
|
|
||||||
query_params,
|
|
||||||
headers={
|
|
||||||
"accept": "application/json",
|
|
||||||
"PRIVATE-TOKEN": self.auth_key,
|
|
||||||
},
|
|
||||||
verify=False,
|
|
||||||
) as resp:
|
|
||||||
return resp.json()
|
|
||||||
|
|
||||||
def get_projects(self, **filters: str) -> list[GitlabProject]:
|
|
||||||
ret: list[GitlabProject] = []
|
|
||||||
page = 1
|
|
||||||
while projs := self._get(
|
|
||||||
"/projects",
|
|
||||||
active="true",
|
|
||||||
simple="true",
|
|
||||||
per_page="100",
|
|
||||||
page=str(page),
|
|
||||||
):
|
|
||||||
ret.extend(GitlabProject.model_validate(proj) for proj in projs)
|
|
||||||
page = page + 1
|
|
||||||
if len(projs) < 100:
|
|
||||||
break
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_issues(self, projects: list[GitlabProject]) -> list[GitlabIssue]:
|
|
||||||
ret: list[GitlabIssue] = []
|
|
||||||
pids = {p.id for p in projects}
|
|
||||||
page = 1
|
|
||||||
while True:
|
|
||||||
issues = self._get(
|
|
||||||
"/issues",
|
|
||||||
per_page="100",
|
|
||||||
page=str(page),
|
|
||||||
)
|
|
||||||
ret.extend(
|
|
||||||
GitlabIssue.model_validate(iss) for iss in issues if int(iss["project_id"]) in pids
|
|
||||||
)
|
|
||||||
page = page + 1
|
|
||||||
if len(issues) < 100:
|
|
||||||
break
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_merge_requests(self, projects: list[GitlabProject]) -> list[GitlabMergeRequest]:
|
|
||||||
ret: list[GitlabMergeRequest] = []
|
|
||||||
pids = {p.id for p in projects}
|
|
||||||
page = 1
|
|
||||||
while True:
|
|
||||||
merge_requests = self._get(
|
|
||||||
"/merge_requests",
|
|
||||||
simple="true",
|
|
||||||
per_page="100",
|
|
||||||
page=str(page),
|
|
||||||
)
|
|
||||||
ret.extend(
|
|
||||||
GitlabMergeRequest.model_validate(mr)
|
|
||||||
for mr in merge_requests
|
|
||||||
if int(mr["project_id"]) in pids
|
|
||||||
)
|
|
||||||
page = page + 1
|
|
||||||
if len(merge_requests) < 100:
|
|
||||||
break
|
|
||||||
|
|
||||||
return ret
|
|
||||||
-435
@@ -1,435 +0,0 @@
|
|||||||
from enum import Enum, IntEnum
|
|
||||||
import re
|
|
||||||
|
|
||||||
from lsprotocol.types import (
|
|
||||||
INITIALIZED,
|
|
||||||
TEXT_DOCUMENT_CODE_ACTION,
|
|
||||||
TEXT_DOCUMENT_COMPLETION,
|
|
||||||
TEXT_DOCUMENT_DOCUMENT_SYMBOL,
|
|
||||||
TEXT_DOCUMENT_HOVER,
|
|
||||||
TEXT_DOCUMENT_INLAY_HINT,
|
|
||||||
TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
|
||||||
WORKSPACE_INLAY_HINT_REFRESH,
|
|
||||||
CodeAction,
|
|
||||||
CodeActionKind,
|
|
||||||
CodeActionOptions,
|
|
||||||
CodeActionParams,
|
|
||||||
Command,
|
|
||||||
CompletionItem,
|
|
||||||
CompletionItemKind,
|
|
||||||
CompletionItemLabelDetails,
|
|
||||||
CompletionOptions,
|
|
||||||
CompletionParams,
|
|
||||||
DocumentSymbol,
|
|
||||||
DocumentSymbolParams,
|
|
||||||
Hover,
|
|
||||||
HoverParams,
|
|
||||||
InitializedParams,
|
|
||||||
InlayHint,
|
|
||||||
InlayHintParams,
|
|
||||||
MarkupContent,
|
|
||||||
MarkupKind,
|
|
||||||
NotebookDocumentSyncOptions,
|
|
||||||
Position,
|
|
||||||
Range,
|
|
||||||
SemanticTokens,
|
|
||||||
SemanticTokensLegend,
|
|
||||||
SemanticTokensParams,
|
|
||||||
SymbolKind,
|
|
||||||
TextDocumentSyncKind,
|
|
||||||
WorkDoneProgressBegin,
|
|
||||||
WorkDoneProgressEnd,
|
|
||||||
WorkDoneProgressReport,
|
|
||||||
)
|
|
||||||
from pygls.lsp.server import LanguageServer
|
|
||||||
|
|
||||||
from eta.gitlab import GitlabProject, GitlabSession
|
|
||||||
|
|
||||||
from .clickup import ClickupSession, ClickupTask
|
|
||||||
|
|
||||||
GL_PRJ_PATTERN = r"#project\/(?P<ns>((\w+)/)+)(?P<prj>\w+)"
|
|
||||||
GL_ID_PATTERN = r"#(?P<idt>mr|issue)\/(?P<sid>\d+)"
|
|
||||||
CU_PATTERN = r"#task/(?P<id>\w{8,})"
|
|
||||||
|
|
||||||
|
|
||||||
class CustomServer(LanguageServer):
|
|
||||||
cu_cache: dict[str, ClickupTask]
|
|
||||||
cu_session: ClickupSession
|
|
||||||
|
|
||||||
gl_cache: dict[str, GitlabProject]
|
|
||||||
gl_session: GitlabSession
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
version: str,
|
|
||||||
text_document_sync_kind: TextDocumentSyncKind = TextDocumentSyncKind.Incremental,
|
|
||||||
notebook_document_sync: NotebookDocumentSyncOptions | None = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(name, version, text_document_sync_kind, notebook_document_sync)
|
|
||||||
self.cu_cache = {}
|
|
||||||
self.cu_session = ClickupSession()
|
|
||||||
self.gl_cache = {}
|
|
||||||
self.gl_session = GitlabSession()
|
|
||||||
|
|
||||||
async def update_task_cache(self) -> None:
|
|
||||||
self.cu_cache = {}
|
|
||||||
tasks = self.cu_session.get_tasks()
|
|
||||||
for ti, t in enumerate(tasks):
|
|
||||||
self.cu_cache[t.id] = t
|
|
||||||
self.protocol.progress.report(
|
|
||||||
"startup",
|
|
||||||
WorkDoneProgressReport(
|
|
||||||
message="ClickUp Tasks", percentage=int(100 * (1 + ti) / len(tasks))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
async def update_proj_cache(self) -> None:
|
|
||||||
self.gl_cache = {}
|
|
||||||
projs = self.gl_session.get_projects()
|
|
||||||
for pi, p in enumerate(projs):
|
|
||||||
self.gl_cache[p.path_with_namespace] = p
|
|
||||||
self.protocol.progress.report(
|
|
||||||
"startup",
|
|
||||||
WorkDoneProgressReport(
|
|
||||||
message="Gitlab Prjects", percentage=int(100 * (1 + pi) / len(projs))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.update_issue_cache(projs)
|
|
||||||
await self.update_mr_cache(projs)
|
|
||||||
|
|
||||||
async def update_issue_cache(self, prjs: list[GitlabProject]) -> None:
|
|
||||||
p_by_id = {p.id: p for p in prjs}
|
|
||||||
issues = self.gl_session.get_issues(prjs)
|
|
||||||
for issue in issues:
|
|
||||||
self.gl_cache[p_by_id[issue.project_id].path_with_namespace].issues.append(issue)
|
|
||||||
|
|
||||||
async def update_mr_cache(self, prjs: list[GitlabProject]) -> None:
|
|
||||||
p_by_id = {p.id: p for p in prjs}
|
|
||||||
mrs = self.gl_session.get_merge_requests(prjs)
|
|
||||||
for mr in mrs:
|
|
||||||
self.gl_cache[p_by_id[mr.project_id].path_with_namespace].merge_requests.append(mr)
|
|
||||||
|
|
||||||
|
|
||||||
server = CustomServer("eta-server", "0.1.0")
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(INITIALIZED)
|
|
||||||
async def on_init(params: InitializedParams) -> None:
|
|
||||||
server.protocol.progress.begin(
|
|
||||||
"startup", WorkDoneProgressBegin("Caching ", percentage=0, cancellable=True)
|
|
||||||
)
|
|
||||||
await server.update_task_cache()
|
|
||||||
await server.update_proj_cache()
|
|
||||||
server.protocol.progress.end("startup", WorkDoneProgressEnd(message="Done Caching"))
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(TEXT_DOCUMENT_DOCUMENT_SYMBOL)
|
|
||||||
async def list_ids(params: DocumentSymbolParams) -> list[DocumentSymbol]:
|
|
||||||
return [
|
|
||||||
DocumentSymbol(
|
|
||||||
t.id,
|
|
||||||
SymbolKind.Enum,
|
|
||||||
Range(Position(i, 0), Position(i, 0)),
|
|
||||||
Range(Position(i, 0), Position(i, 0)),
|
|
||||||
detail=t.name,
|
|
||||||
)
|
|
||||||
for i, t in enumerate(server.cu_cache.values())
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(TEXT_DOCUMENT_COMPLETION, CompletionOptions(trigger_characters=["/", "!", "#"]))
|
|
||||||
async def complete_cu_ids(params: CompletionParams) -> list[CompletionItem]:
|
|
||||||
doc = server.workspace.get_text_document(params.text_document.uri)
|
|
||||||
line = doc.lines[params.position.line]
|
|
||||||
|
|
||||||
if not line[: params.position.character].strip().endswith(("/", "!", "#")):
|
|
||||||
return []
|
|
||||||
|
|
||||||
prev = (
|
|
||||||
line[: params.position.character]
|
|
||||||
.strip()
|
|
||||||
.removesuffix("/")
|
|
||||||
.removesuffix("!")
|
|
||||||
.removesuffix("#")
|
|
||||||
.split("#")[-1]
|
|
||||||
)
|
|
||||||
if prev.endswith(("task", "cu", "clickup")):
|
|
||||||
return [
|
|
||||||
CompletionItem(
|
|
||||||
f"{t.name}",
|
|
||||||
CompletionItemLabelDetails(detail=f" #{t.id}"),
|
|
||||||
kind=CompletionItemKind.Constant,
|
|
||||||
insert_text=f"{t.id}",
|
|
||||||
)
|
|
||||||
for t in server.cu_cache.values()
|
|
||||||
]
|
|
||||||
if prev.endswith(("project", "gitlab", "gl")):
|
|
||||||
return [
|
|
||||||
CompletionItem(
|
|
||||||
p.path_with_namespace,
|
|
||||||
detail=f" {p.path_with_namespace}",
|
|
||||||
kind=CompletionItemKind.Enum,
|
|
||||||
)
|
|
||||||
for p in server.gl_cache.values()
|
|
||||||
]
|
|
||||||
|
|
||||||
prj = next(re.finditer(GL_PRJ_PATTERN, line), None)
|
|
||||||
if prj is None:
|
|
||||||
return [
|
|
||||||
CompletionItem(
|
|
||||||
f"{line}: {prj}",
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
if prev.endswith("issue"):
|
|
||||||
return [
|
|
||||||
CompletionItem(
|
|
||||||
i.title,
|
|
||||||
insert_text=f"{i.iid}",
|
|
||||||
detail=f"#{i.iid}: {i.title} {' '.join('[' + t + ']' for t in i.labels)}",
|
|
||||||
documentation=i.description,
|
|
||||||
kind=CompletionItemKind.EnumMember,
|
|
||||||
)
|
|
||||||
for p in server.gl_cache.values()
|
|
||||||
for i in p.issues
|
|
||||||
if i.state == "opened"
|
|
||||||
and p.path_with_namespace == f"{prj.group('ns')}{prj.group('prj')}"
|
|
||||||
]
|
|
||||||
|
|
||||||
if prev.endswith("mr"):
|
|
||||||
return [
|
|
||||||
CompletionItem(
|
|
||||||
f"!{m.title} ({p.path_with_namespace}!{m.iid})",
|
|
||||||
insert_text=f"{m.iid}",
|
|
||||||
detail=f"!{m.iid}: {m.title} {' '.join('[' + t + ']' for t in m.labels)}",
|
|
||||||
documentation=m.description,
|
|
||||||
kind=CompletionItemKind.EnumMember,
|
|
||||||
)
|
|
||||||
for p in server.gl_cache.values()
|
|
||||||
for m in p.merge_requests
|
|
||||||
if m.state == "opened"
|
|
||||||
and p.path_with_namespace.casefold()
|
|
||||||
== f"{prj.group('ns')}{prj.group('prj')}".casefold()
|
|
||||||
]
|
|
||||||
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(TEXT_DOCUMENT_INLAY_HINT)
|
|
||||||
async def inlay_info(params: InlayHintParams) -> list[InlayHint]:
|
|
||||||
ret: list[InlayHint] = []
|
|
||||||
for lid, line in enumerate(server.workspace.text_documents[params.text_document.uri].lines):
|
|
||||||
# for m in re.finditer(GL_PATTERN, line):
|
|
||||||
# ns = m.group("ns")
|
|
||||||
# prj = m.group("prj")
|
|
||||||
# idt = m.group("styp")
|
|
||||||
# id = m.group("sid")
|
|
||||||
#
|
|
||||||
# if p := server.gl_cache.get(f"{ns}{prj}"):
|
|
||||||
# if not idt:
|
|
||||||
# pass
|
|
||||||
# elif idt == "!" and (mr := next(m for m in p.merge_requests if str(m.iid) == id)):
|
|
||||||
# ret.append(
|
|
||||||
# InlayHint(
|
|
||||||
# Position(line=lid, character=m.end()),
|
|
||||||
# label=f"({mr.title} | {mr.state})",
|
|
||||||
# padding_right=True,
|
|
||||||
# padding_left=True,
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
# elif idt == "#" and (issue := next(i for i in p.issues if str(i.iid) == id)):
|
|
||||||
# ret.append(
|
|
||||||
# InlayHint(
|
|
||||||
# Position(line=lid, character=m.end()),
|
|
||||||
# label=f"({issue.title} | {issue.state})",
|
|
||||||
# padding_right=True,
|
|
||||||
# padding_left=True,
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
for m in re.finditer(CU_PATTERN, line):
|
|
||||||
id = m.group(1)
|
|
||||||
if t := server.cu_cache.get(id):
|
|
||||||
ret.append(
|
|
||||||
InlayHint(
|
|
||||||
Position(line=lid, character=m.start()),
|
|
||||||
label=f"{t.status.status_symbol}",
|
|
||||||
padding_left=False,
|
|
||||||
padding_right=False,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
ret.append(
|
|
||||||
InlayHint(
|
|
||||||
Position(line=lid, character=m.end()),
|
|
||||||
label=f"{t.name}",
|
|
||||||
padding_left=True,
|
|
||||||
padding_right=False,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
@server.command("recache_gl")
|
|
||||||
async def recache_gl(*_) -> None:
|
|
||||||
await server.update_proj_cache()
|
|
||||||
await server.protocol.send_request_async(WORKSPACE_INLAY_HINT_REFRESH, None)
|
|
||||||
|
|
||||||
|
|
||||||
@server.command("recache_cu")
|
|
||||||
async def recache_cu(*_) -> None:
|
|
||||||
await server.update_task_cache()
|
|
||||||
await server.protocol.send_request_async(WORKSPACE_INLAY_HINT_REFRESH, None)
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(
|
|
||||||
TEXT_DOCUMENT_CODE_ACTION,
|
|
||||||
CodeActionOptions(code_action_kinds=[CodeActionKind.QuickFix]),
|
|
||||||
)
|
|
||||||
def code_actions(params: CodeActionParams) -> list[CodeAction]:
|
|
||||||
return [
|
|
||||||
CodeAction(
|
|
||||||
"Re-Cache GitLab Project Info",
|
|
||||||
kind=CodeActionKind.QuickFix,
|
|
||||||
command=Command("recache gl", "recache_gl"),
|
|
||||||
),
|
|
||||||
CodeAction(
|
|
||||||
"Re-Cache ClickUp Task Info",
|
|
||||||
kind=CodeActionKind.QuickFix,
|
|
||||||
command=Command("recache cu", "recache_cu"),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(TEXT_DOCUMENT_HOVER)
|
|
||||||
def on_hover(params: HoverParams) -> Hover | None:
|
|
||||||
doc = server.workspace.get_text_document(params.text_document.uri)
|
|
||||||
line = doc.lines[params.position.line]
|
|
||||||
|
|
||||||
# prj_match = list(re.finditer(GL_PRJ_PATTERN, line))[0]
|
|
||||||
# ns = prj_match.group("ns")
|
|
||||||
# prj = prj_match.group("prj")
|
|
||||||
# id_match = list(re.finditer(GL_ID_PATTERN, line))
|
|
||||||
#
|
|
||||||
# if p := server.gl_cache.get(f"{ns}{prj}"):
|
|
||||||
# for m in id_match:
|
|
||||||
# if params.position.character >= m.start() and params.position.character < m.end():
|
|
||||||
# idt = m.group("idt")
|
|
||||||
# id = m.group("sid")
|
|
||||||
#
|
|
||||||
# if not idt:
|
|
||||||
# pass
|
|
||||||
# elif idt == "mr" and (mr := next(m for m in p.merge_requests if str(m.iid) == id)):
|
|
||||||
# return Hover(
|
|
||||||
# MarkupContent(
|
|
||||||
# kind=MarkupKind.Markdown,
|
|
||||||
# value=f"# {mr.title}\n\n{mr.description or ''}",
|
|
||||||
# ),
|
|
||||||
# range=Range(
|
|
||||||
# Position(line=params.position.line, character=m.start()),
|
|
||||||
# Position(line=params.position.line, character=m.end()),
|
|
||||||
# ),
|
|
||||||
# )
|
|
||||||
# elif idt == "issue" and (issue := next(i for i in p.issues if str(i.iid) == id)):
|
|
||||||
# return Hover(
|
|
||||||
# MarkupContent(
|
|
||||||
# kind=MarkupKind.Markdown,
|
|
||||||
# value=f"# {issue.title}\n\n{issue.description or ''}",
|
|
||||||
# ),
|
|
||||||
# range=Range(
|
|
||||||
# Position(line=params.position.line, character=m.start()),
|
|
||||||
# Position(line=params.position.line, character=m.end()),
|
|
||||||
# ),
|
|
||||||
# )
|
|
||||||
|
|
||||||
for m in re.finditer(CU_PATTERN, line):
|
|
||||||
if params.position.character >= m.start() and params.position.character < m.end():
|
|
||||||
id = m.group("id")
|
|
||||||
|
|
||||||
if t := server.cu_cache.get(id):
|
|
||||||
return Hover(
|
|
||||||
MarkupContent(
|
|
||||||
kind=MarkupKind.Markdown,
|
|
||||||
value=f"# {t.name} - {t.status.status}\n\n{t.markdown_description}",
|
|
||||||
),
|
|
||||||
range=Range(
|
|
||||||
Position(line=params.position.line, character=m.start()),
|
|
||||||
Position(line=params.position.line, character=m.end()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return Hover(
|
|
||||||
MarkupContent(
|
|
||||||
kind=MarkupKind.Markdown,
|
|
||||||
value=f"# {id}: {m.group(0)}\n\n{list(server.cu_cache)}",
|
|
||||||
),
|
|
||||||
range=Range(
|
|
||||||
Position(line=params.position.line, character=m.start()),
|
|
||||||
Position(line=params.position.line, character=m.end()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def token_offset(rest: list[int], current: tuple[int, int]) -> tuple[int, int]:
|
|
||||||
lines = rest[::5]
|
|
||||||
# offsets = rest[:-4:-5]
|
|
||||||
|
|
||||||
last_line = sum(lines)
|
|
||||||
return (current[0] - last_line, current[1])
|
|
||||||
|
|
||||||
|
|
||||||
class TaskModifiers(Enum):
|
|
||||||
Backlog = "backlog"
|
|
||||||
Selected = "selected for development"
|
|
||||||
Progress = "in progress"
|
|
||||||
Review = "in review"
|
|
||||||
Done = "done"
|
|
||||||
Closed = "closed"
|
|
||||||
|
|
||||||
|
|
||||||
@server.feature(
|
|
||||||
TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
|
||||||
SemanticTokensLegend(["cuTask"], list(t.name for t in TaskModifiers)),
|
|
||||||
)
|
|
||||||
def sem_tokens(params: SemanticTokensParams) -> SemanticTokens:
|
|
||||||
ret: list[int] = []
|
|
||||||
doc = server.workspace.get_text_document(params.text_document.uri)
|
|
||||||
|
|
||||||
for lix, line in enumerate(doc.lines):
|
|
||||||
# ms = re.finditer(GL_PATTERN, line)
|
|
||||||
#
|
|
||||||
# for m in ms:
|
|
||||||
# idt = m.group("styp")
|
|
||||||
# id = m.group("sid")
|
|
||||||
# rel_line, rel_char = token_offset(ret, (lix, m.start()))
|
|
||||||
#
|
|
||||||
# if not idt:
|
|
||||||
# ret.extend([rel_line, rel_char, len(m.group(0)), 0, 0])
|
|
||||||
# elif idt == "!":
|
|
||||||
# ret.extend([rel_line, rel_char, len(m.group(0)), 2, 0])
|
|
||||||
# elif idt == "#":
|
|
||||||
# ret.extend([rel_line, rel_char, len(m.group(0)), 2, 0])
|
|
||||||
|
|
||||||
for m in re.finditer(CU_PATTERN, line):
|
|
||||||
id = m.group("id")
|
|
||||||
rel_line, rel_char = token_offset(ret, (lix, m.start()))
|
|
||||||
|
|
||||||
if t := server.cu_cache.get(id):
|
|
||||||
ret.extend(
|
|
||||||
[
|
|
||||||
rel_line,
|
|
||||||
rel_char,
|
|
||||||
len(m.group(0)),
|
|
||||||
0,
|
|
||||||
list(t.value for t in TaskModifiers).index(t.status.status),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
return SemanticTokens(data=ret)
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
server.start_io()
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
local curl = require("plenary.curl")
|
|
||||||
local helpers = require("eta.helpers")
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
---@class eta.clickup.Session: eta.Session
|
|
||||||
---@field user string
|
|
||||||
---@field workspace string
|
|
||||||
---@field default_reviewer string
|
|
||||||
|
|
||||||
---@class eta.clickup.Ref
|
|
||||||
---@field name string
|
|
||||||
---@field id string
|
|
||||||
|
|
||||||
---@class eta.clickup.Dep
|
|
||||||
---@field task_id string
|
|
||||||
---@field depends_on string
|
|
||||||
|
|
||||||
---@class eta.clickup.Task
|
|
||||||
---@field id string
|
|
||||||
---@field name string
|
|
||||||
---@field tags? table[]
|
|
||||||
---@field locations? table[]
|
|
||||||
---@field list? eta.clickup.Ref
|
|
||||||
---@field parent? string | nil
|
|
||||||
---@field dependencies? eta.clickup.Dep[]
|
|
||||||
---@field [string] string
|
|
||||||
|
|
||||||
---@param self eta.clickup.Session
|
|
||||||
---@return eta.clickup.Task[]
|
|
||||||
M.latest_tasks = function(self)
|
|
||||||
local ret = helpers.request("get", self, "/team/" .. self.workspace .. "/task",
|
|
||||||
{ subtasks = "true", include_markdown_description = "true", ['assignees[]'] = self.user })
|
|
||||||
if ret then
|
|
||||||
return ret.tasks
|
|
||||||
end
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.clickup.Session
|
|
||||||
---@param id string
|
|
||||||
---@return eta.clickup.Task
|
|
||||||
M.task = function(self, id)
|
|
||||||
local ret = helpers.request("get", self, "/task/" .. id, { include_markdown_description = "true" }) or {}
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.clickup.Session
|
|
||||||
---@param id string
|
|
||||||
M.task_relations = function(self, id)
|
|
||||||
local ret = helpers.request("get", self, "/task/" .. id .. "/dependency", {}) or {}
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
M.insert_ref = function()
|
|
||||||
local pos = vim.api.nvim_win_get_cursor(0)
|
|
||||||
local row = pos[1] - 1
|
|
||||||
local col = pos[2]
|
|
||||||
local tasks = M.latest_tasks(require("plugin.eta").clickup_session)
|
|
||||||
|
|
||||||
---@type SelectionItem[]
|
|
||||||
local items = {}
|
|
||||||
|
|
||||||
for tix, t in ipairs(tasks) do
|
|
||||||
if string.sub(t.name, -7, -1) ~= "Absence" then
|
|
||||||
local preview_frontmatter = ""
|
|
||||||
|
|
||||||
---@type SelectionItem
|
|
||||||
local prepared = {
|
|
||||||
idx = tix,
|
|
||||||
id = t.id,
|
|
||||||
text = t.name .. t.id .. t.markdown_description,
|
|
||||||
name = t.name,
|
|
||||||
tags = require("plugin.eta").retrieve_subkeys(t.tags, { "name" }),
|
|
||||||
status = t.status.status,
|
|
||||||
parent = t.parent,
|
|
||||||
list = t.list.name,
|
|
||||||
description = t.markdown_description,
|
|
||||||
preview = {
|
|
||||||
ft = "markdown",
|
|
||||||
},
|
|
||||||
action = M._on_select_task
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k in ipairs({ "id", "name", "status", "tags", "parent" }) do
|
|
||||||
preview_frontmatter = preview_frontmatter .. "\n" .. k .. ": " .. vim.json.encode(prepared[k])
|
|
||||||
end
|
|
||||||
|
|
||||||
prepared.preview.text = "---" .. preview_frontmatter .. "\n---\n" .. t.markdown_description
|
|
||||||
table.insert(items, #items + 1, prepared)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
require("snacks.picker").pick({
|
|
||||||
title = "Select Task",
|
|
||||||
format = require("plugin.eta")._item_format,
|
|
||||||
preview = "preview",
|
|
||||||
confirm = function(picker, item)
|
|
||||||
picker:close()
|
|
||||||
vim.api.nvim_buf_set_text(0, row, col, row, col,
|
|
||||||
{ "[#" .. item.id .. "](https://app.clickup.com/t/" .. item.id .. ")" })
|
|
||||||
end,
|
|
||||||
items = items
|
|
||||||
})
|
|
||||||
end
|
|
||||||
return M
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
local notify = require("snacks.notifier").notify
|
|
||||||
local helpers = require("eta.helpers")
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
---@class eta.gitlab.Session: eta.Session
|
|
||||||
---@field auth string personal access token `PRIVATE_TOKEN: <auth_token>`
|
|
||||||
|
|
||||||
---@class eta.gitlab.Namespace
|
|
||||||
---@field full_path string
|
|
||||||
|
|
||||||
---@class eta.gitlab.Project
|
|
||||||
---@field id number
|
|
||||||
---@field name string
|
|
||||||
---@field path_with_namespace string
|
|
||||||
---@field tag_list string[]
|
|
||||||
---@field text? string
|
|
||||||
---@field namespace eta.gitlab.Namespace
|
|
||||||
---@field preview? {ft: string, text: string}
|
|
||||||
|
|
||||||
---@class eta.gitlab.Milestone
|
|
||||||
---@field id number
|
|
||||||
---@field title string
|
|
||||||
|
|
||||||
---@class eta.gitlab.Assignee
|
|
||||||
---@field username string
|
|
||||||
---@field id number
|
|
||||||
|
|
||||||
---@class eta.gitlab.Issue
|
|
||||||
---@field id number
|
|
||||||
---@field milestone eta.gitlab.Milestone
|
|
||||||
---@field title string
|
|
||||||
---@field assignees eta.gitlab.Assignee[]
|
|
||||||
---@field description string
|
|
||||||
---@field labels string[]
|
|
||||||
|
|
||||||
|
|
||||||
---@param session eta.gitlab.Session
|
|
||||||
---@return eta.gitlab.Project[]
|
|
||||||
M.possible_projects = function(session)
|
|
||||||
return helpers.request("get", session, "/projects", {simple="true", per_page="100"}) or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param prj eta.gitlab.Project
|
|
||||||
M._project_format = function(prj)
|
|
||||||
local ret = {}
|
|
||||||
|
|
||||||
ret[#ret + 1] = { prj.namespace.full_path .. "/", "SnacksPickerComment" }
|
|
||||||
ret[#ret + 1] = { prj.name }
|
|
||||||
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.gitlab.Session
|
|
||||||
---@return eta.gitlab.Project | nil
|
|
||||||
M.update_current_project = function(self)
|
|
||||||
local cmd = "git remote -v | grep fetch | cut -f2 | cut -d' ' -f1 | cut -d':' -f2"
|
|
||||||
local handle, _ = io.popen(cmd, 'r')
|
|
||||||
if not handle then return nil end
|
|
||||||
local repo = handle:read("*a")
|
|
||||||
handle:close()
|
|
||||||
|
|
||||||
local prjs = M.possible_projects(self)
|
|
||||||
for _, prj in ipairs(prjs) do
|
|
||||||
if prj.path_with_namespace == repo then
|
|
||||||
M.active_project = prj
|
|
||||||
notify("selected " .. prj.path_with_namespace, "info", { title = "ETA", style = 'fancy' })
|
|
||||||
return prj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@type eta.gitlab.Project
|
|
||||||
M.active_project = nil
|
|
||||||
|
|
||||||
---@param picker snacks.Picker
|
|
||||||
---@param item eta.gitlab.Project
|
|
||||||
M._on_project_select = function(picker, item)
|
|
||||||
M.active_project = item
|
|
||||||
picker:close()
|
|
||||||
notify("selected " .. item.path_with_namespace, "info", { title = "ETA", style = 'fancy' })
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.gitlab.Session
|
|
||||||
M.select_project = function(self)
|
|
||||||
local prjs = M.possible_projects(self)
|
|
||||||
require("snacks.picker").pick({
|
|
||||||
title = "Select Project",
|
|
||||||
format = M._project_format,
|
|
||||||
preview = "preview",
|
|
||||||
confirm = M._on_project_select,
|
|
||||||
items = prjs
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.gitlab.Session
|
|
||||||
---@return eta.gitlab.Issue[]
|
|
||||||
M.active_issues = function(self)
|
|
||||||
if not M.active_project then
|
|
||||||
if not M.update_current_project(self) then
|
|
||||||
M.select_project(self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return request("get", self, "/projects/" .. tostring(M.active_project.id) .. "/issues", {})
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.gitlab.Session
|
|
||||||
---@param name string
|
|
||||||
---@param clickup_task_id string
|
|
||||||
---@param tags string[]
|
|
||||||
M.new_issue = function(self, name, clickup_task_id, tags)
|
|
||||||
if not M.active_project then
|
|
||||||
if not M.update_current_project(self) then
|
|
||||||
M.select_project(self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local description = "%23" .. clickup_task_id
|
|
||||||
local title = name:gsub("%s", "%20")
|
|
||||||
|
|
||||||
return request("post", self, "/projects/" ..
|
|
||||||
tostring(M.active_project.id) ..
|
|
||||||
"/issues", {
|
|
||||||
title=title, description=description, labels=table.concat(tags, ",")
|
|
||||||
})
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param self eta.gitlab.Session
|
|
||||||
---@param name string
|
|
||||||
---@param issue number
|
|
||||||
---@param clickup_task_id string
|
|
||||||
---@param tags string[]
|
|
||||||
M.new_mr = function(self, name, issue, clickup_task_id, tags)
|
|
||||||
if not M.active_project then
|
|
||||||
if not M.update_current_project(self) then
|
|
||||||
M.select_project(self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local description = "Closes %23" .. tostring(issue) .. " | %23" .. clickup_task_id
|
|
||||||
local title = name:gsub("%s", "%20")
|
|
||||||
|
|
||||||
return request("post", self, "/projects/" .. tostring(M.active_project.id) .. "/merge_requests", {
|
|
||||||
title=title, description=description, labels=table.concat(tags, ",")
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
local curl = require("plenary.curl")
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
---@class eta.Session
|
|
||||||
---@field auth string
|
|
||||||
---@field base_url string
|
|
||||||
|
|
||||||
---@param method `get` | `post`
|
|
||||||
---@param session eta.Session
|
|
||||||
---@param endpoint string
|
|
||||||
---@param params {[string]: string}
|
|
||||||
---@returns table | nil
|
|
||||||
M.request = function(method, session, endpoint, params)
|
|
||||||
local url = session.base_url .. endpoint
|
|
||||||
local resp = nil
|
|
||||||
if method == "get" then
|
|
||||||
local param_list = {}
|
|
||||||
for param_name, param_value in pairs(params) do
|
|
||||||
table.insert(param_list, param_name .. "=" .. param_value)
|
|
||||||
end
|
|
||||||
if #param_list then
|
|
||||||
url = url .. "?" .. table.concat(param_list, "&")
|
|
||||||
end
|
|
||||||
resp = curl.get(url, {
|
|
||||||
headers = {
|
|
||||||
-- ['PRIVATE-TOKEN'] = session.auth,
|
|
||||||
['Authorization'] = session.auth,
|
|
||||||
["content-type"] = "application/json",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
elseif method == "post" then
|
|
||||||
resp = curl.post(url, {
|
|
||||||
headers = {
|
|
||||||
-- ['PRIVATE-TOKEN'] = session.auth,
|
|
||||||
['Authorization'] = session.auth,
|
|
||||||
["content-type"] = "application/json",
|
|
||||||
},
|
|
||||||
body = vim.json.encode(params)
|
|
||||||
})
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if resp.status == 200 then
|
|
||||||
local prjs = vim.json.decode(resp.body)
|
|
||||||
for _, prj in ipairs(prjs) do
|
|
||||||
local fcmd = "echo '" .. vim.json.encode(prj) .. "' | jq"
|
|
||||||
local fhandle, _ = io.popen(fcmd, 'r')
|
|
||||||
if not fhandle then goto continue end
|
|
||||||
local formatted = fhandle:read("*a")
|
|
||||||
fhandle:close()
|
|
||||||
|
|
||||||
prj.text = prj.path_with_namespace
|
|
||||||
prj.preview = {
|
|
||||||
ft = "json",
|
|
||||||
text = formatted
|
|
||||||
}
|
|
||||||
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
return prjs
|
|
||||||
end
|
|
||||||
|
|
||||||
error("failed http request: " .. tostring(resp.status) .. " (" .. resp.body .. ", " .. url .. ")")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- @param str string
|
|
||||||
--- @param char? string defaults to " "
|
|
||||||
--- @return string[]
|
|
||||||
M.split = function(str, char)
|
|
||||||
char = char or " "
|
|
||||||
--- @type string[]
|
|
||||||
local ret = {}
|
|
||||||
for part in str:gmatch("[^" .. char .. "]+") do
|
|
||||||
table.insert(ret, part)
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
local curl = require("plenary.curl")
|
|
||||||
local notifier = require("snacks.notifier")
|
|
||||||
local notify = require("snacks.notifier").notify
|
|
||||||
local gitlab = require("eta.gitlab")
|
|
||||||
local clickup = require("eta.clickup")
|
|
||||||
local helpers = require("eta.helpers")
|
|
||||||
local nio = require("nio")
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
---@param data table
|
|
||||||
---@return string | nil
|
|
||||||
M.table_to_yaml = function(data)
|
|
||||||
local json = vim.json.encode(data)
|
|
||||||
|
|
||||||
-- Nutzt 'yq' um JSON zu YAML zu konvertieren
|
|
||||||
local handle = io.popen("echo '" .. json .. "' | yq -y")
|
|
||||||
local result = handle:read("*a")
|
|
||||||
handle:close()
|
|
||||||
|
|
||||||
if not result then
|
|
||||||
print("Error: yq not installed or got invalid json data")
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param yaml_string string
|
|
||||||
---@return table | nil
|
|
||||||
M.yaml_to_table = function(yaml_string)
|
|
||||||
-- 1. YAML String in yq einspeisen und JSON ausgeben lassen
|
|
||||||
-- Das Flag -o=json sorgt für die Konvertierung
|
|
||||||
local temp_file = os.tmpname()
|
|
||||||
local temp_file_handle = io.open(temp_file, "w+b")
|
|
||||||
if not temp_file_handle then
|
|
||||||
print("Error: could not open temp file")
|
|
||||||
print(" temp_file: " .. temp_file)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
temp_file_handle:write(yaml_string)
|
|
||||||
temp_file_handle:flush()
|
|
||||||
temp_file_handle:close()
|
|
||||||
|
|
||||||
local cmd = "cat " .. temp_file .. " | yq"
|
|
||||||
local handle, errres = io.popen(cmd, 'r')
|
|
||||||
local json_result = handle:read("*a")
|
|
||||||
handle:close()
|
|
||||||
|
|
||||||
|
|
||||||
-- 2. Fehlerprüfung
|
|
||||||
if json_result == "" then
|
|
||||||
print("Error: yq not installed or got invalid yaml data")
|
|
||||||
print(" cmd: " .. cmd)
|
|
||||||
print(" err: " .. errres)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 3. JSON in Lua-Table umwandeln
|
|
||||||
local ok, table_result = pcall(vim.json.decode, json_result)
|
|
||||||
if not ok then
|
|
||||||
print("Error: failed to decode json")
|
|
||||||
print(" cmd: " .. cmd)
|
|
||||||
print(" json: " .. json_result)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
os.remove(temp_file)
|
|
||||||
return table_result
|
|
||||||
end
|
|
||||||
|
|
||||||
---@type eta.clickup.Session
|
|
||||||
M.clickup_session = nil
|
|
||||||
|
|
||||||
---@type eta.gitlab.Session
|
|
||||||
M.gitlab_session = nil
|
|
||||||
|
|
||||||
|
|
||||||
---@param task eta.clickup.Task
|
|
||||||
---@return eta.clickup.Task
|
|
||||||
M._update_task = function(task)
|
|
||||||
local update_table = {}
|
|
||||||
|
|
||||||
for _, k in ipairs({ "name", "markdown_content", "status" }) do
|
|
||||||
if task[k] then
|
|
||||||
update_table[k] = task[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local last_task = clickup.task(M.clickup_session, task.id)
|
|
||||||
|
|
||||||
if task.status == "in review" and last_task.status.status == "in progress" then
|
|
||||||
local resp = curl.post(M.clickup_session.base_url .. "/task/" .. task.id .. "/comment", {
|
|
||||||
headers = {
|
|
||||||
['Authorization'] = M.clickup_session.auth,
|
|
||||||
["accept"] = "application/json",
|
|
||||||
["content-type"] = "application/json",
|
|
||||||
},
|
|
||||||
body = vim.json.encode({
|
|
||||||
comment_text = "pls review",
|
|
||||||
assignee = M.clickup_session.default_reviewer,
|
|
||||||
notify_all = "false",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if resp.status ~= 200 then
|
|
||||||
error("failed to comment " .. task.id .. "\n(" .. resp.body .. ")")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local resp = curl.put(M.clickup_session.base_url .. "/task/" .. task.id, {
|
|
||||||
headers = {
|
|
||||||
['Authorization'] = M.clickup_session.auth,
|
|
||||||
["accept"] = "application/json",
|
|
||||||
["content-type"] = "application/json",
|
|
||||||
},
|
|
||||||
body = vim.json.encode(update_table)
|
|
||||||
})
|
|
||||||
|
|
||||||
if resp.status ~= 200 then
|
|
||||||
error("failed to update " .. task.id .. "\n(" .. resp.body .. ")")
|
|
||||||
end
|
|
||||||
|
|
||||||
return vim.json.decode(resp.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param args vim.api.keyset.create_autocmd.callback_args
|
|
||||||
M._on_tempbuf_write = function(args)
|
|
||||||
local lines = vim.api.nvim_buf_get_lines(args.buf, 0, -1, false)
|
|
||||||
---@type string[]
|
|
||||||
local parts = {}
|
|
||||||
---@type string[]
|
|
||||||
local current = {}
|
|
||||||
for _, line in ipairs(lines) do
|
|
||||||
if line == "---" then
|
|
||||||
if #current then
|
|
||||||
table.insert(parts, table.concat(current, "\n"))
|
|
||||||
current = {}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
table.insert(current, line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(parts, table.concat(current, "\n"))
|
|
||||||
|
|
||||||
---@type eta.clickup.Task
|
|
||||||
local data = M.yaml_to_table(parts[2]) or {}
|
|
||||||
|
|
||||||
data['markdown_content'] = string.gsub(parts[3], "%-%-%-\n", "")
|
|
||||||
|
|
||||||
M._update_task(data)
|
|
||||||
|
|
||||||
vim.api.nvim_set_option_value("modified", false, { buf = args.buf })
|
|
||||||
local notif_id = notify("updated task #" .. data.id, "info", { title = "ETA", style = 'fancy' })
|
|
||||||
end
|
|
||||||
|
|
||||||
---@class SelectionItem
|
|
||||||
---@field status string
|
|
||||||
---@field parent string | nil
|
|
||||||
---@field list string
|
|
||||||
---@field name string
|
|
||||||
---@field description string
|
|
||||||
---@field tags string[]
|
|
||||||
---@field id string
|
|
||||||
|
|
||||||
---@param picker snacks.Picker | nil
|
|
||||||
---@param item SelectionItem
|
|
||||||
M._on_select_task = function(picker, item)
|
|
||||||
local notif_id = notify("opening task #" .. item.id, "info", { title = "ETA", style = 'fancy' })
|
|
||||||
local new_name = "[ClickUp] " .. item.name
|
|
||||||
local new_buf_no = vim.api.nvim_create_buf(true, false)
|
|
||||||
|
|
||||||
local status, _ = pcall(vim.api.nvim_buf_set_name, new_buf_no, new_name)
|
|
||||||
if status then
|
|
||||||
-- vim.api.nvim_set_option_value("buftype", "nofile", { buf = new_buf_no })
|
|
||||||
vim.api.nvim_set_option_value("filetype", "markdown", { buf = new_buf_no })
|
|
||||||
vim.api.nvim_create_autocmd({ "BufWriteCmd" }, { buffer = new_buf_no, callback = M._on_tempbuf_write })
|
|
||||||
local content = { "---" }
|
|
||||||
local to_dump = {}
|
|
||||||
for _, k in ipairs({ "id", "name", "status", "tags", "list", "parent", "dependencies" }) do
|
|
||||||
to_dump[k] = item[k]
|
|
||||||
end
|
|
||||||
local yaml_string = M.table_to_yaml(to_dump) or ""
|
|
||||||
for line in yaml_string:gmatch("([^\n]*)\n?") do
|
|
||||||
table.insert(content, line)
|
|
||||||
end
|
|
||||||
-- table.insert(content, "}")
|
|
||||||
table.insert(content, "---")
|
|
||||||
for line in string.gmatch(item.description, "[^\r\n]+") do
|
|
||||||
table.insert(content, line)
|
|
||||||
end
|
|
||||||
vim.api.nvim_buf_set_lines(new_buf_no, 0, 0, false, content)
|
|
||||||
vim.api.nvim_set_option_value("modified", false, { buf = new_buf_no })
|
|
||||||
vim.api.nvim_win_set_buf(0, new_buf_no)
|
|
||||||
else
|
|
||||||
vim.api.nvim_buf_delete(new_buf_no, {})
|
|
||||||
if picker then
|
|
||||||
picker:close()
|
|
||||||
end
|
|
||||||
local to_open = vim.fn.bufnr(new_name)
|
|
||||||
vim.api.nvim_win_set_buf(0, to_open)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param item SelectionItem
|
|
||||||
M._item_format = function(item, _)
|
|
||||||
local ret = {}
|
|
||||||
|
|
||||||
local hl = "SnacksPickerComment"
|
|
||||||
if item.status == "in progress" then
|
|
||||||
hl = "@method"
|
|
||||||
elseif item.status == "selected for development" then
|
|
||||||
hl = "@constant.builtin"
|
|
||||||
elseif item.status == "in review" then
|
|
||||||
hl = "@keyword"
|
|
||||||
elseif item.status == "done" then
|
|
||||||
hl = "@variable.builtin"
|
|
||||||
end
|
|
||||||
|
|
||||||
if item.parent ~= vim.NIL then
|
|
||||||
ret[#ret + 1] = { " ", "SnacksPickerComment" }
|
|
||||||
end
|
|
||||||
|
|
||||||
ret[#ret + 1] = { item.name, hl }
|
|
||||||
|
|
||||||
for _, v in ipairs(item.tags) do
|
|
||||||
ret[#ret + 1] = { " #" .. v, "SnacksPickerComment" }
|
|
||||||
end
|
|
||||||
|
|
||||||
ret[#ret + 1] = {
|
|
||||||
" " .. item.id,
|
|
||||||
"SnacksPickerComment"
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param list table[]
|
|
||||||
---@param keys string[]
|
|
||||||
M.retrieve_subkeys = function(list, keys)
|
|
||||||
local ret = {}
|
|
||||||
local interm = list
|
|
||||||
|
|
||||||
for _, key in ipairs(keys) do
|
|
||||||
ret = {}
|
|
||||||
for _, item in ipairs(interm) do
|
|
||||||
table.insert(ret, item[key])
|
|
||||||
end
|
|
||||||
interm = ret
|
|
||||||
end
|
|
||||||
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param id string
|
|
||||||
M.open_task = function(id)
|
|
||||||
if id:match("[a-z0-9]+") then
|
|
||||||
local notif_id = notify("opening #" .. id, "info", { timeout = 1000, title = "ETA", style = 'fancy' })
|
|
||||||
local t = clickup.task(M.clickup_session, id)
|
|
||||||
---@type SelectionItem
|
|
||||||
local item = {
|
|
||||||
idx = nil,
|
|
||||||
id = t.id,
|
|
||||||
text = t.name .. t.id .. t.markdown_description,
|
|
||||||
name = t.name,
|
|
||||||
tags = M.retrieve_subkeys(t.tags, { "name" }),
|
|
||||||
status = t.status.status,
|
|
||||||
parent = t.parent,
|
|
||||||
list = t.list.name,
|
|
||||||
description = t.markdown_description,
|
|
||||||
preview = {
|
|
||||||
ft = "markdown",
|
|
||||||
},
|
|
||||||
action = nil
|
|
||||||
}
|
|
||||||
pcall(M._on_select_task, nil, item)
|
|
||||||
else
|
|
||||||
error("invalid id format")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param data vim.api.keyset.create_user_command.command_args
|
|
||||||
M.select_task = function(data)
|
|
||||||
local notif_id = notify("fetching tasks", "warn", { timeout = 10000, title = "ETA", style = 'fancy' })
|
|
||||||
|
|
||||||
local args = data.fargs
|
|
||||||
|
|
||||||
if args[1] == "start" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not pcall(M.open_task, vim.fn.expand("<cword>")) then
|
|
||||||
---@type SelectionItem[]
|
|
||||||
local items = {}
|
|
||||||
|
|
||||||
local tasks = clickup.latest_tasks(M.clickup_session)
|
|
||||||
|
|
||||||
for tix, t in ipairs(tasks) do
|
|
||||||
if string.sub(t.name, -7, -1) ~= "Absence" then
|
|
||||||
local preview_frontmatter = ""
|
|
||||||
|
|
||||||
local deps = {}
|
|
||||||
for _, dependency in ipairs(t.dependencies) do
|
|
||||||
table.insert(deps, dependency.depends_on)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@type SelectionItem
|
|
||||||
local prepared = {
|
|
||||||
idx = tix,
|
|
||||||
id = t.id,
|
|
||||||
text = t.name .. t.id .. t.markdown_description,
|
|
||||||
name = t.name,
|
|
||||||
tags = M.retrieve_subkeys(t.tags, { "name" }),
|
|
||||||
status = t.status.status,
|
|
||||||
parent = t.parent,
|
|
||||||
list = t.list.name,
|
|
||||||
description = t.markdown_description,
|
|
||||||
dependencies = deps,
|
|
||||||
preview = {
|
|
||||||
ft = "markdown",
|
|
||||||
},
|
|
||||||
action = M._on_select_task
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k in ipairs({ "id", "name", "status", "tags", "parent" }) do
|
|
||||||
preview_frontmatter = preview_frontmatter .. "\n" .. k .. ": " .. vim.json.encode(prepared[k])
|
|
||||||
end
|
|
||||||
|
|
||||||
prepared.preview.text = "---" .. preview_frontmatter .. "\n---\n" .. t.markdown_description
|
|
||||||
table.insert(items, #items + 1, prepared)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
require("snacks.notifier").hide(notif_id)
|
|
||||||
require("snacks.picker").pick({
|
|
||||||
title = "Select Task",
|
|
||||||
format = M._item_format,
|
|
||||||
preview = "preview",
|
|
||||||
confirm = M._on_select_task,
|
|
||||||
items = items
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param data vim.api.keyset.create_user_command.command_args
|
|
||||||
M.mr_from_task = function(data)
|
|
||||||
if data.args then
|
|
||||||
notify(data.args, "info", { title = "ETA" })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
local notify = require("snacks.notifier").notify
|
|
||||||
local helpers = require("eta.helpers")
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
---@class eta.solidtime.Session: eta.Session
|
|
||||||
---@field auth string personal access token in the form of `Bearer <TOKEN>`
|
|
||||||
---@field org string organization id
|
|
||||||
|
|
||||||
---@class eta.solidtime.User
|
|
||||||
---@field name string
|
|
||||||
---@field id string
|
|
||||||
|
|
||||||
---@param session eta.solidtime.Session
|
|
||||||
---@return eta.solidtime.User
|
|
||||||
M.get_user = function(session)
|
|
||||||
return helpers.request(
|
|
||||||
"get",
|
|
||||||
session,
|
|
||||||
"/users/me",
|
|
||||||
{}
|
|
||||||
).data
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param session eta.solidtime.Session
|
|
||||||
---@param task eta.clickup.Task
|
|
||||||
---@param project? string
|
|
||||||
M.start_new = function(session, task, project)
|
|
||||||
local req = helpers.request(
|
|
||||||
"post",
|
|
||||||
session,
|
|
||||||
"/organizations/" .. session.org .. "/time-entries",
|
|
||||||
{
|
|
||||||
billable = false,
|
|
||||||
member_id = M.get_user(session).id,
|
|
||||||
start = os.date("%Y-%m-%dT%H:%M:%SZ")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
-- 1. Map each status to a distinct color, Nerd Font icon, and styling
|
|
||||||
local status_configs = {
|
|
||||||
["backlog"] = { fg = "#7f8c8d", icon = " ", bold = false }, -- Clipboard List
|
|
||||||
["selected for development"] = { fg = "#3498db", icon = " ", bold = false }, -- Target / Bullseye
|
|
||||||
["in progress"] = { fg = "#f1c40f", icon = " ", bold = true }, -- Lightning Bolt
|
|
||||||
["in review"] = { fg = "#9b59b6", icon = " ", bold = true }, -- Eye / Review
|
|
||||||
["on hold"] = { fg = "#e67e22", icon = " ", bold = false }, -- Pause Circle
|
|
||||||
["done"] = { fg = "#2ecc71", icon = " ", bold = true }, -- Checkmark
|
|
||||||
["closed"] = { fg = "#555555", icon = " ", strikethrough = true }, -- Blocked / Minus Circle
|
|
||||||
}
|
|
||||||
|
|
||||||
-- 2. Dynamically build the Neovim Highlight Groups
|
|
||||||
for status, config in pairs(status_configs) do
|
|
||||||
local hl_name = "TaskStatus_" .. status:gsub(" ", "_")
|
|
||||||
vim.api.nvim_set_hl(0, hl_name, {
|
|
||||||
fg = config.fg,
|
|
||||||
bold = config.bold,
|
|
||||||
strikethrough = config.strikethrough
|
|
||||||
})
|
|
||||||
config.hl_group = hl_name
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Subtle gray style for the task title
|
|
||||||
vim.api.nvim_set_hl(0, "TaskTitle", { fg = "#abb2bf", italic = true })
|
|
||||||
|
|
||||||
-- 3. Create a unique namespace
|
|
||||||
local task_hint_ns = vim.api.nvim_create_namespace("custom_task_inlay_hints")
|
|
||||||
|
|
||||||
-- 4. Hijack the native LSP Inlay Hint Renderer
|
|
||||||
local native_inlay_handler = vim.lsp.handlers["textDocument/inlayHint"]
|
|
||||||
|
|
||||||
vim.lsp.handlers["textDocument/inlayHint"] = function(err, result, ctx, config)
|
|
||||||
if err or not result then
|
|
||||||
return native_inlay_handler(err, result, ctx, config)
|
|
||||||
end
|
|
||||||
|
|
||||||
local standard_hints = {}
|
|
||||||
local bufnr = ctx.bufnr or 0
|
|
||||||
|
|
||||||
if vim.api.nvim_buf_is_loaded(bufnr) then
|
|
||||||
vim.api.nvim_buf_clear_namespace(bufnr, task_hint_ns, 0, -1)
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, hint in ipairs(result) do
|
|
||||||
local raw_label = ""
|
|
||||||
if type(hint.label) == "string" then
|
|
||||||
raw_label = hint.label
|
|
||||||
elseif type(hint.label) == "table" then
|
|
||||||
for _, part in ipairs(hint.label) do
|
|
||||||
raw_label = raw_label .. part.value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Match format: [<status>] <title>
|
|
||||||
local status, title = raw_label:match("^%[(.-)%]%s*(.*)$")
|
|
||||||
local norm_status = status and status:lower() or ""
|
|
||||||
|
|
||||||
if status_configs[norm_status] then
|
|
||||||
local cfg = status_configs[norm_status]
|
|
||||||
|
|
||||||
-- Multi-colored array using the clean Nerd Font icons
|
|
||||||
local virtual_text_chunks = {
|
|
||||||
{ " ── ", "Comment" },
|
|
||||||
{ cfg.icon, cfg.hl_group }, -- Nerd Font Symbol
|
|
||||||
{ "[" .. status:upper() .. "] ", cfg.hl_group }, -- Colored Status text
|
|
||||||
{ title, "TaskTitle" } -- Muted task name
|
|
||||||
}
|
|
||||||
|
|
||||||
vim.api.nvim_buf_set_extmark(bufnr, task_hint_ns, hint.position.line, hint.position.character, {
|
|
||||||
virt_text = virtual_text_chunks,
|
|
||||||
virt_text_pos = "inline", -- Swap to "eol" if it disrupts typing alignment
|
|
||||||
})
|
|
||||||
else
|
|
||||||
table.insert(standard_hints, hint)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return native_inlay_handler(err, standard_hints, ctx, config)
|
|
||||||
end
|
|
||||||
-169
@@ -1,169 +0,0 @@
|
|||||||
local eta = require("eta")
|
|
||||||
local eta_clickup = require("eta.clickup")
|
|
||||||
|
|
||||||
vim.api.nvim_create_user_command("ETA", eta.select_task, { nargs = "?" })
|
|
||||||
|
|
||||||
---@type eta.clickup.Session
|
|
||||||
eta.clickup_session = {
|
|
||||||
auth = os.getenv("CLICKUP_AUTH") or "",
|
|
||||||
user = os.getenv("CLICKUP_USER_ID") or "",
|
|
||||||
workspace = os.getenv("CLICKUP_WORKSPACE_ID") or "",
|
|
||||||
base_url = "https://api.clickup.com/api/v2",
|
|
||||||
default_reviewer = os.getenv("CLICKUP_DEFAULT_REVIEWER") or "",
|
|
||||||
}
|
|
||||||
|
|
||||||
---@type eta.gitlab.Session
|
|
||||||
eta.gitlab_session = {
|
|
||||||
auth = os.getenv("GITLAB_AUTH") or "",
|
|
||||||
base_url = "https://git.extoll.de/api/v4",
|
|
||||||
}
|
|
||||||
|
|
||||||
---@type eta.solidtime.Session
|
|
||||||
eta.solidtime_session = {
|
|
||||||
auth = os.getenv("SOLIDTIME_AUTH") or "",
|
|
||||||
org = os.getenv("SOLIDTIME_ORG") or "",
|
|
||||||
base_url = os.getenv("SOLIDTIME_URL") or "",
|
|
||||||
user = os.getenv("SOLIDTIME_USER") or "",
|
|
||||||
}
|
|
||||||
|
|
||||||
eta.ext = {
|
|
||||||
ns = vim.api.nvim_create_namespace("eta"),
|
|
||||||
}
|
|
||||||
vim.api.nvim_set_hl(0, "EtaHlTagKey", { fg = "#a6adc8", bg = "bg", bold = true })
|
|
||||||
vim.api.nvim_set_hl(0, "EtaHlTagVal", { bg = "bg", fg = "#a6adc8" })
|
|
||||||
|
|
||||||
local special_val_hl_cases = {
|
|
||||||
fail = "#f38ba8",
|
|
||||||
failed = "#f38ba8",
|
|
||||||
wontfix = "#f38ba8",
|
|
||||||
error = "#f38ba8",
|
|
||||||
err = "#f38ba8",
|
|
||||||
problem = "#f38ba8",
|
|
||||||
success = "#a6e3a1",
|
|
||||||
succeeded = "#a6e3a1",
|
|
||||||
ok = "#a6e3a1",
|
|
||||||
running = "#f9e2af",
|
|
||||||
in_progress = "#f9e2af",
|
|
||||||
progress = "#f9e2af",
|
|
||||||
warning = "#f9e2af",
|
|
||||||
warn = "#f9e2af",
|
|
||||||
in_review = "#94e2d5",
|
|
||||||
review = "#94e2d5",
|
|
||||||
selected = "#eba0ac",
|
|
||||||
selected_for_development = "#eba0ac",
|
|
||||||
backlog = "#7f849c",
|
|
||||||
}
|
|
||||||
|
|
||||||
local special_key_hl_cases = {
|
|
||||||
project = "#fab387",
|
|
||||||
mr = "#fab387",
|
|
||||||
issue = "#fab387",
|
|
||||||
task = "#b4befe",
|
|
||||||
lib = "#89b4fa",
|
|
||||||
library = "#89b4fa",
|
|
||||||
cell = "#74c7ec",
|
|
||||||
run = "#89dceb",
|
|
||||||
}
|
|
||||||
|
|
||||||
for special, special_hl in pairs(special_val_hl_cases) do
|
|
||||||
vim.api.nvim_set_hl(0, "EtaHlTagVal" .. special, { bg = "bg", fg = special_hl })
|
|
||||||
vim.api.nvim_set_hl(0, "EtaHlTagKey" .. special, { bg = "bg", fg = special_hl })
|
|
||||||
end
|
|
||||||
for special, special_hl in pairs(special_key_hl_cases) do
|
|
||||||
vim.api.nvim_set_hl(0, "EtaHlTagVal" .. special, { bg = "bg", fg = special_hl })
|
|
||||||
vim.api.nvim_set_hl(0, "EtaHlTagKey" .. special, { bg = "bg", fg = special_hl })
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.api.nvim_create_autocmd({ "CursorHold" }, {
|
|
||||||
callback = function(args)
|
|
||||||
local eid = 1;
|
|
||||||
for lix, line in ipairs(vim.api.nvim_buf_get_lines(args.buf, 0, -1, false)) do
|
|
||||||
for match in line:gmatch("#[a-z0-9_-]+/%S+") do
|
|
||||||
local offset, mend = line:find(match, 1, true)
|
|
||||||
local start, colend = line:find("/%s*", offset)
|
|
||||||
|
|
||||||
local val = line:sub(colend + 1 or 0, mend):gsub("%W", "_")
|
|
||||||
local key = line:sub(offset + 1, start - 1):gsub("%W", "_")
|
|
||||||
|
|
||||||
local vhl = "EtaHlTagVal"
|
|
||||||
local khl = "EtaHlTagKey"
|
|
||||||
|
|
||||||
for case, _ in pairs(special_key_hl_cases) do
|
|
||||||
if case == key then
|
|
||||||
vhl = vhl .. key
|
|
||||||
khl = khl .. key
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for case, _ in pairs(special_val_hl_cases) do
|
|
||||||
if case == val then
|
|
||||||
vhl = vhl .. val
|
|
||||||
khl = khl .. val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
vim.api.nvim_buf_set_extmark(args.buf, eta.ext.ns, lix - 1, colend or 0, {
|
|
||||||
id = eid,
|
|
||||||
end_row = lix - 1,
|
|
||||||
end_col = mend,
|
|
||||||
hl_group = { "EtaHlTagVal", vhl },
|
|
||||||
})
|
|
||||||
vim.api.nvim_buf_set_extmark(args.buf, eta.ext.ns, lix - 1, offset - 1, {
|
|
||||||
id = eid + 1,
|
|
||||||
end_row = lix - 1,
|
|
||||||
end_col = colend - 1,
|
|
||||||
hl_group = { "EtaHlTagKey", khl },
|
|
||||||
})
|
|
||||||
vim.api.nvim_buf_set_extmark(args.buf, eta.ext.ns, lix - 1, start - 1, {
|
|
||||||
id = eid + 2,
|
|
||||||
end_row = lix - 1,
|
|
||||||
end_col = colend,
|
|
||||||
conceal = " ",
|
|
||||||
hl_group = { khl },
|
|
||||||
})
|
|
||||||
vim.api.nvim_buf_set_extmark(args.buf, eta.ext.ns, lix - 1, offset - 1, {
|
|
||||||
id = eid + 3,
|
|
||||||
end_row = lix - 1,
|
|
||||||
end_col = offset,
|
|
||||||
conceal = " ",
|
|
||||||
hl_group = { khl },
|
|
||||||
})
|
|
||||||
vim.api.nvim_buf_set_extmark(args.buf, eta.ext.ns, lix - 1, mend or 0, {
|
|
||||||
id = eid + 4,
|
|
||||||
end_row = lix - 1,
|
|
||||||
end_col = mend,
|
|
||||||
conceal = "",
|
|
||||||
hl_group = { khl },
|
|
||||||
priority = 200,
|
|
||||||
})
|
|
||||||
|
|
||||||
for special_key, special_key_repl in pairs({
|
|
||||||
mr = " ",
|
|
||||||
issue = " ",
|
|
||||||
task = "",
|
|
||||||
created = " ",
|
|
||||||
closed = " ",
|
|
||||||
project = " ",
|
|
||||||
branch = "",
|
|
||||||
lib = " ",
|
|
||||||
library = " ",
|
|
||||||
cell = " ",
|
|
||||||
run = "",
|
|
||||||
}) do
|
|
||||||
if key == special_key then
|
|
||||||
vim.api.nvim_buf_set_extmark(args.buf, eta.ext.ns, lix - 1, offset, {
|
|
||||||
id = eid + 5,
|
|
||||||
end_row = lix - 1,
|
|
||||||
end_col = start,
|
|
||||||
conceal = special_key_repl,
|
|
||||||
hl_group = { khl },
|
|
||||||
priority = 200,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
eid = eid + 6
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
+6
-20
@@ -1,25 +1,11 @@
|
|||||||
[build-system]
|
|
||||||
requires = ['setuptools>=57', "wheel"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "eta-lsp"
|
name = "mrpy-nvim"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "EXTOLL Task Access"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pygls~=2.0",
|
"pydantic-settings~=2.12",
|
||||||
"pydantic~=2.12",
|
"pynvim~=0.6.0",
|
||||||
"requests~=2.32",
|
"requests>=2.32.5",
|
||||||
]
|
]
|
||||||
authors = [
|
|
||||||
{ name = "Patrick Nisble", email = "acereca@outlook.de"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.scripts]
|
|
||||||
eta-lsp = "eta.main:main"
|
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
|
||||||
include = ['eta']
|
|
||||||
namespaces = false
|
|
||||||
|
|||||||
+85
-160
@@ -1,105 +1,97 @@
|
|||||||
from collections.abc import Sequence
|
from dataclasses import dataclass, field
|
||||||
from dataclasses import dataclass, field, fields
|
|
||||||
from json import loads
|
from json import loads
|
||||||
from os import environ
|
from os import environ
|
||||||
from typing import Any, Callable, Self, TypedDict
|
from typing import Any, Callable
|
||||||
from urllib.error import HTTPError
|
|
||||||
|
|
||||||
from .hints import JSONDataMap
|
from pydantic import AliasPath, BaseModel, Field, field_validator
|
||||||
from .requests import delete, get, put, post
|
|
||||||
from .env import EnvVar
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
|
|
||||||
class TaskRespCheckItemDict(TypedDict):
|
def get(
|
||||||
name: str
|
url: str,
|
||||||
resolved: int
|
query_params: dict[str, str] | None = None,
|
||||||
|
headers: dict[str, str] | None = None,
|
||||||
|
) -> str:
|
||||||
|
with urlopen(
|
||||||
|
Request(
|
||||||
|
url + ("?" + "&".join(f"{k}={v}" for k, v in query_params.items()))
|
||||||
|
if query_params
|
||||||
|
else "",
|
||||||
|
headers=headers or {},
|
||||||
|
method="GET",
|
||||||
|
),
|
||||||
|
) as resp:
|
||||||
|
return resp.read().decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
class TaskRespCheckDict(TypedDict):
|
def put(
|
||||||
name: str
|
url: str,
|
||||||
items: list[TaskRespCheckItemDict]
|
data: dict[str, str] | None = None,
|
||||||
|
headers: dict[str, str] | None = None,
|
||||||
|
) -> str:
|
||||||
|
with urlopen(
|
||||||
|
Request(
|
||||||
|
url,
|
||||||
|
str(data).encode(),
|
||||||
|
headers=headers or {},
|
||||||
|
method="PUT",
|
||||||
|
),
|
||||||
|
) as resp:
|
||||||
|
return resp.read().decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
class TaskRespDict(TypedDict):
|
class ClickupTask(BaseModel):
|
||||||
|
"""fields marked with `exclude=True` will not be pushed for updates"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
markdown_description: str
|
markdown_description: str
|
||||||
status: dict[str, str]
|
status: str = Field(validation_alias=AliasPath("status", "status"))
|
||||||
|
|
||||||
id: str
|
id: str = Field(exclude=True)
|
||||||
assignees: list[dict[str, str]]
|
assignees: list[str] = Field(exclude=True)
|
||||||
tags: list[dict[str, str]]
|
tags: list[str] = Field(exclude=True)
|
||||||
parent: str | None
|
parent: str | None = Field(None, exclude=True)
|
||||||
locations: list[dict[str, str]]
|
parent_list: str = Field(validation_alias=AliasPath("list", "id"), exclude=True)
|
||||||
checklists: list[TaskRespCheckDict]
|
locations: list[str] = Field(exclude=True)
|
||||||
list: dict[str, str]
|
checklists: dict[str, bool] = Field(exclude=True)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
|
||||||
class ClickupTask:
|
|
||||||
"""fields marked with ``repr=False`` will not be pushed for updates"""
|
|
||||||
|
|
||||||
name: str
|
|
||||||
status: str
|
|
||||||
|
|
||||||
id: str | None = field(default=None, repr=False)
|
|
||||||
assignees: list[str] | None = field(default=None, repr=False)
|
|
||||||
tags: list[str] | None = field(default=None, repr=False)
|
|
||||||
parent_list: str = field(repr=False)
|
|
||||||
locations: list[str] | None = field(default=None, repr=False)
|
|
||||||
checklists: dict[str, dict[str, bool]] | None = field(default=None, repr=False)
|
|
||||||
parent: str | None = field(default=None, repr=False)
|
|
||||||
|
|
||||||
markdown_content: str
|
|
||||||
|
|
||||||
|
@field_validator("checklists", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_resp_data(cls, resp_data_raw: dict[str, Any]) -> Self:
|
def convert_checklists(cls, content: list[Any]) -> dict[str, bool]:
|
||||||
resp_data = TaskRespDict(**resp_data_raw)
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
name=resp_data["name"],
|
|
||||||
markdown_content=resp_data["markdown_description"],
|
|
||||||
status=resp_data["status"]["status"],
|
|
||||||
id=resp_data["id"],
|
|
||||||
assignees=cls.convert_assignees(resp_data["assignees"]),
|
|
||||||
tags=cls.convert_simple_list_with_names(resp_data["tags"]),
|
|
||||||
parent=resp_data.get("parent"),
|
|
||||||
parent_list=resp_data["list"]["id"],
|
|
||||||
locations=cls.convert_simple_list_with_names(resp_data["locations"]),
|
|
||||||
checklists={
|
|
||||||
tlist["name"]: {t["name"]: bool(t["resolved"]) for t in tlist["items"]}
|
|
||||||
for tlist in resp_data["checklists"]
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def convert_checklists(cls, content: Sequence[Any]) -> dict[str, bool]:
|
|
||||||
return {
|
return {
|
||||||
entry["name"]: entry["resolved"]
|
entry["name"]: entry["resolved"]
|
||||||
for checklist in content
|
for checklist in content
|
||||||
for entry in checklist["items"]
|
for entry in checklist["items"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@field_validator("assignees", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_assignees(cls, content: Sequence[str | dict[str, str]]) -> list[str]:
|
def convert_assignees(cls, content: list[str | dict[str, Any]]) -> list[str]:
|
||||||
return [(e if isinstance(e, str) else e["username"]) for e in content]
|
return [(e if isinstance(e, str) else e["username"]) for e in content]
|
||||||
|
|
||||||
|
@field_validator("tags", "locations", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_simple_list_with_names(
|
def convert_simple_list_with_names(
|
||||||
cls,
|
cls,
|
||||||
content: Sequence[str | dict[str, str]],
|
content: list[str | dict[str, Any]],
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
return [(e if isinstance(e, str) else e["name"]) for e in content]
|
return [(e if isinstance(e, str) else e["name"]) for e in content]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def updateables(self) -> dict[str, Any]:
|
def updateables(self) -> dict[str, Any]:
|
||||||
return {f.name: getattr(self, f.name, None) for f in fields(type(self)) if f.repr}
|
return {
|
||||||
|
k: getattr(self, k, None)
|
||||||
|
for k, v in type(self).model_fields.items()
|
||||||
|
if not v.exclude
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def showables(self) -> dict[str, Any]:
|
def showables(self) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
dcf.name: getattr(self, dcf.name, ...)
|
k: getattr(self, k, None)
|
||||||
for dcf in fields(self)
|
for k in type(self).model_fields
|
||||||
if getattr(self, dcf.name, ...) is not None
|
if k != "markdown_description"
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -109,54 +101,34 @@ class ClickupTask:
|
|||||||
if self.parent:
|
if self.parent:
|
||||||
ret += " \033[32m "
|
ret += " \033[32m "
|
||||||
|
|
||||||
ret += self.name
|
ret += f"{self.name} (#{self.id})"
|
||||||
|
|
||||||
if self.tags:
|
|
||||||
ret += "".join(f" #{t}" for t in self.tags)
|
|
||||||
|
|
||||||
ret += f" (#{self.id})"
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def get_env_var(var_name: str) -> Callable[[], str]:
|
||||||
|
return lambda var=var_name: environ[var]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ClickupSession:
|
class ClickupSession:
|
||||||
auth_key: str = field(
|
auth_key: str = field(default_factory=get_env_var("CLICKUP_AUTH"))
|
||||||
default_factory=EnvVar(
|
workspace_id: str = field(default_factory=get_env_var("CLICKUP_WORKSPACE_ID"))
|
||||||
"CLICKUP_AUTH",
|
user_id: str = field(default_factory=get_env_var("CLICKUP_USER_ID"))
|
||||||
"clickup auth token is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
workspace_id: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"CLICKUP_WORKSPACE_ID",
|
|
||||||
"clickup workspace id is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
user_id: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"CLICKUP_USER_ID",
|
|
||||||
"clickup user id is required to be set",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
base_url: str = "https://api.clickup.com/api/v2"
|
base_url: str = "https://api.clickup.com/api/v2"
|
||||||
|
|
||||||
def _get(self, endpoint: str, **query_params: str) -> JSONDataMap:
|
def _get(self, endpoint: str, **query_params: Any) -> dict[str, Any]:
|
||||||
try:
|
raw_data = get(
|
||||||
raw_data = get(
|
self.base_url + endpoint,
|
||||||
self.base_url + endpoint,
|
query_params,
|
||||||
query_params,
|
headers={
|
||||||
headers={
|
"accept": "application/json",
|
||||||
"accept": "application/json",
|
"Authorization": self.auth_key,
|
||||||
"Authorization": self.auth_key,
|
},
|
||||||
},
|
)
|
||||||
)
|
return loads(raw_data)
|
||||||
return loads(raw_data)
|
|
||||||
except HTTPError as e:
|
|
||||||
e.add_note(e.url)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def _put(self, endpoint: str, **body_params: str) -> JSONDataMap:
|
def _put(self, endpoint: str, **body_params: Any) -> dict[str, Any]:
|
||||||
raw_data = put(
|
raw_data = put(
|
||||||
self.base_url + endpoint,
|
self.base_url + endpoint,
|
||||||
body_params,
|
body_params,
|
||||||
@@ -168,63 +140,16 @@ class ClickupSession:
|
|||||||
)
|
)
|
||||||
return loads(raw_data)
|
return loads(raw_data)
|
||||||
|
|
||||||
def _post(self, endpoint: str, **body_params: str) -> JSONDataMap:
|
def get_tasks(self) -> list[ClickupTask]:
|
||||||
raw_data = post(
|
|
||||||
self.base_url + endpoint,
|
|
||||||
body_params,
|
|
||||||
headers={
|
|
||||||
"accept": "application/json",
|
|
||||||
"content-type": "application/json",
|
|
||||||
"Authorization": self.auth_key,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return loads(raw_data)
|
|
||||||
|
|
||||||
def _delete(self, endpoint: str) -> JSONDataMap:
|
|
||||||
raw_data = delete(
|
|
||||||
self.base_url + endpoint,
|
|
||||||
headers={
|
|
||||||
"accept": "application/json",
|
|
||||||
"content-type": "application/json",
|
|
||||||
"Authorization": self.auth_key,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return loads(raw_data)
|
|
||||||
|
|
||||||
def get_tasks(self, **filters: str) -> list[ClickupTask]:
|
|
||||||
data = self._get(
|
data = self._get(
|
||||||
f"/team/{self.workspace_id}/task",
|
f"/team/{self.workspace_id}/task?subtasks=true&include_markdown_description=true&assignees[]={self.user_id}"
|
||||||
**{
|
)
|
||||||
"subtask": "true",
|
return [ClickupTask.model_validate(t) for t in data["tasks"]]
|
||||||
"include_markdown_description": "true",
|
|
||||||
"assignees[]": self.user_id,
|
|
||||||
}
|
|
||||||
| filters,
|
|
||||||
).get("tasks", [])
|
|
||||||
if isinstance(data, list):
|
|
||||||
return [ClickupTask.from_resp_data(t) for t in data if isinstance(t, dict)]
|
|
||||||
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_task(self, task_id: str) -> ClickupTask:
|
def get_task(self, task_id: str) -> ClickupTask:
|
||||||
return ClickupTask.from_resp_data(
|
return ClickupTask.model_validate(
|
||||||
self._get(
|
self._get(f"/task/{task_id}?include_markdown_description=true")
|
||||||
f"/task/{task_id}",
|
|
||||||
include_markdown_description="true",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def update(self, data: ClickupTask) -> None:
|
def update(self, data: ClickupTask) -> None:
|
||||||
ret_task = self._put(f"/task/{data.id}", **data.updateables)
|
_ = self._put(f"/task/{data.id}", **data.updateables)
|
||||||
current_tags: set[str] = set(ret_task["tags"])
|
|
||||||
new_tags = set(data.tags)
|
|
||||||
|
|
||||||
for del_tag in current_tags - new_tags:
|
|
||||||
self._delete(f"/task/{data.id}/tag/{del_tag}")
|
|
||||||
|
|
||||||
for add_tag in new_tags - current_tags:
|
|
||||||
self._post(f"/task/{data.id}/tag/{add_tag}")
|
|
||||||
|
|
||||||
def create(self, data: ClickupTask) -> str:
|
|
||||||
ret_task = self._post(f"/list/{data.parent_list}/task", **data.updateables)
|
|
||||||
return str(ret_task["id"])
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
from os import environ
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class EnvVar:
|
|
||||||
"""
|
|
||||||
Environment Variable fetcher for use in dataclass ``field(default_factory=...)``
|
|
||||||
|
|
||||||
>>> @dataclass
|
|
||||||
>>> class SomeDataclass:
|
|
||||||
... field_name: str = field(default_factory=EnvVar("SOME_VAR_NAME", "err msg"))
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
var_name: str
|
|
||||||
err_msg: str = ""
|
|
||||||
|
|
||||||
def __call__(self) -> str:
|
|
||||||
try:
|
|
||||||
return environ[self.var_name]
|
|
||||||
except KeyError as e:
|
|
||||||
e.add_note(self.err_msg)
|
|
||||||
raise
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
from dataclasses import dataclass, field, fields
|
|
||||||
from functools import cached_property
|
|
||||||
from json import loads
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from pynvim import Nvim
|
|
||||||
|
|
||||||
from .requests import request
|
|
||||||
from .ui import Select
|
|
||||||
|
|
||||||
from .clickup import ClickupTask
|
|
||||||
from .env import EnvVar
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class GitlabMergeRequest:
|
|
||||||
@property
|
|
||||||
def updateables(self) -> dict[str, Any]:
|
|
||||||
return {f.name: getattr(self, f.name, None) for f in fields(type(self)) if f.repr}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
|
||||||
class GitlabIssue:
|
|
||||||
project: int | str = field(repr=False)
|
|
||||||
"""project id or url encoded path to project, e.g. `ope%2Fopepipeline`"""
|
|
||||||
|
|
||||||
title: str
|
|
||||||
assignee_id: int | None = None
|
|
||||||
description: str | None = None
|
|
||||||
labels: list[str] | None = None
|
|
||||||
milestone_id: int | None = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def updateables(self) -> dict[str, Any]:
|
|
||||||
return {f.name: getattr(self, f.name, None) for f in fields(type(self)) if f.repr}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class GitlabSession:
|
|
||||||
auth_key: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"GITLAB_AUTH",
|
|
||||||
"gitlab autho token is required to be set",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
user_id: str = field(
|
|
||||||
default_factory=EnvVar(
|
|
||||||
"GITLAB_USER_ID",
|
|
||||||
"gitlab user id is required to be set",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
base_url: str = "https://git.extoll.de/api/v4"
|
|
||||||
|
|
||||||
def _authed_request(
|
|
||||||
self,
|
|
||||||
method: str,
|
|
||||||
url: str,
|
|
||||||
data: dict[str, str] | None = None,
|
|
||||||
headers: dict[str, str] | None = None,
|
|
||||||
) -> str:
|
|
||||||
return request(
|
|
||||||
url,
|
|
||||||
method,
|
|
||||||
data=data,
|
|
||||||
headers=(headers or {}) | {"PRIVATE_TOKEN": self.auth_key},
|
|
||||||
)
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def projects(self) -> list[str]:
|
|
||||||
return [
|
|
||||||
p["path_with_namespace"]
|
|
||||||
for p in loads(self._authed_request("GET", self.base_url + "/projects"))
|
|
||||||
]
|
|
||||||
|
|
||||||
def new_issue(self, nvim: Nvim, clickup_task: ClickupTask) -> GitlabIssue:
|
|
||||||
issue_new = GitlabIssue(
|
|
||||||
project=Select(nvim, self.projects)(),
|
|
||||||
title=clickup_task.name,
|
|
||||||
assignee_id=int(self.user_id),
|
|
||||||
description=f"#{clickup_task.id}",
|
|
||||||
)
|
|
||||||
self._authed_request(
|
|
||||||
"POST",
|
|
||||||
self.base_url + f"/projects/{issue_new.project}/issues",
|
|
||||||
data=issue_new.updateables,
|
|
||||||
)
|
|
||||||
|
|
||||||
return issue_new
|
|
||||||
|
|
||||||
def new_mr(self, from_issue: GitlabIssue) -> GitlabMergeRequest:
|
|
||||||
mr_new = GitlabMergeRequest()
|
|
||||||
self._authed_request(
|
|
||||||
"POST",
|
|
||||||
self.base_url + f"/projects/{from_issue.project}/merge_requests",
|
|
||||||
data=mr_new.updateables,
|
|
||||||
)
|
|
||||||
|
|
||||||
return mr_new
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
from __future__ import annotations
|
type JSONDataScalar = str | None | float | bool
|
||||||
from typing import TypeAlias
|
type JSONDataList = list[JSONDataScalar | "JSONDataMap" | "JSONDataList"]
|
||||||
|
type JSONDataMap = dict[str, JSONDataScalar | JSONDataList | "JSONDataMap"]
|
||||||
|
type JSONData = JSONDataMap | JSONDataList
|
||||||
JSONDataScalar: TypeAlias = str | None | float | bool
|
|
||||||
JSONDataList: TypeAlias = list["JSONDataScalar | JSONDataMap | JSONDataList"]
|
|
||||||
JSONDataMap: TypeAlias = dict[str, "JSONDataScalar | JSONDataList | JSONDataMap"]
|
|
||||||
JSONData: TypeAlias = "JSONDataMap | JSONDataList"
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
from collections.abc import Callable, Sequence
|
from collections.abc import Callable, Sequence
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from pynvim import Nvim, command, plugin
|
from pynvim import Nvim, command, plugin
|
||||||
from pynvim.api import Buffer
|
from pynvim.api import Buffer
|
||||||
|
|
||||||
from .ui import Select
|
from .clickup import ClickupSession
|
||||||
|
|
||||||
from .clickup import ClickupSession, ClickupTask
|
|
||||||
from .hints import JSONData
|
from .hints import JSONData
|
||||||
from .yaml import load, dump
|
from .yaml import load, dump
|
||||||
|
|
||||||
@@ -32,20 +28,18 @@ class MrPyPlugin:
|
|||||||
"assignees": usernames_from_objs,
|
"assignees": usernames_from_objs,
|
||||||
}
|
}
|
||||||
|
|
||||||
def select_task_id(self, tags: set[str] | None = None) -> None:
|
def select_task_id(self) -> None:
|
||||||
tasks = self.clickup.get_tasks(**({"tags[]": "&tags[]=".join(tags)} if tags else {}))
|
tasks = self.clickup.get_tasks()
|
||||||
task_names_by_id = [
|
task_names_by_id = [
|
||||||
{
|
{
|
||||||
"idx": tix + 1,
|
"idx": tix + 1,
|
||||||
"id": t.id,
|
"id": t.id,
|
||||||
"text": t.short,
|
|
||||||
"name": t.name,
|
"name": t.name,
|
||||||
"tags": t.tags,
|
|
||||||
"status": t.status,
|
"status": t.status,
|
||||||
"is_child": bool(t.parent),
|
"is_child": bool(t.parent),
|
||||||
"preview": {
|
"preview": {
|
||||||
"text": dump(t.showables),
|
"text": f"---\n{dump(t.showables)}---\n{t.markdown_description}",
|
||||||
"ft": "yaml",
|
"ft": "markdown",
|
||||||
},
|
},
|
||||||
"action": f":Mrpy {t.id}",
|
"action": f":Mrpy {t.id}",
|
||||||
}
|
}
|
||||||
@@ -76,12 +70,8 @@ class MrPyPlugin:
|
|||||||
|
|
||||||
ret[#ret + 1] = { item.name, hl }
|
ret[#ret + 1] = { item.name, hl }
|
||||||
|
|
||||||
for _, v in ipairs(item.tags) do
|
|
||||||
ret[#ret + 1] = { " #" .. v, "SnacksPickerComment" }
|
|
||||||
end
|
|
||||||
|
|
||||||
ret[#ret + 1] = {
|
ret[#ret + 1] = {
|
||||||
" " .. item.id,
|
" (#" .. item.id .. ")",
|
||||||
"SnacksPickerComment"
|
"SnacksPickerComment"
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
@@ -101,36 +91,36 @@ class MrPyPlugin:
|
|||||||
task = self.clickup.get_task(task_id)
|
task = self.clickup.get_task(task_id)
|
||||||
temp_buf: Buffer = self.nvim.api.create_buf(True, False)
|
temp_buf: Buffer = self.nvim.api.create_buf(True, False)
|
||||||
self.nvim.api.buf_set_name(temp_buf, f"[ClickUp] {task.name}")
|
self.nvim.api.buf_set_name(temp_buf, f"[ClickUp] {task.name}")
|
||||||
self.nvim.buffers[temp_buf.number].options["filetype"] = "yaml"
|
self.nvim.buffers[temp_buf.number].options["filetype"] = "markdown"
|
||||||
self.nvim.api.create_autocmd(
|
self.nvim.api.create_autocmd(
|
||||||
["BufWriteCmd"],
|
["BufWriteCmd"],
|
||||||
{"buffer": temp_buf.number, "command": "MrpyPush " + str(temp_buf.number)},
|
{"buffer": temp_buf.number, "command": "MrpyPush " + str(temp_buf.number)},
|
||||||
)
|
)
|
||||||
|
|
||||||
content = [
|
content = ["---"]
|
||||||
f"# yaml-language-server: $schema={Path(__file__).parent.parent.parent.parent}/schema.json ",
|
|
||||||
"---",
|
|
||||||
]
|
|
||||||
content.extend(
|
content.extend(
|
||||||
dump(
|
dump(
|
||||||
task.showables,
|
task.showables,
|
||||||
).splitlines()
|
).splitlines()
|
||||||
)
|
)
|
||||||
|
content.append("---")
|
||||||
|
content.extend(task.markdown_description.splitlines())
|
||||||
|
|
||||||
self.nvim.api.buf_set_lines(temp_buf, 0, 0, False, content)
|
self.nvim.api.buf_set_lines(temp_buf, 0, 0, False, content)
|
||||||
self.nvim.buffers[temp_buf.number].options["modified"] = False
|
self.nvim.buffers[temp_buf.number].options["modified"] = False
|
||||||
self.nvim.api.win_set_buf(0, temp_buf)
|
self.nvim.api.win_set_buf(0, temp_buf)
|
||||||
|
|
||||||
|
@command("Mrpy", nargs="?")
|
||||||
def entry(self, args: Sequence[str] = ()) -> None:
|
def entry(self, args: Sequence[str] = ()) -> None:
|
||||||
match args:
|
match args:
|
||||||
case (str() as task_id,):
|
case (str() as task_id,):
|
||||||
try:
|
self.open_task_buffer(task_id)
|
||||||
self.open_task_buffer(task_id)
|
case ():
|
||||||
except:
|
self.select_task_id()
|
||||||
self.select_task_id({task_id})
|
case _:
|
||||||
case tags:
|
pass
|
||||||
self.select_task_id(set(tags))
|
|
||||||
|
|
||||||
|
@command("MrpyPush", nargs="?")
|
||||||
def on_vbuf_write(self, args: Sequence[str] = ()) -> None:
|
def on_vbuf_write(self, args: Sequence[str] = ()) -> None:
|
||||||
match args:
|
match args:
|
||||||
case "0", *_:
|
case "0", *_:
|
||||||
@@ -142,64 +132,14 @@ class MrPyPlugin:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
a = self.nvim.buffers[buf_no][0:-1]
|
a = self.nvim.buffers[buf_no][0:-1]
|
||||||
fm = "\n".join(a)
|
_, fm, *text = "\n".join(a).split("---\n")
|
||||||
data = load(fm)
|
data = load(fm)
|
||||||
assert isinstance(data, dict)
|
assert isinstance(data, dict)
|
||||||
|
|
||||||
data["markdown_content"] = data["markdown_content"].strip() + "\n"
|
data["markdown_description"] = "\n\n".join(text)
|
||||||
|
|
||||||
self.clickup.update(ClickupTask(**data))
|
self.nvim.err_write(str(data) + "\n")
|
||||||
|
# self.clickup.update(data)
|
||||||
self.nvim.buffers[buf_no].options["modified"] = False
|
self.nvim.buffers[buf_no].options["modified"] = False
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_new_task(self) -> None:
|
|
||||||
task = ClickupTask(name="", status="backlog", markdown_content="", parent_list="")
|
|
||||||
temp_buf: Buffer = self.nvim.api.create_buf(True, False)
|
|
||||||
self.nvim.api.buf_set_name(temp_buf, f"[ClickUp] New Task")
|
|
||||||
self.nvim.buffers[temp_buf.number].options["filetype"] = "yaml"
|
|
||||||
self.nvim.api.create_autocmd(
|
|
||||||
["BufWriteCmd"],
|
|
||||||
{"buffer": temp_buf.number, "command": "MrpyPushNew " + str(temp_buf.number)},
|
|
||||||
)
|
|
||||||
|
|
||||||
content = [
|
|
||||||
f"# yaml-language-server: $schema={Path(__file__).parent.parent.parent.parent}/schema.json ",
|
|
||||||
"---",
|
|
||||||
]
|
|
||||||
content.extend(
|
|
||||||
dump(
|
|
||||||
task.showables,
|
|
||||||
).splitlines()
|
|
||||||
)
|
|
||||||
|
|
||||||
self.nvim.api.buf_set_lines(temp_buf, 0, 0, False, content)
|
|
||||||
self.nvim.buffers[temp_buf.number].options["modified"] = False
|
|
||||||
self.nvim.api.win_set_buf(0, temp_buf)
|
|
||||||
|
|
||||||
def on_new_vbuf_write(self, buf_no: Sequence[Any] = ()) -> None:
|
|
||||||
buf_no = int(buf_no[0])
|
|
||||||
|
|
||||||
try:
|
|
||||||
a = self.nvim.buffers[buf_no][0:-1]
|
|
||||||
fm = "\n".join(a)
|
|
||||||
data = load(fm)
|
|
||||||
assert isinstance(data, dict)
|
|
||||||
|
|
||||||
data["markdown_content"] = data["markdown_content"].strip() + "\n"
|
|
||||||
|
|
||||||
new_task = ClickupTask(**data)
|
|
||||||
new_task_id = self.clickup.create(new_task)
|
|
||||||
|
|
||||||
self.nvim.buffers[buf_no].options["modified"] = False
|
|
||||||
self.nvim.command("bdelete " + str(buf_no))
|
|
||||||
|
|
||||||
self.entry([new_task_id])
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def handle_test(self, choice: Any) -> None:
|
|
||||||
self.nvim.err_write(str(choice))
|
|
||||||
|
|
||||||
def test(self) -> None:
|
|
||||||
self.nvim.ui.select(["a", "b"], {"prompt": "hi"}, self.handle_test)
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
from json import dumps
|
|
||||||
from ssl import SSLContext, create_default_context
|
|
||||||
from urllib.error import HTTPError
|
|
||||||
from urllib.request import Request, urlopen
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
|
|
||||||
|
|
||||||
def request(
|
|
||||||
url: str,
|
|
||||||
method: str,
|
|
||||||
query_params: dict[str, str] | None = None,
|
|
||||||
data: dict[str, str] | None = None,
|
|
||||||
headers: dict[str, str] | None = None,
|
|
||||||
) -> str:
|
|
||||||
try:
|
|
||||||
with urlopen(
|
|
||||||
Request(
|
|
||||||
url
|
|
||||||
+ (
|
|
||||||
("?" + "&".join(f"{k}={v}" for k, v in query_params.items()))
|
|
||||||
if query_params
|
|
||||||
else ""
|
|
||||||
),
|
|
||||||
dumps(data).encode() if data else None,
|
|
||||||
headers=headers or {},
|
|
||||||
method=method,
|
|
||||||
),
|
|
||||||
context=create_default_context(),
|
|
||||||
) as resp:
|
|
||||||
return resp.read().decode("utf-8")
|
|
||||||
except HTTPError as e:
|
|
||||||
e.add_note(e.url)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def get(
|
|
||||||
url: str,
|
|
||||||
query_params: dict[str, str] | None = None,
|
|
||||||
headers: dict[str, str] | None = None,
|
|
||||||
) -> str:
|
|
||||||
return request(url, "GET", query_params=query_params, headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
def post(
|
|
||||||
url: str,
|
|
||||||
data: dict[str, str] | None = None,
|
|
||||||
headers: dict[str, str] | None = None,
|
|
||||||
) -> str:
|
|
||||||
return request(url, "POST", data=data, headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
def put(
|
|
||||||
url: str,
|
|
||||||
data: dict[str, str] | None = None,
|
|
||||||
headers: dict[str, str] | None = None,
|
|
||||||
) -> str:
|
|
||||||
return request(url, "PUT", data=data, headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
def delete(
|
|
||||||
url: str,
|
|
||||||
headers: dict[str, str] | None = None,
|
|
||||||
) -> str:
|
|
||||||
return request(url, "DELETE", headers=headers)
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
from pynvim import Nvim
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Select:
|
|
||||||
nvim: Nvim
|
|
||||||
options: list[str]
|
|
||||||
|
|
||||||
def __call__(self) -> str:
|
|
||||||
return self.nvim.call(
|
|
||||||
"""
|
|
||||||
return vim.fn.inputlist(...)
|
|
||||||
""",
|
|
||||||
self.options,
|
|
||||||
async_=False,
|
|
||||||
)
|
|
||||||
@@ -14,44 +14,20 @@ def dump_scalar(entry: hints.JSONDataScalar) -> str:
|
|||||||
case False:
|
case False:
|
||||||
return "false\n"
|
return "false\n"
|
||||||
case _:
|
case _:
|
||||||
return f"{entry}\n"
|
return f"{entry:s}\n"
|
||||||
|
|
||||||
|
|
||||||
def dump(obj: hints.JSONDataMap) -> str:
|
def dump(obj: dict[str, hints.JSONDataScalar | list[hints.JSONDataScalar]]) -> str:
|
||||||
ret = ""
|
ret = ""
|
||||||
for key, value in obj.items():
|
for key, value in obj.items():
|
||||||
ret += key
|
ret += key
|
||||||
ret += ":"
|
ret += ":"
|
||||||
|
|
||||||
match value:
|
match value:
|
||||||
case []:
|
|
||||||
ret += " []\n"
|
|
||||||
case {}:
|
|
||||||
ret += " {}\n"
|
|
||||||
case "":
|
|
||||||
ret += ' ""\n'
|
|
||||||
case list() as entries:
|
case list() as entries:
|
||||||
ret += "\n"
|
ret += "\n"
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
match entry:
|
ret += f" - {dump_scalar(entry)}"
|
||||||
case dict():
|
|
||||||
subdump = dump(entry)
|
|
||||||
ret += "\n".join(" " + l for l in subdump.splitlines())
|
|
||||||
case list():
|
|
||||||
pass
|
|
||||||
case _:
|
|
||||||
ret += f" - {dump_scalar(entry)}"
|
|
||||||
case dict() as substruct:
|
|
||||||
ret += "\n"
|
|
||||||
subdump = dump(substruct)
|
|
||||||
ret += "\n".join(" " + l for l in subdump.splitlines()) + "\n"
|
|
||||||
|
|
||||||
case str() as mlstring if key == "markdown_content":
|
|
||||||
if mlstring.strip() == "" or dump_scalar(mlstring).strip() == "null":
|
|
||||||
ret += ' ""\n'
|
|
||||||
else:
|
|
||||||
indented = "\n".join((" " + l) for l in dump_scalar(mlstring).splitlines())
|
|
||||||
ret += f" >\n{indented}\n"
|
|
||||||
case entry:
|
case entry:
|
||||||
ret += f" {dump_scalar(entry)}"
|
ret += f" {dump_scalar(entry)}"
|
||||||
|
|
||||||
@@ -77,10 +53,6 @@ def load(content: str) -> hints.JSONData:
|
|||||||
... key10:
|
... key10:
|
||||||
... - str
|
... - str
|
||||||
... - "str"
|
... - "str"
|
||||||
... key11: >
|
|
||||||
... * a
|
|
||||||
... * b:
|
|
||||||
... * c
|
|
||||||
... '''
|
... '''
|
||||||
>>> yaml_parsed = load(yaml)
|
>>> yaml_parsed = load(yaml)
|
||||||
>>> compare = {
|
>>> compare = {
|
||||||
@@ -94,8 +66,8 @@ def load(content: str) -> hints.JSONData:
|
|||||||
... 'key8': False,
|
... 'key8': False,
|
||||||
... 'key9': [1, 23.2],
|
... 'key9': [1, 23.2],
|
||||||
... 'key10': ['str', 'str'],
|
... 'key10': ['str', 'str'],
|
||||||
... 'key11': "* a\\n* b:\\n * c",
|
|
||||||
... }
|
... }
|
||||||
|
|
||||||
>>> {k: yaml_parsed.get(k, None) for k in compare if compare[k] != yaml_parsed[k]}
|
>>> {k: yaml_parsed.get(k, None) for k in compare if compare[k] != yaml_parsed[k]}
|
||||||
{}
|
{}
|
||||||
"""
|
"""
|
||||||
@@ -103,34 +75,20 @@ def load(content: str) -> hints.JSONData:
|
|||||||
ret = {}
|
ret = {}
|
||||||
key = None
|
key = None
|
||||||
value = None
|
value = None
|
||||||
mlstring = False
|
for line in sub(r":[\s\n]*", ":\n ", dedent(content).strip()).splitlines():
|
||||||
for line in sub(r"(:( >)?)[\s\n]*", r"\1\n ", dedent(content).strip()).splitlines():
|
if line.endswith(":"):
|
||||||
if line.startswith("#") or line.strip() == "---":
|
|
||||||
continue
|
|
||||||
elif line.endswith(":"):
|
|
||||||
if key:
|
if key:
|
||||||
ret[key] = value
|
ret[key] = value
|
||||||
value = None
|
value = None
|
||||||
mlstring = False
|
|
||||||
|
|
||||||
key = line.removesuffix(":")
|
key = line.removesuffix(":")
|
||||||
elif line.endswith(": >"):
|
elif line.startswith(" -"):
|
||||||
if key:
|
|
||||||
ret[key] = value
|
|
||||||
value = None
|
|
||||||
mlstring = True
|
|
||||||
|
|
||||||
key = line.removesuffix(": >")
|
|
||||||
elif line.startswith(" -") and not mlstring:
|
|
||||||
value = value or []
|
value = value or []
|
||||||
try:
|
try:
|
||||||
parsed = loads(line.removeprefix(" -").strip())
|
parsed = loads(line.removeprefix(" -").strip())
|
||||||
except:
|
except:
|
||||||
parsed = loads('"' + line.removeprefix(" -").strip() + '"')
|
parsed = loads('"' + line.removeprefix(" -").strip() + '"')
|
||||||
value.append(parsed)
|
value.append(parsed)
|
||||||
elif line.startswith(" ") and mlstring:
|
|
||||||
value = value or ""
|
|
||||||
value += line.removeprefix(" ") + "\n"
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
value = loads(line.strip())
|
value = loads(line.strip())
|
||||||
|
|||||||
-44
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
||||||
"description": "ETA yaml frontmatter",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"backlog",
|
|
||||||
"selected for development",
|
|
||||||
"in progress",
|
|
||||||
"in review",
|
|
||||||
"on hold",
|
|
||||||
"done",
|
|
||||||
"closed"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"markdown_content": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[a-z0-9]+$"
|
|
||||||
},
|
|
||||||
"parent_list": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"const": 900400316794,
|
|
||||||
"description": "OPE Tooling"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"status",
|
|
||||||
"markdown_content",
|
|
||||||
"parent_list"
|
|
||||||
],
|
|
||||||
"title": "clickup task",
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
@@ -1,69 +1,31 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "annotated-types"
|
name = "annotated-types"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "attrs"
|
|
||||||
version = "25.4.0"
|
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cattrs"
|
|
||||||
version = "25.3.0"
|
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "attrs" },
|
|
||||||
{ name = "typing-extensions" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/6e/00/2432bb2d445b39b5407f0a90e01b9a271475eea7caf913d7a86bcb956385/cattrs-25.3.0.tar.gz", hash = "sha256:1ac88d9e5eda10436c4517e390a4142d88638fe682c436c93db7ce4a277b884a", size = 509321, upload-time = "2025-10-07T12:26:08.737Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d8/2b/a40e1488fdfa02d3f9a653a61a5935ea08b3c2225ee818db6a76c7ba9695/cattrs-25.3.0-py3-none-any.whl", hash = "sha256:9896e84e0a5bf723bc7b4b68f4481785367ce07a8a02e7e9ee6eb2819bc306ff", size = 70738, upload-time = "2025-10-07T12:26:06.603Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2026.1.4"
|
version = "2025.11.12"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
|
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "charset-normalizer"
|
name = "charset-normalizer"
|
||||||
version = "3.4.4"
|
version = "3.4.4"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
|
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
|
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
|
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
|
||||||
@@ -116,48 +78,120 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eta-lsp"
|
name = "greenlet"
|
||||||
version = "0.1.0"
|
version = "3.3.0"
|
||||||
source = { editable = "." }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" }
|
||||||
{ name = "pydantic" },
|
wheels = [
|
||||||
{ name = "pygls" },
|
{ url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" },
|
||||||
{ name = "requests" },
|
{ url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" },
|
||||||
]
|
{ url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" },
|
||||||
[package.metadata]
|
{ url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" },
|
||||||
requires-dist = [
|
{ url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" },
|
||||||
{ name = "pydantic", specifier = "~=2.12" },
|
{ url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" },
|
||||||
{ name = "pygls", specifier = "~=2.0" },
|
{ url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" },
|
||||||
{ name = "requests", specifier = "~=2.32" },
|
{ url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/71/ba21c3fb8c5dce83b8c01f458a42e99ffdb1963aeec08fff5a18588d8fd7/greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", size = 301833, upload-time = "2025-12-04T14:32:23.929Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/9a/9030e6f9aa8fd7808e9c31ba4c38f87c4f8ec324ee67431d181fe396d705/greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", size = 305387, upload-time = "2025-12-04T14:26:51.063Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.11"
|
version = "3.11"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsprotocol"
|
name = "mrpy-nvim"
|
||||||
version = "2025.0.0"
|
version = "0.1.0"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "attrs" },
|
{ name = "pydantic-settings" },
|
||||||
{ name = "cattrs" },
|
{ name = "pynvim" },
|
||||||
|
{ name = "requests" },
|
||||||
|
{ name = "ruamel-yaml" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e9/26/67b84e6ec1402f0e6764ef3d2a0aaf9a79522cc1d37738f4e5bb0b21521a/lsprotocol-2025.0.0.tar.gz", hash = "sha256:e879da2b9301e82cfc3e60d805630487ac2f7ab17492f4f5ba5aaba94fe56c29", size = 74896, upload-time = "2025-06-17T21:30:18.156Z" }
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "pydantic-settings", specifier = "~=2.12" },
|
||||||
|
{ name = "pynvim", specifier = "~=0.6.0" },
|
||||||
|
{ name = "requests", specifier = ">=2.32.5" },
|
||||||
|
{ name = "ruamel-yaml", specifier = "~=0.18.17" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "msgpack"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7b/f0/92f2d609d6642b5f30cb50a885d2bf1483301c69d5786286500d15651ef2/lsprotocol-2025.0.0-py3-none-any.whl", hash = "sha256:f9d78f25221f2a60eaa4a96d3b4ffae011b107537facee61d3da3313880995c7", size = 76250, upload-time = "2025-06-17T21:30:19.455Z" },
|
{ url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.12.5"
|
version = "2.12.5"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "annotated-types" },
|
{ name = "annotated-types" },
|
||||||
{ name = "pydantic-core" },
|
{ name = "pydantic-core" },
|
||||||
@@ -172,26 +206,12 @@ wheels = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic-core"
|
name = "pydantic-core"
|
||||||
version = "2.41.5"
|
version = "2.41.5"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
|
{ url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
|
{ url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
|
||||||
@@ -248,42 +268,52 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
|
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
|
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
|
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
|
{ url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
|
{ url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
|
{ url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pygls"
|
name = "pydantic-settings"
|
||||||
version = "2.0.0"
|
version = "2.12.0"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "attrs" },
|
{ name = "pydantic" },
|
||||||
{ name = "cattrs" },
|
{ name = "python-dotenv" },
|
||||||
{ name = "lsprotocol" },
|
{ name = "typing-inspection" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/87/50/2bfc32f3acbc8941042919b59c9f592291127b55d7331b72e67ce7b62f08/pygls-2.0.0.tar.gz", hash = "sha256:99accd03de1ca76fe1e7e317f0968ebccf7b9955afed6e2e3e188606a20b4f07", size = 55796, upload-time = "2025-10-17T19:22:47.925Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/cc/09/14feafc13bebb9c85b29b374889c1549d3700cb572f2d43a1bb940d70315/pygls-2.0.0-py3-none-any.whl", hash = "sha256:b4e54bba806f76781017ded8fd07463b98670f959042c44170cd362088b200cc", size = 69533, upload-time = "2025-10-17T19:22:46.63Z" },
|
{ url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pynvim"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "greenlet", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
|
{ name = "msgpack" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/04/d7/c4412e6219661fd8689cdd9553988f8ea38c151067d70c49436977688aa9/pynvim-0.6.0.tar.gz", hash = "sha256:0ffcb879322d08f9e9061e1123dd58ba3a5ccfbd4999bb1157bac525822aa590", size = 51478, upload-time = "2025-09-07T18:35:37.601Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/2d/c28b9293975ed9ee05e52f1d316cb402ba6edb232baa0497754a70182ca2/pynvim-0.6.0-py3-none-any.whl", hash = "sha256:29f92ff3fde9e52c263e6bfd7f30345be05bfc7b5c21484da1cc38a8d8e5e98f", size = 47633, upload-time = "2025-09-07T18:35:36.348Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dotenv"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.32.5"
|
version = "2.32.5"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "certifi" },
|
{ name = "certifi" },
|
||||||
{ name = "charset-normalizer" },
|
{ name = "charset-normalizer" },
|
||||||
@@ -295,10 +325,60 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruamel-yaml"
|
||||||
|
version = "0.18.17"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "ruamel-yaml-clib", marker = "python_full_version < '3.15' and platform_python_implementation == 'CPython'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3a/2b/7a1f1ebcd6b3f14febdc003e658778d81e76b40df2267904ee6b13f0c5c6/ruamel_yaml-0.18.17.tar.gz", hash = "sha256:9091cd6e2d93a3a4b157ddb8fabf348c3de7f1fb1381346d985b6b247dcd8d3c", size = 149602, upload-time = "2025-12-17T20:02:55.757Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/fe/b6045c782f1fd1ae317d2a6ca1884857ce5c20f59befe6ab25a8603c43a7/ruamel_yaml-0.18.17-py3-none-any.whl", hash = "sha256:9c8ba9eb3e793efdf924b60d521820869d5bf0cb9c6f1b82d82de8295e290b9d", size = 121594, upload-time = "2025-12-17T20:02:07.657Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruamel-yaml-clib"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ea/97/60fda20e2fb54b83a61ae14648b0817c8f5d84a3821e40bfbdae1437026a/ruamel_yaml_clib-0.2.15.tar.gz", hash = "sha256:46e4cc8c43ef6a94885f72512094e482114a8a706d3c555a34ed4b0d20200600", size = 225794, upload-time = "2025-11-16T16:12:59.761Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/4b/5fde11a0722d676e469d3d6f78c6a17591b9c7e0072ca359801c4bd17eee/ruamel_yaml_clib-0.2.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cb15a2e2a90c8475df45c0949793af1ff413acfb0a716b8b94e488ea95ce7cff", size = 149088, upload-time = "2025-11-16T16:13:22.836Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/82/4d08ac65ecf0ef3b046421985e66301a242804eb9a62c93ca3437dc94ee0/ruamel_yaml_clib-0.2.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:64da03cbe93c1e91af133f5bec37fd24d0d4ba2418eaf970d7166b0a26a148a2", size = 134553, upload-time = "2025-11-16T16:13:24.151Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/cb/22366d68b280e281a932403b76da7a988108287adff2bfa5ce881200107a/ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f6d3655e95a80325b84c4e14c080b2470fe4f33b6846f288379ce36154993fb1", size = 737468, upload-time = "2025-11-16T20:22:47.335Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/73/81230babf8c9e33770d43ed9056f603f6f5f9665aea4177a2c30ae48e3f3/ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71845d377c7a47afc6592aacfea738cc8a7e876d586dfba814501d8c53c1ba60", size = 753349, upload-time = "2025-11-16T16:13:26.269Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/62/150c841f24cda9e30f588ef396ed83f64cfdc13b92d2f925bb96df337ba9/ruamel_yaml_clib-0.2.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e5499db1ccbc7f4b41f0565e4f799d863ea720e01d3e99fa0b7b5fcd7802c9", size = 788211, upload-time = "2025-11-16T16:13:27.441Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/93/e79bd9cbecc3267499d9ead919bd61f7ddf55d793fb5ef2b1d7d92444f35/ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b293a37dc97e2b1e8a1aec62792d1e52027087c8eea4fc7b5abd2bdafdd6642", size = 743203, upload-time = "2025-11-16T16:13:28.671Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/06/1eb640065c3a27ce92d76157f8efddb184bd484ed2639b712396a20d6dce/ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:512571ad41bba04eac7268fe33f7f4742210ca26a81fe0c75357fa682636c690", size = 747292, upload-time = "2025-11-16T20:22:48.584Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/21/ee353e882350beab65fcc47a91b6bdc512cace4358ee327af2962892ff16/ruamel_yaml_clib-0.2.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5e9f630c73a490b758bf14d859a39f375e6999aea5ddd2e2e9da89b9953486a", size = 771624, upload-time = "2025-11-16T16:13:29.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/34/cc1b94057aa867c963ecf9ea92ac59198ec2ee3a8d22a126af0b4d4be712/ruamel_yaml_clib-0.2.15-cp312-cp312-win32.whl", hash = "sha256:f4421ab780c37210a07d138e56dd4b51f8642187cdfb433eb687fe8c11de0144", size = 100342, upload-time = "2025-11-16T16:13:31.067Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/e5/8925a4208f131b218f9a7e459c0d6fcac8324ae35da269cb437894576366/ruamel_yaml_clib-0.2.15-cp312-cp312-win_amd64.whl", hash = "sha256:2b216904750889133d9222b7b873c199d48ecbb12912aca78970f84a5aa1a4bc", size = 119013, upload-time = "2025-11-16T16:13:32.164Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/5e/2f970ce4c573dc30c2f95825f2691c96d55560268ddc67603dc6ea2dd08e/ruamel_yaml_clib-0.2.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dcec721fddbb62e60c2801ba08c87010bd6b700054a09998c4d09c08147b8fb", size = 147450, upload-time = "2025-11-16T16:13:33.542Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/03/a1baa5b94f71383913f21b96172fb3a2eb5576a4637729adbf7cd9f797f8/ruamel_yaml_clib-0.2.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:65f48245279f9bb301d1276f9679b82e4c080a1ae25e679f682ac62446fac471", size = 133139, upload-time = "2025-11-16T16:13:34.587Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/19/40d676802390f85784235a05788fd28940923382e3f8b943d25febbb98b7/ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:46895c17ead5e22bea5e576f1db7e41cb273e8d062c04a6a49013d9f60996c25", size = 731474, upload-time = "2025-11-16T20:22:49.934Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/bb/6ef5abfa43b48dd55c30d53e997f8f978722f02add61efba31380d73e42e/ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3eb199178b08956e5be6288ee0b05b2fb0b5c1f309725ad25d9c6ea7e27f962a", size = 748047, upload-time = "2025-11-16T16:13:35.633Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/5d/e4f84c9c448613e12bd62e90b23aa127ea4c46b697f3d760acc32cb94f25/ruamel_yaml_clib-0.2.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d1032919280ebc04a80e4fb1e93f7a738129857eaec9448310e638c8bccefcf", size = 782129, upload-time = "2025-11-16T16:13:36.781Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/4b/e98086e88f76c00c88a6bcf15eae27a1454f661a9eb72b111e6bbb69024d/ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab0df0648d86a7ecbd9c632e8f8d6b21bb21b5fc9d9e095c796cacf32a728d2d", size = 736848, upload-time = "2025-11-16T16:13:37.952Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/5c/5964fcd1fd9acc53b7a3a5d9a05ea4f95ead9495d980003a557deb9769c7/ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:331fb180858dd8534f0e61aa243b944f25e73a4dae9962bd44c46d1761126bbf", size = 741630, upload-time = "2025-11-16T20:22:51.718Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/1e/99660f5a30fceb58494598e7d15df883a07292346ef5696f0c0ae5dee8c6/ruamel_yaml_clib-0.2.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51", size = 766619, upload-time = "2025-11-16T16:13:39.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/2f/fa0344a9327b58b54970e56a27b32416ffbcfe4dcc0700605516708579b2/ruamel_yaml_clib-0.2.15-cp313-cp313-win32.whl", hash = "sha256:bf0846d629e160223805db9fe8cc7aec16aaa11a07310c50c8c7164efa440aec", size = 100171, upload-time = "2025-11-16T16:13:40.456Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/c4/c124fbcef0684fcf3c9b72374c2a8c35c94464d8694c50f37eef27f5a145/ruamel_yaml_clib-0.2.15-cp313-cp313-win_amd64.whl", hash = "sha256:45702dfbea1420ba3450bb3dd9a80b33f0badd57539c6aac09f42584303e0db6", size = 118845, upload-time = "2025-11-16T16:13:41.481Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/bd/ab8459c8bb759c14a146990bf07f632c1cbec0910d4853feeee4be2ab8bb/ruamel_yaml_clib-0.2.15-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:753faf20b3a5906faf1fc50e4ddb8c074cb9b251e00b14c18b28492f933ac8ef", size = 147248, upload-time = "2025-11-16T16:13:42.872Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/f2/c4cec0a30f1955510fde498aac451d2e52b24afdbcb00204d3a951b772c3/ruamel_yaml_clib-0.2.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:480894aee0b29752560a9de46c0e5f84a82602f2bc5c6cde8db9a345319acfdf", size = 133764, upload-time = "2025-11-16T16:13:43.932Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/c7/2480d062281385a2ea4f7cc9476712446e0c548cd74090bff92b4b49e898/ruamel_yaml_clib-0.2.15-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d3b58ab2454b4747442ac76fab66739c72b1e2bb9bd173d7694b9f9dbc9c000", size = 730537, upload-time = "2025-11-16T20:22:52.918Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/08/e365ee305367559f57ba6179d836ecc3d31c7d3fdff2a40ebf6c32823a1f/ruamel_yaml_clib-0.2.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bfd309b316228acecfa30670c3887dcedf9b7a44ea39e2101e75d2654522acd4", size = 746944, upload-time = "2025-11-16T16:13:45.338Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/5c/8b56b08db91e569d0a4fbfa3e492ed2026081bdd7e892f63ba1c88a2f548/ruamel_yaml_clib-0.2.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2812ff359ec1f30129b62372e5f22a52936fac13d5d21e70373dbca5d64bb97c", size = 778249, upload-time = "2025-11-16T16:13:46.871Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/1d/70dbda370bd0e1a92942754c873bd28f513da6198127d1736fa98bb2a16f/ruamel_yaml_clib-0.2.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7e74ea87307303ba91073b63e67f2c667e93f05a8c63079ee5b7a5c8d0d7b043", size = 737140, upload-time = "2025-11-16T16:13:48.349Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/87/822d95874216922e1120afb9d3fafa795a18fdd0c444f5c4c382f6dac761/ruamel_yaml_clib-0.2.15-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:713cd68af9dfbe0bb588e144a61aad8dcc00ef92a82d2e87183ca662d242f524", size = 741070, upload-time = "2025-11-16T20:22:54.151Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/17/4e01a602693b572149f92c983c1f25bd608df02c3f5cf50fd1f94e124a59/ruamel_yaml_clib-0.2.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:542d77b72786a35563f97069b9379ce762944e67055bea293480f7734b2c7e5e", size = 765882, upload-time = "2025-11-16T16:13:49.526Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/17/7999399081d39ebb79e807314de6b611e1d1374458924eb2a489c01fc5ad/ruamel_yaml_clib-0.2.15-cp314-cp314-win32.whl", hash = "sha256:424ead8cef3939d690c4b5c85ef5b52155a231ff8b252961b6516ed7cf05f6aa", size = 102567, upload-time = "2025-11-16T16:13:50.78Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/67/be582a7370fdc9e6846c5be4888a530dcadd055eef5b932e0e85c33c7d73/ruamel_yaml_clib-0.2.15-cp314-cp314-win_amd64.whl", hash = "sha256:ac9b8d5fa4bb7fd2917ab5027f60d4234345fd366fe39aa711d5dca090aa1467", size = 122847, upload-time = "2025-11-16T16:13:51.807Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.15.0"
|
version = "4.15.0"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||||
@@ -307,7 +387,7 @@ wheels = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-inspection"
|
name = "typing-inspection"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
@@ -318,9 +398,9 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.6.3"
|
version = "2.6.2"
|
||||||
source = { registry = "https://pypi.extoll.de/" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
{ url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" },
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user