1+ """Devpi PyPI to test with."""
12from __future__ import annotations
23
34import random
910from pathlib import Path
1011from subprocess import PIPE , Popen , run
1112from threading import Thread
12- from types import TracebackType
13- from typing import IO , Iterator , Sequence , cast
13+ from typing import IO , TYPE_CHECKING , Iterator , Sequence , cast
1414
1515from ._version import __version__
1616
17+ if TYPE_CHECKING :
18+ from types import TracebackType
19+
1720
1821def _check_call (cmd : list [str ]) -> None :
19- run (cmd , check = True , capture_output = True )
22+ run (cmd , check = True , capture_output = True ) # noqa: S603
2023
2124
2225class Index :
26+ """Index."""
27+
2328 def __init__ (self , base_url : str , name : str , user : str , client_cmd_base : list [str ]) -> None :
29+ """
30+ Create index.
31+
32+ :param base_url: base url
33+ :param name: name for the index server
34+ :param user: the username to use
35+ :param client_cmd_base:
36+ """
2437 self ._client_cmd_base = client_cmd_base
2538 self ._server_url = base_url
2639 self .name = name
2740 self .user = user
2841
2942 @property
3043 def url (self ) -> str :
44+ """:return: the URL to the index server"""
3145 return f"{ self ._server_url } /{ self .name } /+simple/"
3246
3347 def use (self ) -> None :
34- _check_call (self ._client_cmd_base + ["use" , f"{ self .user } /{ self .name } " ])
48+ """Use this index server."""
49+ _check_call ([* self ._client_cmd_base , "use" , f"{ self .user } /{ self .name } " ])
3550
3651 def upload (self , * files : Path ) -> None :
52+ """
53+ Upload packages to the index.
54+
55+ :param files: the files to upload
56+ """
3757 cmd = self ._client_cmd_base + ["upload" , "--index" , self .name ] + [str (i ) for i in files ]
3858 _check_call (cmd )
3959
4060 def __repr__ (self ) -> str :
61+ """:return: repr of the index"""
4162 return f"{ self .__class__ .__name__ } (url={ self .url } )"
4263
4364
4465class IndexServer :
45- def __init__ (self , path : Path , with_root_pypi : bool = False , start_args : Sequence [str ] | None = None ) -> None :
66+ """A PyPI index server locally."""
67+
68+ def __init__ (
69+ self ,
70+ path : Path ,
71+ with_root_pypi : bool = False , # noqa: FBT001, FBT002
72+ start_args : Sequence [str ] | None = None ,
73+ ) -> None :
74+ """
75+ Create the local index server.
76+
77+ :param path: the path where to host files
78+ :param with_root_pypi: access to upstream PyPI
79+ :param start_args: additional arguments to start the server
80+ """
4681 self .path = path
4782 self ._with_root_pypi = with_root_pypi
4883 self ._start_args : Sequence [str ] = [] if start_args is None else start_args
4984
5085 self .host , self .port = "localhost" , _find_free_port ()
51- self ._passwd = "" .join (random .choices (string .ascii_letters , k = 8 ))
86+ self ._passwd = "" .join (random .choices (string .ascii_letters , k = 8 )) # noqa: S311
5287
5388 scripts_dir = sysconfig .get_path ("scripts" )
5489 if scripts_dir is None :
55- raise RuntimeError ("could not get scripts folder of host interpreter" ) # pragma: no cover
90+ msg = "could not get scripts folder of host interpreter" # pragma: no cover
91+ raise RuntimeError (msg ) # pragma: no cover
5692
5793 def _exe (name : str ) -> str :
5894 return str (Path (scripts_dir ) / f"{ name } { '.exe' if sys .platform == 'win32' else '' } " )
@@ -70,9 +106,11 @@ def _exe(name: str) -> str:
70106
71107 @property
72108 def user (self ) -> str :
109+ """:return: username of the index server"""
73110 return "root"
74111
75112 def __enter__ (self ) -> IndexServer :
113+ """:return: start the index server"""
76114 self ._create_and_start_server ()
77115 self ._setup_client ()
78116 return self
@@ -89,7 +127,7 @@ def _create_and_start_server(self) -> None:
89127 # 2. start the server
90128 cmd = [self ._server , "--serverdir" , server_at , "--port" , str (self .port )]
91129 cmd .extend (self ._start_args )
92- self ._process = Popen (cmd , stdout = PIPE , universal_newlines = True )
130+ self ._process = Popen (cmd , stdout = PIPE , universal_newlines = True ) # noqa: S603
93131 stdout = self ._drain_stdout ()
94132 for line in stdout : # pragma: no branch # will always loop at least once
95133 if "serving at url" in line :
@@ -108,42 +146,59 @@ def _drain_stdout(self) -> Iterator[str]:
108146 stdout = cast (IO [str ], process .stdout )
109147 while True :
110148 if process .poll () is not None : # pragma: no cover
111- print (f"devpi server with pid { process .pid } at { self ._server_dir } died" )
149+ print (f"devpi server with pid { process .pid } at { self ._server_dir } died" ) # noqa: T201
112150 break
113151 yield stdout .readline ()
114152
115153 def _setup_client (self ) -> None :
116- """create a user on the server and authenticate it"""
154+ """Create a user on the server and authenticate it. """
117155 self ._client_dir .mkdir (exist_ok = True )
118156 base = ["--clientdir" , str (self ._client_dir )]
119- _check_call ([self ._client , "use" ] + base + [ self .url ])
120- _check_call ([self ._client , "login" ] + base + [ self .user , "--password" , self ._passwd ])
157+ _check_call ([self ._client , "use" , * base , self .url ])
158+ _check_call ([self ._client , "login" , * base , self .user , "--password" , self ._passwd ])
121159
122160 def create_index (self , name : str , * args : str ) -> Index :
161+ """
162+ Create an index on the server.
163+
164+ :param name: with name
165+ :param args: additional arguments
166+ :return: the created index
167+ """
123168 if name in self ._indexes : # pragma: no cover
124- raise ValueError (f"index { name } already exists" )
169+ msg = f"index { name } already exists"
170+ raise ValueError (msg )
125171 base = [self ._client , "--clientdir" , str (self ._client_dir )]
126- _check_call (base + [ "index" , "-c" , name , * args ])
172+ _check_call ([ * base , "index" , "-c" , name , * args ])
127173 index = Index (f"{ self .url } /{ self .user } " , name , self .user , base )
128174 self ._indexes [name ] = index
129175 return index
130176
131177 def __exit__ (
132178 self ,
133- exc_type : type [BaseException ] | None , # noqa: U100
134- exc_val : BaseException | None , # noqa: U100
135- exc_tb : TracebackType | None , # noqa: U100
179+ exc_type : type [BaseException ] | None ,
180+ exc_val : BaseException | None ,
181+ exc_tb : TracebackType | None ,
136182 ) -> None :
183+ """
184+ Stop the index server.
185+
186+ :param exc_type:
187+ :param exc_val:
188+ :param exc_tb:
189+ """
137190 if self ._process is not None : # pragma: no cover # defend against devpi startup fail
138191 self ._process .terminate ()
139192 if self ._stdout_drain is not None and self ._stdout_drain .is_alive (): # pragma: no cover # devpi startup fail
140193 self ._stdout_drain .join ()
141194
142195 @property
143196 def url (self ) -> str :
197+ """:return: url to the index server"""
144198 return f"http://{ self .host } :{ self .port } "
145199
146200 def __repr__ (self ) -> str :
201+ """:return: repr of the index server"""
147202 return f"{ self .__class__ .__name__ } (url={ self .url } , indexes={ list (self ._indexes )} )"
148203
149204
0 commit comments