├── .gitignore ├── HISTORY.md ├── LICENSE ├── README.md ├── requirements.txt ├── setup.py ├── tests ├── conftest.py ├── test_group.py ├── test_repo.py ├── test_request_client.py └── test_user.py └── yuque_py ├── __init__.py ├── clients ├── __init__.py ├── abstract_client.py └── client.py ├── exceptions ├── __init__.py └── request_error.py ├── models ├── __init__.py ├── doc.py ├── group.py ├── repo.py └── user.py └── yuque.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | .idea 106 | .pytest_cache 107 | .vscode -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | Release History 2 | =============== 3 | 4 | 0.0.3(2020-01-08) 5 | 6 | * fix type hint error 7 | 8 | 0.0.1(2019-08-28) 9 | 10 | * support basic function -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Manjusaka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yuque-py 2 | 3 | Python SDK for [yuque](https://www.yuque.com/yuque/developer/api) 4 | 5 | 6 | ## Install 7 | 8 | ```bash 9 | pip install yuque-py 10 | ``` 11 | 12 | ## Usage 13 | 14 | ```python 15 | from yuque_py import Yuque 16 | 17 | yuque=Yuque(api_host="",user_token="") 18 | yuque.docs 19 | ``` 20 | 21 | 22 | ## API 23 | 24 | see [Yuque API Docs](https://www.yuque.com/yuque/developer/api) for more details. 25 | 26 | ### users 27 | 28 | see the source. 29 | 30 | ### groups 31 | 32 | see the source. 33 | 34 | ### repos 35 | 36 | see the source. 37 | 38 | ### docs 39 | 40 | see the source. 41 | 42 | ## TODO 43 | 44 | - [ ] API docs 45 | - [ ] JSDocs definition for result info 46 | - [ ] add `d.ts` or refactor to TypeScript 47 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==5.1.1 2 | pytest-cov==2.7.1 3 | requests==2.22.0 4 | requests-mock==1.6.0 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os 3 | from setuptools import setup 4 | from yuque_py import __version__ 5 | 6 | here = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | readme = codecs.open('README.md', encoding='utf-8').read() 9 | history = codecs.open('HISTORY.md', encoding='utf-8').read() 10 | 11 | packages = ["yuque_py", "yuque_py.models", "yuque_py.clients", "yuque_py.exceptions"] 12 | 13 | requires = [ 14 | "pytest==5.1.1", 15 | "pytest-cov==2.7.1", 16 | "requests==2.22.0", 17 | "requests-mock==1.6.0" 18 | ] 19 | 20 | setup( 21 | name="yuque-py", 22 | version=__version__, 23 | description="yuque api for python version", 24 | long_description=u'\n\n'.join([readme, history]), 25 | long_description_content_type='text/markdown', 26 | author="Manjusaka", 27 | author_email="me@manjusaka.me", 28 | url="https://github.com/Zheaoli/yuque-py", 29 | packages=packages, 30 | install_requires=requires, 31 | include_package_data=True, 32 | license="MIT License", 33 | python_requires=">=3.6", 34 | classifiers=[ 35 | "Intended Audience :: Developers", 36 | "License :: OSI Approved :: MIT License", 37 | "Operating System :: MacOS :: MacOS X", 38 | "Operating System :: Microsoft :: Windows", 39 | "Operating System :: POSIX", 40 | "Programming Language :: Python", 41 | "Programming Language :: Python :: 2", 42 | "Programming Language :: Python :: 3", 43 | "Topic :: Software Development :: Libraries :: Python Modules", 44 | "Programming Language :: Python :: Implementation :: PyPy", 45 | "Programming Language :: Python :: Implementation :: CPython", 46 | ], 47 | ) 48 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import pytest 4 | from yuque_py.clients.client import Client 5 | from yuque_py.clients.abstract_client import AbstractClient 6 | 7 | API_HOST = "http://mock" 8 | USER_TOKEN = "ABC" 9 | 10 | 11 | @pytest.fixture 12 | def standard_client(): 13 | return Client(f"{API_HOST}", f"{USER_TOKEN}") 14 | 15 | 16 | @pytest.fixture 17 | def api_host(): 18 | return API_HOST 19 | 20 | 21 | @pytest.fixture 22 | def user_token(): 23 | return USER_TOKEN 24 | 25 | 26 | class MockClient(AbstractClient): 27 | def __init__(self): 28 | self.api = None 29 | self.method = None 30 | self.request_data = None 31 | 32 | def request( 33 | self, 34 | api: str, 35 | method: str, 36 | requests_data: typing.Optional[typing.Dict[str, typing.Any]] = None, 37 | ) -> typing.Dict: 38 | self.api = api 39 | self.method = method 40 | self.request_data = requests_data 41 | return {} 42 | 43 | 44 | @pytest.fixture 45 | def mock_client(): 46 | return MockClient() 47 | -------------------------------------------------------------------------------- /tests/test_group.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from yuque_py.models.group import Group 4 | 5 | 6 | def test_group_list_with_user(mock_client): 7 | group = Group(mock_client) 8 | group.list("bac") 9 | assert mock_client.api == "users/bac/groups" 10 | 11 | 12 | def test_group_list_without_user(mock_client): 13 | group = Group(mock_client) 14 | group.list() 15 | assert mock_client.api == "groups" 16 | 17 | 18 | def test_group_create(mock_client): 19 | group = Group(mock_client) 20 | data = {"name": 1, "login": "abc"} 21 | group.create(data) 22 | assert mock_client.request_data == data 23 | 24 | 25 | def test_group_create_with_assert_error(mock_client): 26 | group = Group(mock_client) 27 | data = {"login": "abc"} 28 | with pytest.raises(AssertionError): 29 | group.create(data) 30 | 31 | 32 | def test_group_get(mock_client): 33 | group = Group(mock_client) 34 | group.get("abc") 35 | assert mock_client.api == "groups/abc" 36 | 37 | 38 | def test_group_update(mock_client): 39 | group = Group(mock_client) 40 | group.update("abc", {}) 41 | assert mock_client.api == "groups/abc" 42 | 43 | 44 | def test_group_delete(mock_client): 45 | group = Group(mock_client) 46 | group.delete("abc") 47 | assert mock_client.api == "groups/abc" 48 | 49 | 50 | def test_group_list_user(mock_client): 51 | group = Group(mock_client) 52 | group.list_user("abc") 53 | assert mock_client.api == "groups/abc/users" 54 | -------------------------------------------------------------------------------- /tests/test_repo.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from yuque_py.models.repo import Repo 4 | 5 | 6 | def test_repo_list_with_user(mock_client): 7 | repo = Repo(mock_client) 8 | repo.list("bac") 9 | assert mock_client.api == "users/bac/repos" 10 | 11 | 12 | def test_repo_list_with_group(mock_client): 13 | repo = Repo(mock_client) 14 | repo.list(group="bac") 15 | assert mock_client.api == "groups/bac/repos" 16 | 17 | 18 | def test_repo_list_with_assert_error(mock_client): 19 | repo = Repo(mock_client) 20 | with pytest.raises(AssertionError): 21 | repo.list() 22 | 23 | 24 | def test_repo_create_with_user(mock_client): 25 | repo = Repo(mock_client) 26 | repo.list("bac") 27 | assert mock_client.api == "users/bac/repos" 28 | 29 | 30 | def test_repo_create_with_group(mock_client): 31 | repo = Repo(mock_client) 32 | repo.list(group="bac") 33 | assert mock_client.api == "groups/bac/repos" 34 | 35 | 36 | def test_repo_create_with_assert_error(mock_client): 37 | repo = Repo(mock_client) 38 | with pytest.raises(AssertionError): 39 | repo.list() 40 | 41 | 42 | def test_repo_get(mock_client): 43 | repo = Repo(mock_client) 44 | repo.get("abc") 45 | assert mock_client.api == "repos/abc" 46 | 47 | 48 | def test_repo_update(mock_client): 49 | repo = Repo(mock_client) 50 | repo.update("abc", {}) 51 | assert mock_client.api == "repos/abc" 52 | 53 | 54 | def test_delete_update(mock_client): 55 | repo = Repo(mock_client) 56 | repo.delete("abc") 57 | assert mock_client.api == "repos/abc" 58 | -------------------------------------------------------------------------------- /tests/test_request_client.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import requests_mock 4 | import pytest 5 | from yuque_py.exceptions.request_error import RequestError 6 | 7 | 8 | def test_get_request_with_no_data(standard_client, api_host, user_token): 9 | api = "abc" 10 | with requests_mock.Mocker() as m: 11 | request = m.get(f"{api_host}/{api}", json={"data": {}}) 12 | response = standard_client.request(api, method="GET") 13 | assert request.last_request.path == f"/{api}" 14 | assert response == {"data": {}} 15 | assert request.last_request.headers["User-Agent"] == "@yuque/sdk" 16 | assert request.last_request.headers["X-Auth-Token"] == user_token 17 | 18 | 19 | def test_get_request_with_query(standard_client, api_host, user_token): 20 | api = "abc" 21 | data = {"abc": 1} 22 | with requests_mock.Mocker() as m: 23 | request = m.get(f"{api_host}/{api}?abc=1", json={"data": {}}) 24 | response = standard_client.request(api, method="GET", requests_data=data) 25 | assert request.last_request.path == f"/{api}?abc=1" 26 | assert response == {"data": {}} 27 | assert request.last_request.headers["User-Agent"] == "@yuque/sdk" 28 | assert request.last_request.headers["X-Auth-Token"] == user_token 29 | 30 | 31 | def test_post_request(standard_client, api_host, user_token): 32 | api = "abc" 33 | data = {"abc": 1} 34 | with requests_mock.Mocker() as m: 35 | request = m.post(f"{api_host}/{api}", json={"data": {}}) 36 | response = standard_client.request(api, method="POST", requests_data=data) 37 | assert json.loads(request.last_request.text) == data 38 | assert response == {"data": {}} 39 | assert request.last_request.headers["User-Agent"] == "@yuque/sdk" 40 | assert request.last_request.headers["X-Auth-Token"] == user_token 41 | assert request.last_request.headers["Content-Type"] == "application/json" 42 | 43 | 44 | def test_put_request(standard_client, api_host, user_token): 45 | api = "abc" 46 | data = {"abc": 1} 47 | with requests_mock.Mocker() as m: 48 | request = m.put(f"{api_host}/{api}", json={"data": {}}) 49 | response = standard_client.request(api, method="PUT", requests_data=data) 50 | assert json.loads(request.last_request.text) == data 51 | assert response == {"data": {}} 52 | assert request.last_request.headers["User-Agent"] == "@yuque/sdk" 53 | assert request.last_request.headers["X-Auth-Token"] == user_token 54 | assert request.last_request.headers["Content-Type"] == "application/json" 55 | 56 | 57 | def test_delete_request(standard_client, api_host, user_token): 58 | api = "abc" 59 | with requests_mock.Mocker() as m: 60 | request = m.delete(f"{api_host}/{api}", json={"data": {}}) 61 | response = standard_client.request(api, method="DELETE") 62 | assert response == {"data": {}} 63 | assert request.last_request.headers["User-Agent"] == "@yuque/sdk" 64 | assert request.last_request.headers["X-Auth-Token"] == user_token 65 | 66 | 67 | def test_request_with_exception(standard_client, api_host, user_token): 68 | with pytest.raises(RequestError): 69 | api = "abc" 70 | with requests_mock.Mocker() as m: 71 | request = m.delete(f"{api_host}/{api}", status_code=401) 72 | response = standard_client.request(api, method="DELETE") 73 | -------------------------------------------------------------------------------- /tests/test_user.py: -------------------------------------------------------------------------------- 1 | from yuque_py.models.user import User 2 | 3 | 4 | def test_user_get_with_login(mock_client): 5 | user = User(mock_client) 6 | user.get("abc") 7 | assert mock_client.api == f"users/abc" 8 | 9 | 10 | def test_user_get_with_no_login(mock_client): 11 | user = User(mock_client) 12 | user.get() 13 | assert mock_client.api == f"user" 14 | -------------------------------------------------------------------------------- /yuque_py/__init__.py: -------------------------------------------------------------------------------- 1 | from .yuque import Yuque 2 | 3 | __all__ = ["Yuque"] 4 | 5 | __version__ = "0.0.4" 6 | -------------------------------------------------------------------------------- /yuque_py/clients/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zheaoli/yuque-py/90905558455640c58787a24652c6b96e696147e1/yuque_py/clients/__init__.py -------------------------------------------------------------------------------- /yuque_py/clients/abstract_client.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import typing 3 | 4 | 5 | class AbstractClient: 6 | @abc.abstractmethod 7 | def request( 8 | self, 9 | api: str, 10 | method: str, 11 | requests_data: typing.Optional[typing.Dict[str, typing.Any]] = None, 12 | ) -> typing.Dict: 13 | pass 14 | -------------------------------------------------------------------------------- /yuque_py/clients/client.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | import requests 4 | from urllib.parse import urlencode 5 | 6 | from .abstract_client import AbstractClient 7 | from yuque_py.exceptions.request_error import RequestError 8 | 9 | 10 | class Client(AbstractClient): 11 | api_host: str 12 | user_token: str 13 | 14 | def __init__(self, api_host: str, user_token: str) -> None: 15 | self.api_host = api_host 16 | self.user_token = user_token 17 | 18 | def request( 19 | self, 20 | api: str, 21 | method: str, 22 | requests_data: typing.Optional[typing.Dict[str, typing.Any]] = None, 23 | user_agent: str = "@yuque/sdk", 24 | ) -> typing.Dict: 25 | request_url = f"{self.api_host}/{api}" 26 | request_header = {"User-Agent": user_agent, "X-Auth-Token": self.user_token} 27 | if method == "GET": 28 | func = self._get_request 29 | elif method == "POST": 30 | request_header["Content-Type"] = "application/json" 31 | func = self._post_request 32 | elif method == "PUT": 33 | request_header["Content-Type"] = "application/json" 34 | func = self._put_request 35 | elif method == "DELETE": 36 | func = self._delete_request 37 | else: 38 | raise ValueError 39 | response = func(request_url, requests_data, request_header) 40 | if response.status_code != 200: 41 | raise RequestError(response.status_code, response.text) 42 | return response.json() 43 | 44 | @staticmethod 45 | def _get_request( 46 | request_url: str, 47 | requests_data: typing.Optional[typing.Dict[str, typing.Any]], 48 | request_header: typing.Dict[str, str], 49 | ) -> requests.Response: 50 | if requests_data: 51 | request_url = f"{request_url}?{urlencode(requests_data)}" 52 | 53 | return requests.get(request_url, headers=request_header) 54 | 55 | @staticmethod 56 | def _post_request( 57 | request_url: str, 58 | requests_data: typing.Optional[typing.Dict[str, typing.Any]], 59 | request_header: typing.Dict[str, str], 60 | ) -> requests.Response: 61 | return requests.post(request_url, json=requests_data, headers=request_header) 62 | 63 | @staticmethod 64 | def _put_request( 65 | request_url: str, 66 | requests_data: typing.Optional[typing.Dict[str, typing.Any]], 67 | request_header: typing.Dict[str, str], 68 | ) -> requests.Response: 69 | return requests.put(request_url, json=requests_data, headers=request_header) 70 | 71 | @staticmethod 72 | def _delete_request( 73 | request_url: str, 74 | requests_data: typing.Optional[typing.Dict[str, typing.Any]], 75 | request_header: typing.Dict[str, str], 76 | ) -> requests.Response: 77 | return requests.delete(request_url, headers=request_header) 78 | -------------------------------------------------------------------------------- /yuque_py/exceptions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zheaoli/yuque-py/90905558455640c58787a24652c6b96e696147e1/yuque_py/exceptions/__init__.py -------------------------------------------------------------------------------- /yuque_py/exceptions/request_error.py: -------------------------------------------------------------------------------- 1 | class RequestError(Exception): 2 | def __init__(self, status_code: int, response_body: str): 3 | message = f"Request for yuque failed, response_code:{status_code},response_body:{response_body}" 4 | super().__init__(message) 5 | -------------------------------------------------------------------------------- /yuque_py/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .doc import Doc 2 | from .group import Group 3 | from .repo import Repo 4 | from .user import User 5 | -------------------------------------------------------------------------------- /yuque_py/models/doc.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from yuque_py.clients.abstract_client import AbstractClient 4 | 5 | 6 | class Doc: 7 | def __init__(self, client: AbstractClient): 8 | self._client = client 9 | 10 | def list( 11 | self, namespace: str, data: typing.Optional[typing.Dict] = None 12 | ) -> typing.Dict: 13 | assert namespace 14 | api = f"repos/{namespace}/docs" 15 | return self._client.request(api,method='GET',requests_data=data) 16 | 17 | def get( 18 | self, namespace: str, slug: str, data: typing.Optional[typing.Dict] = None 19 | ) -> typing.Dict: 20 | assert namespace 21 | assert slug 22 | api = f"repos/{namespace}/docs/{slug}" 23 | return self._client.request(api, method="GET", requests_data=data) 24 | 25 | def create( 26 | self, namespace: str, data: typing.Optional[typing.Dict] = None 27 | ) -> typing.Dict: 28 | assert namespace 29 | api = f"repos/{namespace}/docs" 30 | return self._client.request(api, method="POST", requests_data=data) 31 | 32 | def update( 33 | self, namespace: str, doc_id: str, data: typing.Optional[typing.Dict] = None 34 | ) -> typing.Dict: 35 | assert namespace 36 | assert doc_id 37 | api = f"repos/{namespace}/docs/{doc_id}" 38 | return self._client.request(api, method="PUT", requests_data=data) 39 | 40 | def delete(self, namespace: str, doc_id: str) -> typing.Dict: 41 | assert namespace 42 | assert doc_id 43 | api = f"repos/{namespace}/docs/{doc_id}" 44 | return self._client.request(api, method="DELETE") 45 | -------------------------------------------------------------------------------- /yuque_py/models/group.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from yuque_py.clients.abstract_client import AbstractClient 4 | 5 | 6 | class Group: 7 | def __init__(self, client: AbstractClient): 8 | self._client = client 9 | 10 | def list( 11 | self, 12 | login: typing.Optional[str] = None, 13 | data: typing.Optional[typing.Dict] = None, 14 | ) -> typing.Dict: 15 | api = f"users/{login}/groups" if login else "groups" 16 | return self._client.request(api, method="GET", requests_data=data) 17 | 18 | def create(self, data: typing.Dict) -> typing.Dict: 19 | assert "name" in data 20 | assert "login" in data 21 | api = "groups" 22 | return self._client.request(api, method="POST", requests_data=data) 23 | 24 | def get(self, login: str) -> typing.Dict: 25 | assert login 26 | api = f"groups/{login}" 27 | return self._client.request(api, method="GET") 28 | 29 | def update(self, login: str, data: typing.Dict) -> typing.Dict: 30 | assert login 31 | api = f"groups/{login}" 32 | return self._client.request(api, method="PUT", requests_data=data) 33 | 34 | def delete(self, login: str) -> typing.Dict: 35 | assert login 36 | api = f"groups/{login}" 37 | return self._client.request(api, method="DELETE") 38 | 39 | def list_user(self, login: str) -> typing.Dict: 40 | return self._client.request(f"groups/{login}/users", method="GET") 41 | 42 | def add_user(self, group: str, user: str, data: typing.Dict) -> typing.Dict: 43 | assert group 44 | assert user 45 | api = f"groups/{group}/users/{user}" 46 | return self._client.request(api, method="PUT", requests_data=data) 47 | 48 | def remove_user(self, group: str, user: str) -> typing.Dict: 49 | assert group 50 | assert user 51 | api = f"groups/{group}/users/{user}" 52 | return self._client.request(api, method="DELETE") 53 | 54 | @staticmethod 55 | def _get_url(user: str, group: str): 56 | assert user or group 57 | api = f"users/{user}/repos" if user else f"users/{group}/repos" 58 | return api 59 | -------------------------------------------------------------------------------- /yuque_py/models/repo.py: -------------------------------------------------------------------------------- 1 | import typing 2 | import warnings 3 | from yuque_py.clients.abstract_client import AbstractClient 4 | 5 | 6 | class Repo: 7 | def __init__(self, client: AbstractClient): 8 | self._client = client 9 | 10 | def list( 11 | self, 12 | user: typing.Optional[str] = None, 13 | group: typing.Optional[str] = None, 14 | data: typing.Optional[typing.Dict] = None, 15 | ) -> typing.Dict: 16 | api = self._get_url(user, group) 17 | return self._client.request(api, method="GET", requests_data=data) 18 | 19 | def create( 20 | self, 21 | user: typing.Optional[str] = None, 22 | group: typing.Optional[str] = None, 23 | data: typing.Optional[typing.Dict] = None, 24 | ) -> typing.Dict: 25 | api = self._get_url(user, group) 26 | assert data 27 | return self._client.request(api, method="POST", requests_data=data) 28 | 29 | def get(self, namespace: str, data: typing.Dict = None) -> typing.Dict: 30 | assert namespace 31 | return self._client.request( 32 | f"repos/{namespace}", method="GET", requests_data=data 33 | ) 34 | 35 | def update(self, namespace: str, data: typing.Dict) -> typing.Dict: 36 | assert namespace 37 | return self._client.request( 38 | f"repos/{namespace}", method="PUT", requests_data=data 39 | ) 40 | 41 | def delete(self, namespace: str) -> typing.Dict: 42 | assert namespace 43 | return self._client.request(f"repos/{namespace}", method="DELETE") 44 | 45 | def list_toc(self, namespace: str) -> typing.Dict: 46 | warnings.warn("Toc api will be updated in the future, please refer to https://www.yuque.com/yuque/developer/ag3xgd for more information", DeprecationWarning) 47 | assert namespace 48 | return self._client.request(f"repos/{namespace}/toc", method="GET") 49 | 50 | def update_toc(self, namespace: str, data: typing.Dict) -> typing.Dict: 51 | warnings.warn("Toc api will be updated in the future, please refer to https://www.yuque.com/yuque/developer/ag3xgd for more information", DeprecationWarning) 52 | assert namespace 53 | assert data 54 | return self._client.request(f"repos/{namespace}/toc",method="PUT",requests_data=data) 55 | 56 | 57 | @staticmethod 58 | def _get_url(user: typing.Optional[str], group: typing.Optional[str]): 59 | assert user or group 60 | api = f"users/{user}/repos" if user else f"groups/{group}/repos" 61 | return api 62 | -------------------------------------------------------------------------------- /yuque_py/models/user.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from yuque_py.clients.abstract_client import AbstractClient 4 | 5 | 6 | class User: 7 | def __init__(self, client: AbstractClient): 8 | self._client = client 9 | 10 | def get(self, login: typing.Optional[str] = None) -> typing.Dict: 11 | api = f"users/{login}" if login else "user" 12 | return self._client.request(api=api, method="GET", requests_data=None) 13 | -------------------------------------------------------------------------------- /yuque_py/yuque.py: -------------------------------------------------------------------------------- 1 | from yuque_py.models import User, Group, Repo, Doc 2 | from yuque_py.clients.client import Client 3 | 4 | 5 | class Yuque: 6 | def __init__(self, api_host: str, user_token: str): 7 | self._client = Client(api_host, user_token) 8 | self.users = User(self._client) 9 | self.groups = Group(self._client) 10 | self.repos = Repo(self._client) 11 | self.docs = Doc(self._client) 12 | --------------------------------------------------------------------------------