Skip to content

Commit 7523019

Browse files
sakshamg1304rohitesh-wingify
authored andcommitted
feat: attribute based targeting
1 parent 364f70d commit 7523019

File tree

12 files changed

+359
-76
lines changed

12 files changed

+359
-76
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
8+
## [1.13.0] - 2025-09-04
9+
10+
### Added
11+
12+
- Post-segmentation variables are now automatically included as unregistered attributes, enabling post-segmentation without requiring manual setup.
13+
- Added support for built-in targeting conditions, including browser version, OS version, and IP address, with advanced operator support (greaterThan, lessThan, regex).
14+
715
## [1.12.0] - 2025-09-02
816

917
### Added

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def run(self):
121121

122122
setup(
123123
name="vwo-fme-python-sdk",
124-
version="1.12.0",
124+
version="1.13.0",
125125
description="VWO Feature Management and Experimentation SDK for Python",
126126
long_description=long_description,
127127
long_description_content_type="text/markdown",

vwo/constants/Constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Constants:
1717
# TODO: read from setup.py
1818
sdk_meta = {
1919
"name": "vwo-fme-python-sdk",
20-
"version": "1.12.0"
20+
"version": "1.13.0"
2121
}
2222

2323
# Constants

vwo/models/user/context_model.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515

1616
from .context_vwo_model import ContextVWOModel
17-
from typing import Dict
17+
from typing import Dict, List
1818

1919

2020
class ContextModel:
@@ -27,6 +27,7 @@ def __init__(self, context: Dict):
2727
"variation_targeting_variables", {}
2828
)
2929
self._vwo = ContextVWOModel(context.get("_vwo")) if "_vwo" in context else None
30+
self.post_segmentation_variables = context.get("post_segmentation_variables", [])
3031

3132
def get_id(self) -> str:
3233
return str(self.id) if self.id is not None else None
@@ -56,3 +57,9 @@ def get_vwo(self) -> ContextVWOModel:
5657

5758
def set_vwo(self, vwo: ContextVWOModel) -> None:
5859
self._vwo = vwo
60+
61+
def get_post_segmentation_variables(self) -> List[str]:
62+
return self.post_segmentation_variables
63+
64+
def set_post_segmentation_variables(self, post_segmentation_variables: List[str]) -> None:
65+
self.post_segmentation_variables = post_segmentation_variables

vwo/packages/segmentation_evaluator/core/segmentation_manager.py

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
from ....models.campaign.feature_model import FeatureModel
2323
from ....models.user.context_model import ContextModel
2424
from ....utils.gateway_service_util import get_query_params, get_from_gateway_service
25+
from ....constants.Constants import Constants
26+
from ....services.url_service import UrlService
2527

2628

2729
class SegmentationManager:
@@ -77,27 +79,32 @@ def set_contextual_data(
7779
if not context.get_user_agent() and not context.get_ip_address():
7880
return
7981

80-
if (
81-
feature.get_is_gateway_service_required()
82-
): # Check if gateway service is required
83-
if SettingsManager.get_instance().is_gateway_service_provided and (
84-
context.get_vwo() is None
85-
):
86-
query_params = {}
87-
if context.get_user_agent():
88-
query_params["userAgent"] = context.get_user_agent()
89-
90-
if context.get_ip_address():
91-
query_params["ipAddress"] = context.get_ip_address()
92-
93-
try:
94-
params = get_query_params(query_params)
95-
_vwo = get_from_gateway_service(params, UrlEnum.GET_USER_DATA.value)
96-
context.set_vwo(ContextVWOModel(_vwo))
97-
except Exception as err:
98-
LogManager.get_instance().error(
99-
f"Error in setting contextual data for segmentation. Got error: {err}"
100-
)
82+
# Call gateway service if required for segmentation OR if gateway service is provided and user agent is available
83+
should_call_gateway_service = (
84+
(feature.get_is_gateway_service_required() and Constants.HOST_NAME not in UrlService.get_base_url()) or
85+
(Constants.HOST_NAME not in UrlService.get_base_url() and
86+
(context.get_user_agent() or context.get_ip_address()))
87+
)
88+
89+
if should_call_gateway_service and context.get_vwo() is None:
90+
query_params = {}
91+
if not context.get_user_agent() and not context.get_ip_address():
92+
return
93+
94+
if context.get_user_agent():
95+
query_params["userAgent"] = context.get_user_agent()
96+
97+
if context.get_ip_address():
98+
query_params["ipAddress"] = context.get_ip_address()
99+
100+
try:
101+
params = get_query_params(query_params)
102+
_vwo = get_from_gateway_service(params, UrlEnum.GET_USER_DATA.value)
103+
context.set_vwo(ContextVWOModel(_vwo))
104+
except Exception as err:
105+
LogManager.get_instance().error(
106+
f"Error in setting contextual data for segmentation. Got error: {err}"
107+
)
101108

102109
def validate_segmentation(self, dsl, properties):
103110
"""

vwo/packages/segmentation_evaluator/enums/segment_operand_regex_enum.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class SegmentOperandRegexEnum(Enum):
2525
REGEX_MATCH = r"^regex\((.*)\)"
2626
STARTING_STAR = r"^\*"
2727
ENDING_STAR = r"\*$"
28-
GREATER_THAN_MATCH = r"^gt\((\d+\.?\d*|\.\d+)\)$"
29-
GREATER_THAN_EQUAL_TO_MATCH = r"^gte\((\d+\.?\d*|\.\d+)\)$"
30-
LESS_THAN_MATCH = r"^lt\((\d+\.?\d*|\.\d+)\)$"
31-
LESS_THAN_EQUAL_TO_MATCH = r"^lte\((\d+\.?\d*|\.\d+)\)$"
28+
GREATER_THAN_MATCH = r"^gt\(([\d.]+)\)$"
29+
GREATER_THAN_EQUAL_TO_MATCH = r"^gte\(([\d.]+)\)$"
30+
LESS_THAN_MATCH = r"^lt\(([\d.]+)\)$"
31+
LESS_THAN_EQUAL_TO_MATCH = r"^lte\(([\d.]+)\)$"

vwo/packages/segmentation_evaluator/enums/segment_operator_value_enum.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ class SegmentOperatorValueEnum(Enum):
3131
BROWSER_AGENT = "browser_string"
3232
UA = "ua"
3333
FEATURE_ID = "featureId"
34+
IP = "ip_address"
35+
BROWSER_VERSION = "browser_version"
36+
OS_VERSION = "os_version"

vwo/packages/segmentation_evaluator/evaluators/segment_evaluator.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ def is_segmentation_valid(self, dsl, properties):
5555
return SegmentOperandEvaluator().evaluate_user_agent_dsl(
5656
sub_dsl, self.context
5757
)
58+
elif operator == SegmentOperatorValueEnum.IP.value:
59+
return SegmentOperandEvaluator().evaluate_string_operand_dsl(
60+
sub_dsl, self.context, SegmentOperatorValueEnum.IP.value
61+
)
62+
elif operator == SegmentOperatorValueEnum.BROWSER_VERSION.value:
63+
return SegmentOperandEvaluator().evaluate_string_operand_dsl(
64+
sub_dsl, self.context, SegmentOperatorValueEnum.BROWSER_VERSION.value
65+
)
66+
elif operator == SegmentOperatorValueEnum.OS_VERSION.value:
67+
return SegmentOperandEvaluator().evaluate_string_operand_dsl(
68+
sub_dsl, self.context, SegmentOperatorValueEnum.OS_VERSION.value
69+
)
5870
else:
5971
return False
6072

0 commit comments

Comments
 (0)