pyznuny 0.0.7__tar.gz → 0.0.9__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.
@@ -1,11 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyznuny
3
- Version: 0.0.7
3
+ Version: 0.0.9
4
4
  Summary: A Python client for interacting with the Znuny ticketing system API.
5
5
  Author-email: Junior Rosa <jr.dasrosas@gmail.com>, Pablo Gascon <pablogasconiel445@gmail.com>
6
+ License-Expression: MIT
6
7
  Project-URL: Homepage, https://github.com/Junior-Rosa/py-znuny
7
8
  Project-URL: Repository, https://github.com/Junior-Rosa/py-znuny
8
9
  Project-URL: Issues, https://github.com/Junior-Rosa/py-znuny/issues
10
+ Project-URL: Documentation, https://pyznuny.readthedocs.io/en/latest/
9
11
  Classifier: Development Status :: 3 - Alpha
10
12
  Classifier: Intended Audience :: Developers
11
13
  Classifier: Operating System :: OS Independent
@@ -26,6 +28,9 @@ Dynamic: license-file
26
28
 
27
29
  # pyznuny
28
30
 
31
+ [![PyPI version](https://img.shields.io/pypi/v/pyznuny)](https://pypi.org/project/pyznuny/)
32
+ [![PyPI license](https://img.shields.io/pypi/l/pyznuny)](https://pypi.org/project/pyznuny/)
33
+
29
34
  A Python client for interacting with the Znuny ticketing system API.
30
35
 
31
36
  ## Features
@@ -46,6 +51,10 @@ Or with uv:
46
51
  uv add pyznuny
47
52
  ```
48
53
 
54
+ ## Documentation
55
+
56
+ For a complete API Reference and guide on how to use pyznuny, please visit our [documentation](https://pyznuny.readthedocs.io/en/latest/).
57
+
49
58
  ## Quick start
50
59
 
51
60
  Create a client and authenticate using environment variables.
@@ -1,5 +1,8 @@
1
1
  # pyznuny
2
2
 
3
+ [![PyPI version](https://img.shields.io/pypi/v/pyznuny)](https://pypi.org/project/pyznuny/)
4
+ [![PyPI license](https://img.shields.io/pypi/l/pyznuny)](https://pypi.org/project/pyznuny/)
5
+
3
6
  A Python client for interacting with the Znuny ticketing system API.
4
7
 
5
8
  ## Features
@@ -20,6 +23,10 @@ Or with uv:
20
23
  uv add pyznuny
21
24
  ```
22
25
 
26
+ ## Documentation
27
+
28
+ For a complete API Reference and guide on how to use pyznuny, please visit our [documentation](https://pyznuny.readthedocs.io/en/latest/).
29
+
23
30
  ## Quick start
24
31
 
25
32
  Create a client and authenticate using environment variables.
@@ -1,12 +1,13 @@
1
1
  [project]
2
2
  name = "pyznuny"
3
- version = "0.0.7"
3
+ version = "0.0.9"
4
4
  description = "A Python client for interacting with the Znuny ticketing system API."
5
5
  authors = [
6
6
  { name = "Junior Rosa", email = "jr.dasrosas@gmail.com" },
7
7
  { name = "Pablo Gascon", email = "pablogasconiel445@gmail.com" }
8
8
  ]
9
9
  readme = "README.md"
10
+ license = "MIT"
10
11
  requires-python = ">=3.10"
11
12
  dependencies = [
12
13
  "httpx>=0.28.1",
@@ -30,6 +31,7 @@ classifiers = [
30
31
  Homepage = "https://github.com/Junior-Rosa/py-znuny"
31
32
  Repository = "https://github.com/Junior-Rosa/py-znuny"
32
33
  Issues = "https://github.com/Junior-Rosa/py-znuny/issues"
34
+ Documentation = "https://pyznuny.readthedocs.io/en/latest/"
33
35
 
34
36
  [dependency-groups]
35
37
  dev = [
@@ -5,42 +5,16 @@ from typing import Any
5
5
 
6
6
  import httpx
7
7
 
8
- if __name__ == "__main__" and __package__ is None:
9
- import os
10
- import sys
11
-
12
- sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
13
- from pyznuny.ticket.endpoints import (
14
- _DEFAULT_ENDPOINT_IDENTIFIERS,
15
- _DEFAULT_ENDPOINTS,
16
- Endpoint,
17
- EndpointSetter,
18
- EndpointsRegistry,
19
- )
20
- from pyznuny.ticket.exceptions import TicketClientError
21
- from pyznuny.ticket.models import (
22
- TicketCreateArticle,
23
- TicketCreatePayload,
24
- TicketCreateTicket,
25
- )
26
- from pyznuny.ticket.routes import SessionRoutes, TicketRoutes
27
- else:
28
- from .endpoints import (
29
- _DEFAULT_ENDPOINT_IDENTIFIERS,
30
- _DEFAULT_ENDPOINTS,
31
- Endpoint,
32
- EndpointSetter,
33
- EndpointsRegistry,
34
- )
35
- from .exceptions import TicketClientError
36
- from .models import (
37
- TicketCreateArticle,
38
- TicketCreatePayload,
39
- TicketCreateTicket,
40
- )
41
- from .routes import SessionRoutes, TicketRoutes
42
-
43
-
8
+ from .endpoints import (
9
+ _DEFAULT_ENDPOINT_IDENTIFIERS,
10
+ _DEFAULT_ENDPOINTS,
11
+ Endpoint,
12
+ EndpointSetter,
13
+ EndpointsRegistry,
14
+ )
15
+ from .exceptions import TicketClientError
16
+ from .models import HttpMethod
17
+ from .routes import SessionRoutes, TicketRoutes
44
18
 
45
19
 
46
20
  class TicketClient:
@@ -94,14 +68,14 @@ class TicketClient:
94
68
  def endpoints(self) -> EndpointsRegistry:
95
69
  return self._endpoints
96
70
 
97
- def register_endpoint(self, name: str, method: str, path: str) -> Endpoint:
71
+ def register_endpoint(self, name: str, method: HttpMethod, path: str) -> Endpoint:
98
72
  """
99
73
  Registers a custom endpoint for the Ticket API
100
74
 
101
75
  :param name: Name of the endpoint
102
76
  :type name: str
103
77
  :param method: HTTP method for the endpoint
104
- :type method: str
78
+ :type method: HttpMethod
105
79
  :param path: Endpoint path
106
80
  :type path: str
107
81
  :return: Registered endpoint
@@ -147,13 +121,14 @@ class TicketClient:
147
121
  """
148
122
  response = self.session.create(username, password)
149
123
  self.session_id = response.json().get("SessionID")
124
+ return response
150
125
 
151
126
 
152
127
  def request(
153
128
  self,
154
129
  endpoint_name: str,
155
130
  *,
156
- method: str | None = None,
131
+ method: HttpMethod | None = None,
157
132
  path: str | None = None,
158
133
  path_params: Mapping[str, Any] | None = None,
159
134
  **kwargs: Any,
@@ -164,7 +139,7 @@ class TicketClient:
164
139
  :param endpoint_name: Name of the endpoint
165
140
  :type endpoint_name: str
166
141
  :param method: HTTP method for the request, defaults to None
167
- :type method: str | None
142
+ :type method: HttpMethod | None
168
143
  :param path: Custom endpoint path, defaults to None
169
144
  :type path: str | None
170
145
  :param path_params: Parameters for the endpoint path, defaults to None
@@ -218,65 +193,4 @@ class TicketClient:
218
193
  if not self._endpoints.has(name):
219
194
  self._endpoints.register(
220
195
  Endpoint(name=name, method=method, path=path)
221
- )
222
-
223
-
224
- if __name__ == "__main__":
225
- from dotenv import load_dotenv
226
- load_dotenv()
227
- import os
228
-
229
- class_payload_create = TicketCreatePayload(
230
- Ticket=TicketCreateTicket(
231
- Title="Erro no login",
232
- Queue="ITS::Ops-TechOps::Sentinelops::Cops React - N1",
233
- State="new",
234
- Priority="3 normal",
235
- CustomerUser="joel.junior@eitisolucoes.com.br",
236
- Type="Monitoramento",
237
- ),
238
- Article=TicketCreateArticle(
239
- Subject="Não consigo acessar",
240
- Body="Detalhes do problema...",
241
- ContentType="text/plain; charset=utf-8",
242
- Charset="utf-8",
243
- MimeType="text/plain",
244
- SenderType="customer",
245
- From_="joel.junior@eitisolucoes.com.br",
246
- ),
247
- )
248
-
249
- payload_create = {
250
- "Ticket": {
251
- "Title": "Erro no login",
252
- "Queue": "ITS::Ops-TechOps::Sentinelops::Cops React - N1",
253
- "State": "new",
254
- "Priority": "3 normal",
255
- "CustomerUser": "joel.junior@eitisolucoes.com.br",
256
- "Type": "Monitoramento",
257
- },
258
- "Article": {
259
- "Subject": "Não consigo acessar",
260
- "Body": "Detalhes do problema...",
261
- "ContentType": "text/plain; charset=utf-8",
262
- "Charset": "utf-8",
263
- "MimeType": "text/plain",
264
- "SenderType": "customer",
265
- "From": "joel.junior@eitisolucoes.com.br",
266
- },
267
- }
268
-
269
- payload_update = {
270
- "Ticket": {
271
- "State": "open",
272
- }
273
- }
274
-
275
-
276
- client = TicketClient(base_url=os.getenv("HOST"),
277
- username=os.getenv("USER_LOGIN"), password=os.getenv("PASS"))
278
-
279
- client.set_endpoint.ticket_get(endpoint="Tickets/{ticket_id}",
280
- identifier="ticket_id")
281
- response = client.ticket.get(ticket_id=5853276)
282
- print("GET Ticket Response:", response.json())
196
+ )
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Iterable, Mapping, MutableMapping
4
4
 
5
- from .models import Endpoint
5
+ from .models import Endpoint, HttpMethod
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from pyznuny.ticket.client import TicketClient
@@ -31,15 +31,14 @@ class EndpointSetter:
31
31
  def __init__(self, client: "TicketClient") -> None:
32
32
  self._client = client
33
33
 
34
-
35
- def ticket_create(self, *, endpoint: str, method: str = "POST") -> Endpoint:
34
+ def ticket_create(self, *, endpoint: str, method: HttpMethod = "POST") -> Endpoint:
36
35
  """
37
36
  Sets a custom endpoint for creating tickets
38
37
 
39
38
  :param endpoint: Custom endpoint for creating tickets
40
39
  :type endpoint: str
41
40
  :param method: HTTP method for creating tickets, defaults to POST
42
- :type method: str
41
+ :type method: HttpMethod
43
42
  :return: Endpoint object
44
43
  :rtype: Endpoint
45
44
  """
@@ -50,7 +49,7 @@ class EndpointSetter:
50
49
  *,
51
50
  endpoint: str,
52
51
  identifier: str = "ticket_id",
53
- method: str = "GET",
52
+ method: HttpMethod = "GET",
54
53
  ) -> Endpoint:
55
54
  """
56
55
  Sets a custom endpoint for retrieving a ticket.
@@ -60,7 +59,7 @@ class EndpointSetter:
60
59
  :param identifier: Identifier for the ticket ID in the endpoint path
61
60
  :type identifier: str
62
61
  :param method: HTTP method for the endpoint, defaults to GET
63
- :type method: str
62
+ :type method: HttpMethod
64
63
  :return: Registered endpoint
65
64
  :rtype: Endpoint
66
65
  """
@@ -77,7 +76,7 @@ class EndpointSetter:
77
76
  *,
78
77
  endpoint: str,
79
78
  identifier: str = "ticket_id",
80
- method: str = "POST",
79
+ method: HttpMethod = "POST",
81
80
  ) -> Endpoint:
82
81
  """
83
82
  Sets a custom endpoint for updating a ticket.
@@ -87,7 +86,7 @@ class EndpointSetter:
87
86
  :param identifier: Identifier for the ticket ID in the endpoint path
88
87
  :type identifier: str
89
88
  :param method: HTTP method for the endpoint, defaults to POST
90
- :type method: str
89
+ :type method: HttpMethod
91
90
  :return: Registered endpoint
92
91
  :rtype: Endpoint
93
92
  """
@@ -133,7 +132,7 @@ class EndpointsRegistry:
133
132
  self._endpoints[endpoint.name] = endpoint
134
133
  return endpoint
135
134
 
136
- def configure(self, mapping: Mapping[str, tuple[str, str]]) -> None:
135
+ def configure(self, mapping: Mapping[str, tuple[HttpMethod, str]]) -> None:
137
136
  for name, (method, path) in mapping.items():
138
137
  self.register(Endpoint(name=name, method=method, path=path))
139
138
 
@@ -150,5 +149,5 @@ class EndpointsRegistry:
150
149
  endpoint = self.get(name)
151
150
  return endpoint.full_path(self._base_path)
152
151
 
153
- def method_for(self, name: str) -> str:
152
+ def method_for(self, name: str) -> HttpMethod:
154
153
  return self.get(name).method
@@ -1,12 +1,9 @@
1
-
2
-
3
1
  from typing import Any, Mapping
4
2
 
5
3
 
6
4
  class TicketClientError(Exception):
7
5
  """
8
- Docstring for TicketClientError
9
- Represents an error returned by the TicketClient API.
6
+ Error returned by the TicketClient API.
10
7
  """
11
8
  def __init__(self, error: Mapping[str, Any] | str) -> None:
12
9
 
@@ -1,18 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import Any, Mapping
4
+ from typing import Any, Literal, Mapping
5
5
 
6
- _VALID_METHODS = {
7
- "GET",
8
- "POST",
9
- "PUT",
10
- "PATCH",
11
- "DELETE",
12
- "HEAD",
13
- "OPTIONS",
14
- }
6
+ from pydantic import BaseModel
15
7
 
8
+ HttpMethod = Literal["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]
16
9
 
17
10
  def _clean_dict(data: Mapping[str, Any]) -> dict[str, Any]:
18
11
  return {key: value for key, value in data.items() if value is not None}
@@ -22,15 +15,6 @@ def _require_non_empty(value: str, field: str) -> None:
22
15
  if not value or not str(value).strip():
23
16
  raise ValueError(f"{field} is required.")
24
17
 
25
-
26
- def _normalize_method(method: str) -> str:
27
- normalized = method.strip().upper()
28
- if normalized not in _VALID_METHODS:
29
- valid = ", ".join(sorted(_VALID_METHODS))
30
- raise ValueError(f"Unsupported HTTP method: {method!r}. Use one of: {valid}")
31
- return normalized
32
-
33
-
34
18
  def _normalize_path(path: str) -> str:
35
19
  normalized = "/" + path.lstrip("/")
36
20
  if normalized == "/":
@@ -45,24 +29,24 @@ def _join_base_path(base_path: str, endpoint_path: str) -> str:
45
29
  return "/" + tail
46
30
  return f"/{base}/{tail}"
47
31
 
48
- @dataclass(frozen=True, slots=True)
49
- class Endpoint:
32
+ class Endpoint(BaseModel):
50
33
  """
51
34
  Object representing an API endpoint
52
35
 
53
36
  :arg name: Name of the endpoint
54
37
  :type name: str
55
38
  :arg method: HTTP method for the endpoint
56
- :type method: str
39
+ :type method: HttpMethod
57
40
  :arg path: Endpoint path
58
41
  :type path: str
42
+ :raises pydantic.ValidationError: If http method is invalid
43
+ :raises ValueError: If endpoint path is empty
59
44
  """
60
45
  name: str
61
- method: str
46
+ method: HttpMethod
62
47
  path: str
63
48
 
64
49
  def __post_init__(self) -> None:
65
- object.__setattr__(self, "method", _normalize_method(self.method))
66
50
  object.__setattr__(self, "path", _normalize_path(self.path))
67
51
 
68
52
  def full_path(self, base_path: str = "") -> str:
@@ -80,6 +64,29 @@ class Endpoint:
80
64
 
81
65
  @dataclass(slots=True)
82
66
  class TicketCreateTicket:
67
+ """
68
+ Represents the metadata for a ticket
69
+
70
+ :param Title: Title of the ticket
71
+ :type Title: str
72
+ :param Queue: Queue of the ticket
73
+ :type Queue: str
74
+ :param State: State of the ticket
75
+ :type State: str
76
+ :param Priority: Priority of the ticket
77
+ :type Priority: str
78
+ :param CustomerUser: Customer user of the ticket
79
+ :type CustomerUser: str | None
80
+ :param Type: Type of the ticket
81
+ :type Type: str | None
82
+ :param Service: Service of the ticket
83
+ :type Service: str | None
84
+ :param SLA: SLA of the ticket
85
+ :type SLA: str | None
86
+ :param Owner: Owner of the ticket
87
+ :type Owner: str | None
88
+ :raises ValueError: If any required field is empty
89
+ """
83
90
  Title: str
84
91
  Queue: str
85
92
  State: str
@@ -117,6 +124,25 @@ class TicketCreateTicket:
117
124
 
118
125
  @dataclass(slots=True)
119
126
  class TicketCreateArticle:
127
+ """
128
+ Represents the article content for a ticket
129
+
130
+ :param Subject: Subject of the article
131
+ :type Subject: str
132
+ :param Body: Body of the article
133
+ :type Body: str
134
+ :param ContentType: Content type of the article
135
+ :type ContentType: str
136
+ :param Charset: Charset of the article, defaults to None
137
+ :type Charset: str | None
138
+ :param MimeType: MIME type of the article, defaults to None
139
+ :type MimeType: str | None
140
+ :param SenderType: Sender type of the article, defaults to None
141
+ :type SenderType: str | None
142
+ :param From_: From address of the article, defaults to None
143
+ :type From_: str | None
144
+ :raises ValueError: If any required field is empty
145
+ """
120
146
  Subject: str
121
147
  Body: str
122
148
  ContentType: str
@@ -147,6 +173,20 @@ class TicketCreateArticle:
147
173
 
148
174
  @dataclass(slots=True)
149
175
  class TicketCreatePayload:
176
+ """
177
+ Represents the payload for creating a ticket
178
+
179
+ :param Ticket: Ticket metadata
180
+ :type Ticket: TicketCreateTicket
181
+ :param Article: Article content
182
+ :type Article: TicketCreateArticle
183
+ :param DynamicField: Dynamic fields for the ticket, defaults to None
184
+ :type DynamicField: Mapping[str, Any] | None
185
+ :param Attachment: Attachments for the ticket, defaults to None
186
+ :type Attachment: list[Mapping[str, Any]] | None
187
+ :param TimeUnit: Time unit for the ticket, defaults to None
188
+ :type TimeUnit: int | None
189
+ """
150
190
  Ticket: TicketCreateTicket
151
191
  Article: TicketCreateArticle
152
192
  DynamicField: Mapping[str, Any] | None = None
@@ -4,13 +4,17 @@ from typing import TYPE_CHECKING, Any, Mapping
4
4
 
5
5
  import httpx
6
6
 
7
- from pyznuny.ticket.models import TicketCreatePayload
7
+ from .models import TicketCreatePayload
8
8
 
9
9
  if TYPE_CHECKING:
10
- from pyznuny.ticket.client import TicketClient
10
+ from .client import TicketClient
11
11
 
12
12
 
13
13
  class SessionRoutes:
14
+ """
15
+ Object representing the routes for creating a session with the Ticket API, this is
16
+ abstracted by the TicketClient
17
+ """
14
18
  def __init__(self, client: "TicketClient") -> None:
15
19
  self._client = client
16
20
 
@@ -32,6 +36,10 @@ class SessionRoutes:
32
36
 
33
37
 
34
38
  class TicketRoutes:
39
+ """
40
+ Object representing the routes for the Ticket API, this is abstracted
41
+ by the TicketClient
42
+ """
35
43
  def __init__(self, client: "TicketClient") -> None:
36
44
  self._client = client
37
45
 
@@ -40,7 +48,16 @@ class TicketRoutes:
40
48
  payload: TicketCreatePayload | Mapping[str, Any] | None = None,
41
49
  **payload_kwargs: Any,
42
50
  ) -> httpx.Response:
43
-
51
+ """
52
+ Creates a new ticket
53
+
54
+ :param payload: Ticket creation payload
55
+ :type payload: TicketCreatePayload | Mapping[str, Any] | None
56
+ :param payload_kwargs: Additional keyword arguments for the payload
57
+ :type payload_kwargs: Any
58
+ :return: Response object
59
+ :rtype: httpx.Response
60
+ """
44
61
  if payload is None:
45
62
  payload_dict = dict(payload_kwargs)
46
63
 
@@ -56,6 +73,16 @@ class TicketRoutes:
56
73
 
57
74
 
58
75
  def update(self, ticket_id: str | int , **payload: dict) -> httpx.Response:
76
+ """
77
+ Updates an existing ticket
78
+
79
+ :param ticket_id: ID of the ticket to update
80
+ :type ticket_id: str | int
81
+ :param payload: Map of the fields to update
82
+ :type payload: dict
83
+ :return: Response object
84
+ :rtype: httpx.Response
85
+ """
59
86
  identifier = self._client.endpoint_identifier("ticket_update")
60
87
 
61
88
  payload.update({"SessionID": self._client.session_id})
@@ -68,6 +95,19 @@ class TicketRoutes:
68
95
  def get(self, ticket_id: str | int,
69
96
  dynamic_fields:int=0,
70
97
  all_articles:int=0) -> httpx.Response:
98
+ """
99
+ Retrieves an existing ticket
100
+
101
+ :param ticket_id: ID of the ticket to retrieve
102
+ :type ticket_id: str | int
103
+ :param dynamic_fields: Number of dynamic fields to retrieve, defaults to 0
104
+ :type dynamic_fields: int
105
+ :param all_articles: Whether to retrieve all articles, 1 for true 0 for false,
106
+ defaults to 0
107
+ :type all_articles: int
108
+ :return: Response object
109
+ :rtype: httpx.Response
110
+ """
71
111
  identifier = self._client.endpoint_identifier("ticket_get")
72
112
  return self._client.request(
73
113
  "ticket_get",
@@ -1,11 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyznuny
3
- Version: 0.0.7
3
+ Version: 0.0.9
4
4
  Summary: A Python client for interacting with the Znuny ticketing system API.
5
5
  Author-email: Junior Rosa <jr.dasrosas@gmail.com>, Pablo Gascon <pablogasconiel445@gmail.com>
6
+ License-Expression: MIT
6
7
  Project-URL: Homepage, https://github.com/Junior-Rosa/py-znuny
7
8
  Project-URL: Repository, https://github.com/Junior-Rosa/py-znuny
8
9
  Project-URL: Issues, https://github.com/Junior-Rosa/py-znuny/issues
10
+ Project-URL: Documentation, https://pyznuny.readthedocs.io/en/latest/
9
11
  Classifier: Development Status :: 3 - Alpha
10
12
  Classifier: Intended Audience :: Developers
11
13
  Classifier: Operating System :: OS Independent
@@ -26,6 +28,9 @@ Dynamic: license-file
26
28
 
27
29
  # pyznuny
28
30
 
31
+ [![PyPI version](https://img.shields.io/pypi/v/pyznuny)](https://pypi.org/project/pyznuny/)
32
+ [![PyPI license](https://img.shields.io/pypi/l/pyznuny)](https://pypi.org/project/pyznuny/)
33
+
29
34
  A Python client for interacting with the Znuny ticketing system API.
30
35
 
31
36
  ## Features
@@ -46,6 +51,10 @@ Or with uv:
46
51
  uv add pyznuny
47
52
  ```
48
53
 
54
+ ## Documentation
55
+
56
+ For a complete API Reference and guide on how to use pyznuny, please visit our [documentation](https://pyznuny.readthedocs.io/en/latest/).
57
+
49
58
  ## Quick start
50
59
 
51
60
  Create a client and authenticate using environment variables.
File without changes
File without changes
File without changes
File without changes