classer 0.0.3__py3-none-any.whl
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.
- classer/__init__.py +69 -0
- classer/client.py +186 -0
- classer/exceptions.py +26 -0
- classer/types.py +35 -0
- classer-0.0.3.dist-info/METADATA +162 -0
- classer-0.0.3.dist-info/RECORD +7 -0
- classer-0.0.3.dist-info/WHEEL +4 -0
classer/__init__.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Classer SDK - Low-cost, fast AI classification API."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from .client import ClasserClient
|
|
6
|
+
from .exceptions import ClasserError
|
|
7
|
+
from .types import (
|
|
8
|
+
ClassifyResponse,
|
|
9
|
+
TagLabel,
|
|
10
|
+
TagResponse,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"ClasserClient",
|
|
15
|
+
"ClasserError",
|
|
16
|
+
"ClassifyResponse",
|
|
17
|
+
"TagLabel",
|
|
18
|
+
"TagResponse",
|
|
19
|
+
"classify",
|
|
20
|
+
"tag",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
# Default client instance
|
|
24
|
+
_default_client: ClasserClient | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _get_default_client() -> ClasserClient:
|
|
28
|
+
global _default_client
|
|
29
|
+
if _default_client is None:
|
|
30
|
+
_default_client = ClasserClient()
|
|
31
|
+
return _default_client
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def classify(
|
|
35
|
+
text: str,
|
|
36
|
+
labels: Optional[list[str]] = None,
|
|
37
|
+
classifier: Optional[str] = None,
|
|
38
|
+
descriptions: Optional[dict[str, str]] = None,
|
|
39
|
+
speed: Optional[str] = None,
|
|
40
|
+
cache: Optional[bool] = None,
|
|
41
|
+
) -> ClassifyResponse:
|
|
42
|
+
"""Classify text into one of the provided labels (single-label).
|
|
43
|
+
|
|
44
|
+
See ClasserClient.classify for full parameter documentation.
|
|
45
|
+
"""
|
|
46
|
+
return _get_default_client().classify(
|
|
47
|
+
text, labels=labels, classifier=classifier,
|
|
48
|
+
descriptions=descriptions, speed=speed, cache=cache,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def tag(
|
|
53
|
+
text: str,
|
|
54
|
+
labels: Optional[list[str]] = None,
|
|
55
|
+
classifier: Optional[str] = None,
|
|
56
|
+
descriptions: Optional[dict[str, str]] = None,
|
|
57
|
+
threshold: Optional[float] = None,
|
|
58
|
+
speed: Optional[str] = None,
|
|
59
|
+
cache: Optional[bool] = None,
|
|
60
|
+
) -> TagResponse:
|
|
61
|
+
"""Tag text with multiple labels (multi-label).
|
|
62
|
+
|
|
63
|
+
See ClasserClient.tag for full parameter documentation.
|
|
64
|
+
"""
|
|
65
|
+
return _get_default_client().tag(
|
|
66
|
+
text, labels=labels, classifier=classifier,
|
|
67
|
+
descriptions=descriptions, threshold=threshold,
|
|
68
|
+
speed=speed, cache=cache,
|
|
69
|
+
)
|
classer/client.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Classer client implementation."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from .exceptions import ClasserError
|
|
9
|
+
from .types import (
|
|
10
|
+
ClassifyResponse,
|
|
11
|
+
TagLabel,
|
|
12
|
+
TagResponse,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ClasserClient:
|
|
17
|
+
"""Client for the Classer API."""
|
|
18
|
+
|
|
19
|
+
BASE_URL = "https://api.classer.ai"
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
api_key: Optional[str] = None,
|
|
24
|
+
timeout: float = 30.0,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Initialize the Classer client.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
api_key: API key for authentication. Falls back to CLASSER_API_KEY env var.
|
|
31
|
+
timeout: Request timeout in seconds.
|
|
32
|
+
"""
|
|
33
|
+
self.api_key = api_key or os.environ.get("CLASSER_API_KEY", "")
|
|
34
|
+
self.timeout = timeout
|
|
35
|
+
|
|
36
|
+
def _request(self, endpoint: str, body: dict) -> dict:
|
|
37
|
+
"""Make a POST request to the API."""
|
|
38
|
+
url = f"{self.BASE_URL}{endpoint}"
|
|
39
|
+
|
|
40
|
+
headers = {"Content-Type": "application/json"}
|
|
41
|
+
if self.api_key:
|
|
42
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
43
|
+
|
|
44
|
+
response = httpx.post(url, json=body, headers=headers, timeout=self.timeout)
|
|
45
|
+
|
|
46
|
+
if not response.is_success:
|
|
47
|
+
detail = None
|
|
48
|
+
try:
|
|
49
|
+
error_data = response.json()
|
|
50
|
+
detail = error_data.get("detail") if isinstance(error_data, dict) else None
|
|
51
|
+
except (ValueError, TypeError):
|
|
52
|
+
detail = response.text[:200] if response.text else None
|
|
53
|
+
raise ClasserError(
|
|
54
|
+
f"Request failed with status {response.status_code}",
|
|
55
|
+
status=response.status_code,
|
|
56
|
+
detail=detail,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return response.json()
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _build_body(
|
|
63
|
+
text: str,
|
|
64
|
+
labels: Optional[list[str]] = None,
|
|
65
|
+
classifier: Optional[str] = None,
|
|
66
|
+
descriptions: Optional[dict[str, str]] = None,
|
|
67
|
+
speed: Optional[str] = None,
|
|
68
|
+
cache: Optional[bool] = None,
|
|
69
|
+
threshold: Optional[float] = None,
|
|
70
|
+
) -> dict:
|
|
71
|
+
"""Build a request body dict, omitting None/empty fields."""
|
|
72
|
+
body: dict = {"text": text}
|
|
73
|
+
if classifier:
|
|
74
|
+
body["classifier"] = classifier
|
|
75
|
+
if labels:
|
|
76
|
+
body["labels"] = labels
|
|
77
|
+
if descriptions:
|
|
78
|
+
body["descriptions"] = descriptions
|
|
79
|
+
if threshold is not None:
|
|
80
|
+
body["threshold"] = threshold
|
|
81
|
+
if speed:
|
|
82
|
+
body["speed"] = speed
|
|
83
|
+
if cache is not None:
|
|
84
|
+
body["cache"] = cache
|
|
85
|
+
return body
|
|
86
|
+
|
|
87
|
+
def classify(
|
|
88
|
+
self,
|
|
89
|
+
text: str,
|
|
90
|
+
labels: Optional[list[str]] = None,
|
|
91
|
+
classifier: Optional[str] = None,
|
|
92
|
+
descriptions: Optional[dict[str, str]] = None,
|
|
93
|
+
speed: Optional[str] = None,
|
|
94
|
+
cache: Optional[bool] = None,
|
|
95
|
+
) -> ClassifyResponse:
|
|
96
|
+
"""
|
|
97
|
+
Classify text into one of the provided labels (single-label).
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
text: Text to classify.
|
|
101
|
+
labels: List of possible labels (1-200).
|
|
102
|
+
classifier: Saved classifier name or "name@vN" reference.
|
|
103
|
+
descriptions: Maps label name to description for better accuracy.
|
|
104
|
+
speed: Speed tier — "standard" (default, <1s) or "fast" (<200ms).
|
|
105
|
+
cache: Set to False to bypass cache. Default: True.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
ClassifyResponse with label and confidence.
|
|
109
|
+
|
|
110
|
+
Example:
|
|
111
|
+
>>> result = classer.classify(
|
|
112
|
+
... text="I can't log in",
|
|
113
|
+
... labels=["billing", "technical_support", "sales"]
|
|
114
|
+
... )
|
|
115
|
+
>>> print(result.label) # "technical_support"
|
|
116
|
+
"""
|
|
117
|
+
body = self._build_body(
|
|
118
|
+
text, labels=labels, classifier=classifier,
|
|
119
|
+
descriptions=descriptions, speed=speed, cache=cache,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
data = self._request("/v1/classify", body)
|
|
123
|
+
|
|
124
|
+
return ClassifyResponse(
|
|
125
|
+
label=data.get("label"),
|
|
126
|
+
confidence=data.get("confidence"),
|
|
127
|
+
tokens=data.get("tokens", 0),
|
|
128
|
+
latency_ms=data.get("latency_ms", 0),
|
|
129
|
+
cached=data.get("cached", False),
|
|
130
|
+
public=data.get("public"),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def tag(
|
|
134
|
+
self,
|
|
135
|
+
text: str,
|
|
136
|
+
labels: Optional[list[str]] = None,
|
|
137
|
+
classifier: Optional[str] = None,
|
|
138
|
+
descriptions: Optional[dict[str, str]] = None,
|
|
139
|
+
threshold: Optional[float] = None,
|
|
140
|
+
speed: Optional[str] = None,
|
|
141
|
+
cache: Optional[bool] = None,
|
|
142
|
+
) -> TagResponse:
|
|
143
|
+
"""
|
|
144
|
+
Tag text with multiple labels that exceed a confidence threshold.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
text: Text to tag.
|
|
148
|
+
labels: List of possible labels (1-200).
|
|
149
|
+
classifier: Saved classifier name or "name@vN" reference.
|
|
150
|
+
descriptions: Maps label name to description for better accuracy.
|
|
151
|
+
threshold: Confidence threshold (0-1). Default: 0.3.
|
|
152
|
+
speed: Speed tier — "standard" (default, <1s) or "fast" (<200ms).
|
|
153
|
+
cache: Set to False to bypass cache. Default: True.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
TagResponse with labels list (each has label and confidence).
|
|
157
|
+
|
|
158
|
+
Example:
|
|
159
|
+
>>> result = classer.tag(
|
|
160
|
+
... text="Breaking: Tech stocks surge amid AI boom",
|
|
161
|
+
... labels=["politics", "technology", "finance", "sports"],
|
|
162
|
+
... threshold=0.3
|
|
163
|
+
... )
|
|
164
|
+
>>> for tag in result.labels:
|
|
165
|
+
... print(f"{tag.label}: {tag.confidence}")
|
|
166
|
+
"""
|
|
167
|
+
body = self._build_body(
|
|
168
|
+
text, labels=labels, classifier=classifier,
|
|
169
|
+
descriptions=descriptions, threshold=threshold,
|
|
170
|
+
speed=speed, cache=cache,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
data = self._request("/v1/tag", body)
|
|
174
|
+
|
|
175
|
+
tag_labels = [
|
|
176
|
+
TagLabel(label=item["label"], confidence=item["confidence"])
|
|
177
|
+
for item in data.get("labels") or []
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
return TagResponse(
|
|
181
|
+
labels=tag_labels,
|
|
182
|
+
tokens=data.get("tokens", 0),
|
|
183
|
+
latency_ms=data.get("latency_ms", 0),
|
|
184
|
+
cached=data.get("cached", False),
|
|
185
|
+
public=data.get("public"),
|
|
186
|
+
)
|
classer/exceptions.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Exception classes for the Classer SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ClasserError(Exception):
|
|
7
|
+
"""Base exception for Classer SDK errors."""
|
|
8
|
+
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
message: str,
|
|
12
|
+
status: Optional[int] = None,
|
|
13
|
+
detail: Optional[str] = None,
|
|
14
|
+
):
|
|
15
|
+
super().__init__(message)
|
|
16
|
+
self.message = message
|
|
17
|
+
self.status = status
|
|
18
|
+
self.detail = detail
|
|
19
|
+
|
|
20
|
+
def __str__(self) -> str:
|
|
21
|
+
parts = [self.message]
|
|
22
|
+
if self.status:
|
|
23
|
+
parts.append(f"(status: {self.status})")
|
|
24
|
+
if self.detail:
|
|
25
|
+
parts.append(f"- {self.detail}")
|
|
26
|
+
return " ".join(parts)
|
classer/types.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Type definitions for the Classer SDK."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ClassifyResponse:
|
|
9
|
+
"""Response from single-label classification."""
|
|
10
|
+
|
|
11
|
+
label: Optional[str] = None
|
|
12
|
+
confidence: Optional[float] = None
|
|
13
|
+
tokens: int = 0
|
|
14
|
+
latency_ms: float = 0.0
|
|
15
|
+
cached: bool = False
|
|
16
|
+
public: Optional[bool] = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class TagLabel:
|
|
21
|
+
"""Single label with confidence in a tag response."""
|
|
22
|
+
|
|
23
|
+
label: str
|
|
24
|
+
confidence: float
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class TagResponse:
|
|
29
|
+
"""Response from multi-label tagging."""
|
|
30
|
+
|
|
31
|
+
labels: list[TagLabel] = field(default_factory=list)
|
|
32
|
+
tokens: int = 0
|
|
33
|
+
latency_ms: float = 0.0
|
|
34
|
+
cached: bool = False
|
|
35
|
+
public: Optional[bool] = None
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: classer
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: High-performance AI classification — <200ms latency, up to 100x cheaper, beats GPT-5 mini accuracy
|
|
5
|
+
Project-URL: Homepage, https://classer.ai
|
|
6
|
+
Project-URL: Documentation, https://docs.classer.ai
|
|
7
|
+
Project-URL: Repository, https://github.com/classer-ai/classer-python
|
|
8
|
+
Author: Classer.ai
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: ai,classification,llm,machine-learning,nlp,text-classification
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: httpx>=0.25.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
exit
|
|
29
|
+
# [classer](https://classer.ai)
|
|
30
|
+
|
|
31
|
+
High-performance AI classification
|
|
32
|
+
|
|
33
|
+
<200ms latency · up to 100x cheaper · beats GPT-5 mini accuracy · self-calibrating accuracy · no prompt engineering
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install classer
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import classer
|
|
45
|
+
|
|
46
|
+
# Single-label classification
|
|
47
|
+
result = classer.classify(
|
|
48
|
+
text="I can't log in and need a password reset.",
|
|
49
|
+
labels=["billing", "technical_support", "sales", "spam"]
|
|
50
|
+
)
|
|
51
|
+
print(result.label) # "technical_support"
|
|
52
|
+
print(result.confidence) # 0.94
|
|
53
|
+
|
|
54
|
+
# With descriptions for better accuracy
|
|
55
|
+
lead = classer.classify(
|
|
56
|
+
text="We need a solution for 500 users, what's your enterprise pricing?",
|
|
57
|
+
labels=["hot", "warm", "cold"],
|
|
58
|
+
descriptions={
|
|
59
|
+
"hot": "Ready to buy, asking for pricing or demo",
|
|
60
|
+
"warm": "Interested but exploring options",
|
|
61
|
+
"cold": "Just browsing, no clear intent"
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
print(lead.label) # "hot"
|
|
65
|
+
|
|
66
|
+
# Multi-label tagging
|
|
67
|
+
result = classer.tag(
|
|
68
|
+
text="Breaking: Tech stocks surge amid AI boom",
|
|
69
|
+
labels=["politics", "technology", "finance", "sports"],
|
|
70
|
+
threshold=0.3
|
|
71
|
+
)
|
|
72
|
+
for t in result.labels:
|
|
73
|
+
print(f"{t.label}: {t.confidence}")
|
|
74
|
+
# technology: 0.92
|
|
75
|
+
# finance: 0.78
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
No API key is needed to get started. To unlock higher rate limits, get an API key from [classer.ai/api-keys](https://classer.ai/api-keys).
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
export CLASSER_API_KEY=your-api-key
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Or configure programmatically:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from classer import ClasserClient
|
|
90
|
+
|
|
91
|
+
client = ClasserClient(
|
|
92
|
+
api_key="your-api-key"
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API Reference
|
|
97
|
+
|
|
98
|
+
### `classify(text, labels=None, classifier=None, descriptions=None, speed=None, cache=None)`
|
|
99
|
+
|
|
100
|
+
Classify text into exactly one of the provided labels.
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
result = classer.classify(
|
|
104
|
+
text="Text to classify",
|
|
105
|
+
labels=["label1", "label2"], # 1-200 possible labels
|
|
106
|
+
descriptions={"label1": "Description for better accuracy"},
|
|
107
|
+
speed="standard", # "standard" (default, <1s) or "fast" (<200ms)
|
|
108
|
+
cache=True # Set to False to bypass cache. Default: True
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
result.label # Selected label
|
|
112
|
+
result.confidence # 0-1 confidence score
|
|
113
|
+
result.tokens # Total tokens used
|
|
114
|
+
result.latency_ms # Processing time in ms
|
|
115
|
+
result.cached # Whether served from cache
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `tag(text, labels=None, classifier=None, descriptions=None, threshold=None, speed=None, cache=None)`
|
|
119
|
+
|
|
120
|
+
Multi-label tagging — returns all labels above a confidence threshold.
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
result = classer.tag(
|
|
124
|
+
text="Text to tag",
|
|
125
|
+
labels=["label1", "label2"], # 1-200 possible labels
|
|
126
|
+
descriptions={"label1": "Description"},
|
|
127
|
+
threshold=0.3, # Default: 0.3
|
|
128
|
+
speed="standard", # "standard" (default, <1s) or "fast" (<200ms)
|
|
129
|
+
cache=True # Set to False to bypass cache. Default: True
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
for t in result.labels:
|
|
133
|
+
print(f"{t.label}: {t.confidence}")
|
|
134
|
+
|
|
135
|
+
result.tokens # Total tokens used
|
|
136
|
+
result.latency_ms # Processing time in ms
|
|
137
|
+
result.cached # Whether served from cache
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Error Handling
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from classer import ClasserError
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
result = classer.classify(text="hello", labels=["a", "b"])
|
|
147
|
+
except ClasserError as e:
|
|
148
|
+
print(e.status) # HTTP status code
|
|
149
|
+
print(e.detail) # Error detail from API
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Documentation
|
|
153
|
+
|
|
154
|
+
Full API reference and guides at [docs.classer.ai](https://docs.classer.ai).
|
|
155
|
+
|
|
156
|
+
## GitHub
|
|
157
|
+
|
|
158
|
+
[github.com/classer-ai/classer-python](https://github.com/classer-ai/classer-python)
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
classer/__init__.py,sha256=CMP550ePsx_AEofILAY_6q72FySK-q0NBQyQNTLG7Lo,1764
|
|
2
|
+
classer/client.py,sha256=j0QT1DGQN5Xy-skxfkAZGgnGBqpfPDsftuzZQc9D2fs,6122
|
|
3
|
+
classer/exceptions.py,sha256=98CxeqMJ1OW8VzSLIPu3dWzEPR6VHGQ-vzihOz_Rlk0,656
|
|
4
|
+
classer/types.py,sha256=Bctr4OCDiRPAe0uyhDf5pgBZbHVKG_-x1oX7FVdssc4,750
|
|
5
|
+
classer-0.0.3.dist-info/METADATA,sha256=W41-9xJCOnHg9novtJXpUkmrcr7AHMwYvBtBOPa1YcI,4603
|
|
6
|
+
classer-0.0.3.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
7
|
+
classer-0.0.3.dist-info/RECORD,,
|