Best Python code snippet using autotest_python
views.py
Source:views.py
1from urllib.parse import urlparse, urlunparse2from django.conf import settings3# Avoid shadowing the login() and logout() views below.4from django.contrib.auth import (5 REDIRECT_FIELD_NAME, get_user_model, login as auth_login,6 logout as auth_logout, update_session_auth_hash,7)8from django.contrib.auth.decorators import login_required9from django.contrib.auth.forms import (10 AuthenticationForm, PasswordChangeForm, PasswordResetForm, SetPasswordForm,11)12from django.contrib.auth.tokens import default_token_generator13from django.contrib.sites.shortcuts import get_current_site14from django.core.exceptions import ValidationError15from django.http import HttpResponseRedirect, QueryDict16from django.shortcuts import resolve_url17from django.urls import reverse_lazy18from django.utils.decorators import method_decorator19from django.utils.http import (20 url_has_allowed_host_and_scheme, urlsafe_base64_decode,21)22from django.utils.translation import gettext_lazy as _23from django.views.decorators.cache import never_cache24from django.views.decorators.csrf import csrf_protect25from django.views.decorators.debug import sensitive_post_parameters26from django.views.generic.base import TemplateView27from django.views.generic.edit import FormView28UserModel = get_user_model()29class SuccessURLAllowedHostsMixin:30 success_url_allowed_hosts = set()31 def get_success_url_allowed_hosts(self):32 return {self.request.get_host(), *self.success_url_allowed_hosts}33class LoginView(SuccessURLAllowedHostsMixin, FormView):34 """35 Display the login form and handle the login action.36 """37 form_class = AuthenticationForm38 authentication_form = None39 redirect_field_name = REDIRECT_FIELD_NAME40 template_name = 'registration/login.html'41 redirect_authenticated_user = False42 extra_context = None43 @method_decorator(sensitive_post_parameters())44 @method_decorator(csrf_protect)45 @method_decorator(never_cache)46 def dispatch(self, request, *args, **kwargs):47 if self.redirect_authenticated_user and self.request.user.is_authenticated:48 redirect_to = self.get_success_url()49 if redirect_to == self.request.path:50 raise ValueError(51 "Redirection loop for authenticated user detected. Check that "52 "your LOGIN_REDIRECT_URL doesn't point to a login page."53 )54 return HttpResponseRedirect(redirect_to)55 return super().dispatch(request, *args, **kwargs)56 def get_success_url(self):57 url = self.get_redirect_url()58 return url or resolve_url(settings.LOGIN_REDIRECT_URL)59 def get_redirect_url(self):60 """Return the user-originating redirect URL if it's safe."""61 redirect_to = self.request.POST.get(62 self.redirect_field_name,63 self.request.GET.get(self.redirect_field_name, '')64 )65 url_is_safe = url_has_allowed_host_and_scheme(66 url=redirect_to,67 allowed_hosts=self.get_success_url_allowed_hosts(),68 require_https=self.request.is_secure(),69 )70 return redirect_to if url_is_safe else ''71 def get_form_class(self):72 return self.authentication_form or self.form_class73 def get_form_kwargs(self):74 kwargs = super().get_form_kwargs()75 kwargs['request'] = self.request76 return kwargs77 def form_valid(self, form):78 """Security check complete. Log the user in."""79 auth_login(self.request, form.get_user())80 return HttpResponseRedirect(self.get_success_url())81 def get_context_data(self, **kwargs):82 context = super().get_context_data(**kwargs)83 current_site = get_current_site(self.request)84 context.update({85 self.redirect_field_name: self.get_redirect_url(),86 'site': current_site,87 'site_name': current_site.name,88 **(self.extra_context or {})89 })90 return context91class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):92 """93 Log out the user and display the 'You are logged out' message.94 """95 next_page = None96 redirect_field_name = REDIRECT_FIELD_NAME97 template_name = 'registration/logged_out.html'98 extra_context = None99 @method_decorator(never_cache)100 def dispatch(self, request, *args, **kwargs):101 auth_logout(request)102 next_page = self.get_next_page()103 if next_page:104 # Redirect to this page until the session has been cleared.105 return HttpResponseRedirect(next_page)106 return super().dispatch(request, *args, **kwargs)107 def post(self, request, *args, **kwargs):108 """Logout may be done via POST."""109 return self.get(request, *args, **kwargs)110 def get_next_page(self):111 if self.next_page is not None:112 next_page = resolve_url(self.next_page)113 elif settings.LOGOUT_REDIRECT_URL:114 next_page = resolve_url(settings.LOGOUT_REDIRECT_URL)115 else:116 next_page = self.next_page117 if (self.redirect_field_name in self.request.POST or118 self.redirect_field_name in self.request.GET):119 next_page = self.request.POST.get(120 self.redirect_field_name,121 self.request.GET.get(self.redirect_field_name)122 )123 url_is_safe = url_has_allowed_host_and_scheme(124 url=next_page,125 allowed_hosts=self.get_success_url_allowed_hosts(),126 require_https=self.request.is_secure(),127 )128 # Security check -- Ensure the user-originating redirection URL is129 # safe.130 if not url_is_safe:131 next_page = self.request.path132 return next_page133 def get_context_data(self, **kwargs):134 context = super().get_context_data(**kwargs)135 current_site = get_current_site(self.request)136 context.update({137 'site': current_site,138 'site_name': current_site.name,139 'title': _('Logged out'),140 **(self.extra_context or {})141 })142 return context143def logout_then_login(request, login_url=None):144 """145 Log out the user if they are logged in. Then redirect to the login page.146 """147 login_url = resolve_url(login_url or settings.LOGIN_URL)148 return LogoutView.as_view(next_page=login_url)(request)149def redirect_to_login(next, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):150 """151 Redirect the user to the login page, passing the given 'next' page.152 """153 resolved_url = resolve_url(login_url or settings.LOGIN_URL)154 login_url_parts = list(urlparse(resolved_url))155 if redirect_field_name:156 querystring = QueryDict(login_url_parts[4], mutable=True)157 querystring[redirect_field_name] = next158 login_url_parts[4] = querystring.urlencode(safe='/')159 return HttpResponseRedirect(urlunparse(login_url_parts))160# Class-based password reset views161# - PasswordResetView sends the mail162# - PasswordResetDoneView shows a success message for the above163# - PasswordResetConfirmView checks the link the user clicked and164# prompts for a new password165# - PasswordResetCompleteView shows a success message for the above166class PasswordContextMixin:167 extra_context = None168 def get_context_data(self, **kwargs):169 context = super().get_context_data(**kwargs)170 context.update({171 'title': self.title,172 **(self.extra_context or {})173 })174 return context175class PasswordResetView(PasswordContextMixin, FormView):176 email_template_name = 'registration/password_reset_email.html'177 extra_email_context = None178 form_class = PasswordResetForm179 from_email = None180 html_email_template_name = None181 subject_template_name = 'registration/password_reset_subject.txt'182 success_url = reverse_lazy('password_reset_done')183 template_name = 'registration/password_reset_form.html'184 title = _('Password reset')185 token_generator = default_token_generator186 @method_decorator(csrf_protect)187 def dispatch(self, *args, **kwargs):188 return super().dispatch(*args, **kwargs)189 def form_valid(self, form):190 opts = {191 'use_https': self.request.is_secure(),192 'token_generator': self.token_generator,193 'from_email': self.from_email,194 'email_template_name': self.email_template_name,195 'subject_template_name': self.subject_template_name,196 'request': self.request,197 'html_email_template_name': self.html_email_template_name,198 'extra_email_context': self.extra_email_context,199 }200 form.save(**opts)201 return super().form_valid(form)202INTERNAL_RESET_SESSION_TOKEN = '_password_reset_token'203class PasswordResetDoneView(PasswordContextMixin, TemplateView):204 template_name = 'registration/password_reset_done.html'205 title = _('Password reset sent')206class PasswordResetConfirmView(PasswordContextMixin, FormView):207 form_class = SetPasswordForm208 post_reset_login = False209 post_reset_login_backend = None210 reset_url_token = 'set-password'211 success_url = reverse_lazy('password_reset_complete')212 template_name = 'registration/password_reset_confirm.html'213 title = _('Enter new password')214 token_generator = default_token_generator215 @method_decorator(sensitive_post_parameters())216 @method_decorator(never_cache)217 def dispatch(self, *args, **kwargs):218 assert 'uidb64' in kwargs and 'token' in kwargs219 self.validlink = False220 self.user = self.get_user(kwargs['uidb64'])221 if self.user is not None:222 token = kwargs['token']223 if token == self.reset_url_token:224 session_token = self.request.session.get(INTERNAL_RESET_SESSION_TOKEN)225 if self.token_generator.check_token(self.user, session_token):226 # If the token is valid, display the password reset form.227 self.validlink = True228 return super().dispatch(*args, **kwargs)229 else:230 if self.token_generator.check_token(self.user, token):231 # Store the token in the session and redirect to the232 # password reset form at a URL without the token. That233 # avoids the possibility of leaking the token in the234 # HTTP Referer header.235 self.request.session[INTERNAL_RESET_SESSION_TOKEN] = token236 redirect_url = self.request.path.replace(token, self.reset_url_token)237 return HttpResponseRedirect(redirect_url)238 # Display the "Password reset unsuccessful" page.239 return self.render_to_response(self.get_context_data())240 def get_user(self, uidb64):241 try:242 # urlsafe_base64_decode() decodes to bytestring243 uid = urlsafe_base64_decode(uidb64).decode()244 user = UserModel._default_manager.get(pk=uid)245 except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist, ValidationError):246 user = None247 return user248 def get_form_kwargs(self):249 kwargs = super().get_form_kwargs()250 kwargs['user'] = self.user251 return kwargs252 def form_valid(self, form):253 user = form.save()254 del self.request.session[INTERNAL_RESET_SESSION_TOKEN]255 if self.post_reset_login:256 auth_login(self.request, user, self.post_reset_login_backend)257 return super().form_valid(form)258 def get_context_data(self, **kwargs):259 context = super().get_context_data(**kwargs)260 if self.validlink:261 context['validlink'] = True262 else:263 context.update({264 'form': None,265 'title': _('Password reset unsuccessful'),266 'validlink': False,267 })268 return context269class PasswordResetCompleteView(PasswordContextMixin, TemplateView):270 template_name = 'registration/password_reset_complete.html'271 title = _('Password reset complete')272 def get_context_data(self, **kwargs):273 context = super().get_context_data(**kwargs)274 context['login_url'] = resolve_url(settings.LOGIN_URL)275 return context276class PasswordChangeView(PasswordContextMixin, FormView):277 form_class = PasswordChangeForm278 success_url = reverse_lazy('password_change_done')279 template_name = 'registration/password_change_form.html'280 title = _('Password change')281 @method_decorator(sensitive_post_parameters())282 @method_decorator(csrf_protect)283 @method_decorator(login_required)284 def dispatch(self, *args, **kwargs):285 return super().dispatch(*args, **kwargs)286 def get_form_kwargs(self):287 kwargs = super().get_form_kwargs()288 kwargs['user'] = self.request.user289 return kwargs290 def form_valid(self, form):291 form.save()292 # Updating the password logs out all other sessions for the user293 # except the current one.294 update_session_auth_hash(self.request, form.user)295 return super().form_valid(form)296class PasswordChangeDoneView(PasswordContextMixin, TemplateView):297 template_name = 'registration/password_change_done.html'298 title = _('Password change successful')299 @method_decorator(login_required)300 def dispatch(self, *args, **kwargs):...
retry.py
Source:retry.py
1import time2import logging3from ..exceptions import (4 ConnectTimeoutError,5 MaxRetryError,6 ProtocolError,7 ReadTimeoutError,8 ResponseError,9)10from ..packages import six11log = logging.getLogger(__name__)12class Retry(object):13 """ Retry configuration.14 Each retry attempt will create a new Retry object with updated values, so15 they can be safely reused.16 Retries can be defined as a default for a pool::17 retries = Retry(connect=5, read=2, redirect=5)18 http = PoolManager(retries=retries)19 response = http.request('GET', 'http://example.com/')20 Or per-request (which overrides the default for the pool)::21 response = http.request('GET', 'http://example.com/', retries=Retry(10))22 Retries can be disabled by passing ``False``::23 response = http.request('GET', 'http://example.com/', retries=False)24 Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless25 retries are disabled, in which case the causing exception will be raised.26 :param int total:27 Total number of retries to allow. Takes precedence over other counts.28 Set to ``None`` to remove this constraint and fall back on other29 counts. It's a good idea to set this to some sensibly-high value to30 account for unexpected edge cases and avoid infinite retry loops.31 Set to ``0`` to fail on the first retry.32 Set to ``False`` to disable and imply ``raise_on_redirect=False``.33 :param int connect:34 How many connection-related errors to retry on.35 These are errors raised before the request is sent to the remote server,36 which we assume has not triggered the server to process the request.37 Set to ``0`` to fail on the first retry of this type.38 :param int read:39 How many times to retry on read errors.40 These errors are raised after the request was sent to the server, so the41 request may have side-effects.42 Set to ``0`` to fail on the first retry of this type.43 :param int redirect:44 How many redirects to perform. Limit this to avoid infinite redirect45 loops.46 A redirect is a HTTP response with a status code 301, 302, 303, 307 or47 308.48 Set to ``0`` to fail on the first retry of this type.49 Set to ``False`` to disable and imply ``raise_on_redirect=False``.50 :param iterable method_whitelist:51 Set of uppercased HTTP method verbs that we should retry on.52 By default, we only retry on methods which are considered to be53 indempotent (multiple requests with the same parameters end with the54 same state). See :attr:`Retry.DEFAULT_METHOD_WHITELIST`.55 :param iterable status_forcelist:56 A set of HTTP status codes that we should force a retry on.57 By default, this is disabled with ``None``.58 :param float backoff_factor:59 A backoff factor to apply between attempts. urllib3 will sleep for::60 {backoff factor} * (2 ^ ({number of total retries} - 1))61 seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep62 for [0.1s, 0.2s, 0.4s, ...] between retries. It will never be longer63 than :attr:`Retry.MAX_BACKOFF`.64 By default, backoff is disabled (set to 0).65 :param bool raise_on_redirect: Whether, if the number of redirects is66 exhausted, to raise a MaxRetryError, or to return a response with a67 response code in the 3xx range.68 """69 DEFAULT_METHOD_WHITELIST = frozenset([70 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'])71 #: Maximum backoff time.72 BACKOFF_MAX = 12073 def __init__(self, total=10, connect=None, read=None, redirect=None,74 method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None,75 backoff_factor=0, raise_on_redirect=True, _observed_errors=0):76 self.total = total77 self.connect = connect78 self.read = read79 if redirect is False or total is False:80 redirect = 081 raise_on_redirect = False82 self.redirect = redirect83 self.status_forcelist = status_forcelist or set()84 self.method_whitelist = method_whitelist85 self.backoff_factor = backoff_factor86 self.raise_on_redirect = raise_on_redirect87 self._observed_errors = _observed_errors # TODO: use .history instead?88 def new(self, **kw):89 params = dict(90 total=self.total,91 connect=self.connect, read=self.read, redirect=self.redirect,92 method_whitelist=self.method_whitelist,93 status_forcelist=self.status_forcelist,94 backoff_factor=self.backoff_factor,95 raise_on_redirect=self.raise_on_redirect,96 _observed_errors=self._observed_errors,97 )98 params.update(kw)99 return type(self)(**params)100 @classmethod101 def from_int(cls, retries, redirect=True, default=None):102 """ Backwards-compatibility for the old retries format."""103 if retries is None:104 retries = default if default is not None else cls.DEFAULT105 if isinstance(retries, Retry):106 return retries107 redirect = bool(redirect) and None108 new_retries = cls(retries, redirect=redirect)109 log.debug("Converted retries value: %r -> %r" % (retries, new_retries))110 return new_retries111 def get_backoff_time(self):112 """ Formula for computing the current backoff113 :rtype: float114 """115 if self._observed_errors <= 1:116 return 0117 backoff_value = self.backoff_factor * (2 ** (self._observed_errors - 1))118 return min(self.BACKOFF_MAX, backoff_value)119 def sleep(self):120 """ Sleep between retry attempts using an exponential backoff.121 By default, the backoff factor is 0 and this method will return122 immediately.123 """124 backoff = self.get_backoff_time()125 if backoff <= 0:126 return127 time.sleep(backoff)128 def _is_connection_error(self, err):129 """ Errors when we're fairly sure that the server did not receive the130 request, so it should be safe to retry.131 """132 return isinstance(err, ConnectTimeoutError)133 def _is_read_error(self, err):134 """ Errors that occur after the request has been started, so we should135 assume that the server began processing it.136 """137 return isinstance(err, (ReadTimeoutError, ProtocolError))138 def is_forced_retry(self, method, status_code):139 """ Is this method/status code retryable? (Based on method/codes whitelists)140 """141 if self.method_whitelist and method.upper() not in self.method_whitelist:142 return False143 return self.status_forcelist and status_code in self.status_forcelist144 def is_exhausted(self):145 """ Are we out of retries? """146 retry_counts = (self.total, self.connect, self.read, self.redirect)147 retry_counts = list(filter(None, retry_counts))148 if not retry_counts:149 return False150 return min(retry_counts) < 0151 def increment(self, method=None, url=None, response=None, error=None, _pool=None, _stacktrace=None):152 """ Return a new Retry object with incremented retry counters.153 :param response: A response object, or None, if the server did not154 return a response.155 :type response: :class:`~urllib3.response.HTTPResponse`156 :param Exception error: An error encountered during the request, or157 None if the response was received successfully.158 :return: A new ``Retry`` object.159 """160 if self.total is False and error:161 # Disabled, indicate to re-raise the error.162 raise six.reraise(type(error), error, _stacktrace)163 total = self.total164 if total is not None:165 total -= 1166 _observed_errors = self._observed_errors167 connect = self.connect168 read = self.read169 redirect = self.redirect170 cause = 'unknown'171 if error and self._is_connection_error(error):172 # Connect retry?173 if connect is False:174 raise six.reraise(type(error), error, _stacktrace)175 elif connect is not None:176 connect -= 1177 _observed_errors += 1178 elif error and self._is_read_error(error):179 # Read retry?180 if read is False:181 raise six.reraise(type(error), error, _stacktrace)182 elif read is not None:183 read -= 1184 _observed_errors += 1185 elif response and response.get_redirect_location():186 # Redirect retry?187 if redirect is not None:188 redirect -= 1189 cause = 'too many redirects'190 else:191 # Incrementing because of a server error like a 500 in192 # status_forcelist and a the given method is in the whitelist193 _observed_errors += 1194 cause = ResponseError.GENERIC_ERROR195 if response and response.status:196 cause = ResponseError.SPECIFIC_ERROR.format(197 status_code=response.status)198 new_retry = self.new(199 total=total,200 connect=connect, read=read, redirect=redirect,201 _observed_errors=_observed_errors)202 if new_retry.is_exhausted():203 raise MaxRetryError(_pool, url, error or ResponseError(cause))204 log.debug("Incremented Retry for (url='%s'): %r" % (url, new_retry))205 return new_retry206 def __repr__(self):207 return ('{cls.__name__}(total={self.total}, connect={self.connect}, '208 'read={self.read}, redirect={self.redirect})').format(209 cls=type(self), self=self)210# For backwards compatibility (equivalent to pre-v1.9):...
redirector2.py
Source:redirector2.py
...34 return35 else:36 self.server.printer.warn("No 'Content-Length' received")37 self._log()38 def _send_redirect(self):39 redirect_url = self.server.ssrf_url40 if self.server.expand:41 if redirect_url.endswith('/'):42 redirect_url = redirect_url[:-1]43 redirect_url += self.path44 self.server.printer.debug("Redirecting with {} to {}".format(self.server.redirect_code, redirect_url))45 self.send_response(self.server.redirect_code)46 self.send_header('Location', redirect_url)47 self.end_headers()48 def do_GET(self):49 self._log()50 self._send_redirect()51 def do_HEAD(self):52 self._log()53 self._send_redirect()54 def do_POST(self):55 self._log_with_body()56 self._send_redirect()57 def do_PUT(self):58 self._log_with_body()59 self._send_redirect()60 def do_DELETE(self):61 self._log()62 self._send_redirect()63 def do_PATCH(self):64 self._log_with_body()65 self._send_redirect()66 def do_OPTIONS(self):67 self._log()68 self._send_redirect()69 def log_message(self, format, *args):70 # suppress default access logs71 return72class RedirectHTTPServer(HTTPServer):73 def __init__(self, printer, args, server_address, RequestHandlerClass=Redirect, bind_and_activate=True):74 super().__init__(server_address, RequestHandlerClass, bind_and_activate)75 self.printer = printer76 self.ssrf_url = args.ssrf_url77 self.redirect_code = args.redirect_code78 self.quiet = args.quiet79 self.expand = args.expand80class Printer:81 DEBUG = '\033[90m'82 PURPLE = '\033[95m'...
test_iostream.py
Source:test_iostream.py
...65 assert capture == "ab"66def test_flush(capfd):67 msg = "(not flushed)"68 msg2 = "(flushed)"69 with m.ostream_redirect():70 m.noisy_function(msg, flush=False)71 stdout, stderr = capfd.readouterr()72 assert stdout == ''73 m.noisy_function(msg2, flush=True)74 stdout, stderr = capfd.readouterr()75 assert stdout == msg + msg276 m.noisy_function(msg, flush=False)77 stdout, stderr = capfd.readouterr()78 assert stdout == msg79def test_not_captured(capfd):80 msg = "Something that should not show up in log"81 stream = StringIO()82 with redirect_stdout(stream):83 m.raw_output(msg)84 stdout, stderr = capfd.readouterr()85 assert stdout == msg86 assert stderr == ''87 assert stream.getvalue() == ''88 stream = StringIO()89 with redirect_stdout(stream):90 m.captured_output(msg)91 stdout, stderr = capfd.readouterr()92 assert stdout == ''93 assert stderr == ''94 assert stream.getvalue() == msg95def test_err(capfd):96 msg = "Something that should not show up in log"97 stream = StringIO()98 with redirect_stderr(stream):99 m.raw_err(msg)100 stdout, stderr = capfd.readouterr()101 assert stdout == ''102 assert stderr == msg103 assert stream.getvalue() == ''104 stream = StringIO()105 with redirect_stderr(stream):106 m.captured_err(msg)107 stdout, stderr = capfd.readouterr()108 assert stdout == ''109 assert stderr == ''110 assert stream.getvalue() == msg111def test_multi_captured(capfd):112 stream = StringIO()113 with redirect_stdout(stream):114 m.captured_output("a")115 m.raw_output("b")116 m.captured_output("c")117 m.raw_output("d")118 stdout, stderr = capfd.readouterr()119 assert stdout == 'bd'120 assert stream.getvalue() == 'ac'121def test_dual(capsys):122 m.captured_dual("a", "b")123 stdout, stderr = capsys.readouterr()124 assert stdout == "a"125 assert stderr == "b"126def test_redirect(capfd):127 msg = "Should not be in log!"128 stream = StringIO()129 with redirect_stdout(stream):130 m.raw_output(msg)131 stdout, stderr = capfd.readouterr()132 assert stdout == msg133 assert stream.getvalue() == ''134 stream = StringIO()135 with redirect_stdout(stream):136 with m.ostream_redirect():137 m.raw_output(msg)138 stdout, stderr = capfd.readouterr()139 assert stdout == ''140 assert stream.getvalue() == msg141 stream = StringIO()142 with redirect_stdout(stream):143 m.raw_output(msg)144 stdout, stderr = capfd.readouterr()145 assert stdout == msg146 assert stream.getvalue() == ''147def test_redirect_err(capfd):148 msg = "StdOut"149 msg2 = "StdErr"150 stream = StringIO()151 with redirect_stderr(stream):152 with m.ostream_redirect(stdout=False):153 m.raw_output(msg)154 m.raw_err(msg2)155 stdout, stderr = capfd.readouterr()156 assert stdout == msg157 assert stderr == ''158 assert stream.getvalue() == msg2159def test_redirect_both(capfd):160 msg = "StdOut"161 msg2 = "StdErr"162 stream = StringIO()163 stream2 = StringIO()164 with redirect_stdout(stream):165 with redirect_stderr(stream2):166 with m.ostream_redirect():167 m.raw_output(msg)168 m.raw_err(msg2)169 stdout, stderr = capfd.readouterr()170 assert stdout == ''171 assert stderr == ''172 assert stream.getvalue() == msg...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!