youtrack-python 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- youtrack_python-0.1.1/.coveragerc +9 -0
- youtrack_python-0.1.1/.github/workflows/lint-and-test.yml +68 -0
- youtrack_python-0.1.1/.github/workflows/release.yml +90 -0
- youtrack_python-0.1.1/.gitignore +8 -0
- youtrack_python-0.1.1/.idea/watcherTasks.xml +46 -0
- youtrack_python-0.1.1/.run/Run Tests.run.xml +21 -0
- youtrack_python-0.1.1/LICENSE +22 -0
- youtrack_python-0.1.1/PKG-INFO +149 -0
- youtrack_python-0.1.1/README.md +107 -0
- youtrack_python-0.1.1/examples/list_project_custom_fields.py +274 -0
- youtrack_python-0.1.1/pyproject.toml +57 -0
- youtrack_python-0.1.1/pyrightconfig.json +15 -0
- youtrack_python-0.1.1/ruff.toml +20 -0
- youtrack_python-0.1.1/scripts/check.py +55 -0
- youtrack_python-0.1.1/tests/__init__.py +0 -0
- youtrack_python-0.1.1/tests/responses/agile.json +44 -0
- youtrack_python-0.1.1/tests/responses/agiles.json +86 -0
- youtrack_python-0.1.1/tests/responses/issue.json +200 -0
- youtrack_python-0.1.1/tests/responses/issue_comments.json +64 -0
- youtrack_python-0.1.1/tests/responses/issue_link_types.json +54 -0
- youtrack_python-0.1.1/tests/responses/issue_links.json +214 -0
- youtrack_python-0.1.1/tests/responses/issue_work_items.json +38 -0
- youtrack_python-0.1.1/tests/responses/issues.json +389 -0
- youtrack_python-0.1.1/tests/responses/issues_custom_model.json +102 -0
- youtrack_python-0.1.1/tests/responses/project_custom_fields.json +159 -0
- youtrack_python-0.1.1/tests/responses/projects.json +14 -0
- youtrack_python-0.1.1/tests/responses/sprint.json +18 -0
- youtrack_python-0.1.1/tests/responses/sprints.json +239 -0
- youtrack_python-0.1.1/tests/responses/tags.json +17 -0
- youtrack_python-0.1.1/tests/responses/users.json +31 -0
- youtrack_python-0.1.1/tests/responses/work_item_types.json +17 -0
- youtrack_python-0.1.1/tests/test_async_client.py +878 -0
- youtrack_python-0.1.1/tests/test_client.py +842 -0
- youtrack_python-0.1.1/tests/test_converters.py +169 -0
- youtrack_python-0.1.1/tests/test_definitions.py +545 -0
- youtrack_python-0.1.1/tests/test_helpers.py +63 -0
- youtrack_python-0.1.1/tests/test_types.py +148 -0
- youtrack_python-0.1.1/uv.lock +501 -0
- youtrack_python-0.1.1/youtrack_sdk/__init__.py +4 -0
- youtrack_python-0.1.1/youtrack_sdk/async_client.py +712 -0
- youtrack_python-0.1.1/youtrack_sdk/base_client.py +75 -0
- youtrack_python-0.1.1/youtrack_sdk/client.py +712 -0
- youtrack_python-0.1.1/youtrack_sdk/entities.py +907 -0
- youtrack_python-0.1.1/youtrack_sdk/exceptions.py +14 -0
- youtrack_python-0.1.1/youtrack_sdk/helpers.py +152 -0
- youtrack_python-0.1.1/youtrack_sdk/py.typed +1 -0
- youtrack_python-0.1.1/youtrack_sdk/types.py +54 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Lint and Test (ruff + pyright + pytest)
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint-and-test:
|
|
10
|
+
name: Lint and Test
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Check out code
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@v6
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
cache-dependency-glob: |
|
|
22
|
+
**/pyproject.toml
|
|
23
|
+
**/uv.lock
|
|
24
|
+
|
|
25
|
+
- name: Show uv version
|
|
26
|
+
run: uv --version
|
|
27
|
+
|
|
28
|
+
- name: Sync dependencies (frozen)
|
|
29
|
+
run: uv sync --frozen
|
|
30
|
+
|
|
31
|
+
- name: Check formatting (ruff)
|
|
32
|
+
run: uv run ruff format --check
|
|
33
|
+
|
|
34
|
+
- name: Lint (ruff)
|
|
35
|
+
run: uv run ruff check
|
|
36
|
+
|
|
37
|
+
- name: Static type checking
|
|
38
|
+
run: uv run pyright
|
|
39
|
+
|
|
40
|
+
- name: Tests with coverage (pytest-cov)
|
|
41
|
+
run: |
|
|
42
|
+
uv run \
|
|
43
|
+
pytest tests/ \
|
|
44
|
+
--cov=youtrack_sdk \
|
|
45
|
+
--cov-branch \
|
|
46
|
+
--cov-config="${{ github.workspace }}/.coveragerc" \
|
|
47
|
+
--cov-report=term-missing:skip-covered \
|
|
48
|
+
--cov-report=xml:coverage.xml \
|
|
49
|
+
--cov-report=html:coverage_html \
|
|
50
|
+
--cov-fail-under=85
|
|
51
|
+
|
|
52
|
+
- name: Add coverage summary
|
|
53
|
+
run: |
|
|
54
|
+
python3 - <<'PY' | tee -a "$GITHUB_STEP_SUMMARY"
|
|
55
|
+
import xml.etree.ElementTree as ET
|
|
56
|
+
r = float(ET.parse('coverage.xml').getroot().get('branch-rate'))*100
|
|
57
|
+
print(f"coverage: {r:.2f}%")
|
|
58
|
+
PY
|
|
59
|
+
|
|
60
|
+
- name: Upload coverage artifacts
|
|
61
|
+
uses: actions/upload-artifact@v4
|
|
62
|
+
with:
|
|
63
|
+
name: coverage-reports
|
|
64
|
+
path: |
|
|
65
|
+
coverage.xml
|
|
66
|
+
coverage_html
|
|
67
|
+
if-no-files-found: ignore
|
|
68
|
+
retention-days: 14
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: Release (build + publish to PyPI)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
verify-version:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
steps:
|
|
13
|
+
- name: Check out tag
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
ref: ${{ github.event.release.tag_name }}
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
|
|
23
|
+
- name: Verify tag matches pyproject.toml version
|
|
24
|
+
env:
|
|
25
|
+
TAG_NAME: ${{ github.event.release.tag_name }}
|
|
26
|
+
run: |
|
|
27
|
+
python - <<'PY'
|
|
28
|
+
import os, re, sys, pathlib, tomllib
|
|
29
|
+
|
|
30
|
+
tag = os.environ["TAG_NAME"]
|
|
31
|
+
m = re.fullmatch(r"v(\d+\.\d+\.\d+)", tag)
|
|
32
|
+
if not m:
|
|
33
|
+
print(f"ERROR: Release tag {tag!r} is not in vX.Y.Z format.")
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
|
|
36
|
+
data = tomllib.loads(pathlib.Path("pyproject.toml").read_text("utf-8"))
|
|
37
|
+
version = data.get("project", {}).get("version")
|
|
38
|
+
if not version:
|
|
39
|
+
print("ERROR: Missing [project].version in pyproject.toml.")
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
tag_version = m.group(1)
|
|
43
|
+
if version != tag_version:
|
|
44
|
+
print(f"ERROR: Version mismatch: pyproject.toml={version!r} tag={tag_version!r}")
|
|
45
|
+
sys.exit(1)
|
|
46
|
+
|
|
47
|
+
print(f"OK: {version} matches {tag}")
|
|
48
|
+
PY
|
|
49
|
+
|
|
50
|
+
build:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
needs: [verify-version]
|
|
53
|
+
permissions:
|
|
54
|
+
contents: read
|
|
55
|
+
steps:
|
|
56
|
+
- name: Check out tag
|
|
57
|
+
uses: actions/checkout@v4
|
|
58
|
+
with:
|
|
59
|
+
ref: ${{ github.event.release.tag_name }}
|
|
60
|
+
|
|
61
|
+
- name: Install uv
|
|
62
|
+
uses: astral-sh/setup-uv@v3
|
|
63
|
+
|
|
64
|
+
- name: Build distributions
|
|
65
|
+
run: uv build
|
|
66
|
+
|
|
67
|
+
- name: Upload dist artifacts
|
|
68
|
+
uses: actions/upload-artifact@v4
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/*
|
|
72
|
+
|
|
73
|
+
publish:
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
needs: [build]
|
|
76
|
+
environment:
|
|
77
|
+
name: pypi
|
|
78
|
+
url: https://pypi.org/p/youtrack-python
|
|
79
|
+
permissions:
|
|
80
|
+
id-token: write
|
|
81
|
+
contents: read
|
|
82
|
+
steps:
|
|
83
|
+
- name: Download dist artifacts
|
|
84
|
+
uses: actions/download-artifact@v4
|
|
85
|
+
with:
|
|
86
|
+
name: dist
|
|
87
|
+
path: dist
|
|
88
|
+
|
|
89
|
+
- name: Publish to PyPI (Trusted Publishing)
|
|
90
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectTasksOptions">
|
|
4
|
+
<TaskOptions isEnabled="true">
|
|
5
|
+
<option name="arguments" value="sh -c "$PyInterpreterDirectory$/ruff check --fix $FilePath$ ; $PyInterpreterDirectory$/ruff format $FilePath$ ; $PyInterpreterDirectory$/ruff check --fix $FilePath$ ; $PyInterpreterDirectory$/ruff format $FilePath$"" />
|
|
6
|
+
<option name="checkSyntaxErrors" value="true" />
|
|
7
|
+
<option name="description" />
|
|
8
|
+
<option name="exitCodeBehavior" value="NEVER" />
|
|
9
|
+
<option name="fileExtension" value="py" />
|
|
10
|
+
<option name="immediateSync" value="false" />
|
|
11
|
+
<option name="name" value="ruff" />
|
|
12
|
+
<option name="output" value="$FilePath$" />
|
|
13
|
+
<option name="outputFilters">
|
|
14
|
+
<array />
|
|
15
|
+
</option>
|
|
16
|
+
<option name="outputFromStdout" value="false" />
|
|
17
|
+
<option name="program" value="env" />
|
|
18
|
+
<option name="runOnExternalChanges" value="true" />
|
|
19
|
+
<option name="scopeName" value="Project Files" />
|
|
20
|
+
<option name="trackOnlyRoot" value="false" />
|
|
21
|
+
<option name="workingDir" value="$ProjectFileDir$" />
|
|
22
|
+
<envs />
|
|
23
|
+
</TaskOptions>
|
|
24
|
+
|
|
25
|
+
<TaskOptions isEnabled="true">
|
|
26
|
+
<option name="arguments" value="-m json.tool --indent 2 --no-ensure-ascii $FilePath$ $FilePath$" />
|
|
27
|
+
<option name="checkSyntaxErrors" value="true" />
|
|
28
|
+
<option name="description" />
|
|
29
|
+
<option name="exitCodeBehavior" value="ERROR" />
|
|
30
|
+
<option name="fileExtension" value="json" />
|
|
31
|
+
<option name="immediateSync" value="false" />
|
|
32
|
+
<option name="name" value="JSON formatting" />
|
|
33
|
+
<option name="output" value="$FilePath$" />
|
|
34
|
+
<option name="outputFilters">
|
|
35
|
+
<array />
|
|
36
|
+
</option>
|
|
37
|
+
<option name="outputFromStdout" value="false" />
|
|
38
|
+
<option name="program" value="$PyInterpreterDirectory$/python" />
|
|
39
|
+
<option name="runOnExternalChanges" value="true" />
|
|
40
|
+
<option name="scopeName" value="All Changed Files" />
|
|
41
|
+
<option name="trackOnlyRoot" value="false" />
|
|
42
|
+
<option name="workingDir" value="$ProjectFileDir$" />
|
|
43
|
+
<envs />
|
|
44
|
+
</TaskOptions>
|
|
45
|
+
</component>
|
|
46
|
+
</project>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<component name="ProjectRunConfigurationManager">
|
|
2
|
+
<configuration default="false" name="Run Tests" type="tests" factoryName="py.test">
|
|
3
|
+
<module name="youtrack-sdk" />
|
|
4
|
+
<option name="ENV_FILES" value="" />
|
|
5
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
6
|
+
<option name="PARENT_ENVS" value="true" />
|
|
7
|
+
<option name="SDK_HOME" value="" />
|
|
8
|
+
<option name="WORKING_DIRECTORY" value="" />
|
|
9
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
10
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
11
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
12
|
+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
|
13
|
+
<option name="RUN_TOOL" value="true" />
|
|
14
|
+
<option name="_new_keywords" value="""" />
|
|
15
|
+
<option name="_new_parameters" value="""" />
|
|
16
|
+
<option name="_new_additionalArguments" value="""" />
|
|
17
|
+
<option name="_new_target" value=""$PROJECT_DIR$/tests"" />
|
|
18
|
+
<option name="_new_targetType" value=""PATH"" />
|
|
19
|
+
<method v="2" />
|
|
20
|
+
</configuration>
|
|
21
|
+
</component>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2024 moneymeets GmbH
|
|
4
|
+
Copyright (c) 2026 Ninjaneers GmbH
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: youtrack-python
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: YouTrack SDK
|
|
5
|
+
Project-URL: Repository, https://github.com/ninjaneers-team/youtrack-sdk
|
|
6
|
+
Project-URL: Homepage, https://github.com/moneymeets/youtrack-sdk
|
|
7
|
+
Author-email: moneymeets <service@moneymeets.com>, Michael Gerhold <michael.gerhold@ninjaneers.de>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2023-2024 moneymeets GmbH
|
|
11
|
+
Copyright (c) 2026 Ninjaneers GmbH
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: sdk,youtrack
|
|
32
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
38
|
+
Requires-Python: >=3.13
|
|
39
|
+
Requires-Dist: httpx>=0.28.1
|
|
40
|
+
Requires-Dist: pydantic>=2.12.5
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# YouTrack REST API Client
|
|
44
|
+
|
|
45
|
+
A client library for accessing YouTrack REST API.
|
|
46
|
+
|
|
47
|
+
This is a fork of [moneymeets/youtrack-sdk](https://github.com/moneymeets/youtrack-sdk) with several enhancements.
|
|
48
|
+
|
|
49
|
+
## Key Changes from Original
|
|
50
|
+
|
|
51
|
+
This fork includes the following improvements over the original repository:
|
|
52
|
+
|
|
53
|
+
- **AsyncClient Implementation**: Full async/await support with `AsyncClient` for non-blocking I/O operations
|
|
54
|
+
- **Project Custom Fields API**: New `get_project_custom_fields()` method to retrieve custom field definitions for projects
|
|
55
|
+
- **Migrated to UV**: Switched from Poetry to UV for dependency management
|
|
56
|
+
- **Enhanced Testing**: Migrated test suite from unittest to Pytest with async test support
|
|
57
|
+
- **Modern Python**: Updated to require Python 3.13+ with improved type hints and linting
|
|
58
|
+
- **Improved Code Quality**: Enhanced linting with Ruff and type checking with Pyright
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
### Synchronous Client
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from datetime import date
|
|
66
|
+
from youtrack_sdk import Client
|
|
67
|
+
from youtrack_sdk.entities import (
|
|
68
|
+
DateIssueCustomField,
|
|
69
|
+
EnumBundleElement,
|
|
70
|
+
Issue,
|
|
71
|
+
Tag,
|
|
72
|
+
Project,
|
|
73
|
+
SingleEnumIssueCustomField,
|
|
74
|
+
SingleUserIssueCustomField,
|
|
75
|
+
StateBundleElement,
|
|
76
|
+
StateIssueCustomField,
|
|
77
|
+
User,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
with Client(base_url="https://dummy.myjetbrains.com/youtrack", token="dummy") as client:
|
|
81
|
+
result = client.create_issue(
|
|
82
|
+
issue=Issue(
|
|
83
|
+
project=Project(id="0-0"),
|
|
84
|
+
summary="Created from YouTrack SDK",
|
|
85
|
+
description="Description **text**.",
|
|
86
|
+
tags=[
|
|
87
|
+
Tag(id="6-0"),
|
|
88
|
+
],
|
|
89
|
+
custom_fields=[
|
|
90
|
+
StateIssueCustomField(
|
|
91
|
+
name="State",
|
|
92
|
+
value=StateBundleElement(
|
|
93
|
+
name="In Progress",
|
|
94
|
+
),
|
|
95
|
+
),
|
|
96
|
+
SingleUserIssueCustomField(
|
|
97
|
+
name="Assignee",
|
|
98
|
+
value=User(
|
|
99
|
+
ring_id="00000000-a31c-4174-bb27-abd3387df67a",
|
|
100
|
+
),
|
|
101
|
+
),
|
|
102
|
+
SingleEnumIssueCustomField(
|
|
103
|
+
name="Type",
|
|
104
|
+
value=EnumBundleElement(
|
|
105
|
+
name="Bug",
|
|
106
|
+
),
|
|
107
|
+
),
|
|
108
|
+
DateIssueCustomField(
|
|
109
|
+
name="Due Date",
|
|
110
|
+
value=date(2005, 12, 31),
|
|
111
|
+
),
|
|
112
|
+
],
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Async Client
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import asyncio
|
|
121
|
+
from youtrack_sdk import AsyncClient
|
|
122
|
+
from youtrack_sdk.entities import Project
|
|
123
|
+
|
|
124
|
+
async def main():
|
|
125
|
+
async with AsyncClient(base_url="https://dummy.myjetbrains.com/youtrack", token="dummy") as client:
|
|
126
|
+
projects = await client.get_projects()
|
|
127
|
+
for project in projects:
|
|
128
|
+
print(f"Project: {project.name}")
|
|
129
|
+
|
|
130
|
+
asyncio.run(main())
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Fetching Project Custom Fields
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from youtrack_sdk import Client
|
|
137
|
+
|
|
138
|
+
with Client(base_url="https://dummy.myjetbrains.com/youtrack", token="dummy") as client:
|
|
139
|
+
custom_fields = client.get_project_custom_fields(project_id="0-0")
|
|
140
|
+
|
|
141
|
+
for field in custom_fields:
|
|
142
|
+
print(f"Field: {field.field.name}, Type: {type(field).__name__}")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
See [examples/list_project_custom_fields.py](examples/list_project_custom_fields.py) for a complete example.
|
|
146
|
+
|
|
147
|
+
## Note
|
|
148
|
+
|
|
149
|
+
- You should prefer to use internal entity IDs everywhere. Some methods accept readable issue IDs (e.g. HD-99) but it's not supported everywhere.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# YouTrack REST API Client
|
|
2
|
+
|
|
3
|
+
A client library for accessing YouTrack REST API.
|
|
4
|
+
|
|
5
|
+
This is a fork of [moneymeets/youtrack-sdk](https://github.com/moneymeets/youtrack-sdk) with several enhancements.
|
|
6
|
+
|
|
7
|
+
## Key Changes from Original
|
|
8
|
+
|
|
9
|
+
This fork includes the following improvements over the original repository:
|
|
10
|
+
|
|
11
|
+
- **AsyncClient Implementation**: Full async/await support with `AsyncClient` for non-blocking I/O operations
|
|
12
|
+
- **Project Custom Fields API**: New `get_project_custom_fields()` method to retrieve custom field definitions for projects
|
|
13
|
+
- **Migrated to UV**: Switched from Poetry to UV for dependency management
|
|
14
|
+
- **Enhanced Testing**: Migrated test suite from unittest to Pytest with async test support
|
|
15
|
+
- **Modern Python**: Updated to require Python 3.13+ with improved type hints and linting
|
|
16
|
+
- **Improved Code Quality**: Enhanced linting with Ruff and type checking with Pyright
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Synchronous Client
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from datetime import date
|
|
24
|
+
from youtrack_sdk import Client
|
|
25
|
+
from youtrack_sdk.entities import (
|
|
26
|
+
DateIssueCustomField,
|
|
27
|
+
EnumBundleElement,
|
|
28
|
+
Issue,
|
|
29
|
+
Tag,
|
|
30
|
+
Project,
|
|
31
|
+
SingleEnumIssueCustomField,
|
|
32
|
+
SingleUserIssueCustomField,
|
|
33
|
+
StateBundleElement,
|
|
34
|
+
StateIssueCustomField,
|
|
35
|
+
User,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
with Client(base_url="https://dummy.myjetbrains.com/youtrack", token="dummy") as client:
|
|
39
|
+
result = client.create_issue(
|
|
40
|
+
issue=Issue(
|
|
41
|
+
project=Project(id="0-0"),
|
|
42
|
+
summary="Created from YouTrack SDK",
|
|
43
|
+
description="Description **text**.",
|
|
44
|
+
tags=[
|
|
45
|
+
Tag(id="6-0"),
|
|
46
|
+
],
|
|
47
|
+
custom_fields=[
|
|
48
|
+
StateIssueCustomField(
|
|
49
|
+
name="State",
|
|
50
|
+
value=StateBundleElement(
|
|
51
|
+
name="In Progress",
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
SingleUserIssueCustomField(
|
|
55
|
+
name="Assignee",
|
|
56
|
+
value=User(
|
|
57
|
+
ring_id="00000000-a31c-4174-bb27-abd3387df67a",
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
SingleEnumIssueCustomField(
|
|
61
|
+
name="Type",
|
|
62
|
+
value=EnumBundleElement(
|
|
63
|
+
name="Bug",
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
DateIssueCustomField(
|
|
67
|
+
name="Due Date",
|
|
68
|
+
value=date(2005, 12, 31),
|
|
69
|
+
),
|
|
70
|
+
],
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Async Client
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import asyncio
|
|
79
|
+
from youtrack_sdk import AsyncClient
|
|
80
|
+
from youtrack_sdk.entities import Project
|
|
81
|
+
|
|
82
|
+
async def main():
|
|
83
|
+
async with AsyncClient(base_url="https://dummy.myjetbrains.com/youtrack", token="dummy") as client:
|
|
84
|
+
projects = await client.get_projects()
|
|
85
|
+
for project in projects:
|
|
86
|
+
print(f"Project: {project.name}")
|
|
87
|
+
|
|
88
|
+
asyncio.run(main())
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Fetching Project Custom Fields
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from youtrack_sdk import Client
|
|
95
|
+
|
|
96
|
+
with Client(base_url="https://dummy.myjetbrains.com/youtrack", token="dummy") as client:
|
|
97
|
+
custom_fields = client.get_project_custom_fields(project_id="0-0")
|
|
98
|
+
|
|
99
|
+
for field in custom_fields:
|
|
100
|
+
print(f"Field: {field.field.name}, Type: {type(field).__name__}")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
See [examples/list_project_custom_fields.py](examples/list_project_custom_fields.py) for a complete example.
|
|
104
|
+
|
|
105
|
+
## Note
|
|
106
|
+
|
|
107
|
+
- You should prefer to use internal entity IDs everywhere. Some methods accept readable issue IDs (e.g. HD-99) but it's not supported everywhere.
|