
    k7i"                       S SK Jr  S SKrS SKrS SKrS SKrS SKrS SKJrJ	r	J
r
  S SKJrJrJr  S SKJrJrJr  S SKJrJr  S SKrS SKrS SKJr  S SKJr  S S	KJr  \(       a  S S
KJr  \SS j5       r SS jr!\SSSS.             SS jj5       r"\    S           SS jj5       r#\S 5       r$ " S S\5      r%g)    )annotationsN)AsyncGeneratorCallable	Generator)asynccontextmanagercontextmanagersuppress)TYPE_CHECKINGAnyLiteral)parse_qsurlparse)settings)OAuth)find_available_port)FastMCPc            	   +  j  #    [         R                  " [        5      n U R                  5        H  u  p#[        R                  " X#5        M     Sv   U  H(  n[        R                  " X!R                  U5      5        M*     g! U  H(  n[        R                  " X!R                  U5      5        M*     f = f7f)a  
Temporarily override FastMCP setting values.

Args:
    **kwargs: The settings to override, including nested settings.

Example:
    Temporarily override a setting:
    ```python
    import fastmcp
    from fastmcp.utilities.tests import temporary_settings

    with temporary_settings(log_level='DEBUG'):
        assert fastmcp.settings.log_level == 'DEBUG'
    assert fastmcp.settings.log_level == 'INFO'
    ```
N)copydeepcopyr   itemsset_settingget_setting)kwargsold_settingsattrvalues       Q/home/james-whalen/.local/lib/python3.13/site-packages/fastmcp/utilities/tests.pytemporary_settingsr      s     & ==*L	G!<<>KD  - * D  '?'?'EF FD  '?'?'EF s   B33B  /B3 0B00B3c           
         US:X  a  U R                  SS9nO[        SU 35      e[        R                  " [        R                  " USUSSS9S9nUR                  5         g )	Nsse)	transportzInvalid transport: 	127.0.0.1errorzwebsockets-sansio)apphostport	log_levelws)config)http_app
ValueErroruvicornServerConfigrun)
mcp_serverr!   r&   r$   uvicorn_servers        r   _run_serverr2   9   sg    E!!E!2.yk:;;^^~~"
N     Tr"   )provide_host_and_portr%   r&   c             /    #    Uc
  [        5       nU(       a  XRUS.-  n[        R                  " XUSS9nUR                  5         SnSnX:  af  UR	                  5       (       aQ   [
        R
                  " [
        R                  [
        R                  5       n	U	R                  X#45         SSS5        O[        SU S35      eSU SU 3v   UR                  5         UR                  SS9  UR	                  5       (       a@  UR                  5         UR                  SS9  UR	                  5       (       a  [        S5      egg! , (       d  f       Oh= f! [         aX    US:  a  [        R                  " S5        O3US	:  a  [        R                  " S
5        O[        R                  " S5        US-  n Of = fX:  d  GM  UR	                  5       (       a  GMu  GN&7f)a  
Context manager that runs a FastMCP server in a separate process and
returns the server URL. When the context manager is exited, the server process is killed.

Args:
    server_fn: The function that runs a FastMCP server. FastMCP servers are
        not pickleable, so we need a function that creates and runs one.
    *args: Arguments to pass to the server function.
    provide_host_and_port: Whether to provide the host and port to the server function as kwargs.
    host: Host to bind the server to (default: "127.0.0.1").
    port: Port to bind the server to (default: find available port).
    **kwargs: Keyword arguments to pass to the server function.

Returns:
    The server URL.
N)r%   r&   T)targetargsr   daemon   r      g?   皙?g?   zServer failed to start after z	 attemptshttp://:)timeout   z2Server process failed to terminate even after kill)r   multiprocessingProcessstartis_alivesocketAF_INETSOCK_STREAMconnectConnectionRefusedErrortimesleepRuntimeError	terminatejoinkill)
	server_fnr4   r%   r&   r7   r   procmax_attemptsattemptss
             r   run_server_in_processrV   K   s    4 |"$..""F4D 	JJL LG

 T]]__	v~~v/A/ABa		4,' CB :<.	RSSD64&
!!NNIIaI}}				!	==??STT 	 % CB & 	{

4 2

3

3qLG	 
 T]]__sV   A G#3E E*E 2BG
EE GE AF41G3F44G?Gc           
    .  #    SSK nUc
  [        5       nUR                  S5      I Sh  vN   UR                  U R	                  UUUUSS95      nUR                  S5      I Sh  vN    SU SU U 37v   UR                  5         [        UR                  5         UI Sh  vN   SSS5        g N NM N! , (       d  f       g= f! UR                  5         [        UR                  5         UI Sh  vN    SSS5        f ! , (       d  f       f = f= f7f)	a  
Start a FastMCP server as an asyncio task for in-process async testing.

This is the recommended way to test FastMCP servers. It runs the server
as an async task in the same process, eliminating subprocess coordination,
sleeps, and cleanup issues.

Args:
    server: FastMCP server instance
    port: Port to bind to (default: find available port)
    transport: Transport type ("http", "streamable-http", or "sse")
    path: URL path for the server (default: "/mcp")
    host: Host to bind to (default: "127.0.0.1")

Yields:
    Server URL string

Example:
    ```python
    import pytest
    from fastmcp import FastMCP, Client
    from fastmcp.client.transports import StreamableHttpTransport
    from fastmcp.utilities.tests import run_server_async

    @pytest.fixture
    async def server():
        mcp = FastMCP("test")

        @mcp.tool()
        def greet(name: str) -> str:
            return f"Hello, {name}!"

        async with run_server_async(mcp) as url:
            yield url

    async def test_greet(server: str):
        async with Client(StreamableHttpTransport(server)) as client:
            result = await client.call_tool("greet", {"name": "World"})
            assert result.content[0].text == "Hello, World!"
    ```
r   Ng{Gz?F)r%   r&   r!   pathshow_bannerr<   r>   r?   )asyncior   rL   create_taskrun_http_asynccancelr	   CancelledError)serverr&   r!   rX   r%   rZ   server_tasks          r   run_server_asyncra      s    b |"$ --
 %% 	 	
K --
vQtfTF++ 	g,,- .-+    .- 	g,,- .--s   &DB/:D#B1$D)C 6%DB5!B3"B5&
D1D3B55
C?D&D,D2C5
3D8	D
DDDc              #    #    U R                  5         [        R                  " S5      nUR                  U R                  5         U v   UR                  U R                  5        g! UR                  U R                  5        f = f7f)zWContext manager to capture logs from FastMCP loggers even when propagation is disabled.fastmcpN)clearlogging	getLogger
addHandlerhandlerremoveHandler)caplogloggers     r   caplog_for_fastmcprl      s`      LLNy)F
fnn%-V^^,V^^,s   ABA% 	B%BBc                  D   ^  \ rS rSrSrSU 4S jjrSS jrS	S jrSrU =r	$ )
HeadlessOAuth   z
OAuth provider that bypasses browser interaction for testing.

This simulates the complete OAuth flow programmatically by making HTTP requests
instead of opening a browser and running a callback server. Useful for automated testing.
c                6   > SU l         [        TU ]  " U40 UD6  g)z7Initialize HeadlessOAuth with stored response tracking.N)_stored_responsesuper__init__)selfmcp_urlr   	__class__s      r   rs   HeadlessOAuth.__init__   s     $+F+r3   c                   #    [         R                  " 5        ISh  vN nUR                  USS9I Sh  vN nX0l        SSS5      ISh  vN   g N3 N N	! , ISh  vN  (       d  f       g= f7f)zOMake HTTP request to authorization URL and store response for callback handler.NF)follow_redirects)httpxAsyncClientgetrq   )rt   authorization_urlclientresponses       r   redirect_handlerHeadlessOAuth.redirect_handler   sN     $$&&&#ZZ(9EZRRH$,! '&&R '&&&sS   A0AA0AA
AA0
AA0AA0A-AA-)A0c                  #    U R                   (       d  [        S5      eU R                   nUR                  S:X  a  UR                  S   n[	        U5      n[        UR                  5      nSU;   a/  US   S   nUR                  SS/5      S   n[        SU S	U 35      eUS
   S   nUR                  SS/5      S   nXx4$ [        SUR                   35      e7f)z4Parse stored response and return (auth_code, state).zHNo authorization response stored. redirect_handler must be called first.i.  locationr#   r   error_descriptionzUnknown errorzOAuth authorization failed: z - codestateNzAuthorization failed: )rq   rM   status_codeheadersr   r   queryr|   )	rt   r   redirect_urlparsedquery_paramsr#   
error_desc	auth_coder   s	            r   callback_handlerHeadlessOAuth.callback_handler   s     $$Z  (( 3&#++J7Ll+F#FLL1L,&$W-a0)--.AOCTUVWX
"25'ZLI  %V,Q/I $$Wtf5a8E##!78L8L7MNOOs   CC)rq   )ru   str)r}   r   returnNone)r   ztuple[str, str | None])
__name__
__module____qualname____firstlineno____doc__rs   r   r   __static_attributes____classcell__)rv   s   @r   rn   rn      s    ,
-P Pr3   rn   )r   r   )r0   r   r!   zLiteral['sse']r&   intr   r   )rQ   zCallable[..., None]r7   r   r4   boolr%   r   r&   
int | Noner   r   r   zGenerator[str, None, None])Nhttpz/mcpr"   )r_   r   r&   r   r!   z)Literal['http', 'streamable-http', 'sse']rX   r   r%   r   r   zAsyncGenerator[str, None])&
__future__r   r   re   rB   rF   rK   collections.abcr   r   r   
contextlibr   r   r	   typingr
   r   r   urllib.parser   r   rz   r,   rc   r   fastmcp.client.auth.oauthr   fastmcp.utilities.httpr   fastmcp.server.serverr   r   r2   rV   ra   rl   rn    r3   r   <module>r      sV   "      ? ? D D . . +    + 6- G G@$  #'@U"@U@U  @U 	@U
 @U @U  @U @UF  ;ALL
L 9L 	L
 L L L^ - --PE -Pr3   