Skip to content

Commit

Permalink
Merge branch 'master' into ivana/populate-tox-2
Browse files Browse the repository at this point in the history
  • Loading branch information
sentrivana committed Jan 8, 2025
2 parents 87b3609 + c6a89d6 commit 29c4a8f
Show file tree
Hide file tree
Showing 16 changed files with 661 additions and 284 deletions.
10 changes: 1 addition & 9 deletions .github/workflows/test-integrations-misc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["2.7","3.4","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13"]
python-version: ["3.4","3.5","3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13"]
# python3.6 reached EOL and is no longer being supported on
# new versions of hosted runners on Github Actions
# ubuntu-20.04 is the last version that supported python3.6
Expand All @@ -47,18 +47,10 @@ jobs:
- name: Erase coverage
run: |
coverage erase
- name: Test launchdarkly
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-launchdarkly"
- name: Test loguru
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-loguru"
- name: Test openfeature
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-openfeature"
- name: Test opentelemetry
run: |
set -x # print commands that are executed
Expand Down
1 change: 1 addition & 0 deletions requirements-linting.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ pre-commit # local linting
httpcore
openfeature-sdk
launchdarkly-server-sdk
UnleashClient
typer
77 changes: 40 additions & 37 deletions scripts/populate_tox/populate_tox.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import functools
import time
from collections import defaultdict
from datetime import datetime, timedelta
from pathlib import Path
from typing import Optional
Expand All @@ -25,13 +26,7 @@
CLASSIFIER_PREFIX = "Programming Language :: Python :: "


# XXX for each, we need:
# package
# name (opt)
# minimal supported version
# deal with variants like notiktoken (if name, package are separate, this is just a new test suite)
GROUPS = {
# Group: [(Test Suite Name, main package name)]
"Common": [
"common",
],
Expand All @@ -55,16 +50,6 @@
"cloud_resource_context",
"gcp",
],
"Tasks": [
"arq",
"beam",
"celery",
"dramatiq",
"huey",
"ray",
"rq",
"spark",
],
"DBs": [
"asyncpg",
"clickhouse-driver",
Expand All @@ -73,6 +58,11 @@
"redis-py-cluster-legacy",
"sqlalchemy",
],
"Flags": [
"launchdarkly",
"openfeature",
"unleash",
],
"GraphQL": [
"ariadne",
"gql",
Expand All @@ -85,6 +75,16 @@
"httpx",
"requests",
],
"Tasks": [
"arq",
"beam",
"celery",
"dramatiq",
"huey",
"ray",
"rq",
"spark",
],
"Web 1": [
"django",
"flask",
Expand All @@ -104,9 +104,7 @@
"tornado",
],
"Misc": [
"launchdarkly",
"loguru",
"openfeature",
"opentelemetry",
"potel",
"pure_eval",
Expand All @@ -115,8 +113,9 @@
],
}

# Do not try auto-generating the tox entries for these
IGNORE = {
# Do not try auto-generating the tox entries for these. They will be
# hardcoded in tox.ini.
"common",
"gevent",
"asgi",
Expand Down Expand Up @@ -335,17 +334,19 @@ def determine_python_versions(
def write_tox_file(packages: dict) -> None:
template = ENV.get_template("tox.jinja")

context = {"integrations": []}
for data in packages.values():
context["integrations"].append(
{
"name": data["name"],
"package": data["package"],
"extra": data["extra"],
"releases": data["releases"],
"dependencies": DEPENDENCIES[data["name"]][1:],
}
)
context = {"groups": {}}
for group, integrations in packages.items():
context["groups"][group] = []
for integration in integrations:
context["groups"][group].append(
{
"name": integration["name"],
"package": integration["package"],
"extra": integration["extra"],
"releases": integration["releases"],
"dependencies": DEPENDENCIES[integration["name"]][1:],
}
)

rendered = template.render(context)

Expand All @@ -361,7 +362,7 @@ def write_tox_file(packages: dict) -> None:
f"The SDK supports Python versions {LOWEST_SUPPORTED_PYTHON_VERSION} to {HIGHEST_SUPPORTED_PYTHON_VERSION}. Only considering framework releases that overlap..."
)

packages = {}
packages = defaultdict(list)

for group, integrations in GROUPS.items():
for integration in integrations:
Expand Down Expand Up @@ -407,11 +408,13 @@ def write_tox_file(packages: dict) -> None:
release for release in test_releases if release.python_versions
]
if test_releases:
packages[integration] = {
"name": integration,
"package": package,
"extra": extra,
"releases": test_releases,
}
packages[group].append(
{
"name": integration,
"package": package,
"extra": extra,
"releases": test_releases,
}
)

write_tox_file(packages)
27 changes: 15 additions & 12 deletions scripts/split_tox_gh_actions/split_tox_gh_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,6 @@
"cloud_resource_context",
"gcp",
],
"Tasks": [
"arq",
"beam",
"celery",
"dramatiq",
"huey",
"ray",
"rq",
"spark",
],
"DBs": [
"asyncpg",
"clickhouse_driver",
Expand All @@ -94,6 +84,11 @@
"redis_py_cluster_legacy",
"sqlalchemy",
],
"Flags": [
"launchdarkly",
"openfeature",
"unleash",
],
"GraphQL": [
"ariadne",
"gql",
Expand All @@ -106,6 +101,16 @@
"httpx",
"requests",
],
"Tasks": [
"arq",
"beam",
"celery",
"dramatiq",
"huey",
"ray",
"rq",
"spark",
],
"Web 1": [
"django",
"flask",
Expand All @@ -125,9 +130,7 @@
"tornado",
],
"Misc": [
"launchdarkly",
"loguru",
"openfeature",
"opentelemetry",
"potel",
"pure_eval",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class FeatureFlagsIntegration(Integration):
@example
```
import sentry_sdk
from sentry_sdk.integrations.featureflags import FeatureFlagsIntegration, add_feature_flag
from sentry_sdk.integrations.feature_flags import FeatureFlagsIntegration, add_feature_flag
sentry_sdk.init(dsn="my_dsn", integrations=[FeatureFlagsIntegration()]);
Expand All @@ -25,7 +25,7 @@ class FeatureFlagsIntegration(Integration):
```
"""

identifier = "featureflags"
identifier = "feature_flags"

@staticmethod
def setup_once():
Expand Down
14 changes: 7 additions & 7 deletions sentry_sdk/integrations/launchdarkly.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,27 @@

class LaunchDarklyIntegration(Integration):
identifier = "launchdarkly"
_ld_client = None # type: LDClient | None

def __init__(self, ld_client=None):
# type: (LDClient | None) -> None
"""
:param client: An initialized LDClient instance. If a client is not provided, this
integration will attempt to use the shared global instance.
"""
self.__class__._ld_client = ld_client

@staticmethod
def setup_once():
# type: () -> None
try:
client = LaunchDarklyIntegration._ld_client or ldclient.get()
client = ld_client or ldclient.get()
except Exception as exc:
raise DidNotEnable("Error getting LaunchDarkly client. " + repr(exc))

if not client.is_initialized():
raise DidNotEnable("LaunchDarkly client is not initialized.")

# Register the flag collection hook with the LD client.
client.add_hook(LaunchDarklyHook())

@staticmethod
def setup_once():
# type: () -> None
scope = sentry_sdk.get_current_scope()
scope.add_error_processor(flag_error_processor)

Expand Down
55 changes: 55 additions & 0 deletions sentry_sdk/integrations/unleash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from functools import wraps
from typing import Any

import sentry_sdk
from sentry_sdk.flag_utils import flag_error_processor
from sentry_sdk.integrations import Integration, DidNotEnable

try:
from UnleashClient import UnleashClient
except ImportError:
raise DidNotEnable("UnleashClient is not installed")


class UnleashIntegration(Integration):
identifier = "unleash"

@staticmethod
def setup_once():
# type: () -> None
# Wrap and patch evaluation methods (instance methods)
old_is_enabled = UnleashClient.is_enabled
old_get_variant = UnleashClient.get_variant

@wraps(old_is_enabled)
def sentry_is_enabled(self, feature, *args, **kwargs):
# type: (UnleashClient, str, *Any, **Any) -> Any
enabled = old_is_enabled(self, feature, *args, **kwargs)

# We have no way of knowing what type of unleash feature this is, so we have to treat
# it as a boolean / toggle feature.
flags = sentry_sdk.get_current_scope().flags
flags.set(feature, enabled)

return enabled

@wraps(old_get_variant)
def sentry_get_variant(self, feature, *args, **kwargs):
# type: (UnleashClient, str, *Any, **Any) -> Any
variant = old_get_variant(self, feature, *args, **kwargs)
enabled = variant.get("enabled", False)

# Payloads are not always used as the feature's value for application logic. They
# may be used for metrics or debugging context instead. Therefore, we treat every
# variant as a boolean toggle, using the `enabled` field.
flags = sentry_sdk.get_current_scope().flags
flags.set(feature, enabled)

return variant

UnleashClient.is_enabled = sentry_is_enabled # type: ignore
UnleashClient.get_variant = sentry_get_variant # type: ignore

# Error processor
scope = sentry_sdk.get_current_scope()
scope.add_error_processor(flag_error_processor)
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def get_file_text(file_name):
"starlette": ["starlette>=0.19.1"],
"starlite": ["starlite>=1.48"],
"tornado": ["tornado>=6"],
"unleash": ["UnleashClient>=6.0.1"],
},
entry_points={
"opentelemetry_propagator": [
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import pytest
import jsonschema


try:
import gevent
except ImportError:
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

import sentry_sdk
from sentry_sdk.integrations.featureflags import (
from sentry_sdk.integrations.feature_flags import (
FeatureFlagsIntegration,
add_feature_flag,
)
Expand Down
Loading

0 comments on commit 29c4a8f

Please sign in to comment.