From a4066d4c767049218b0813c2eb742bf1c17dc2b9 Mon Sep 17 00:00:00 2001 From: phanirithvij Date: Sat, 26 Sep 2026 10:08:30 +0530 Subject: [PATCH 1/2] typesense: 29.0 -> 29.1 closes https://github.com/NixOS/nixpkgs/issues/531281 Changelog: https://github.com/typesense/typesense/releases/tag/v29.1 Diff: https://github.com/typesense/typesense/compare/v29.0...v29.1 Not-cherry-picked-because: 29.1 is not available in unstable Signed-off-by: phanirithvij --- pkgs/by-name/ty/typesense/sources.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/by-name/ty/typesense/sources.json b/pkgs/by-name/ty/typesense/sources.json index 31bbf29f9a95..2d0c17daa767 100644 --- a/pkgs/by-name/ty/typesense/sources.json +++ b/pkgs/by-name/ty/typesense/sources.json @@ -1,21 +1,21 @@ { - "version": "29.0", + "version": "29.1", "platforms": { "aarch64-linux": { "arch": "linux-arm64", - "hash": "sha256-ztjCyK2378tg9yT9D6ProINlMT5GyUIEH8duHivCQ2E=" + "hash": "sha256-A5HmrKZ4WQ6wh5uLBcns2bsYyKIF8eAdZi6v29XUgXU=" }, "x86_64-linux": { "arch": "linux-amd64", - "hash": "sha256-BD0qE1dEVKVUPwO2fMO0SMXiwG9dD0RMnAzkVZitFKA=" + "hash": "sha256-Jq5I78pNNJKYFtk+rBbOt/JqA0I+MMLV75FspqvF8RU=" }, "x86_64-darwin": { "arch": "darwin-amd64", - "hash": "sha256-9imHOPW8OkFczuNxXGn3bXFI49BIdUJ5GGh1mrvcMgE=" + "hash": "sha256-hSSPkPcqwqdb/V9vRvTLYwSzAdk0e94hVgCpQUNZcfo=" }, "aarch64-darwin": { "arch": "darwin-arm64", - "hash": "sha256-yAOR/bGYBQGp8Mllhh0yKyqmItd2+IfLib3W+lIHwr0=" + "hash": "sha256-BH6h27FU9rrGqRPgN22kfOf3a1yQ4InNVY+ms0WXkpk=" } } } From 18e4330d1867c153aff2a378680def8408023edd Mon Sep 17 00:00:00 2001 From: phanirithvij Date: Sat, 26 Sep 2026 10:34:02 +0530 Subject: [PATCH 2/2] python3Packages.typesense: 1.1.1 -> 1.3.0 https://github.com/typesense/typesense-python#compatibility Diff: https://github.com/typesense/typesense-python/compare/v1.1.1...v1.3.0 Not-cherry-picked-because: patches are specific to 1.3.0 which is unavailable in unstable Signed-off-by: phanirithvij --- ...cs.patch => 0001-linux-only-metrics.patch} | 34 +-- ...h.patch => 0002-generated-temp-path.patch} | 0 .../typesense/0003-tests-fix-rule_id.patch | 13 + ...e-v30-collection-schema-expectations.patch | 256 ++++++++++++++++++ .../python-modules/typesense/default.nix | 49 ++-- 5 files changed, 310 insertions(+), 42 deletions(-) rename pkgs/development/python-modules/typesense/{linux-only-metrics.patch => 0001-linux-only-metrics.patch} (55%) rename pkgs/development/python-modules/typesense/{generated-temp-path.patch => 0002-generated-temp-path.patch} (100%) create mode 100644 pkgs/development/python-modules/typesense/0003-tests-fix-rule_id.patch create mode 100644 pkgs/development/python-modules/typesense/0004-test-gate-v30-collection-schema-expectations.patch diff --git a/pkgs/development/python-modules/typesense/linux-only-metrics.patch b/pkgs/development/python-modules/typesense/0001-linux-only-metrics.patch similarity index 55% rename from pkgs/development/python-modules/typesense/linux-only-metrics.patch rename to pkgs/development/python-modules/typesense/0001-linux-only-metrics.patch index ac667a3e42f1..14a507654874 100644 --- a/pkgs/development/python-modules/typesense/linux-only-metrics.patch +++ b/pkgs/development/python-modules/typesense/0001-linux-only-metrics.patch @@ -1,29 +1,18 @@ -From 9f0024ae3a0377d15788256c72af7a692d250afc Mon Sep 17 00:00:00 2001 -From: dotlambda -Date: Thu, 23 Oct 2025 13:40:33 -0700 -Subject: [PATCH] test(metrics): some metrics only exists on Linux - ---- - tests/metrics_test.py | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - diff --git a/tests/metrics_test.py b/tests/metrics_test.py -index 1e1ea47..fecf3c0 100644 +index 01bb9fa..8555b52 100644 --- a/tests/metrics_test.py +++ b/tests/metrics_test.py -@@ -2,6 +2,8 @@ - - from __future__ import annotations - +@@ -4,18 +4,22 @@ from __future__ import annotations + + from typesense.metrics import Metrics + +import platform + - from typesense.metrics import Metrics - - -@@ -9,13 +11,15 @@ def test_actual_retrieve(actual_metrics: Metrics) -> None: + + def test_actual_retrieve(actual_metrics: Metrics) -> None: """Test that the Debug object can retrieve a debug on Typesense server and verify response structure.""" response = actual_metrics.retrieve() - + - assert "system_cpu_active_percentage" in response + if platform.system() == "Linux": + assert "system_cpu_active_percentage" in response @@ -39,10 +28,3 @@ index 1e1ea47..fecf3c0 100644 assert "typesense_memory_active_bytes" in response assert "typesense_memory_allocated_bytes" in response assert "typesense_memory_fragmentation_ratio" in response -@@ -23,4 +27,4 @@ def test_actual_retrieve(actual_metrics: Metrics) -> None: - assert "typesense_memory_mapped_bytes" in response - assert "typesense_memory_metadata_bytes" in response - assert "typesense_memory_resident_bytes" in response -- assert "typesense_memory_retained_bytes" in response -\ No newline at end of file -+ assert "typesense_memory_retained_bytes" in response diff --git a/pkgs/development/python-modules/typesense/generated-temp-path.patch b/pkgs/development/python-modules/typesense/0002-generated-temp-path.patch similarity index 100% rename from pkgs/development/python-modules/typesense/generated-temp-path.patch rename to pkgs/development/python-modules/typesense/0002-generated-temp-path.patch diff --git a/pkgs/development/python-modules/typesense/0003-tests-fix-rule_id.patch b/pkgs/development/python-modules/typesense/0003-tests-fix-rule_id.patch new file mode 100644 index 000000000000..ce42e8761ee1 --- /dev/null +++ b/pkgs/development/python-modules/typesense/0003-tests-fix-rule_id.patch @@ -0,0 +1,13 @@ +diff --git a/tests/analytics_rules_v1_test.py b/tests/analytics_rules_v1_test.py +index d222d99..d1021d8 100644 +--- a/tests/analytics_rules_v1_test.py ++++ b/tests/analytics_rules_v1_test.py +@@ -45,7 +45,7 @@ def test_get_missing_analytics_rule(fake_analytics_rules: AnalyticsRulesV1) -> N + """Test that the AnalyticsRulesV1 object can get a missing analytics_rule.""" + analytics_rule = fake_analytics_rules["company_analytics_rule"] + +- assert analytics_rule.rule_id == "company_analytics_rule" ++ assert analytics_rule.rule_name == "company_analytics_rule" + assert_match_object(analytics_rule.api_call, fake_analytics_rules.api_call) + assert_object_lists_match( + analytics_rule.api_call.node_manager.nodes, diff --git a/pkgs/development/python-modules/typesense/0004-test-gate-v30-collection-schema-expectations.patch b/pkgs/development/python-modules/typesense/0004-test-gate-v30-collection-schema-expectations.patch new file mode 100644 index 000000000000..de798811aae3 --- /dev/null +++ b/pkgs/development/python-modules/typesense/0004-test-gate-v30-collection-schema-expectations.patch @@ -0,0 +1,256 @@ +diff --git a/tests/collection_test.py b/tests/collection_test.py +index 56c4429..1f795d2 100644 +--- a/tests/collection_test.py ++++ b/tests/collection_test.py +@@ -11,12 +11,24 @@ from tests.utils.object_assertions import ( + assert_object_lists_match, + assert_to_contain_object, + ) ++from tests.utils.version import is_v30_or_above + from typesense.api_call import ApiCall ++from typesense.client import Client + from typesense.collection import Collection + from typesense.collections import Collections + from typesense.types.collection import CollectionSchema + + ++is_v30_or_above_server = is_v30_or_above( ++ Client( ++ { ++ "api_key": "xyz", ++ "nodes": [{"host": "localhost", "port": 8108, "protocol": "http"}], ++ } ++ ) ++) ++ ++ + def test_init(fake_api_call: ApiCall) -> None: + """Test that the Collection object is initialized correctly.""" + collection = Collection(fake_api_call, "companies") +@@ -204,7 +216,6 @@ def test_actual_retrieve( + "infix": False, + "stem": False, + "stem_dictionary": "", +- "truncate_len": 100, + "store": True, + }, + { +@@ -218,7 +229,6 @@ def test_actual_retrieve( + "infix": False, + "stem": False, + "stem_dictionary": "", +- "truncate_len": 100, + "store": True, + }, + ], +@@ -226,9 +236,12 @@ def test_actual_retrieve( + "num_documents": 0, + "symbols_to_index": [], + "token_separators": [], +- "synonym_sets": [], +- "curation_sets": [], + } ++ if is_v30_or_above_server: ++ expected["synonym_sets"] = [] ++ expected["curation_sets"] = [] ++ expected["fields"][0]["truncate_len"] = 100 ++ expected["fields"][1]["truncate_len"] = 100 + + response.pop("created_at") + +@@ -245,10 +258,8 @@ def test_actual_update( + {"fields": [{"name": "num_locations", "type": "int32"}]}, + ) + +- expected: CollectionSchema = { +- "fields": [ +- {"name": "num_locations", "truncate_len": 100, "type": "int32"}, +- ], +- } ++ expected_field = {"name": "num_locations", "type": "int32"} ++ if is_v30_or_above_server: ++ expected_field["truncate_len"] = 100 + +- assert_to_contain_object(response.get("fields")[0], expected.get("fields")[0]) ++ assert_to_contain_object(response.get("fields")[0], expected_field) +diff --git a/tests/collections_test.py b/tests/collections_test.py +index d742652..1021e8e 100644 +--- a/tests/collections_test.py ++++ b/tests/collections_test.py +@@ -13,10 +13,66 @@ else: + + from tests.utils.object_assertions import assert_match_object, assert_object_lists_match + from typesense.api_call import ApiCall ++from tests.utils.version import is_v30_or_above + from typesense.collections import Collections ++from typesense.client import Client + from typesense.types.collection import CollectionSchema + + ++IS_V30_OR_ABOVE = is_v30_or_above( ++ Client( ++ { ++ "api_key": "xyz", ++ "nodes": [{"host": "localhost", "port": 8108, "protocol": "http"}], ++ } ++ ) ++) ++ ++def expected_collection_field( ++ name: str, ++ type_: str, ++ *, ++ sort: bool, ++) -> dict[str, typing.Any]: ++ field: dict[str, typing.Any] = { ++ "name": name, ++ "type": type_, ++ "facet": False, ++ "index": True, ++ "optional": False, ++ "locale": "", ++ "sort": sort, ++ "infix": False, ++ "stem": False, ++ "stem_dictionary": "", ++ "store": True, ++ } ++ if IS_V30_OR_ABOVE: ++ field["truncate_len"] = 100 ++ return field ++ ++ ++def expected_collection_schema( ++ *, ++ default_sorting_field: str, ++ fields: typing.List[dict[str, typing.Any]], ++ name: str, ++) -> CollectionSchema: ++ expected: CollectionSchema = { ++ "default_sorting_field": default_sorting_field, ++ "enable_nested_fields": False, ++ "fields": fields, ++ "name": name, ++ "num_documents": 0, ++ "symbols_to_index": [], ++ "token_separators": [], ++ } ++ if IS_V30_OR_ABOVE: ++ expected["synonym_sets"] = [] ++ expected["curation_sets"] = [] ++ return expected ++ ++ + def test_init(fake_api_call: ApiCall) -> None: + """Test that the Collections object is initialized correctly.""" + collections = Collections(fake_api_call) +@@ -188,46 +244,14 @@ def test_create(fake_collections: Collections) -> None: + + def test_actual_create(actual_collections: Collections, delete_all: None) -> None: + """Test that the Collections object can create a collection on Typesense Server.""" +- expected: CollectionSchema = { +- "default_sorting_field": "", +- "enable_nested_fields": False, +- "fields": [ +- { +- "name": "company_name", +- "type": "string", +- "facet": False, +- "index": True, +- "optional": False, +- "locale": "", +- "sort": False, +- "infix": False, +- "stem": False, +- "stem_dictionary": "", +- "truncate_len": 100, +- "store": True, +- }, +- { +- "name": "num_employees", +- "type": "int32", +- "facet": False, +- "index": True, +- "optional": False, +- "locale": "", +- "sort": False, +- "infix": False, +- "stem": False, +- "stem_dictionary": "", +- "truncate_len": 100, +- "store": True, +- }, +- ], +- "name": "companies", +- "num_documents": 0, +- "symbols_to_index": [], +- "token_separators": [], +- "synonym_sets": [], +- "curation_sets": [], +- } ++ expected = expected_collection_schema( ++ default_sorting_field="", ++ fields=[ ++ expected_collection_field("company_name", "string", sort=False), ++ expected_collection_field("num_employees", "int32", sort=False), ++ ], ++ name="companies", ++ ) + + response = actual_collections.create( + { +@@ -260,46 +284,14 @@ def test_actual_retrieve( + response = actual_collections.retrieve() + + expected: typing.List[CollectionSchema] = [ +- { +- "default_sorting_field": "num_employees", +- "enable_nested_fields": False, +- "fields": [ +- { +- "name": "company_name", +- "type": "string", +- "facet": False, +- "index": True, +- "optional": False, +- "locale": "", +- "sort": False, +- "infix": False, +- "stem": False, +- "stem_dictionary": "", +- "truncate_len": 100, +- "store": True, +- }, +- { +- "name": "num_employees", +- "type": "int32", +- "facet": False, +- "index": True, +- "optional": False, +- "locale": "", +- "sort": True, +- "infix": False, +- "stem": False, +- "stem_dictionary": "", +- "truncate_len": 100, +- "store": True, +- }, +- ], +- "name": "companies", +- "num_documents": 0, +- "symbols_to_index": [], +- "token_separators": [], +- "synonym_sets": [], +- "curation_sets": [], +- }, ++ expected_collection_schema( ++ default_sorting_field="num_employees", ++ fields=[ ++ expected_collection_field("company_name", "string", sort=False), ++ expected_collection_field("num_employees", "int32", sort=True), ++ ], ++ name="companies", ++ ), + ] + + response[0].pop("created_at") diff --git a/pkgs/development/python-modules/typesense/default.nix b/pkgs/development/python-modules/typesense/default.nix index 78441621aa8d..b941dcf28752 100644 --- a/pkgs/development/python-modules/typesense/default.nix +++ b/pkgs/development/python-modules/typesense/default.nix @@ -14,22 +14,25 @@ isort, }: -buildPythonPackage rec { +buildPythonPackage (finalAttrs: { pname = "typesense"; - version = "1.1.1"; + version = "1.3.0"; pyproject = true; src = fetchFromGitHub { owner = "typesense"; repo = "typesense-python"; - tag = "v${version}"; - hash = "sha256-vo9DW4kinb00zWW4yX8ibyelQxW3eVabn+oMddPEd18="; + tag = "v${finalAttrs.version}"; + hash = "sha256-b3t4l02tOiSMrkqZACV6l5f+Kb5Wfcnq9ZZCld1SKBU="; }; patches = [ - # See . - ./linux-only-metrics.patch - ./generated-temp-path.patch + # See . + # See . + ./0001-linux-only-metrics.patch + ./0002-generated-temp-path.patch + ./0003-tests-fix-rule_id.patch + ./0004-test-gate-v30-collection-schema-expectations.patch ]; build-system = [ setuptools ]; @@ -47,24 +50,36 @@ buildPythonPackage rec { isort ]; disabledTestMarks = [ "open_ai" ]; - disabledTests = [ "import_typing_extensions" ]; + disabledTests = [ + "import_typing_extensions" + # tests/operations_test.py::test_snapshot_async fails when tests are run + # in parallel due to writing to the shared /tmp directory on macOS + "test_snapshot_async" + ]; __darwinAllowLocalNetworking = true; + # For darwin, the nix sandbox doesn't isolate loopback interfaces like linux does. + # So nixpkgs-review builds of python3.x will collide on the hardcoded port 8108. + # So for tests patch it to use random port. preCheck = '' + export TYPESENSE_PORT=$(( 10000 + $$ % 30000 )) + export PEERING_PORT=$(( TYPESENSE_PORT - 1 )) + find tests -type f -exec sed -i "s/8108/$TYPESENSE_PORT/g" {} + + TYPESENSE_API_KEY="xyz" \ TYPESENSE_DATA_DIR="$(mktemp -d)" \ - typesense-server & + typesense-server --api-port=$TYPESENSE_PORT --peering-port=$PEERING_PORT & typesense_pid=$! + # Ensure typesense-server is killed even if tests fail + trap "kill $typesense_pid" EXIT + # Wait for typesense to finish starting. - timeout 20 bash -c ' - while ! curl -s --fail localhost:8108/health; do sleep 1; done - ' || false - ''; - postCheck = '' - kill $typesense_pid + timeout 20 bash -c " + while ! curl -s --fail localhost:$TYPESENSE_PORT/health; do sleep 1; done + " || false ''; pythonImportsCheck = [ "typesense" ]; @@ -74,5 +89,7 @@ buildPythonPackage rec { homepage = "https://github.com/typesense/typesense-python"; license = lib.licenses.asl20; teams = [ lib.teams.ngi ]; + # on x86_64-darwin the typesense server doesn't start + badPlatforms = [ "x86_64-darwin" ]; }; -} +})