[Hyperf]updateOrInsert:must be of the type bool, object returned

Hyperf数据库操作:解决updateOrInsert返回类型问题
在使用Hyperf的DatabaseModelBuilder时遇到updateOrInsert方法返回类型不符的问题,原本期望得到布尔值但实际返回的是对象。经过研究源码和查阅资料发现,由于@mixinHyperfDatabaseQueryBuilder注解,导致了调用错误。解决方法是在调用updateOrInsert前添加toBase方法,确保正确执行更新或插入操作。

Hyperf\Database\Model\Builder的updateOrInsert方法返回类型是对象,不是我想要的布尔类型,花了点时间研究了Hyperf的源码,查阅相关资料之后,才知道Hyperf\Database\Model\Builde类用了@mixin Hyperf\Database\Query\Builder注解,导致调用不到,需要在调用updateOrInsert方法之前调用toBase方法

问题如下图:

解决方法:增加调用toBase方法

C:\Users\20685\AppData\Local\Programs\Python\Python310\python.exe D:\pythonProject_request\run.py ============================= test session starts ============================= platform win32 -- Python 3.10.11, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\20685\AppData\Local\Programs\Python\Python310\python.exe cachedir: .pytest_cache metadata: {'Python': '3.10.11', 'Platform': 'Windows-10-10.0.26100-SP0', 'Packages': {'pytest': '8.3.5', 'pluggy': '1.5.0'}, 'Plugins': {'allure-pytest': '2.14.0', 'base-url': '2.1.0', 'html': '4.1.1', 'metadata': '3.1.1', 'order': '1.3.0', 'ordering': '0.6', 'rerunfailures': '15.1', 'xdist': '3.8.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_131', 'Base URL': ''} rootdir: D:\pythonProject_request configfile: pytest.ini plugins: allure-pytest-2.14.0, base-url-2.1.0, html-4.1.1, metadata-3.1.1, order-1.3.0, ordering-0.6, rerunfailures-15.1, xdist-3.8.0 collecting ... collected 1 item testcaes/test_all_case.py::TestAllCase::test_login[caseinfo0] FAILED ================================== FAILURES =================================== ______________________ TestAllCase.test_login[caseinfo0] ______________________ self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x000002DA1B54E380> conn = <urllib3.connection.HTTPSConnection object at 0x000002DA1B54E980> method = 'POST' url = '/adminapi/login?Content_Type=application%2Fx-www-from-urlencoded' body = 'account=admin&pwd=123456&imgcode=' headers = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '33', 'Content-Type': 'application/x-www-form-urlencoded'} retries = Retry(total=0, connect=None, read=False, redirect=None, status=None) timeout = Timeout(connect=None, read=None, total=None), chunked = False response_conn = <urllib3.connection.HTTPSConnection object at 0x000002DA1B54E980> preload_content = False, decode_content = False, enforce_content_length = True def _make_request( self, conn: BaseHTTPConnection, method: str, url: str, body: _TYPE_BODY | None = None, headers: typing.Mapping[str, str] | None = None, retries: Retry | None = None, timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT, chunked: bool = False, response_conn: BaseHTTPConnection | None = None, preload_content: bool = True, decode_content: bool = True, enforce_content_length: bool = True, ) -> BaseHTTPResponse: """ Perform a request on a given urllib connection object taken from our pool. :param conn: a connection from one of our connection pools :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param response_conn: Set this to ``None`` if you will handle releasing the connection or set the connection to have the response release it. :param preload_content: If True, the response's body will be preloaded during construction. :param decode_content: If True, will attempt to decode the body based on the 'content-encoding' header. :param enforce_content_length: Enforce content length checking. Body returned by server must match value of Content-Length header, if present. Otherwise, raise error. """ self.num_requests += 1 timeout_obj = self._get_timeout(timeout) timeout_obj.start_connect() conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout) try: # Trigger any extra validation we need to do. try: > self._validate_conn(conn) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py:468: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py:1097: in _validate_conn conn.connect() C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connection.py:642: in connect sock_and_verified = _ssl_wrap_socket_and_match_hostname( C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connection.py:783: in _ssl_wrap_socket_and_match_hostname ssl_sock = ssl_wrap_socket( C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\util\ssl_.py:471: in ssl_wrap_socket ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\util\ssl_.py:515: in _ssl_wrap_socket_impl return ssl_context.wrap_socket(sock, server_hostname=server_hostname) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\ssl.py:513: in wrap_socket return self.sslsocket_class._create( C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\ssl.py:1071: in _create self.do_handshake() _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <ssl.SSLSocket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0> block = False @_sslcopydoc def do_handshake(self, block=False): self._check_connected() timeout = self.gettimeout() try: if timeout == 0.0 and block: self.settimeout(None) > self._sslobj.do_handshake() E ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\ssl.py:1342: SSLCertVerificationError During handling of the above exception, another exception occurred: self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x000002DA1B54E380> method = 'POST' url = '/adminapi/login?Content_Type=application%2Fx-www-from-urlencoded' body = 'account=admin&pwd=123456&imgcode=' headers = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '33', 'Content-Type': 'application/x-www-form-urlencoded'} retries = Retry(total=0, connect=None, read=False, redirect=None, status=None) redirect = False, assert_same_host = False timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None release_conn = False, chunked = False, body_pos = None, preload_content = False decode_content = False, response_kw = {} parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/adminapi/login', query='Content_Type=application%2Fx-www-from-urlencoded', fragment=None) destination_scheme = None, conn = None, release_this_conn = True http_tunnel_required = False, err = None, clean_exit = False def urlopen( # type: ignore[override] self, method: str, url: str, body: _TYPE_BODY | None = None, headers: typing.Mapping[str, str] | None = None, retries: Retry | bool | int | None = None, redirect: bool = True, assert_same_host: bool = True, timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT, pool_timeout: int | None = None, release_conn: bool | None = None, chunked: bool = False, body_pos: _TYPE_BODY_POSITION | None = None, preload_content: bool = True, decode_content: bool = True, **response_kw: typing.Any, ) -> BaseHTTPResponse: """ Get a connection from the pool and perform an HTTP request. This is the lowest level call for making a request, so you'll need to specify all the raw details. .. note:: More commonly, it's appropriate to use a convenience method such as :meth:`request`. .. note:: `release_conn` will only behave as expected if `preload_content=False` because we want to make `preload_content=False` the default behaviour someday soon without breaking backwards compatibility. :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param redirect: If True, automatically handle redirects (status codes 301, 302, 303, 307, 308). Each redirect counts as a retry. Disabling retries will disable redirect, too. :param assert_same_host: If ``True``, will make sure that the host of the pool requests is consistent else will raise HostChangedError. When ``False``, you can use the pool on an HTTP proxy and request foreign hosts. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param pool_timeout: If set and the pool is set to block=True, then this method will block for ``pool_timeout`` seconds and raise EmptyPoolError if no connection is available within the time period. :param bool preload_content: If True, the response's body will be preloaded into memory. :param bool decode_content: If True, will attempt to decode the body based on the 'content-encoding' header. :param release_conn: If False, then the urlopen call will not release the connection back into the pool once a response is received (but will release if you read the entire contents of the response such as when `preload_content=True`). This is useful if you're not preloading the response's content immediately. You will need to call ``r.release_conn()`` on the response ``r`` to return the connection back into the pool. If None, it takes the value of ``preload_content`` which defaults to ``True``. :param bool chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param int body_pos: Position to seek to in file-like body in the event of a retry or redirect. Typically this won't need to be set because urllib3 will auto-populate the value when needed. """ parsed_url = parse_url(url) destination_scheme = parsed_url.scheme if headers is None: headers = self.headers if not isinstance(retries, Retry): retries = Retry.from_int(retries, redirect=redirect, default=self.retries) if release_conn is None: release_conn = preload_content # Check host if assert_same_host and not self.is_same_host(url): raise HostChangedError(self, url, retries) # Ensure that the URL we're connecting to is properly encoded if url.startswith("/"): url = to_str(_encode_target(url)) else: url = to_str(parsed_url.url) conn = None # Track whether `conn` needs to be released before # returning/raising/recursing. Update this variable if necessary, and # leave `release_conn` constant throughout the function. That way, if # the function recurses, the original value of `release_conn` will be # passed down into the recursive call, and its value will be respected. # # See issue #651 [1] for details. # # [1] <https://github.com/urllib3/urllib3/issues/651> release_this_conn = release_conn http_tunnel_required = connection_requires_http_tunnel( self.proxy, self.proxy_config, destination_scheme ) # Merge the proxy headers. Only done when not using HTTP CONNECT. We # have to copy the headers dict so we can safely change it without those # changes being reflected in anyone else's copy. if not http_tunnel_required: headers = headers.copy() # type: ignore[attr-defined] headers.update(self.proxy_headers) # type: ignore[union-attr] # Must keep the exception bound to a separate variable or else Python 3 # complains about UnboundLocalError. err = None # Keep track of whether we cleanly exited the except block. This # ensures we do proper cleanup in finally. clean_exit = False # Rewind body position, if needed. Record current position # for future rewinds in the event of a redirect/retry. body_pos = set_file_position(body, body_pos) try: # Request a connection from the queue. timeout_obj = self._get_timeout(timeout) conn = self._get_conn(timeout=pool_timeout) conn.timeout = timeout_obj.connect_timeout # type: ignore[assignment] # Is this a closed/new connection that requires CONNECT tunnelling? if self.proxy is not None and http_tunnel_required and conn.is_closed: try: self._prepare_proxy(conn) except (BaseSSLError, OSError, SocketTimeout) as e: self._raise_timeout( err=e, url=self.proxy.url, timeout_value=conn.timeout ) raise # If we're going to release the connection in ``finally:``, then # the response doesn't need to know about the connection. Otherwise # it will also try to release it and we'll have a double-release # mess. response_conn = conn if not release_conn else None # Make the request on the HTTPConnection object > response = self._make_request( conn, method, url, timeout=timeout_obj, body=body, headers=headers, chunked=chunked, retries=retries, response_conn=response_conn, preload_content=preload_content, decode_content=decode_content, **response_kw, ) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py:791: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x000002DA1B54E380> conn = <urllib3.connection.HTTPSConnection object at 0x000002DA1B54E980> method = 'POST' url = '/adminapi/login?Content_Type=application%2Fx-www-from-urlencoded' body = 'account=admin&pwd=123456&imgcode=' headers = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '33', 'Content-Type': 'application/x-www-form-urlencoded'} retries = Retry(total=0, connect=None, read=False, redirect=None, status=None) timeout = Timeout(connect=None, read=None, total=None), chunked = False response_conn = <urllib3.connection.HTTPSConnection object at 0x000002DA1B54E980> preload_content = False, decode_content = False, enforce_content_length = True def _make_request( self, conn: BaseHTTPConnection, method: str, url: str, body: _TYPE_BODY | None = None, headers: typing.Mapping[str, str] | None = None, retries: Retry | None = None, timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT, chunked: bool = False, response_conn: BaseHTTPConnection | None = None, preload_content: bool = True, decode_content: bool = True, enforce_content_length: bool = True, ) -> BaseHTTPResponse: """ Perform a request on a given urllib connection object taken from our pool. :param conn: a connection from one of our connection pools :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param response_conn: Set this to ``None`` if you will handle releasing the connection or set the connection to have the response release it. :param preload_content: If True, the response's body will be preloaded during construction. :param decode_content: If True, will attempt to decode the body based on the 'content-encoding' header. :param enforce_content_length: Enforce content length checking. Body returned by server must match value of Content-Length header, if present. Otherwise, raise error. """ self.num_requests += 1 timeout_obj = self._get_timeout(timeout) timeout_obj.start_connect() conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout) try: # Trigger any extra validation we need to do. try: self._validate_conn(conn) except (SocketTimeout, BaseSSLError) as e: self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) raise # _validate_conn() starts the connection to an HTTPS proxy # so we need to wrap errors with 'ProxyError' here too. except ( OSError, NewConnectionError, TimeoutError, BaseSSLError, CertificateError, SSLError, ) as e: new_e: Exception = e if isinstance(e, (BaseSSLError, CertificateError)): new_e = SSLError(e) # If the connection didn't successfully connect to it's proxy # then there if isinstance( new_e, (OSError, NewConnectionError, TimeoutError, SSLError) ) and (conn and conn.proxy and not conn.has_connected_to_proxy): new_e = _wrap_proxy_error(new_e, conn.proxy.scheme) > raise new_e E urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py:492: SSLError The above exception was the direct cause of the following exception: self = <requests.adapters.HTTPAdapter object at 0x000002DA1B51A710> request = <PreparedRequest [POST]>, stream = False timeout = Timeout(connect=None, read=None, total=None), verify = True cert = None, proxies = OrderedDict() def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. :param stream: (optional) Whether to stream the request content. :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) <timeouts>` tuple. :type timeout: float or tuple or urllib3 Timeout object :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use :param cert: (optional) Any user-provided SSL certificate to be trusted. :param proxies: (optional) The proxies dictionary to apply to the request. :rtype: requests.Response """ try: conn = self.get_connection_with_tls_context( request, verify, proxies=proxies, cert=cert ) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers( request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies, ) chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) except ValueError: raise ValueError( f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " f"or a single float to set both timeouts to the same value." ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: > resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout, chunked=chunked, ) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\adapters.py:667: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py:845: in urlopen retries = retries.increment( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Retry(total=0, connect=None, read=False, redirect=None, status=None) method = 'POST' url = '/adminapi/login?Content_Type=application%2Fx-www-from-urlencoded' response = None error = SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)')) _pool = <urllib3.connectionpool.HTTPSConnectionPool object at 0x000002DA1B54E380> _stacktrace = <traceback object at 0x000002DA1B279980> def increment( self, method: str | None = None, url: str | None = None, response: BaseHTTPResponse | None = None, error: Exception | None = None, _pool: ConnectionPool | None = None, _stacktrace: TracebackType | None = None, ) -> Retry: """Return a new Retry object with incremented retry counters. :param response: A response object, or None, if the server did not return a response. :type response: :class:`~urllib3.response.BaseHTTPResponse` :param Exception error: An error encountered during the request, or None if the response was received successfully. :return: A new ``Retry`` object. """ if self.total is False and error: # Disabled, indicate to re-raise the error. raise reraise(type(error), error, _stacktrace) total = self.total if total is not None: total -= 1 connect = self.connect read = self.read redirect = self.redirect status_count = self.status other = self.other cause = "unknown" status = None redirect_location = None if error and self._is_connection_error(error): # Connect retry? if connect is False: raise reraise(type(error), error, _stacktrace) elif connect is not None: connect -= 1 elif error and self._is_read_error(error): # Read retry? if read is False or method is None or not self._is_method_retryable(method): raise reraise(type(error), error, _stacktrace) elif read is not None: read -= 1 elif error: # Other retry? if other is not None: other -= 1 elif response and response.get_redirect_location(): # Redirect retry? if redirect is not None: redirect -= 1 cause = "too many redirects" response_redirect_location = response.get_redirect_location() if response_redirect_location: redirect_location = response_redirect_location status = response.status else: # Incrementing because of a server error like a 500 in # status_forcelist and the given method is in the allowed_methods cause = ResponseError.GENERIC_ERROR if response and response.status: if status_count is not None: status_count -= 1 cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) status = response.status history = self.history + ( RequestHistory(method, url, error, status, redirect_location), ) new_retry = self.new( total=total, connect=connect, read=read, redirect=redirect, status=status_count, other=other, history=history, ) if new_retry.is_exhausted(): reason = error or ResponseError(cause) > raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type] E urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='192.168.116.137', port=443): Max retries exceeded with url: /adminapi/login?Content_Type=application%2Fx-www-from-urlencoded (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)'))) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\util\retry.py:515: MaxRetryError During handling of the above exception, another exception occurred: self = <testcaes.test_all_case.TestAllCase object at 0x000002DA1B54E1D0> caseinfo = {'request': {'data': {'account': 'admin', 'imgcode': '', 'pwd': 123456}, 'method': 'post', 'params': {'Content_Type': 'application/x-www-from-urlencoded'}, 'url': 'https://192.168.116.137/adminapi/login'}, 'validate': None, 'verify': False} @pytest.mark.parametrize("caseinfo",read_yaml(yaml_path)) def duyo(self,caseinfo): new_caseinfo = verify_yaml(caseinfo) #在读取yaml内容后调取用例模板方法验证用例是否足够 #发送请求 > RequestUtil().send_all_request(**new_caseinfo.request) testcaes\test_all_case.py:17: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ common\requests_util.py:27: in send_all_request res = RequestUtil.sess.request(**kwargs) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py:589: in request resp = self.send(prep, **send_kwargs) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py:703: in send r = adapter.send(request, **kwargs) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <requests.adapters.HTTPAdapter object at 0x000002DA1B51A710> request = <PreparedRequest [POST]>, stream = False timeout = Timeout(connect=None, read=None, total=None), verify = True cert = None, proxies = OrderedDict() def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ): """Sends PreparedRequest object. Returns Response object. :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. :param stream: (optional) Whether to stream the request content. :param timeout: (optional) How long to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout) <timeouts>` tuple. :type timeout: float or tuple or urllib3 Timeout object :param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use :param cert: (optional) Any user-provided SSL certificate to be trusted. :param proxies: (optional) The proxies dictionary to apply to the request. :rtype: requests.Response """ try: conn = self.get_connection_with_tls_context( request, verify, proxies=proxies, cert=cert ) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers( request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies, ) chunked = not (request.body is None or "Content-Length" in request.headers) if isinstance(timeout, tuple): try: connect, read = timeout timeout = TimeoutSauce(connect=connect, read=read) except ValueError: raise ValueError( f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " f"or a single float to set both timeouts to the same value." ) elif isinstance(timeout, TimeoutSauce): pass else: timeout = TimeoutSauce(connect=timeout, read=timeout) try: resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout, chunked=chunked, ) except (ProtocolError, OSError) as err: raise ConnectionError(err, request=request) except MaxRetryError as e: if isinstance(e.reason, ConnectTimeoutError): # TODO: Remove this in 3.0.0: see #2811 if not isinstance(e.reason, NewConnectionError): raise ConnectTimeout(e, request=request) if isinstance(e.reason, ResponseError): raise RetryError(e, request=request) if isinstance(e.reason, _ProxyError): raise ProxyError(e, request=request) if isinstance(e.reason, _SSLError): # This branch is for urllib3 v1.22 and later. > raise SSLError(e, request=request) E requests.exceptions.SSLError: HTTPSConnectionPool(host='192.168.116.137', port=443): Max retries exceeded with url: /adminapi/login?Content_Type=application%2Fx-www-from-urlencoded (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)'))) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\adapters.py:698: SSLError ============================== warnings summary =============================== C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\_pytest\config\__init__.py:1277 C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\_pytest\config\__init__.py:1277: PytestAssertRewriteWarning: Module already imported so cannot be rewritten: allure_pytest self._mark_plugins_for_rewrite(hook) C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\_pytest\config\__init__.py:1500 C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\_pytest\config\__init__.py:1500: PytestConfigWarning: No files were found in testpaths; consider removing or adjusting your testpaths configuration. Searching recursively from the current directory instead. self.args, self.args_source = self._decide_args( C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\_pytest\config\__init__.py:1441 C:\Users\20685\AppData\Local\Programs\Python\Python310\lib\site-packages\_pytest\config\__init__.py:1441: PytestConfigWarning: Unknown config option: Python_classes self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html =========================== short test summary info =========================== FAILED testcaes/test_all_case.py::TestAllCase::test_login[caseinfo0] - reques... ======================== 1 failed, 3 warnings in 0.25s ======================== 进程已结束,退出代码为 0
08-01
Thanks to your work so far, the library now has a functioning system. However, librarians have reported that some records in the CSV files are corrupted with invalid values. This has caused misbehaviour in the system, sometimes even crashing during busy exam periods, creating unnecessary stress for students. In real-world software engineering, robustness and correctness are just as important as functionality. Programs must gracefully handle unexpected situations and invalid inputs without failing. Two key approaches developers use are: Assertions: Internal checks that validate assumptions made by the programmer (e.g., "This variable should never be negative"). Assertions are mainly used during development and debugging. Defensive programming: Validates inputs and usage patterns to prevent invalid or unexpected behaviour at runtime. This includes checking for correct types, value ranges, and providing helpful error messages when something goes wrong. Description In this task, you will extend your library system by adding custom error handling to make it more robust. Python already raises built-in errors, but here you must define and use custom exceptions (in custom_errors.py) to handle library-specific error conditions. Building upon Task 3, update your user.py and book.py modules to handle invalid input, and modify task4.py to handle exceptions gracefully so that the system does not crash. You must ensure that this system is: Correct: Through use of assert to validate assumptions in your logic. Safe: Through defensive programming techniques that prevent invalid inputs (e.g. wrong types, negative amounts). In this task we will be using custom errors as python will already raise some of these errors when we execute invalid code. Our new errors are located in cusom_errors.py. You must use these custom errors, please see rubric for related penalties in this task. After auditing the CSV data, the librarian has introduced new validation rules to be applied in addition to the requirements described in Tasks 1–3. These rules strengthen data quality and prevent corrupted records from entering the system. Always include a helpful and descriptive error message when raising errors. Doing so contributes to the readability and overall quality of your assignment. Users Every user must have a password. Passwords cannot be empty. Every word in a user's name must contain only alphabetic characters. Numbers, symbols, and special characters are not allowed. Department is mandatory for students and staff, but must remain empty for other users. The only valid departments are: IT, Business, Arts, Science, Engineering, Education, Medicine and Library. Books The library only recognizes two valid book types: physical and online. The following fields are required for all books: Title, Author, Year Each book may have at most 5 keywords. Each word in keywords must consist of letters and numbers only. The only allowed special character is the hyphen (-). Loans Every loan record must be associated with an existing user and an existing book. The due date is a required field and cannot be left empty. Defensive Programming The following exceptions are provided to you in custom_errors.py: CustomTypeError: A value is the wrong type (e.g. a string instead of a float or int). CustomValueError: A value is of the correct type but invalid (e.g. negative copies). CustomDateError: Raised when a date is in the wrong format or when the date logic is invalid (e.g., borrow date occurs in the future). MissingRequiredFieldError: Raised when a required field is missing. UserNotFoundError or BookNotFoundError: Raised when a loan references a user or book that does not exist. CustomOperationError : Raised when an invalid borrow or return action is attempted. CustomLimitError: Raised when a user exceeds their quota or borrowing limit. CustomKeyError: Occurs when you try to access a key in the dictionary that doesn't exist.
10-18
class Image { public: friend class Internal; /// <summary> /// The empty or "NULL" constructor for an <c>Atil::Image</c>. /// </summary> /// /// <remarks> /// An instance of an image created through this constructor is intended only to facilitate /// the later assignment of a valid image. The instance created through this constructor has /// no internal data that can be returned. Attempting access any data from a "NULL" image will /// result in an exception. /// </remarks> Image (); /// <summary> /// The clone constructor of the Image class allows the construction of a new instance based /// on an existing instance. /// </summary> /// /// <param name= 'image'> /// A const reference to the image to be copied. /// </param> /// /// <exception cref="ImageConstructionException">Thrown when the image can /// not be cloned <see cref="ImageConstructionException"/>. /// </exception> /// /// <remarks> /// ATIL implements the Image class with a "letter - envelope" or "Bridge" /// design pattern. See "Design Patterns, ISBN 0-201-63361-2". /// </remarks> /// Image (const Image & image); /// <summary> /// The blank image constructor for an <c>Image</c>. /// </summary> /// /// <param name='size'>The size of the image to be created.</param> /// /// <param name='colorspace'>The DataModel of the image to be created.</param> /// /// <param name='initialColor'>The clear color of the image data.</param> /// /// <param name='sz'>The tile size to use for the image. /// The default, <c>DataModel::TileSize::kUnspecified</c> is recommended. /// </param> /// /// <exception cref="ImageConstructionException">An exception will be thrown /// if the image can not be constructed. <see cref="ImageConstructionException"/>. /// </exception> /// Image (const Size& size, const DataModel* colorspace, ImagePixel initialColor, DataModel::TileSize sz = DataModel::kUnspecified); /// <summary> /// The user supplied buffer constructor for <c>Atil::Image</c>. This method of construction /// will wrap a user supplied buffer with the Image object allowing ATIL and the using /// application mutual access to the image data. Images created in this way are not memory managed. /// </summary> /// /// <param name='pData'>A pointer to the buffer that the image should use for its image /// data storage. /// </param> /// /// <param name='nBytesInBuffer'>An integer that describes the number of bytes /// that have been allocated in the <c>pData</c> parameter. /// </param> /// /// <param name='nBytesPerRow'>An integer that describes the number of bytes in /// one row of the data. This sometimes referred to as the stride of the data. /// The number of bytes from the beginning of one row to the beginning of the next row. /// </param> /// /// <param name='size'>The horizontal and vertical dimensions of the image. /// The buffer in pData must be large enough to hold these dimensions. /// </param> /// /// <param name='pDm'>A constant pointer to a <c>DataModel</c> instance that /// represents the data that will be contained in the image. /// </param> /// /// <exception cref="ImageConstructionException">An exception will be thrown /// if the image can not be constructed. <see cref="ImageConstructionException"/>. /// </exception> /// Image (void* pData, int nBytesInBuffer, int nBytesPerRow, const Size& size, const DataModel* pDm); /// <summary> /// A <c>RowProviderInterface</c> based constructor for Image. /// </summary> /// /// <param name='pPipe'>A source of image data. /// </param> /// /// <param name='sz'>The tile size to be used for the image. /// </param> /// /// <exception cref="ImageConstructionException">An exception will be thrown /// if the image can not be constructed. <see cref="ImageConstructionException"/>. /// </exception> /// /// <remarks> /// This method will "consume" the <c>RowProviderInterface</c> and free the resources /// that it holds. The <c>RowProviderInterface</c> is no longer valid after using /// it in this method. /// </remarks> /// Image (RowProviderInterface* pPipe, DataModel::TileSize sz = DataModel::kUnspecified); /// <summary> /// A <c>RowProviderInterface</c> based constructor for Image with the option. /// to reorient the input. /// </summary> /// /// <param name='pPipe'>A source of image data. /// </param> /// /// <param name='orient'>The orientation to apply to the image when storing /// the data in the image. /// </param> /// /// <param name='sz'>The tile size to be used for the image. /// </param> /// /// <exception cref="ImageConstructionException">An exception will be thrown /// if the image can not be constructed. <see cref="ImageConstructionException"/>. /// </exception> /// Image (RowProviderInterface* pPipe, Atil::Orientation orient, DataModel::TileSize sz = DataModel::kUnspecified); /// <summary> /// The <c>FileReadDescriptor</c> based constructor for Image. This is the constructor /// to use when you want to load an image from a file. /// </summary> /// /// <param name='readDesc'>The <c>FileReadDescriptor</c> source of image data. /// </param> /// /// <param name='sz'>The tile size to be used for the image. /// </param> /// /// <exception cref="ImageConstructionException">An exception will be thrown /// if the image can not be constructed. <see cref="ImageConstructionException"/>. /// </exception> /// /// <remarks> /// The image will be constructed from the current frame set in the FileReadDescriptor. /// </remarks> /// Image (FileReadDescriptor& readDesc, DataModel::TileSize sz = DataModel::kUnspecified); /// <summary> /// The destructor will release all image resources with the exception of /// user allocated buffers. /// </summary> /// ~Image (); /// <summary> /// The assignment operator will destroy the existing image data and make a reference /// to the assigned image data. /// </summary> /// /// <param name= 'image'> /// A const reference to the image to be assigned to <c>*this</c>. /// </param> /// /// <returns> /// This returns a reference to <c>*this</c>. /// </returns> /// const Image& operator= (const Image& image); /// <summary> /// The assignment operator will destroy the existing image data and construct a new /// image from the result of the <c>RowProviderInterface</c>. /// </summary> /// /// <param name="pPipe">An instance of a <c>RowProviderInterface</c> that will supply /// the pixel data to be drawn. The <c>RowProviderInterface</c> is consumed and freed. /// </param> /// /// <returns> /// This returns a reference to <c>*this</c>. /// </returns> /// /// <remarks> /// This method will "consume" the <c>RowProviderInterface</c> and free the resources /// that it holds. The <c>RowProviderInterface</c> is no longer valid after using /// it in this method. /// </remarks> /// const Image& operator= (RowProviderInterface* pPipe); /// <summary> /// The equals operator. /// </summary> /// /// <param name= 'image'> /// A const reference to the image to be compared. /// </param> /// /// <returns> /// This will return true of both objects refer to the same data. /// </returns> /// /// <remarks> /// While this method is provided it is not considered a reliable method for /// testing equality. /// </remarks> /// bool operator== (const Image& image) const; /// <summary> /// The not equals operator. /// </summary> /// /// <param name= 'image'> /// A const reference to the image to be compared. /// </param> /// /// <returns> /// This will return true of both objects do not refer to the same data. /// </returns> /// /// <remarks> /// While this method is provided it is not considered a reliable method for /// testing equality. /// </remarks> /// bool operator!= (const Image& image) const; /// <summary> /// This returns the size of the image in pixels. /// </summary> /// /// <returns> /// This returns a const reference to a <c>Size</c> object. /// </returns> /// const Size& size () const; /// <summary> /// This returns the size of a tile of the image in pixels. /// </summary> /// /// <returns> /// This returns a <c>Size</c> object. /// </returns> /// Size tileSize () const; /// <summary> /// This method returns a const reference to the images dataModel. It is useful /// for testing the qualities of an image. All images have a dataModel. /// </summary> /// /// <returns> /// This returns a const reference to the <c>DataModel</c> for the image. /// </returns> /// const DataModel& dataModel () const; /// <summary> /// This method will return the <c>FileReadDescriptor</c> used to create the image /// if the image was created with a <c>FileReadDescriptor</c>. The return will be /// NULL otherwise. /// </summary> /// /// <returns> /// This returns a const pointer to the <c>FileReadDescriptor</c> if one was used /// to construct the image and NULL if not. /// </returns> /// const FileReadDescriptor* fileReadDescriptor () const; /// <summary> /// This method will return the number of tiles in the image. There is always /// at least one tile in a valid image. /// </summary> /// /// <param name="nRows">A integer reference which will be set to the number of /// tiles used to hold a row of the image. /// </param> /// /// <param name="nColumns">A integer reference which will be set to the number of /// tiles used to hold a column of the image. /// </param> /// /// <returns> /// This returns the number of tiles in the image. /// </returns> /// int numTiles (int& nRows, int& nColumns) const; /// <summary> /// This method returns the clear color of the image. /// </summary> /// /// <returns> /// This returns a const reference to th <c>ImagePixel</c> that holds the clear color. /// </returns> /// const ImagePixel& clearColor () const; /// <summary> /// A new data model may be set onto an image through this method. The datamodel being /// set must be compatible with the number of bands and band width of the image data. /// </summary> /// /// <param name='dataModel'>A constant reference to a <c>DataModel</c> instance that /// will be used as the representation of the data. /// </param> /// /// <exception cref="ImageConstructionException">An exception will be thrown /// if the data type of the image is incompatible with the data model instance being set /// <see cref="ImageConstructionException"/>. /// </exception> /// void setDataModel ( const DataModel& dataModel ); /// <summary> /// This method will set the Image's clear color. /// </summary> /// /// <param name="value">An <c>ImagePixel</c> that holds the color to be /// used as the clear color. /// </param> /// /// <exception cref="ImageException">An exception will be thrown if the pixel type of the /// parameter is incompatible with the data model image <see cref="ImageException"/>. /// </exception> /// /// <remarks> /// The clear color is the color that will be return for any pixel which is not /// set with a value by the constructed image. /// </remarks> /// void setClearColor ( ImagePixel value ); /// <summary> /// Use this method to draw pixels from the <c>RowProviderInterface</c> into the image /// at the specified location. /// </summary> /// /// <param name="pPipe">An instance of a <c>RowProviderInterface</c> that will supply /// the pixel data to be drawn. The <c>RowProviderInterface</c> is consumed and freed. /// </param> /// /// <param name="at">The offset, in pixels, to the upper left corner at which the /// first pixel of the first row from the <c>RowProviderInterface</c> will be drawn. /// </param> /// /// <param name="bRespectTransparency">A defaulted(false) boolean that if true will /// cause pixels that have an alpha of 0 not to be drawn. /// </param> /// /// <remarks> /// This method will "consume" the <c>RowProviderInterface</c> and free the resources /// that it holds. The <c>RowProviderInterface</c> is no longer valid after using /// it in this method. /// </remarks> /// void paste (RowProviderInterface* pPipe, const Offset& at, bool bRespectTransparency = false); /// <summary> /// Use this method to draw pixels into an image from the passed in <c>RowProviderInterface</c> /// drawing the data with the specified alpha value. /// </summary> /// /// <param name="pPipe">An instance of a <c>RowProviderInterface</c> that will supply /// the pixel data to be drawn. The <c>RowProviderInterface</c> is consumed and freed. /// </param> /// /// <param name="at">The offset, in pixels, to the upper left corner at which the /// first pixel of the first row from the <c>RowProviderInterface</c> will be drawn. /// </param> /// /// <param name="nAlphaValue">The input alpha range should vary between 1 and 254. /// </param> /// /// <param name="bRespectTransparency">A defaulted(false) boolean that if true will /// cause pixels that have an alpha of 0 not to be drawn. /// </param> /// /// <exception cref="ImageException">An exception will be thrown if the image does /// not have a RGB data model <see cref="ImageException"/>. /// </exception> /// /// <remarks> /// This works like the <c>paste()</c> method except that it alpha blends the /// input rows into the image. /// Like <c>paste()</c> it will "consume" the <c>RowProviderInterface</c> and /// free the resources that it holds. The <c>RowProviderInterface</c> is no longer /// valid after using it in this method. /// </remarks> /// void blend (RowProviderInterface* pPipe, const Offset& at, int nAlphaValue , bool bRespectTransparency = false); /// <summary> /// This will read a sub-rectangle of data from the image returning it in a /// <c>RowProviderInterface</c> instance. /// </summary> /// /// <param name="size">The size of the sub-region of the image to be read which may /// be up to the full size of the image. /// </param> /// /// <param name="offset">The pixel offset from the upper left corner of the image /// to begin reading the requested <c>size</c> region. /// </param> /// /// <returns> /// An instance of a <c>RowProviderInterface</c> that will supply the data within /// the requested region. /// </returns> /// /// <remarks> /// The requested sub-region must be within the bounds of the image. /// </remarks> /// RowProviderInterface* read (const Size& size, const Offset& offset) const; // Orientation is an enum containing the 8 different read orientations. /// <summary> /// This will read a sub-rectangle of data from the image returning it in a /// <c>RowProviderInterface</c> instance. The data from the image will be /// re-oriented from TopDownLeftRight (normal progression) to the orientation /// passed in. /// </summary> /// /// <param name="size">The size of the sub-region of the image to be read which may /// be up to the full size of the image. /// </param> /// /// <param name="offset">The pixel offset from the upper left corner of the image /// to begin reading the requested <c>size</c> region. /// </param> /// /// <param name="orient">The orientation to be applied to the data before it is /// returned. /// </param> /// /// <returns> /// An instance of a <c>RowProviderInterface</c> that will supply the data within /// the requested region. /// </returns> /// /// <remarks> /// The requested sub-region must be within the bounds of the image. /// </remarks> /// RowProviderInterface* read (const Size& size, const Offset& offset, Atil::Orientation orient) const; /// <summary> /// This method constructs an <c>ImageContext</c> <see cref="ImageContext"/> that /// maybe used to access the pixels of an image directly. /// </summary> /// /// <param name="accessNeeded">An <c>ImageContext</c> can be opened for either /// kRead or kWrite access. ImageContexts opened with kWrite do not cache (internally) /// as aggressively as those opened with kRead. /// </param> /// /// <param name="numTilesToCache">The number of tiles to cache internal to the /// <c>ImageContext</c>. The default of 4 should be sufficient for most usages. /// </param> /// /// <returns> /// This will return either a pointer to a valid <c>ImageContext</c><see cref="ImageContext"/> /// or NULL if the method fails. The returned object must be freed when the caller /// is finished with it. /// </returns> /// /// <remarks> /// An <c>ImageContext</c> holds tiles while it exists. They should be delete'd when /// not in use to free the resources that it holds. /// </remarks> /// ImageContext* createContext (ImageContext::Access accessNeeded, int numTilesToCache = 4 ); /// <summary> /// This method constructs an <c>ImageContext</c> <see cref="ImageContext"/> that /// maybe used to access the pixels of an image directly. /// </summary> /// /// <param name="accessNeeded">An <c>ImageContext</c> can be opened for either /// kRead or kWrite access. ImageContexts opened with kWrite do not cache (internally) /// as aggressively as those opened with kRead. /// </param> /// /// <param name="size">The size of the sub-region of the image to be accessed by the /// context. /// </param> /// /// <param name="offset">The pixel offset from the upper left corner of the image /// of the requested <c>size</c> region. /// </param> /// /// <param name="numTilesToCache">The number of tiles to cache internal to the /// <c>ImageContext</c>. The default of 4 should be sufficient for most usages. /// </param> /// /// <returns> /// This will return either a pointer to a valid <c>ImageContext</c><see cref="ImageContext"/> /// or NULL if the method fails. The returned object must be freed when the caller /// is finished with it. /// </returns> /// /// <remarks> /// An <c>ImageContext</c> holds tiles while it exists. They should be delete'd when /// not in use to free the resources that it holds. /// </remarks> /// ImageContext* createContext (ImageContext::Access accessNeeded, const Size& size, const Offset& offset, int numTilesToCache = 4 ); /// <summary> /// Adds a reactor that will call the owner whenever a tile is saved. /// When a tile is saved, it is assumed to have been edited (written to). /// </summary> /// /// <param name="pReactor">An instance of a reactor to be added to the image. /// </param> /// /// <remarks> /// The <c>ImageReactorInterface</c><see cref="ImageReactorInterface"/> /// can be derived from to track changes in the image. /// </remarks> /// void addReactor ( ImageReactorInterface* pReactor ); /// <summary> /// Removes the reactor that had previously been added to the image. /// </summary> /// /// <param name="pReactor">The instance of a reactor to be removed from the image. /// </param> /// void removeReactor ( ImageReactorInterface* pReactor ); /// <summary> /// This method disables per tile locking. ATIL implements per tile locking for /// read and write. This option is provided as an optimization for instances in /// which a developer can guarantee single-threaded usage. Use it carefully. /// </summary> /// /// <param name= 'bDisable'> /// The boolean will disable per tile locking if set to true. /// </param> /// /// <returns> /// This will return true if per tile locking is disabled. /// </returns> /// bool disablePerTileLocking ( bool bDisable ); /// <summary> /// This method will cause all pixels of the image to be set to the image's /// internal clear color. /// </summary> /// void clear (); /// <summary> /// This method will return true if there is valid data within the image. /// </summary> /// /// <returns> /// This will return true if the image is valid. /// </returns> /// bool isValid () const; /// <summary> /// This method will be set to true if data has been set into the image /// after construction. There is no way to reset it. /// </summary> /// /// <returns> /// This will return true if the image has been written to. /// </returns> /// bool isModified () const; /// <summary> /// This method will return true if the "user buffer" method of construction /// was used to create the image. /// </summary> /// /// <returns> /// This will return true if a "user buffer" was use to construct the image. /// </returns> /// bool usesUserBuffer () const; /// <summary> /// This method will return a pointer to the "user buffer" used to construct /// the image. /// </summary> /// /// <returns> /// This will return the "user buffer" pointer used to construct the image. /// </returns> void* getUserBuffer (); private: ImageRep* mImplementation; }; Atil::Image没有这个getPixel函数啊,你看看Atil::Image定义image->getPixel(x, y);应该怎么修改
最新发布
10-28
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值