sapling-py 4.2.0__tar.gz → 4.3.0__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.
- {sapling_py-4.2.0/sapling_py.egg-info → sapling_py-4.3.0}/PKG-INFO +14 -17
- {sapling_py-4.2.0 → sapling_py-4.3.0}/README.md +9 -2
- sapling_py-4.3.0/pyproject.toml +42 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/sapling/client.py +10 -0
- sapling_py-4.3.0/sapling/version.py +1 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0/sapling_py.egg-info}/PKG-INFO +14 -17
- {sapling_py-4.2.0 → sapling_py-4.3.0}/sapling_py.egg-info/SOURCES.txt +1 -0
- sapling_py-4.3.0/setup.py +53 -0
- sapling_py-4.3.0/test/test_safety.py +56 -0
- sapling_py-4.2.0/sapling/version.py +0 -1
- sapling_py-4.2.0/setup.py +0 -41
- sapling_py-4.2.0/test/test_safety.py +0 -30
- {sapling_py-4.2.0 → sapling_py-4.3.0}/LICENSE +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/sapling/__init__.py +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/sapling_py.egg-info/dependency_links.txt +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/sapling_py.egg-info/requires.txt +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/sapling_py.egg-info/top_level.txt +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/setup.cfg +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/test/test_classify.py +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/test/test_client.py +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/test/test_extract.py +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/test/test_pii.py +0 -0
- {sapling_py-4.2.0 → sapling_py-4.3.0}/test/test_seo.py +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sapling-py
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.0
|
|
4
4
|
Summary: Sapling Python Client
|
|
5
|
-
|
|
6
|
-
Author: Sapling Intelligence
|
|
7
|
-
Author-email: info@sapling.ai
|
|
5
|
+
Author-email: Sapling Intelligence <info@sapling.ai>
|
|
8
6
|
License: Apache License 2.0
|
|
7
|
+
Project-URL: Homepage, https://sapling.ai
|
|
8
|
+
Project-URL: Documentation, https://sapling.readthedocs.io/
|
|
9
|
+
Project-URL: Repository, https://github.com/saplingai/sapling-py
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
12
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -17,18 +18,7 @@ Requires-Dist: requests
|
|
|
17
18
|
Provides-Extra: test
|
|
18
19
|
Requires-Dist: pytest; extra == "test"
|
|
19
20
|
Requires-Dist: responses; extra == "test"
|
|
20
|
-
Dynamic: author
|
|
21
|
-
Dynamic: author-email
|
|
22
|
-
Dynamic: classifier
|
|
23
|
-
Dynamic: description
|
|
24
|
-
Dynamic: description-content-type
|
|
25
|
-
Dynamic: home-page
|
|
26
|
-
Dynamic: license
|
|
27
21
|
Dynamic: license-file
|
|
28
|
-
Dynamic: provides-extra
|
|
29
|
-
Dynamic: requires-dist
|
|
30
|
-
Dynamic: requires-python
|
|
31
|
-
Dynamic: summary
|
|
32
22
|
|
|
33
23
|
# Sapling Python Client
|
|
34
24
|
|
|
@@ -54,12 +44,19 @@ Key Features:
|
|
|
54
44
|
|
|
55
45
|
## Installation
|
|
56
46
|
|
|
57
|
-
Install the `sapling-py` package with
|
|
47
|
+
Install the `sapling-py` package from PyPI with
|
|
48
|
+
[pip](https://pip.pypa.io/en/stable/installation/):
|
|
58
49
|
|
|
59
|
-
```
|
|
50
|
+
```sh
|
|
60
51
|
python -m pip install sapling-py
|
|
61
52
|
```
|
|
62
53
|
|
|
54
|
+
Or add it to a [uv](https://docs.astral.sh/uv/) project:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
uv add sapling-py
|
|
58
|
+
```
|
|
59
|
+
|
|
63
60
|
## Documentation
|
|
64
61
|
Documentation for the client is available at [Read the Docs](https://sapling.readthedocs.io/) and
|
|
65
62
|
documentation for the HTTP API is available at [Sapling.ai](https://sapling.ai/docs).
|
|
@@ -22,12 +22,19 @@ Key Features:
|
|
|
22
22
|
|
|
23
23
|
## Installation
|
|
24
24
|
|
|
25
|
-
Install the `sapling-py` package with
|
|
25
|
+
Install the `sapling-py` package from PyPI with
|
|
26
|
+
[pip](https://pip.pypa.io/en/stable/installation/):
|
|
26
27
|
|
|
27
|
-
```
|
|
28
|
+
```sh
|
|
28
29
|
python -m pip install sapling-py
|
|
29
30
|
```
|
|
30
31
|
|
|
32
|
+
Or add it to a [uv](https://docs.astral.sh/uv/) project:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
uv add sapling-py
|
|
36
|
+
```
|
|
37
|
+
|
|
31
38
|
## Documentation
|
|
32
39
|
Documentation for the client is available at [Read the Docs](https://sapling.readthedocs.io/) and
|
|
33
40
|
documentation for the HTTP API is available at [Sapling.ai](https://sapling.ai/docs).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sapling-py"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Sapling Python Client"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.7"
|
|
11
|
+
license = { text = "Apache License 2.0" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Sapling Intelligence", email = "info@sapling.ai" },
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 5 - Production/Stable",
|
|
17
|
+
"License :: OSI Approved :: Apache Software License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"requests",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
test = [
|
|
27
|
+
"pytest",
|
|
28
|
+
"responses",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://sapling.ai"
|
|
33
|
+
Documentation = "https://sapling.readthedocs.io/"
|
|
34
|
+
Repository = "https://github.com/saplingai/sapling-py"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.dynamic]
|
|
37
|
+
version = { attr = "sapling.version.__version__" }
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
include = ["sapling", "sapling.*"]
|
|
41
|
+
exclude = ["test", "test.*"]
|
|
42
|
+
namespaces = false
|
|
@@ -869,6 +869,7 @@ class SaplingClient:
|
|
|
869
869
|
self,
|
|
870
870
|
text,
|
|
871
871
|
threshold=None,
|
|
872
|
+
spans=None,
|
|
872
873
|
):
|
|
873
874
|
'''
|
|
874
875
|
Scores the provided text on seven content-safety categories: toxicity,
|
|
@@ -879,12 +880,19 @@ class SaplingClient:
|
|
|
879
880
|
:param threshold: Score at or above which a category is flagged.
|
|
880
881
|
Between 0 and 1 inclusive; the API defaults to 0.5.
|
|
881
882
|
:type threshold: float
|
|
883
|
+
:param spans: When True, the response also includes the offending
|
|
884
|
+
passages as spans, each with its text, start/end character offsets
|
|
885
|
+
into the submitted text, per-passage category scores, and
|
|
886
|
+
flagged_categories. The API defaults to False.
|
|
887
|
+
:type spans: bool
|
|
882
888
|
:rtype: dict
|
|
883
889
|
:return:
|
|
884
890
|
- scores: A probability from 0 to 1 for each category.
|
|
885
891
|
- flagged: True if any category scored at or above the threshold.
|
|
886
892
|
- flagged_categories: Categories that scored at or above the threshold.
|
|
887
893
|
- threshold: The threshold that was applied.
|
|
894
|
+
- spans: Only with spans=True — the offending passages, most
|
|
895
|
+
severe first, as {text, start, end, scores, flagged_categories}.
|
|
888
896
|
'''
|
|
889
897
|
url = self.url_endpoint + 'safety'
|
|
890
898
|
data = {
|
|
@@ -893,6 +901,8 @@ class SaplingClient:
|
|
|
893
901
|
}
|
|
894
902
|
if threshold is not None:
|
|
895
903
|
data['threshold'] = threshold
|
|
904
|
+
if spans is not None:
|
|
905
|
+
data['spans'] = spans
|
|
896
906
|
return self._request(url, data)
|
|
897
907
|
|
|
898
908
|
def pii(
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '4.3.0'
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sapling-py
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.0
|
|
4
4
|
Summary: Sapling Python Client
|
|
5
|
-
|
|
6
|
-
Author: Sapling Intelligence
|
|
7
|
-
Author-email: info@sapling.ai
|
|
5
|
+
Author-email: Sapling Intelligence <info@sapling.ai>
|
|
8
6
|
License: Apache License 2.0
|
|
7
|
+
Project-URL: Homepage, https://sapling.ai
|
|
8
|
+
Project-URL: Documentation, https://sapling.readthedocs.io/
|
|
9
|
+
Project-URL: Repository, https://github.com/saplingai/sapling-py
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
12
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -17,18 +18,7 @@ Requires-Dist: requests
|
|
|
17
18
|
Provides-Extra: test
|
|
18
19
|
Requires-Dist: pytest; extra == "test"
|
|
19
20
|
Requires-Dist: responses; extra == "test"
|
|
20
|
-
Dynamic: author
|
|
21
|
-
Dynamic: author-email
|
|
22
|
-
Dynamic: classifier
|
|
23
|
-
Dynamic: description
|
|
24
|
-
Dynamic: description-content-type
|
|
25
|
-
Dynamic: home-page
|
|
26
|
-
Dynamic: license
|
|
27
21
|
Dynamic: license-file
|
|
28
|
-
Dynamic: provides-extra
|
|
29
|
-
Dynamic: requires-dist
|
|
30
|
-
Dynamic: requires-python
|
|
31
|
-
Dynamic: summary
|
|
32
22
|
|
|
33
23
|
# Sapling Python Client
|
|
34
24
|
|
|
@@ -54,12 +44,19 @@ Key Features:
|
|
|
54
44
|
|
|
55
45
|
## Installation
|
|
56
46
|
|
|
57
|
-
Install the `sapling-py` package with
|
|
47
|
+
Install the `sapling-py` package from PyPI with
|
|
48
|
+
[pip](https://pip.pypa.io/en/stable/installation/):
|
|
58
49
|
|
|
59
|
-
```
|
|
50
|
+
```sh
|
|
60
51
|
python -m pip install sapling-py
|
|
61
52
|
```
|
|
62
53
|
|
|
54
|
+
Or add it to a [uv](https://docs.astral.sh/uv/) project:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
uv add sapling-py
|
|
58
|
+
```
|
|
59
|
+
|
|
63
60
|
## Documentation
|
|
64
61
|
Documentation for the client is available at [Read the Docs](https://sapling.readthedocs.io/) and
|
|
65
62
|
documentation for the HTTP API is available at [Sapling.ai](https://sapling.ai/docs).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Compatibility entry point for tools that still invoke ``setup.py`` directly.
|
|
2
|
+
|
|
3
|
+
Modern build frontends use the metadata in ``pyproject.toml``. The explicit
|
|
4
|
+
fallback keeps direct invocations working with setuptools versions that predate
|
|
5
|
+
PEP 621 support.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import setuptools
|
|
11
|
+
from setuptools import find_packages, setup
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _legacy_setup_kwargs():
|
|
15
|
+
this_directory = Path(__file__).parent
|
|
16
|
+
version = {}
|
|
17
|
+
exec((this_directory / 'sapling/version.py').read_text(), version)
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
'name': 'sapling-py',
|
|
21
|
+
'version': version['__version__'],
|
|
22
|
+
'description': 'Sapling Python Client',
|
|
23
|
+
'long_description': (this_directory / 'README.md').read_text(),
|
|
24
|
+
'long_description_content_type': 'text/markdown',
|
|
25
|
+
'url': 'https://sapling.ai',
|
|
26
|
+
'author': 'Sapling Intelligence',
|
|
27
|
+
'author_email': 'info@sapling.ai',
|
|
28
|
+
'license': 'Apache License 2.0',
|
|
29
|
+
'classifiers': [
|
|
30
|
+
'Development Status :: 5 - Production/Stable',
|
|
31
|
+
'License :: OSI Approved :: Apache Software License',
|
|
32
|
+
'Programming Language :: Python :: 3',
|
|
33
|
+
'Programming Language :: Python :: 3 :: Only',
|
|
34
|
+
],
|
|
35
|
+
'packages': find_packages(exclude=['test', 'test.*']),
|
|
36
|
+
'include_package_data': True,
|
|
37
|
+
'python_requires': '>=3.7',
|
|
38
|
+
'install_requires': ['requests'],
|
|
39
|
+
'extras_require': {
|
|
40
|
+
'test': [
|
|
41
|
+
'pytest',
|
|
42
|
+
'responses',
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
setuptools_major_version = int(setuptools.__version__.partition('.')[0])
|
|
50
|
+
except (AttributeError, ValueError):
|
|
51
|
+
setuptools_major_version = 0
|
|
52
|
+
|
|
53
|
+
setup(**_legacy_setup_kwargs() if setuptools_major_version < 61 else {})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import responses
|
|
5
|
+
|
|
6
|
+
from sapling import SaplingClient
|
|
7
|
+
|
|
8
|
+
API_KEY = 'a' * 32
|
|
9
|
+
BASE = 'https://api.sapling.ai/api/v1/'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def client():
|
|
14
|
+
return SaplingClient(api_key=API_KEY)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@responses.activate
|
|
18
|
+
def test_safety_threshold_sent_when_provided(client):
|
|
19
|
+
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
20
|
+
client.safety('some text', threshold=0.8)
|
|
21
|
+
body = json.loads(responses.calls[-1].request.body)
|
|
22
|
+
assert body == {'key': API_KEY, 'text': 'some text', 'threshold': 0.8}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@responses.activate
|
|
26
|
+
def test_safety_threshold_omitted_by_default(client):
|
|
27
|
+
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
28
|
+
client.safety('some text')
|
|
29
|
+
body = json.loads(responses.calls[-1].request.body)
|
|
30
|
+
assert 'threshold' not in body
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@responses.activate
|
|
34
|
+
def test_safety_spans_sent_when_provided(client):
|
|
35
|
+
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
36
|
+
client.safety('some text', spans=True)
|
|
37
|
+
body = json.loads(responses.calls[-1].request.body)
|
|
38
|
+
assert body == {'key': API_KEY, 'text': 'some text', 'spans': True}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@responses.activate
|
|
42
|
+
def test_safety_spans_false_still_sent_explicitly(client):
|
|
43
|
+
# spans=False is a real value (not "unset"): send it rather than silently
|
|
44
|
+
# dropping it, mirroring the threshold-style None sentinel.
|
|
45
|
+
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
46
|
+
client.safety('some text', spans=False)
|
|
47
|
+
body = json.loads(responses.calls[-1].request.body)
|
|
48
|
+
assert body['spans'] is False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@responses.activate
|
|
52
|
+
def test_safety_spans_omitted_by_default(client):
|
|
53
|
+
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
54
|
+
client.safety('some text')
|
|
55
|
+
body = json.loads(responses.calls[-1].request.body)
|
|
56
|
+
assert 'spans' not in body
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '4.2.0'
|
sapling_py-4.2.0/setup.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Always prefer setuptools over distutils
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from setuptools import setup, find_packages
|
|
4
|
-
|
|
5
|
-
this_directory = Path(__file__).parent
|
|
6
|
-
print(this_directory / 'sapling/version.py')
|
|
7
|
-
print(this_directory / "README.md")
|
|
8
|
-
# load module version
|
|
9
|
-
exec(open(this_directory / 'sapling/version.py').read())
|
|
10
|
-
long_description = (this_directory / "README.md").read_text()
|
|
11
|
-
|
|
12
|
-
setup(
|
|
13
|
-
name='sapling-py',
|
|
14
|
-
version=__version__,
|
|
15
|
-
description='Sapling Python Client',
|
|
16
|
-
long_description=long_description,
|
|
17
|
-
long_description_content_type='text/markdown',
|
|
18
|
-
url='https://sapling.ai',
|
|
19
|
-
author='Sapling Intelligence',
|
|
20
|
-
author_email='info@sapling.ai',
|
|
21
|
-
license='Apache License 2.0',
|
|
22
|
-
classifiers=[
|
|
23
|
-
'Development Status :: 5 - Production/Stable',
|
|
24
|
-
'License :: OSI Approved :: Apache Software License',
|
|
25
|
-
'Programming Language :: Python :: 3',
|
|
26
|
-
'Programming Language :: Python :: 3 :: Only',
|
|
27
|
-
],
|
|
28
|
-
packages=find_packages(exclude=['test', 'test.*']),
|
|
29
|
-
package_data={'':[]},
|
|
30
|
-
include_package_data=True,
|
|
31
|
-
python_requires='>=3.7',
|
|
32
|
-
install_requires=[
|
|
33
|
-
'requests'
|
|
34
|
-
],
|
|
35
|
-
extras_require={
|
|
36
|
-
'test': [
|
|
37
|
-
'pytest',
|
|
38
|
-
'responses',
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
)
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
import responses
|
|
5
|
-
|
|
6
|
-
from sapling import SaplingClient
|
|
7
|
-
|
|
8
|
-
API_KEY = 'a' * 32
|
|
9
|
-
BASE = 'https://api.sapling.ai/api/v1/'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@pytest.fixture
|
|
13
|
-
def client():
|
|
14
|
-
return SaplingClient(api_key=API_KEY)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@responses.activate
|
|
18
|
-
def test_safety_threshold_sent_when_provided(client):
|
|
19
|
-
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
20
|
-
client.safety('some text', threshold=0.8)
|
|
21
|
-
body = json.loads(responses.calls[-1].request.body)
|
|
22
|
-
assert body == {'key': API_KEY, 'text': 'some text', 'threshold': 0.8}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@responses.activate
|
|
26
|
-
def test_safety_threshold_omitted_by_default(client):
|
|
27
|
-
responses.add(responses.POST, BASE + 'safety', json={'flagged': False}, status=200)
|
|
28
|
-
client.safety('some text')
|
|
29
|
-
body = json.loads(responses.calls[-1].request.body)
|
|
30
|
-
assert 'threshold' not in body
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|