Skip to content

Commit 7d30e4d

Browse files
authored
Reboot (#15)
* refactor: change CI from Travis to GitHub Actions * refactor: change toolset to pyproject.toml, uv and ruff * refactor: apply ruff format and check * docs: follow-up changes for pyproject.toml and add dev dependency group * chore: apply ruff to pyproject.toml * refactor: maniac breaking changes, introduce lazy initialization. * refactor: add pyright to be "typed python" * refactor: remove unsafe initial value * refactor: remove python2 compatibility * refactor: clear pyright findings. * refactor: apply strict type annotations * fix: do not forget to run pyright in ci.yml * refactor: follow python EOL schedule. * fix: 3.10 treated as 3.1 * fix: remove unused dependency ipython from dev group * bump version
1 parent d6be576 commit 7d30e4d

15 files changed

Lines changed: 714 additions & 262 deletions

.github/workflows/ci.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
11+
strategy:
12+
matrix:
13+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
14+
15+
steps:
16+
- name: Check out code
17+
uses: actions/checkout@v5
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v6
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Install uv
25+
run: pip install uv
26+
27+
- name: Sync dependencies
28+
run: uv sync --group dev
29+
30+
- name: Run ruff and pyright
31+
run: uv run ruff format . && uv run ruff check --fix . && uv run pyright
32+
33+
- name: Run tests
34+
run: uv run python3 -m unittest tests

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,5 @@ tmp
9191
temp
9292
node_modules
9393
bower_components
94+
95+
.devcontainer

.travis.yml

Lines changed: 0 additions & 10 deletions
This file was deleted.

README.md

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,70 @@ pybacklog
33

44
Backlog API v2 Client Library for Python
55

6-
[![Build Status](https://travis-ci.org/netmarkjp/pybacklog.svg?branch=master)](https://travis-ci.org/netmarkjp/pybacklog)
6+
[![CI](https://github.com/netmarkjp/pybacklog/actions/workflows/ci.yml/badge.svg)](https://github.com/netmarkjp/pybacklog/actions/workflows/ci.yml)
77

88
# Requirements
99

10-
- Python 2.7 or Python 3.5+
10+
- Python 3.10+
1111
- requests 2.x
1212

13-
# Install
13+
# Usage: install
1414

1515
```
1616
pip install pybacklog
1717
```
1818

19-
# Usage
19+
# Usage: code
2020

2121
```python
2222
from pybacklog import BacklogClient
23+
import os
2324

24-
client = BacklogClient("your_space_name", "your_api_key")
25+
YOUR_SPACE_NAME = os.getenv("BACKLOG_SPACE_NAME", "")
26+
YOUR_API_KEY = os.getenv("BACKLOG_API_KEY", "")
27+
YOUR_PROJECT = os.getenv("BACKLOG_PROJECT", "")
28+
YOUR_ISSUE_KEY = os.getenv("BACKLOG_ISSUE_KEY", "")
29+
30+
client = BacklogClient(YOUR_SPACE_NAME, YOUR_API_KEY)
2531

2632
# space
27-
space = client.do("GET", "space") # GET /api/v2/space
28-
print(space.get(u"spaceKey"))
33+
space = client.space()
34+
print(space.get("spaceKey"))
2935

3036
# project
3137
projects = client.projects()
3238

3339
# activity
34-
activities = client.project_activities("YOUR_PROJECT", {"activityTypeId[]": [1, 2]})
40+
activities = client.project_activities(YOUR_PROJECT, {"activityTypeId[]": [1, 2]})
3541

3642
# list issue
37-
project_id = client.get_project_id("YOUR_PROJECT")
38-
issues = client.issues({"projectId[]":[project_id], "sort": "dueDate"})
43+
project_id = client.get_project_id(YOUR_PROJECT)
44+
issues = client.issues({"projectId[]": [project_id], "sort": "dueDate"})
3945

4046
# specified issue
41-
issue = client.issue("YOUR_PROJECT-999")
47+
issue = client.issue(YOUR_ISSUE_KEY)
4248

4349
# create issue
44-
project_id = client.get_project_id(project_key)
45-
issue_type_id = client.project_issue_types(project_key)[0][u"id"]
46-
priority_id = client.priorities()[0][u"id"]
50+
project_id = client.get_project_id(YOUR_PROJECT)
51+
issue_type_id = client.project_issue_types(YOUR_PROJECT)[0]["id"]
52+
priority_id = client.priorities()[0]["id"]
4753

48-
client.create_issue(project_id,
49-
u"some summary",
50-
issue_type_id,
51-
priority_id,
52-
{"description": u"a is b and c or d."})
54+
if project_id and issue_type_id and priority_id:
55+
client.create_issue(project_id, "some summary", issue_type_id, priority_id, {"description": "a is b and c or d."})
5356

5457
# add comment
55-
client.add_issue_comment("YOUR_PROJECT-999", u"or ... else e.")
58+
client.add_issue_comment(YOUR_ISSUE_KEY, "or ... else e.")
5659

5760
# top 10 star collector
58-
star_collectors = [(client.user_stars_count(u[u"id"], {"since": "2017-06-01", "until": "2017-06-30"})[u"count"], u[u"name"]) for u in client.users()]
61+
star_collectors = [
62+
(client.user_stars_count(u["id"], {"since": "2017-06-01", "until": "2017-06-30"})["count"], u["name"])
63+
for u in client.users()
64+
]
5965
star_collectors.sort()
6066
star_collectors.reverse()
6167

6268
for i, (c, u) in enumerate(star_collectors[:10]):
63-
print(i+1, c, u)
69+
print(i + 1, c, u)
6470
```
6571

6672
supported operations are `pydoc pybacklog.BacklogClient`
@@ -74,27 +80,30 @@ Use `do` or let's write code and Pull Request.
7480

7581
```python
7682
from pybacklog import BacklogClient
83+
import os
7784

78-
client = BacklogClient("your_space_name", "your_api_key")
85+
YOUR_SPACE_NAME = os.getenv("BACKLOG_SPACE_NAME", "")
86+
YOUR_API_KEY = os.getenv("BACKLOG_API_KEY", "")
87+
YOUR_PROJECT = os.getenv("BACKLOG_PROJECT", "")
88+
89+
client = BacklogClient(YOUR_SPACE_NAME, YOUR_API_KEY)
7990
space = client.do("GET", "space") # GET /api/v2/space
80-
projects = client.do("GET", "projects",
81-
query_params={"archived": false}
82-
) # GET /api/v2/projects?archived=false
83-
activities = client.do("GET", "projects/{project_id_or_key}/activities",
84-
url_params={"project_id_or_key": "myproj"},
85-
query_params={"activityTypeId[]": [1, 2]}
86-
) # GET /api/v2/projects/myproj/activities?activityTypeIds%5B%5D=1&activityTypeIds%5B%5D=2
91+
projects = client.do("GET", "projects", query_params={"archived": False}) # GET /api/v2/projects?archived=false
92+
activities = client.do(
93+
"GET",
94+
"projects/{project_id_or_key}/activities",
95+
url_params={"project_id_or_key": YOUR_PROJECT},
96+
query_params={"activityTypeId[]": [1, 2]},
97+
) # GET /api/v2/projects/myproj/activities?activityTypeIds%5B%5D=1&activityTypeIds%5B%5D=2
8798
```
8899

89100
see also [Backlog API Overview \| Backlog Developer API \| Nulab](https://developer.nulab-inc.com/docs/backlog/)
90101

91102
# Development
92103

93104
```
94-
pip install -r requirements.txt
95-
pip install -r requirements_dev.txt
96-
97-
PYTHONPATH=. python -m unittest tests
105+
uv sync --group dev
106+
uv run python3 -m unittest tests
98107
```
99108

100109
# License

examples/project_activities.py

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,46 @@
11
# -*- coding: utf-8 -*-
22

3+
from typing import List, Tuple
4+
35
from pybacklog import BacklogClient
46
import os
57

6-
_space = os.getenv("BACKLOG_SPACE")
7-
_api_key = os.getenv("BACKLOG_API_KEY")
8-
_project = os.getenv("BACKLOG_PROJECT")
8+
_space = os.getenv("BACKLOG_SPACE", "")
9+
_api_key = os.getenv("BACKLOG_API_KEY", "")
10+
_project = os.getenv("BACKLOG_PROJECT", "")
911

1012

1113
client = BacklogClient(_space, _api_key)
12-
activities = client.do("GET", "projects/{project_id_or_key}/activities",
13-
url_params={"project_id_or_key": _project},
14-
query_params={"activityTypeId[]": [
15-
1, 2, 3, 14], "count": 100}
16-
)
17-
18-
urls = []
19-
items = []
20-
for activity in activities:
21-
url = client.activity_to_issue_url(activity)
22-
if url in urls:
23-
continue
24-
urls.append(url)
25-
26-
item = (activity.get(u"created"), url,
27-
activity.get(u"content").get(u"summary"))
28-
items.append(item)
14+
activities = client.do(
15+
"GET",
16+
"projects/{project_id_or_key}/activities",
17+
url_params={"project_id_or_key": _project},
18+
query_params={"activityTypeId[]": [1, 2, 3, 14], "count": 100},
19+
)
20+
21+
urls: List[str] = []
22+
items: List[Tuple[str, str, str]] = []
23+
if activities:
24+
for activity in activities:
25+
if not isinstance(activity, dict):
26+
continue
27+
28+
created = activity.get("created", "")
29+
30+
url = client.activity_to_issue_url(activity)
31+
if url in urls:
32+
continue
33+
urls.append(url)
34+
35+
try:
36+
summary = activity["content"]["summary"]
37+
except KeyError:
38+
summary = ""
39+
except TypeError:
40+
summary = ""
41+
42+
item = (created, url, summary)
43+
items.append(item)
2944

3045
for item in items:
31-
print(u"{date}\t{url}\t{summary}".format(date=item[0], url=item[1], summary=item[2]))
46+
print("{date}\t{url}\t{summary}".format(date=item[0], url=item[1], summary=item[2]))

examples/project_activities2.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,37 @@
11
# -*- coding: utf-8 -*-
22

3+
from typing import List, Tuple
4+
35
from pybacklog import BacklogClient
46
import os
57

6-
_space = os.getenv("BACKLOG_SPACE")
7-
_api_key = os.getenv("BACKLOG_API_KEY")
8-
_project = os.getenv("BACKLOG_PROJECT")
8+
_space = os.getenv("BACKLOG_SPACE", "")
9+
_api_key = os.getenv("BACKLOG_API_KEY", "")
10+
_project = os.getenv("BACKLOG_PROJECT", "")
911

1012

1113
client = BacklogClient(_space, _api_key)
12-
activities = client.project_activities(
13-
_project,
14-
{"activityTypeId[]": [1, 2, 3, 14], "count": 100})
15-
16-
urls = []
17-
items = []
18-
for activity in activities:
19-
url = client.activity_to_issue_url(activity)
20-
if url in urls:
21-
continue
22-
if "None" in url:
23-
print(activity)
24-
continue
25-
urls.append(url)
26-
27-
item = (activity.get(u"created"), url,
28-
activity.get(u"content").get(u"summary"))
29-
items.append(item)
14+
activities = client.project_activities(_project, {"activityTypeId[]": [1, 2, 3, 14], "count": 100})
15+
16+
urls: List[str] = []
17+
items: List[Tuple[str, str, str]] = []
18+
if activities:
19+
for activity in activities:
20+
url = client.activity_to_issue_url(activity)
21+
if url in urls:
22+
continue
23+
urls.append(url)
24+
25+
created = activity.get("created", "")
26+
27+
try:
28+
summary = activity["content"]["summary"]
29+
except KeyError:
30+
summary = ""
31+
except TypeError:
32+
summary = ""
33+
item = (created, url, summary)
34+
items.append(item)
3035

3136
for item in items:
32-
print(u"{date}\t{url}\t{summary}".format(
33-
date=item[0], url=item[1], summary=item[2]))
37+
print("{date}\t{url}\t{summary}".format(date=item[0], url=item[1], summary=item[2]))

examples/readme.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from pybacklog import BacklogClient
2+
import os
3+
4+
YOUR_SPACE_NAME = os.getenv("BACKLOG_SPACE_NAME", "")
5+
YOUR_API_KEY = os.getenv("BACKLOG_API_KEY", "")
6+
YOUR_PROJECT = os.getenv("BACKLOG_PROJECT", "")
7+
YOUR_ISSUE_KEY = os.getenv("BACKLOG_ISSUE_KEY", "")
8+
9+
client = BacklogClient(YOUR_SPACE_NAME, YOUR_API_KEY)
10+
11+
# space
12+
space = client.space()
13+
print(space.get("spaceKey"))
14+
15+
# project
16+
projects = client.projects()
17+
18+
# activity
19+
activities = client.project_activities(YOUR_PROJECT, {"activityTypeId[]": [1, 2]})
20+
21+
# list issue
22+
project_id = client.get_project_id(YOUR_PROJECT)
23+
issues = client.issues({"projectId[]": [project_id], "sort": "dueDate"})
24+
25+
# specified issue
26+
issue = client.issue(YOUR_ISSUE_KEY)
27+
28+
# create issue
29+
project_id = client.get_project_id(YOUR_PROJECT)
30+
issue_type_id = client.project_issue_types(YOUR_PROJECT)[0]["id"]
31+
priority_id = client.priorities()[0]["id"]
32+
33+
if project_id and issue_type_id and priority_id:
34+
client.create_issue(project_id, "some summary", issue_type_id, priority_id, {"description": "a is b and c or d."})
35+
36+
# add comment
37+
client.add_issue_comment(YOUR_ISSUE_KEY, "or ... else e.")
38+
39+
# top 10 star collector
40+
star_collectors = [
41+
(client.user_stars_count(u["id"], {"since": "2017-06-01", "until": "2017-06-30"})["count"], u["name"])
42+
for u in client.users()
43+
]
44+
star_collectors.sort()
45+
star_collectors.reverse()
46+
47+
for i, (c, u) in enumerate(star_collectors[:10]):
48+
print(i + 1, c, u)

examples/readme2.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from pybacklog import BacklogClient
2+
import os
3+
4+
YOUR_SPACE_NAME = os.getenv("BACKLOG_SPACE_NAME", "")
5+
YOUR_API_KEY = os.getenv("BACKLOG_API_KEY", "")
6+
YOUR_PROJECT = os.getenv("BACKLOG_PROJECT", "")
7+
8+
client = BacklogClient(YOUR_SPACE_NAME, YOUR_API_KEY)
9+
space = client.do("GET", "space") # GET /api/v2/space
10+
projects = client.do("GET", "projects", query_params={"archived": False}) # GET /api/v2/projects?archived=false
11+
activities = client.do(
12+
"GET",
13+
"projects/{project_id_or_key}/activities",
14+
url_params={"project_id_or_key": YOUR_PROJECT},
15+
query_params={"activityTypeId[]": [1, 2]},
16+
) # GET /api/v2/projects/myproj/activities?activityTypeIds%5B%5D=1&activityTypeIds%5B%5D=2

0 commit comments

Comments
 (0)