Skip to content

Commit 3dc1893

Browse files
committed
Deprecate py_asgi and py_wsgi modules
Mark py_asgi and py_wsgi as deprecated in favor of the Channel API (py_channel) or Reactor API (erlang.reactor). - Add -deprecated attribute to both modules - Add deprecation notice to module documentation - Add deprecation notice to web-frameworks.md - Add CHANGELOG entry for deprecation - Add py_web_frameworks_SUITE.erl test suite
1 parent 4cd37f3 commit 3dc1893

File tree

5 files changed

+248
-0
lines changed

5 files changed

+248
-0
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@
144144
- **ErlangEventLoopPolicy always returns ErlangEventLoop** - Previously only
145145
returned ErlangEventLoop for main thread; now consistent across all threads.
146146
147+
### Deprecated
148+
149+
- **`py_asgi` module** - Deprecated in favor of the Channel API (`py_channel`)
150+
or Reactor API (`erlang.reactor`). The module still works but will be removed
151+
in a future release.
152+
153+
- **`py_wsgi` module** - Deprecated in favor of the Channel API (`py_channel`)
154+
or Reactor API (`erlang.reactor`). The module still works but will be removed
155+
in a future release.
156+
147157
### Removed
148158
149159
- **Context affinity functions** - Removed `py:bind`, `py:unbind`, `py:is_bound`,

docs/web-frameworks.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Web Framework Integration (ASGI/WSGI)
22

3+
> **Deprecation Notice:** The `py_asgi` and `py_wsgi` modules are deprecated and will be removed in a future release. For new projects, use the [Channel API](channel.md) or [Reactor API](reactor.md) instead, which provide better performance and more flexible request handling.
4+
35
This guide covers the optimized ASGI and WSGI modules for integrating Python web frameworks with erlang_python.
46

57
## Overview

src/py_asgi.erl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
%%% @doc Optimized ASGI request handling.
1616
%%%
17+
%%% @deprecated This module is deprecated and will be removed in a future release.
18+
%%% Use the Channel API (`py_channel`) or Reactor API (`erlang.reactor`) instead,
19+
%%% which provide better performance and more flexible request handling.
20+
%%%
1721
%%% This module provides high-performance ASGI request handling by using
1822
%%% optimized C-level marshalling between Erlang and Python:
1923
%%%
@@ -52,6 +56,13 @@
5256
%%% @end
5357
-module(py_asgi).
5458

59+
-deprecated([
60+
{run, 4, "use py_channel or erlang.reactor instead"},
61+
{run, 5, "use py_channel or erlang.reactor instead"},
62+
{build_scope, 1, "use py_channel or erlang.reactor instead"},
63+
{build_scope, 2, "use py_channel or erlang.reactor instead"}
64+
]).
65+
5566
-export([
5667
run/4,
5768
run/5,

src/py_wsgi.erl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
%%% @doc Optimized WSGI request handling.
1616
%%%
17+
%%% @deprecated This module is deprecated and will be removed in a future release.
18+
%%% Use the Channel API (`py_channel`) or Reactor API (`erlang.reactor`) instead,
19+
%%% which provide better performance and more flexible request handling.
20+
%%%
1721
%%% This module provides high-performance WSGI request handling by using
1822
%%% optimized C-level marshalling between Erlang and Python:
1923
%%%
@@ -48,6 +52,11 @@
4852
%%% @end
4953
-module(py_wsgi).
5054

55+
-deprecated([
56+
{run, 3, "use py_channel or erlang.reactor instead"},
57+
{run, 4, "use py_channel or erlang.reactor instead"}
58+
]).
59+
5160
-export([
5261
run/3,
5362
run/4

test/py_web_frameworks_SUITE.erl

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
%%% @doc Common Test suite for deprecated ASGI/WSGI modules.
2+
%%%
3+
%%% Tests that py_asgi and py_wsgi modules still work (backward compatibility)
4+
%%% while being marked as deprecated.
5+
-module(py_web_frameworks_SUITE).
6+
7+
-include_lib("common_test/include/ct.hrl").
8+
9+
-export([
10+
all/0,
11+
groups/0,
12+
init_per_suite/1,
13+
end_per_suite/1,
14+
init_per_group/2,
15+
end_per_group/2,
16+
init_per_testcase/2,
17+
end_per_testcase/2
18+
]).
19+
20+
-export([
21+
%% Deprecation tests
22+
test_asgi_deprecated/1,
23+
test_wsgi_deprecated/1,
24+
%% ASGI backward compatibility
25+
test_asgi_run_basic/1,
26+
test_asgi_build_scope/1,
27+
test_asgi_scope_defaults/1,
28+
%% WSGI backward compatibility
29+
test_wsgi_run_basic/1,
30+
test_wsgi_environ_defaults/1
31+
]).
32+
33+
%% ============================================================================
34+
%% Common Test callbacks
35+
%% ============================================================================
36+
37+
all() ->
38+
[
39+
{group, deprecation},
40+
{group, asgi_compat},
41+
{group, wsgi_compat}
42+
].
43+
44+
groups() ->
45+
[
46+
{deprecation, [], [
47+
test_asgi_deprecated,
48+
test_wsgi_deprecated
49+
]},
50+
{asgi_compat, [], [
51+
test_asgi_run_basic,
52+
test_asgi_build_scope,
53+
test_asgi_scope_defaults
54+
]},
55+
{wsgi_compat, [], [
56+
test_wsgi_run_basic,
57+
test_wsgi_environ_defaults
58+
]}
59+
].
60+
61+
init_per_suite(Config) ->
62+
application:ensure_all_started(erlang_python),
63+
Config.
64+
65+
end_per_suite(_Config) ->
66+
ok.
67+
68+
init_per_group(_Group, Config) ->
69+
Config.
70+
71+
end_per_group(_Group, _Config) ->
72+
ok.
73+
74+
init_per_testcase(_TestCase, Config) ->
75+
Config.
76+
77+
end_per_testcase(_TestCase, _Config) ->
78+
ok.
79+
80+
%% ============================================================================
81+
%% Deprecation Tests
82+
%% ============================================================================
83+
84+
%% @doc Test that py_asgi functions are marked as deprecated.
85+
test_asgi_deprecated(_Config) ->
86+
%% Check module attributes for deprecation
87+
Attrs = py_asgi:module_info(attributes),
88+
Deprecated = proplists:get_value(deprecated, Attrs, []),
89+
90+
%% Verify run/4 is deprecated
91+
true = lists:any(fun
92+
({run, 4, _Msg}) -> true;
93+
(_) -> false
94+
end, Deprecated),
95+
96+
%% Verify run/5 is deprecated
97+
true = lists:any(fun
98+
({run, 5, _Msg}) -> true;
99+
(_) -> false
100+
end, Deprecated),
101+
102+
%% Verify build_scope/1 is deprecated
103+
true = lists:any(fun
104+
({build_scope, 1, _Msg}) -> true;
105+
(_) -> false
106+
end, Deprecated),
107+
108+
%% Verify build_scope/2 is deprecated
109+
true = lists:any(fun
110+
({build_scope, 2, _Msg}) -> true;
111+
(_) -> false
112+
end, Deprecated),
113+
114+
ok.
115+
116+
%% @doc Test that py_wsgi functions are marked as deprecated.
117+
test_wsgi_deprecated(_Config) ->
118+
%% Check module attributes for deprecation
119+
Attrs = py_wsgi:module_info(attributes),
120+
Deprecated = proplists:get_value(deprecated, Attrs, []),
121+
122+
%% Verify run/3 is deprecated
123+
true = lists:any(fun
124+
({run, 3, _Msg}) -> true;
125+
(_) -> false
126+
end, Deprecated),
127+
128+
%% Verify run/4 is deprecated
129+
true = lists:any(fun
130+
({run, 4, _Msg}) -> true;
131+
(_) -> false
132+
end, Deprecated),
133+
134+
ok.
135+
136+
%% ============================================================================
137+
%% ASGI Backward Compatibility Tests
138+
%% ============================================================================
139+
140+
%% @doc Test basic ASGI run functionality still works.
141+
test_asgi_run_basic(_Config) ->
142+
%% Test that run/4 can be called (may fail due to missing app, but shouldn't crash)
143+
Scope = #{
144+
type => <<"http">>,
145+
method => <<"GET">>,
146+
path => <<"/">>
147+
},
148+
%% We expect an error because we don't have a real ASGI app,
149+
%% but the function should be callable
150+
Result = py_asgi:run(<<"nonexistent_module">>, <<"app">>, Scope, <<>>),
151+
case Result of
152+
{error, _Reason} -> ok; %% Expected - module doesn't exist
153+
{ok, _} -> ok %% Unexpected but acceptable
154+
end.
155+
156+
%% @doc Test ASGI build_scope functionality.
157+
test_asgi_build_scope(_Config) ->
158+
Scope = #{
159+
type => <<"http">>,
160+
method => <<"POST">>,
161+
path => <<"/api/test">>,
162+
query_string => <<"foo=bar">>
163+
},
164+
%% build_scope should be callable
165+
Result = py_asgi:build_scope(Scope),
166+
case Result of
167+
{ok, _Ref} -> ok;
168+
{error, _Reason} -> ok %% May fail if NIF not available
169+
end.
170+
171+
%% @doc Test ASGI scope defaults are applied correctly.
172+
test_asgi_scope_defaults(_Config) ->
173+
%% Minimal scope - should get defaults applied
174+
MinimalScope = #{
175+
path => <<"/test">>
176+
},
177+
%% This tests internal ensure_scope_defaults/1 via run/4
178+
Result = py_asgi:run(<<"test">>, <<"app">>, MinimalScope, <<>>),
179+
%% Should not crash, error is expected for missing module
180+
case Result of
181+
{error, _} -> ok;
182+
{ok, _} -> ok
183+
end.
184+
185+
%% ============================================================================
186+
%% WSGI Backward Compatibility Tests
187+
%% ============================================================================
188+
189+
%% @doc Test basic WSGI run functionality still works.
190+
test_wsgi_run_basic(_Config) ->
191+
Environ = #{
192+
<<"REQUEST_METHOD">> => <<"GET">>,
193+
<<"PATH_INFO">> => <<"/">>,
194+
<<"wsgi.input">> => <<>>
195+
},
196+
%% We expect an error because we don't have a real WSGI app,
197+
%% but the function should be callable
198+
Result = py_wsgi:run(<<"nonexistent_module">>, <<"app">>, Environ),
199+
case Result of
200+
{error, _Reason} -> ok; %% Expected - module doesn't exist
201+
{ok, _} -> ok %% Unexpected but acceptable
202+
end.
203+
204+
%% @doc Test WSGI environ defaults are applied correctly.
205+
test_wsgi_environ_defaults(_Config) ->
206+
%% Minimal environ - should get defaults applied
207+
MinimalEnviron = #{
208+
<<"PATH_INFO">> => <<"/test">>
209+
},
210+
%% This tests internal ensure_environ_defaults/1 via run/3
211+
Result = py_wsgi:run(<<"test">>, <<"app">>, MinimalEnviron),
212+
%% Should not crash, error is expected for missing module
213+
case Result of
214+
{error, _} -> ok;
215+
{ok, _} -> ok
216+
end.

0 commit comments

Comments
 (0)