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.
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sapling-py
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: Sapling Python Client
5
- Home-page: https://sapling.ai
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 [pip](https://pip.pypa.io/en/stable/installation/)
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 [pip](https://pip.pypa.io/en/stable/installation/)
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.2.0
3
+ Version: 4.3.0
4
4
  Summary: Sapling Python Client
5
- Home-page: https://sapling.ai
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 [pip](https://pip.pypa.io/en/stable/installation/)
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).
@@ -1,5 +1,6 @@
1
1
  LICENSE
2
2
  README.md
3
+ pyproject.toml
3
4
  setup.py
4
5
  sapling/__init__.py
5
6
  sapling/client.py
@@ -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