untitaker: Thanks for this! Since we try to have this interface aligned across SDKs I'll discuss this with the other SDK maintainers first.
crepererum: @untitaker are there any updates on that?
untitaker: @crepererum I forgot to start the discussion at the last meeting, sorry. We have a meeting every monday (so, today again) where I will bring this up, but please note that this is quite low-priority for us and we can't force a decision "at gunpoint".
untitaker: To be clear, I see two versions:

* ```init(http_proxy=False, https_proxy=False)```

* ```init(no_proxy=True)```
untitaker: Sorry, we have an update now: Could you use empty string to represent `False`? We want to port this behavior to other languages and there we can't replicate this type signature.
crepererum: Done. Build failure seems unrelated (pip doesn't like pyproject.toml and editable installs)
untitaker: I made a PR: #349 
diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py
index 8ecea608..15c869a5 100644
--- a/sentry_sdk/client.py
+++ b/sentry_sdk/client.py
@@ -116,13 +116,17 @@ class Client(object):
             and "threads" not in event
         ):
             with capture_internal_exceptions():
-                event["threads"] = [
-                    {
-                        "stacktrace": current_stacktrace(self.options["with_locals"]),
-                        "crashed": False,
-                        "current": True,
-                    }
-                ]
+                event["threads"] = {
+                    "values": [
+                        {
+                            "stacktrace": current_stacktrace(
+                                self.options["with_locals"]
+                            ),
+                            "crashed": False,
+                            "current": True,
+                        }
+                    ]
+                }
 
         for key in "release", "environment", "server_name", "dist":
             if event.get(key) is None and self.options[key] is not None:  # type: ignore
diff --git a/sentry_sdk/integrations/logging.py b/sentry_sdk/integrations/logging.py
index 60fba0dc..bcbe8630 100644
--- a/sentry_sdk/integrations/logging.py
+++ b/sentry_sdk/integrations/logging.py
@@ -170,13 +170,17 @@ class EventHandler(logging.Handler, object):
             event = {}
             hint = None
             with capture_internal_exceptions():
-                event["threads"] = [
-                    {
-                        "stacktrace": current_stacktrace(client_options["with_locals"]),
-                        "crashed": False,
-                        "current": True,
-                    }
-                ]
+                event["threads"] = {
+                    "values": [
+                        {
+                            "stacktrace": current_stacktrace(
+                                client_options["with_locals"]
+                            ),
+                            "crashed": False,
+                            "current": True,
+                        }
+                    ]
+                }
         else:
             event = {}
 
diff --git a/sentry_sdk/transport.py b/sentry_sdk/transport.py
index fe6c41cd..fc071f0d 100644
--- a/sentry_sdk/transport.py
+++ b/sentry_sdk/transport.py
@@ -156,10 +156,15 @@ class HttpTransport(Transport):
         ca_certs,  # type: Optional[Any]
     ):
         # type: (...) -> Union[PoolManager, ProxyManager]
-        # Use http_proxy if scheme is https and https_proxy is not set
-        proxy = parsed_dsn.scheme == "https" and https_proxy or http_proxy
-        if not proxy:
-            proxy = getproxies().get(parsed_dsn.scheme)
+        proxy = None
+
+        # try HTTPS first
+        if parsed_dsn.scheme == "https" and (https_proxy != ""):
+            proxy = https_proxy or getproxies().get("https")
+
+        # maybe fallback to HTTP proxy
+        if not proxy and (http_proxy != ""):
+            proxy = http_proxy or getproxies().get("http")
 
         opts = self._get_pool_options(ca_certs)
 
diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py
index 94e14b20..912dbdb4 100644
--- a/sentry_sdk/utils.py
+++ b/sentry_sdk/utils.py
@@ -587,6 +587,10 @@ def iter_event_stacktraces(event):
     # type: (Dict[str, Any]) -> Iterator[Dict[str, Any]]
     if "stacktrace" in event:
         yield event["stacktrace"]
+    if "threads" in event:
+        for thread in event["threads"].get("values") or ():
+            if "stacktrace" in thread:
+                yield thread["stacktrace"]
     if "exception" in event:
         for exception in event["exception"].get("values") or ():
             if "stacktrace" in exception:

Clarify proxy fallback behavior
I am currently working on #178 and extended the tests for the proxy selection mechanism, especially when the env variables like `HTTP_PROXY` and `HTTPS_PROXY` are present. One thing that I've observed is the fallback behavior:

- no ENV vars: HTTPS DSNs can fallback to HTTP proxies (see [test](https://github.com/getsentry/sentry-python/blob/master/tests/test_client.py#L47-L48))
- only `HTTP_PROXY` env var: no fallback for HTTPS DSNs, i.e. no proxy is auto-selected

Is that behavior intended or a bug? In either case, my PR for #178 will also include tests (and potential fixes) for that.
diff --git a/tests/integrations/logging/test_logging.py b/tests/integrations/logging/test_logging.py
index 73e0f482..d368b447 100644
--- a/tests/integrations/logging/test_logging.py
+++ b/tests/integrations/logging/test_logging.py
@@ -69,7 +69,7 @@ def test_logging_stack(sentry_init, capture_events):
     event_with, event_without, = events
 
     assert event_with["level"] == "error"
-    assert event_with["threads"][0]["stacktrace"]["frames"]
+    assert event_with["threads"]["values"][0]["stacktrace"]["frames"]
 
     assert event_without["level"] == "error"
     assert "threads" not in event_without
diff --git a/tests/test_client.py b/tests/test_client.py
index ec4b77e8..cd5c84c2 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -1,6 +1,7 @@
 # coding: utf-8
 import json
 import logging
+import os
 import pytest
 import subprocess
 import sys
@@ -52,25 +53,106 @@ def test_transport_option(monkeypatch):
     assert str(Client(transport=transport).dsn) == dsn
 
 
-def test_http_proxy(monkeypatch):
-    client = Client("https://foo@sentry.io/123", http_proxy="http://localhost/123")
+def test_proxy_http_use(monkeypatch):
+    client = Client("http://foo@sentry.io/123", http_proxy="http://localhost/123")
     assert client.transport._pool.proxy.scheme == "http"
 
+
+def test_proxy_https_use(monkeypatch):
+    client = Client("https://foo@sentry.io/123", http_proxy="https://localhost/123")
+    assert client.transport._pool.proxy.scheme == "https"
+
+
+def test_proxy_both_select_http(monkeypatch):
     client = Client(
-        "https://foo@sentry.io/123",
+        "http://foo@sentry.io/123",
         https_proxy="https://localhost/123",
         http_proxy="http://localhost/123",
     )
-    assert client.transport._pool.proxy.scheme == "https"
-
-    client = Client("http://foo@sentry.io/123", http_proxy="http://localhost/123")
     assert client.transport._pool.proxy.scheme == "http"
 
+
+def test_proxy_both_select_https(monkeypatch):
     client = Client(
-        "http://foo@sentry.io/123",
+        "https://foo@sentry.io/123",
         https_proxy="https://localhost/123",
         http_proxy="http://localhost/123",
     )
+    assert client.transport._pool.proxy.scheme == "https"
+
+
+def test_proxy_http_fallback_http(monkeypatch):
+    client = Client("https://foo@sentry.io/123", http_proxy="http://localhost/123")
+    assert client.transport._pool.proxy.scheme == "http"
+
+
+def test_proxy_none_noenv(monkeypatch):
+    client = Client("http://foo@sentry.io/123")
+    assert client.transport._pool.proxy is None
+
+
+def test_proxy_none_httpenv_select(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    client = Client("http://foo@sentry.io/123")
+    assert client.transport._pool.proxy.scheme == "http"
+
+
+def test_proxy_none_httpsenv_select(monkeypatch):
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("https://foo@sentry.io/123")
+    assert client.transport._pool.proxy.scheme == "https"
+
+
+def test_proxy_none_httpenv_fallback(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    client = Client("https://foo@sentry.io/123")
+    assert client.transport._pool.proxy.scheme == "http"
+
+
+def test_proxy_bothselect_bothen(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("https://foo@sentry.io/123", http_proxy="", https_proxy="")
+    assert client.transport._pool.proxy is None
+
+
+def test_proxy_bothavoid_bothenv(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("https://foo@sentry.io/123", http_proxy=None, https_proxy=None)
+    assert client.transport._pool.proxy.scheme == "https"
+
+
+def test_proxy_bothselect_httpenv(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    client = Client("https://foo@sentry.io/123", http_proxy=None, https_proxy=None)
+    assert client.transport._pool.proxy.scheme == "http"
+
+
+def test_proxy_httpselect_bothenv(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("https://foo@sentry.io/123", http_proxy=None, https_proxy="")
+    assert client.transport._pool.proxy.scheme == "http"
+
+
+def test_proxy_httpsselect_bothenv(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("https://foo@sentry.io/123", http_proxy="", https_proxy=None)
+    assert client.transport._pool.proxy.scheme == "https"
+
+
+def test_proxy_httpselect_httpsenv(monkeypatch):
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("https://foo@sentry.io/123", http_proxy=None, https_proxy="")
+    assert client.transport._pool.proxy is None
+
+
+def test_proxy_httpsselect_bothenv_http(monkeypatch):
+    os.environ["HTTP_PROXY"] = "http://localhost/123"
+    os.environ["HTTPS_PROXY"] = "https://localhost/123"
+    client = Client("http://foo@sentry.io/123", http_proxy=None, https_proxy=None)
     assert client.transport._pool.proxy.scheme == "http"
 
 
@@ -147,7 +229,7 @@ def test_attach_stacktrace_enabled():
     foo()
 
     event, = events
-    thread, = event["threads"]
+    thread, = event["threads"]["values"]
     functions = [x["function"] for x in thread["stacktrace"]["frames"]]
     assert functions[-2:] == ["foo", "bar"]
 
@@ -167,11 +249,26 @@ def test_attach_stacktrace_enabled_no_locals():
     foo()
 
     event, = events
-    thread, = event["threads"]
+    thread, = event["threads"]["values"]
     local_vars = [x.get("vars") for x in thread["stacktrace"]["frames"]]
     assert local_vars[-2:] == [None, None]
 
 
+def test_attach_stacktrace_in_app(sentry_init, capture_events):
+    sentry_init(attach_stacktrace=True, in_app_exclude=["_pytest"])
+    events = capture_events()
+
+    capture_message("hi")
+
+    event, = events
+    thread, = event["threads"]["values"]
+    frames = thread["stacktrace"]["frames"]
+    pytest_frames = [f for f in frames if f["module"].startswith("_pytest")]
+    assert pytest_frames
+    assert all(f["in_app"] is False for f in pytest_frames)
+    assert any(f["in_app"] for f in frames)
+
+
 def test_attach_stacktrace_disabled():
     events = []
     hub = Hub(Client(attach_stacktrace=False, transport=events.append))
diff --git a/tests/utils/test_general.py b/tests/utils/test_general.py
index d3ed5c5a..a21a7553 100644
--- a/tests/utils/test_general.py
+++ b/tests/utils/test_general.py
@@ -16,6 +16,7 @@ from sentry_sdk.utils import (
     strip_string,
     filename_for_module,
     handle_in_app_impl,
+    iter_event_stacktraces,
 )
 from sentry_sdk._compat import text_type
 
@@ -167,3 +168,15 @@ def test_in_app(empty):
         in_app_include=empty,
         in_app_exclude=["foo"],
     ) == [{"module": "foo", "in_app": False}, {"module": "bar", "in_app": True}]
+
+
+def test_iter_stacktraces():
+    assert set(
+        iter_event_stacktraces(
+            {
+                "threads": {"values": [{"stacktrace": 1}]},
+                "stacktrace": 2,
+                "exception": {"values": [{"stacktrace": 3}]},
+            }
+        )
+    ) == {1, 2, 3}

pip install -e .[flask]
parse_log_pytest
requirements.txt
pytest pytest-xdist pytest-cov pytest-localserver pytest-mock pytest-asyncio
3.7
test-requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
atomicwrites==1.4.1
attrs==24.2.0
blinker==1.6.3
certifi @ file:///croot/certifi_1671487769961/work/certifi
click==8.1.8
coverage==7.2.7
distlib==0.3.9
exceptiongroup==1.2.2
execnet==2.0.2
filelock==3.12.2
Flask==2.2.5
hypothesis==3.69.9
importlib-metadata==6.7.0
iniconfig==2.0.0
itsdangerous==2.1.2
Jinja2==3.1.6
MarkupSafe==2.1.5
more-itertools==9.1.0
packaging==24.0
platformdirs==4.0.0
pluggy==0.13.1
py==1.11.0
pytest==7.4.4
pytest-asyncio==0.21.2
pytest-cov==2.6.0
pytest-forked==1.2.0
pytest-localserver==0.4.1
pytest-mock==3.11.1
pytest-xdist==1.23.0
-e git+https://github.com/getsentry/sentry-python.git@36eeba22305a900793b89a263b3d663ada6d5712#egg=sentry_sdk
six==1.17.0
toml==0.10.2
tomli==2.0.1
tox==3.7.0
typing_extensions==4.7.1
urllib3==2.0.7
virtualenv==20.26.6
Werkzeug==2.2.3
zipp==3.15.0

name: sentry-python
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - atomicwrites==1.4.1
      - attrs==24.2.0
      - blinker==1.6.3
      - click==8.1.8
      - coverage==7.2.7
      - distlib==0.3.9
      - exceptiongroup==1.2.2
      - execnet==2.0.2
      - filelock==3.12.2
      - flask==2.2.5
      - hypothesis==3.69.9
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - itsdangerous==2.1.2
      - jinja2==3.1.6
      - markupsafe==2.1.5
      - more-itertools==9.1.0
      - packaging==24.0
      - platformdirs==4.0.0
      - pluggy==0.13.1
      - py==1.11.0
      - pytest==7.4.4
      - pytest-asyncio==0.21.2
      - pytest-cov==2.6.0
      - pytest-forked==1.2.0
      - pytest-localserver==0.4.1
      - pytest-mock==3.11.1
      - pytest-xdist==1.23.0
      - sentry-sdk==0.7.11
      - six==1.17.0
      - toml==0.10.2
      - tomli==2.0.1
      - tox==3.7.0
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - virtualenv==20.26.6
      - werkzeug==2.2.3
      - zipp==3.15.0
prefix: /opt/conda/envs/sentry-python

tests/integrations/logging/test_logging.py::test_logging_stack tests/test_client.py::test_proxy_none_httpenv_fallback tests/test_client.py::test_proxy_bothselect_bothen tests/test_client.py::test_proxy_bothselect_httpenv tests/test_client.py::test_proxy_httpselect_bothenv tests/test_client.py::test_proxy_httpselect_httpsenv tests/test_client.py::test_attach_stacktrace_enabled tests/test_client.py::test_attach_stacktrace_enabled_no_locals tests/test_client.py::test_attach_stacktrace_in_app tests/utils/test_general.py::test_iter_stacktraces
tests/utils/test_general.py::test_safe_repr_never_broken_for_strings tests/utils/test_general.py::test_filename
tests/integrations/logging/test_logging.py::test_logging_works_with_many_loggers[logger0] tests/integrations/logging/test_logging.py::test_logging_works_with_many_loggers[logger1] tests/integrations/logging/test_logging.py::test_logging_defaults[None] tests/integrations/logging/test_logging.py::test_logging_defaults[integrations1] tests/integrations/logging/test_logging.py::test_logging_defaults[integrations2] tests/integrations/logging/test_logging.py::test_logging_extra_data tests/test_client.py::test_transport_option tests/test_client.py::test_proxy_http_use tests/test_client.py::test_proxy_https_use tests/test_client.py::test_proxy_both_select_http tests/test_client.py::test_proxy_both_select_https tests/test_client.py::test_proxy_http_fallback_http tests/test_client.py::test_proxy_none_noenv tests/test_client.py::test_proxy_none_httpenv_select tests/test_client.py::test_proxy_none_httpsenv_select tests/test_client.py::test_proxy_bothavoid_bothenv tests/test_client.py::test_proxy_httpsselect_bothenv tests/test_client.py::test_proxy_httpsselect_bothenv_http tests/test_client.py::test_simple_transport tests/test_client.py::test_ignore_errors tests/test_client.py::test_with_locals_enabled tests/test_client.py::test_with_locals_disabled tests/test_client.py::test_attach_stacktrace_disabled tests/test_client.py::test_capture_event_works tests/test_client.py::test_atexit[10] tests/test_client.py::test_atexit[20] tests/test_client.py::test_configure_scope_available tests/test_client.py::test_configure_scope_unavailable[True] tests/test_client.py::test_configure_scope_unavailable[False] tests/test_client.py::test_transport_works[True] tests/test_client.py::test_transport_works[False] tests/test_client.py::test_client_debug_option_enabled tests/test_client.py::test_client_debug_option_disabled[True] tests/test_client.py::test_client_debug_option_disabled[False] tests/test_client.py::test_scope_initialized_before_client tests/test_client.py::test_weird_chars tests/test_client.py::test_nan tests/test_client.py::test_cyclic_frame_vars tests/test_client.py::test_cyclic_data tests/test_client.py::test_databag_stripping tests/test_client.py::test_databag_breadth_stripping tests/test_client.py::test_chained_exceptions tests/test_client.py::test_broken_mapping tests/test_client.py::test_errno_errors tests/utils/test_general.py::test_safe_repr_regressions tests/utils/test_general.py::test_abs_path tests/utils/test_general.py::test_non_string_variables tests/utils/test_general.py::test_format_and_strip tests/utils/test_general.py::test_parse_dsn_paths[https://foobar@sentry.io/123-https://sentry.io/api/123/store/] tests/utils/test_general.py::test_parse_dsn_paths[https://foobar@sentry.io/bam/123-https://sentry.io/bam/api/123/store/] tests/utils/test_general.py::test_parse_dsn_paths[https://foobar@sentry.io/bam/baz/123-https://sentry.io/bam/baz/api/123/store/] tests/utils/test_general.py::test_parse_invalid_dsn[https://foobar@sentry.iohttps://foobar@sentry.io/https://foobar@sentry.io/asdfhttps://foobar@sentry.io/asdf/https://foobar@sentry.io/asdf/123/] tests/utils/test_general.py::test_in_app[None] tests/utils/test_general.py::test_in_app[empty1]
sentry_sdk/utils.py sentry_sdk/transport.py sentry_sdk/integrations/logging.py sentry_sdk/client.py
sentry_sdk/utils.py sentry_sdk/transport.py sentry_sdk/integrations/logging.py sentry_sdk/client.py