From f6805b7797a20cb06e59458d109b71392666d0b3 Mon Sep 17 00:00:00 2001
From: Guillem <37125339+guillem-211@users.noreply.github.com>
Date: Thu, 16 Jan 2025 11:48:27 +0000
Subject: [PATCH 01/17] version poetry
---
CHANGELOG.md | 6 ++++++
audiostack/delivery/encoder.py | 10 +++++++++-
pyproject.toml | 2 +-
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e82a37..1b08b8f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [2.7.2] - 2025-01-16
+
+### Improvement
+
+- Adding custom loudness presets support.
+
## [2.7.1] - 2024-12-18
### Improvement
diff --git a/audiostack/delivery/encoder.py b/audiostack/delivery/encoder.py
index 838462e..1713b2a 100644
--- a/audiostack/delivery/encoder.py
+++ b/audiostack/delivery/encoder.py
@@ -44,6 +44,10 @@ def encode_mix(
format: str = "",
bitDepth: Optional[int] = None,
channels: Optional[int] = None,
+ loudnessSettings: str = "",
+ loudnessTarget: Optional[float] = None,
+ dynamicRange: Optional[float] = None,
+ truePeak: Optional[float] = None,
) -> Item:
if productionId and productionItem:
raise Exception(
@@ -65,7 +69,7 @@ def encode_mix(
if not preset:
raise Exception(
- "Either a an encoding preset (preset) or a loudness preset (loudnessPreset) should be supplied"
+ "Either an encoding preset (preset) or a loudness preset (loudnessPreset) should be supplied"
)
body = {
@@ -79,6 +83,10 @@ def encode_mix(
"bitDepth": bitDepth,
"channels": channels,
"loudnessPreset": loudnessPreset,
+ "loudnessSettings": loudnessSettings,
+ "loudnessTarget": loudnessTarget,
+ "dynamicRange": dynamicRange,
+ "truePeak": truePeak,
}
r = Encoder.interface.send_request(
rtype=RequestTypes.POST, route="encoder", json=body
diff --git a/pyproject.toml b/pyproject.toml
index dee7090..57ea356 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.7.1"
+version = "2.8.0"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From f433cba752e679eca2d9914e2b94fdaa209a0007 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Tue, 21 Jan 2025 13:11:27 +0000
Subject: [PATCH 02/17] feat: add query method to Voice with tests
---
CHANGELOG.md | 6 +++
audiostack/speech/voice.py | 24 ++++++++-
audiostack/tests/tts/test_voice.py | 82 ++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
4 files changed, 112 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e82a37..b40787d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [2.8.0] - 2025-01-20
+
+### Added
+
+- Added Voice query endpoint to SDK.
+
## [2.7.1] - 2024-12-18
### Improvement
diff --git a/audiostack/speech/voice.py b/audiostack/speech/voice.py
index 257f952..5586e24 100644
--- a/audiostack/speech/voice.py
+++ b/audiostack/speech/voice.py
@@ -1,4 +1,5 @@
-from typing import Any
+from typing import Any, Dict
+from typing import List as ListType
from audiostack.helpers.api_item import APIResponseItem
from audiostack.helpers.api_list import APIResponseList
@@ -25,6 +26,27 @@ def resolve_item(self, list_type: str, item: Any) -> "Voice.Item":
else:
raise Exception()
+ @staticmethod
+ def query(
+ filters: ListType[Dict] = [],
+ minimumNumberOfResults: int = 3,
+ forceApplyFilters: bool = True,
+ page: int = 1,
+ pageLimit: int = 1000,
+ ) -> "Voice.List":
+ body = {
+ "filters": filters,
+ "minimumNumberOfResults": minimumNumberOfResults,
+ "forceApplyFilters": forceApplyFilters,
+ "page": page,
+ "pageLimit": pageLimit,
+ }
+
+ r = Voice.interface.send_request(
+ rtype=RequestTypes.POST, route="query", json=body
+ )
+ return Voice.List(r, list_type="voices")
+
@staticmethod
def select_for_script(
scriptId: str = "", scriptItem: Any = "", tone: str = "", targetLength: int = 20
diff --git a/audiostack/tests/tts/test_voice.py b/audiostack/tests/tts/test_voice.py
index 9666b2c..8bb17d0 100644
--- a/audiostack/tests/tts/test_voice.py
+++ b/audiostack/tests/tts/test_voice.py
@@ -1,12 +1,40 @@
import os
+from typing import Any
+from unittest.mock import Mock, patch
+
+from pytest import fixture
import audiostack
+from audiostack.helpers.api_item import APIResponseItem
+from audiostack.helpers.request_types import RequestTypes
from audiostack.speech.voice import Voice
audiostack.api_base = os.environ.get("AUDIO_STACK_DEV_URL", "https://v2.api.audio")
audiostack.api_key = os.environ["AUDIO_STACK_DEV_KEY"] # type: ignore
+@fixture
+def voice_data() -> dict:
+ return {
+ "response": "response",
+ "provider": "provider",
+ "alias": "alias",
+ }
+
+
+@fixture
+def mock_send_request() -> Any:
+ with patch("audiostack.speech.Voice.interface.send_request") as mock_:
+ yield mock_
+
+
+def test_item(voice_data: dict) -> None:
+ v = Voice.Item({"data": voice_data})
+ assert v.provider
+ assert v.alias
+ assert v.response
+
+
def test_list() -> None:
voices = Voice.list()
for v in voices:
@@ -19,3 +47,57 @@ def test_list() -> None:
def test_parmaters() -> None:
r = Voice.Parameter.get()
assert r
+
+
+def test_Voice_query(mock_send_request: Mock, voice_data: dict) -> None:
+ mock_send_request.return_value = {"data": {"voices": [voice_data] * 10}}
+ voices = Voice.query()
+ mock_send_request.assert_called_once_with(
+ rtype=RequestTypes.POST,
+ route="query",
+ json={
+ "filters": [],
+ "minimumNumberOfResults": 3,
+ "forceApplyFilters": True,
+ "page": 1,
+ "pageLimit": 1000,
+ },
+ )
+ assert isinstance(voices, Voice.List)
+ assert voices.data == {"voices": [voice_data] * 10}
+
+
+def test_Voice_query_with_parameters(mock_send_request: Mock, voice_data: dict) -> None:
+ mock_send_request.return_value = {"data": {"voices": [voice_data] * 10}}
+ filters = [{"in": {"language": ["dutch"]}}]
+ voices = Voice.query(
+ filters=filters,
+ minimumNumberOfResults=1,
+ forceApplyFilters=False,
+ pageLimit=100,
+ )
+ mock_send_request.assert_called_once_with(
+ rtype=RequestTypes.POST,
+ route="query",
+ json={
+ "filters": filters,
+ "minimumNumberOfResults": 1,
+ "forceApplyFilters": False,
+ "page": 1,
+ "pageLimit": 100,
+ },
+ )
+ assert isinstance(voices, Voice.List)
+ assert voices.data == {"voices": [voice_data] * 10}
+
+
+def test_Voice_select_for_script(mock_send_request: Mock, voice_data: dict) -> None:
+ mock_send_request.return_value = voice_data
+ r = Voice.select_for_script(scriptId="1")
+ mock_send_request.assert_called_once_with(
+ rtype=RequestTypes.POST,
+ route="select",
+ json={"scriptId": "1", "tone": "", "targetLength": 20},
+ )
+ assert isinstance(r, APIResponseItem)
+ assert r.response == voice_data
diff --git a/pyproject.toml b/pyproject.toml
index dee7090..57ea356 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.7.1"
+version = "2.8.0"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From c4d99c9faecd41067df4b0a19917d464a7902785 Mon Sep 17 00:00:00 2001
From: Guillem <37125339+guillem-211@users.noreply.github.com>
Date: Wed, 22 Jan 2025 12:36:07 +0000
Subject: [PATCH 03/17] updoate
---
CHANGELOG.md | 10 ++++++++--
pyproject.toml | 2 +-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b08b8f..77d99a3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,12 +4,18 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
-## [2.7.2] - 2025-01-16
+## [2.8.1] - 2025-01-22
### Improvement
- Adding custom loudness presets support.
+## [2.8.0] - 2025-01-20
+
+### Added
+
+- Added Voice query endpoint to SDK.
+
## [2.7.1] - 2024-12-18
### Improvement
@@ -104,4 +110,4 @@ Improved error messaging for Media files
### Fixes
- Fixed missing argument in `content.list_modules`.
-- Fixed inclusion of missing `x-assume-org` header in `request_interface.download_url`.
+- Fixed inclusion of missing `x-assume-org` header in `request_interface.download_url`.
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 57ea356..737afc3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.8.0"
+version = "2.8.1"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From a3ba2e13ca17d1a8b35cbeb21031ae20a889b8f6 Mon Sep 17 00:00:00 2001
From: Guillem <37125339+guillem-211@users.noreply.github.com>
Date: Wed, 22 Jan 2025 13:46:53 +0000
Subject: [PATCH 04/17] fix comit
---
CHANGELOG.md | 2 +-
pyproject.toml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77d99a3..e9f80c6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
-## [2.8.1] - 2025-01-22
+## [2.8.2] - 2025-01-22
### Improvement
diff --git a/pyproject.toml b/pyproject.toml
index 737afc3..ba4fc8c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.8.1"
+version = "2.8.2"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From 387bd3ef07b21b0060601fac942b04799ed0df19 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Thu, 23 Jan 2025 16:06:57 +0000
Subject: [PATCH 05/17] Fix - remove emojis from section headers and add public
asset link
---
CHANGELOG.md | 7 +++++++
README.md | 20 ++++++++++----------
pyproject.toml | 2 +-
3 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e9f80c6..184b871 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,13 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [2.9.0] - 2025-01-23
+
+### Fixed
+
+- Removed emojis from PyPi document
+- Made example asset public
+
## [2.8.2] - 2025-01-22
### Improvement
diff --git a/README.md b/README.md
index 2ea3f6e..6f3251f 100644
--- a/README.md
+++ b/README.md
@@ -11,15 +11,15 @@
-## 🧐 About
+## About
This repository is actively maintained by [Audiostack](https://audiostack.ai/). For examples, recipes and api reference see the [api.audio docs](https://docs.audiostack.ai/reference/quick-start). Feel free to get in touch with any questions or feedback!
-## :book: Changelog
+## Changelog
You can view [here](https://docs.audiostack.ai/changelog) our updated Changelog.
-## 🏁 Getting Started
+## Getting Started
### Installation
@@ -51,7 +51,7 @@ audiostack.assume_org_id = "your-org-id"
### Create your first audio asset
-#### ✍️ First, create a Script.
+#### First, create a Script.
Audiostack Scripts are the first step in creating audio assets. Not only do they contain the text to be spoken, but also determine the final structure of our audio asset using the [Script Syntax](https://docs.audiostack.ai/docs/script-syntax).
@@ -71,7 +71,7 @@ We are excited to see what you'll create with our product!
""")
```
-#### 🎤 Now, let's read it out load.
+#### Now, let's read it out load.
We integrate all the major TTS voices in the market. You can browse them in our [voice library](https://library.audiostack.ai/).
@@ -88,7 +88,7 @@ When you listen to these files, you'll notice each of them has a certain silence
tts = audiostack.Speech.TTS.remove_padding(speechId=tts.speechId)
```
-#### 🎛️ Now let's mix the speech we just created with a [sound template](https://library.audiostack.ai/sound).
+#### Now let's mix the speech we just created with a [sound template](https://library.audiostack.ai/sound).
```python
mix = audiostack.Production.Mix.create(speechItem=tts, soundTemplate="chill_vibes")
@@ -101,18 +101,18 @@ You can list all the sound templates to see what segments are available or even
Mixing comes with a lot of options to tune your audio to sound just right.
[More on this here.](https://docs.audiostack.ai/docs/advance-timing-parameters)
-#### 🎧 At this point, we can download the mix as a wave file, or convert it to another format.
+#### At this point, we can download the mix as a wave file, or convert it to another format.
```python
enc = audiostack.Delivery.Encoder.encode_mix(productionItem=mix, preset="mp3_high")
enc.download(fileName="example")
```
-Easy right? 🔮 This is the final result:
+Easy right? This is the final result:
-https://github.com/aflorithmic/audiostack-python/assets/64603095/6948cddb-4132-40a7-b84d-457f3fc0803d
+https://file.api.audio/pypi_example.mp3
-## :speedboat: More quickstarts
+## More quickstarts
Get started with our [quickstart recipes](https://docs.audiostack.ai/docs/introduction).
diff --git a/pyproject.toml b/pyproject.toml
index ba4fc8c..115cab0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.8.2"
+version = "2.9.0"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From 8b9c357ac7724c72278ec4abb8343bcf1d94e982 Mon Sep 17 00:00:00 2001
From: CodeBooster97
Date: Thu, 30 Jan 2025 11:40:01 +0100
Subject: [PATCH 06/17] Include changelog
---
pyproject.toml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/pyproject.toml b/pyproject.toml
index 115cab0..e04be06 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,6 +4,7 @@ version = "2.9.0"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
+
readme = "README.md"
classifiers = [
"Programming Language :: Python :: 3",
@@ -12,6 +13,9 @@ classifiers = [
]
exclude = ["audiostack/tests"]
+[tool.poetry.urls]
+Changelog = "https://github.com/aflorithmic/audiostack-python/blob/main/CHANGELOG.md"
+
[tool.poetry.dependencies]
python = "^3.8.1"
requests = "^2.31.0"
From b87b0ba9260b66d8013e064f53b5a4838ad496b9 Mon Sep 17 00:00:00 2001
From: CodeBooster97
Date: Thu, 30 Jan 2025 11:40:22 +0100
Subject: [PATCH 07/17] bump version
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index e04be06..923f02d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.9.0"
+version = "2.9.1"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From a8c1b0ae0d4a824418418621e9e2406a2a187214 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Thu, 13 Feb 2025 12:01:58 +0000
Subject: [PATCH 08/17] feat: add customer trace id header
---
CHANGELOG.md | 6 ++++++
audiostack/__init__.py | 1 +
audiostack/helpers/request_interface.py | 2 ++
pyproject.toml | 2 +-
4 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 184b871..4d13723 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [2.10.0] - 2025-02-13
+
+### Added
+
+- Customer trace id header can now be set.
+
## [2.9.0] - 2025-01-23
### Fixed
diff --git a/audiostack/__init__.py b/audiostack/__init__.py
index f049823..2c4e841 100644
--- a/audiostack/__init__.py
+++ b/audiostack/__init__.py
@@ -3,6 +3,7 @@
api_key = None
assume_org_id = None
app_info = None
+customer_trace_id = None
TIMEOUT_THRESHOLD_S = 300
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index 3ff8a6a..5218122 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -37,6 +37,8 @@ def make_header() -> dict:
"x-api-key": audiostack.api_key,
"x-python-sdk-version": audiostack.sdk_version,
}
+ if audiostack.customer_trace_id:
+ header["x-customer-trace-id"] = audiostack.customer_trace_id
if audiostack.assume_org_id:
header["x-assume-org"] = audiostack.assume_org_id
return header
diff --git a/pyproject.toml b/pyproject.toml
index 923f02d..0dd25b5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.9.1"
+version = "2.10.0"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"
From b343bcb01faac07bffe91d1e405ee4c421fce0b2 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Thu, 13 Feb 2025 13:46:02 +0000
Subject: [PATCH 09/17] feat: enhance header creation to accept custom headers
---
audiostack/helpers/request_interface.py | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index 5218122..0befeab 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -32,16 +32,18 @@ def __init__(self, family: str) -> None:
self.family = family
@staticmethod
- def make_header() -> dict:
- header = {
+ def make_header(headers: Optional[dict] = None) -> dict:
+ new_headers = {
"x-api-key": audiostack.api_key,
"x-python-sdk-version": audiostack.sdk_version,
}
if audiostack.customer_trace_id:
- header["x-customer-trace-id"] = audiostack.customer_trace_id
+ new_headers["x-customer-trace-id"] = audiostack.customer_trace_id
if audiostack.assume_org_id:
- header["x-assume-org"] = audiostack.assume_org_id
- return header
+ new_headers["x-assume-org"] = audiostack.assume_org_id
+ if headers:
+ new_headers.update(headers)
+ return new_headers
def resolve_response(self, r: Any) -> dict:
if self.DEBUG_PRINT:
@@ -84,6 +86,7 @@ def send_request(
path_parameters: Optional[Union[dict, str]] = None,
query_parameters: Optional[Union[dict, str]] = None,
overwrite_base_url: Optional[str] = None,
+ headers: Optional[dict] = None,
) -> Any:
if overwrite_base_url:
url = overwrite_base_url
@@ -113,7 +116,7 @@ def send_request(
}
return self.resolve_response(
- FUNC_MAP[rtype](url=url, json=json, headers=self.make_header())
+ FUNC_MAP[rtype](url=url, json=json, headers=self.make_header(headers))
)
elif rtype == RequestTypes.GET:
if path_parameters:
@@ -121,7 +124,7 @@ def send_request(
return self.resolve_response(
requests.get(
- url=url, params=query_parameters, headers=self.make_header()
+ url=url, params=query_parameters, headers=self.make_header(headers)
)
)
elif rtype == RequestTypes.DELETE:
@@ -130,7 +133,7 @@ def send_request(
return self.resolve_response(
requests.delete(
- url=url, params=query_parameters, headers=self.make_header()
+ url=url, params=query_parameters, headers=self.make_header(headers)
)
)
From 6dc2bc94268deea7dacff4e0b74f374ef87d5d1c Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Thu, 13 Feb 2025 13:47:05 +0000
Subject: [PATCH 10/17] docs: update changelog to include custom headers
feature
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d13723..fad48f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Customer trace id header can now be set.
+- Can pass through custom headers into `send_request`.
## [2.9.0] - 2025-01-23
From 083aeb12ba73165f61ad5fb224f4326b6954ab8b Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Fri, 14 Feb 2025 13:25:05 +0000
Subject: [PATCH 11/17] feat: implement context manager for setting customer
trace id
---
CHANGELOG.md | 2 +-
audiostack/__init__.py | 1 -
audiostack/helpers/request_interface.py | 19 +++++++++++++++++--
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fad48f7..2a221a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
-- Customer trace id header can now be set.
+- Customer trace id header can now be set per production using the `use_trace` context manager.
- Can pass through custom headers into `send_request`.
## [2.9.0] - 2025-01-23
diff --git a/audiostack/__init__.py b/audiostack/__init__.py
index 2c4e841..f049823 100644
--- a/audiostack/__init__.py
+++ b/audiostack/__init__.py
@@ -3,7 +3,6 @@
api_key = None
assume_org_id = None
app_info = None
-customer_trace_id = None
TIMEOUT_THRESHOLD_S = 300
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index 0befeab..cb57af5 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -1,12 +1,16 @@
import json
import shutil
from typing import Any, Callable, Dict, Optional, Union
+import contextlib
+import contextvars
import requests
import audiostack
from audiostack.helpers.request_types import RequestTypes
+_current_trace_id = contextvars.ContextVar("current_trace_id", default=None)
+
def remove_empty(data: Any) -> Any:
if not (isinstance(data, dict) or isinstance(data, list)):
@@ -37,8 +41,9 @@ def make_header(headers: Optional[dict] = None) -> dict:
"x-api-key": audiostack.api_key,
"x-python-sdk-version": audiostack.sdk_version,
}
- if audiostack.customer_trace_id:
- new_headers["x-customer-trace-id"] = audiostack.customer_trace_id
+ current_trace_id = _current_trace_id.get()
+ if current_trace_id is not None:
+ new_headers["x-customer-trace-id"] = current_trace_id
if audiostack.assume_org_id:
new_headers["x-assume-org"] = audiostack.assume_org_id
if headers:
@@ -147,3 +152,13 @@ def download_url(cls, url: str, name: str, destination: str) -> None:
local_filename = f"{destination}/{name}"
with open(local_filename, "wb") as f:
shutil.copyfileobj(r.raw, f)
+
+
+@contextlib.contextmanager
+def use_trace(trace_id):
+ token = _current_trace_id.set(trace_id)
+
+ try:
+ yield
+ finally:
+ _current_trace_id.reset(token)
From 018b319261ae051e53c254b5f7a7e8fdbb982fa6 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Fri, 14 Feb 2025 13:26:51 +0000
Subject: [PATCH 12/17] chore: reorganize imports in request_interface.py
---
audiostack/helpers/request_interface.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index cb57af5..a750555 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -1,8 +1,8 @@
+import contextlib
+import contextvars
import json
import shutil
from typing import Any, Callable, Dict, Optional, Union
-import contextlib
-import contextvars
import requests
From e79a5aeb04d9f8a44063d0cdb1ed85b3f317f96c Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Fri, 14 Feb 2025 14:07:04 +0000
Subject: [PATCH 13/17] feat: update use_trace context manager to specify
return type and add tests for trace id handling
---
audiostack/helpers/request_interface.py | 5 +-
.../tests/helpers/test_request_interface.py | 49 ++++++++++++++++++-
2 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index a750555..1607dce 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -2,7 +2,7 @@
import contextvars
import json
import shutil
-from typing import Any, Callable, Dict, Optional, Union
+from typing import Any, Callable, Dict, Generator, Optional, Union
import requests
@@ -155,9 +155,8 @@ def download_url(cls, url: str, name: str, destination: str) -> None:
@contextlib.contextmanager
-def use_trace(trace_id):
+def use_trace(trace_id: str) -> Generator[None, None, None]:
token = _current_trace_id.set(trace_id)
-
try:
yield
finally:
diff --git a/audiostack/tests/helpers/test_request_interface.py b/audiostack/tests/helpers/test_request_interface.py
index 48a46fd..2d9cad0 100644
--- a/audiostack/tests/helpers/test_request_interface.py
+++ b/audiostack/tests/helpers/test_request_interface.py
@@ -3,7 +3,8 @@
import pytest
import audiostack
-from audiostack.helpers.request_interface import RequestInterface
+from audiostack.helpers.request_interface import RequestInterface, use_trace
+from audiostack.helpers.request_types import RequestTypes
@patch("audiostack.helpers.request_interface.open")
@@ -59,3 +60,49 @@ def test_RequestInterface_download_url_4XX(
mock_requests.get.return_value.status_code = 400
with pytest.raises(Exception):
RequestInterface.download_url(url="foo", name="bar", destination="baz")
+
+
+@patch("audiostack.helpers.request_interface.requests")
+def test_RequestInterface_with_trace_id(mock_requests: Mock) -> None:
+ body = {
+ "scriptText": "scriptText",
+ "projectName": "projectName",
+ "moduleName": "moduleName",
+ "scriptName": "scriptName",
+ "metadata": "metadata",
+ }
+ with use_trace("trace_id"):
+ mock_requests.post.return_value.status_code = 200
+ interface = RequestInterface(family="content")
+ interface.send_request(rtype=RequestTypes.POST, route="script", json=body)
+ mock_requests.post.assert_called_once_with(
+ url=f"{audiostack.api_base}/content/script",
+ headers={
+ "x-api-key": audiostack.api_key,
+ "x-python-sdk-version": audiostack.sdk_version,
+ "x-customer-trace-id": "trace_id",
+ },
+ json=body,
+ )
+
+
+@patch("audiostack.helpers.request_interface.requests")
+def test_RequestInterface_with_no_trace_id(mock_requests: Mock) -> None:
+ body = {
+ "scriptText": "scriptText",
+ "projectName": "projectName",
+ "moduleName": "moduleName",
+ "scriptName": "scriptName",
+ "metadata": "metadata",
+ }
+ mock_requests.post.return_value.status_code = 200
+ interface = RequestInterface(family="content")
+ interface.send_request(rtype=RequestTypes.POST, route="script", json=body)
+ mock_requests.post.assert_called_once_with(
+ url=f"{audiostack.api_base}/content/script",
+ headers={
+ "x-api-key": audiostack.api_key,
+ "x-python-sdk-version": audiostack.sdk_version,
+ },
+ json=body,
+ )
From 5f79d57f5c60d289931345bfe61e5fe20e973e38 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Fri, 14 Feb 2025 14:14:15 +0000
Subject: [PATCH 14/17] fix: update use_trace context manager to improve type
hinting for trace_id
---
audiostack/helpers/request_interface.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index 1607dce..9f342a3 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -156,7 +156,9 @@ def download_url(cls, url: str, name: str, destination: str) -> None:
@contextlib.contextmanager
def use_trace(trace_id: str) -> Generator[None, None, None]:
- token = _current_trace_id.set(trace_id)
+ # This is a workaround to give correct type hints to the context manager but follow ContextVar's .set() method signature
+ any_typed_trace_id: Any = trace_id
+ token = _current_trace_id.set(any_typed_trace_id)
try:
yield
finally:
From feabc63eccf8d7fbb549ccd57c9480e9df8ba453 Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Tue, 18 Feb 2025 11:10:32 +0000
Subject: [PATCH 15/17] fix: improve type hinting for current_trace_id in
request_interface.py
---
audiostack/helpers/request_interface.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index 9f342a3..a634931 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -1,5 +1,5 @@
import contextlib
-import contextvars
+from contextvars import ContextVar
import json
import shutil
from typing import Any, Callable, Dict, Generator, Optional, Union
@@ -9,7 +9,9 @@
import audiostack
from audiostack.helpers.request_types import RequestTypes
-_current_trace_id = contextvars.ContextVar("current_trace_id", default=None)
+_current_trace_id: ContextVar[Optional[str]] = ContextVar(
+ "current_trace_id", default=None
+)
def remove_empty(data: Any) -> Any:
@@ -156,9 +158,7 @@ def download_url(cls, url: str, name: str, destination: str) -> None:
@contextlib.contextmanager
def use_trace(trace_id: str) -> Generator[None, None, None]:
- # This is a workaround to give correct type hints to the context manager but follow ContextVar's .set() method signature
- any_typed_trace_id: Any = trace_id
- token = _current_trace_id.set(any_typed_trace_id)
+ token = _current_trace_id.set(trace_id)
try:
yield
finally:
From d24c926b95632cf8e24b0fb8d88adb09b5c5e39e Mon Sep 17 00:00:00 2001
From: Harry Gardiner
Date: Tue, 18 Feb 2025 11:11:41 +0000
Subject: [PATCH 16/17] chore: reorder imports in request_interface.py for
consistency
---
audiostack/helpers/request_interface.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index a634931..13d8da2 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -1,7 +1,7 @@
import contextlib
-from contextvars import ContextVar
import json
import shutil
+from contextvars import ContextVar
from typing import Any, Callable, Dict, Generator, Optional, Union
import requests
From d72102b45e59e8f0e7693277059141ae791f6c31 Mon Sep 17 00:00:00 2001
From: Marcin Szleszynski <64603095+martinezpl@users.noreply.github.com>
Date: Tue, 25 Feb 2025 10:07:03 +0100
Subject: [PATCH 17/17] fix: pass 0 float values (#73)
* fix: pass 0 float values
* chore: changelog
* chore: lint
---
CHANGELOG.md | 4 ++++
audiostack/helpers/request_interface.py | 4 +++-
pyproject.toml | 2 +-
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a221a2..f4c0e5f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to `audiostack` will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [2.10.1] - 2025-02-24
+- Fixed logic that removed 0 float values from payload
+
+
## [2.10.0] - 2025-02-13
### Added
diff --git a/audiostack/helpers/request_interface.py b/audiostack/helpers/request_interface.py
index 13d8da2..114f3ac 100644
--- a/audiostack/helpers/request_interface.py
+++ b/audiostack/helpers/request_interface.py
@@ -20,7 +20,9 @@ def remove_empty(data: Any) -> Any:
final_dict = {}
for key, val in data.items(): # type: ignore
- if val or isinstance(val, int): # val = int(0) shoud not be removed
+ if (
+ val or isinstance(val, int) or isinstance(val, float)
+ ): # val = int(0), float(0) should not be removed
if isinstance(val, dict):
final_dict[key] = remove_empty(val)
elif isinstance(val, list):
diff --git a/pyproject.toml b/pyproject.toml
index 0dd25b5..1a75309 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "audiostack"
-version = "2.10.0"
+version = "2.10.1"
description = "Python SDK for Audiostack API"
authors = ["Aflorithmic "]
repository = "https://github.com/aflorithmic/audiostack-python"