Re: basic auth request
On 2021-08-22 05:04:43 +1000, Chris Angelico wrote: > On Sun, Aug 22, 2021 at 4:55 AM Martin Di Paola > wrote: > > > > While it is correct to say that Basic Auth without HTTPS is absolutely > > insecure, using Basic Auth *and* HTTPS is not secure either. > > > > Well, the definition of "secure" depends of your threat model. > > Yes. Which makes statements like "not secure" rather suspect :) Right. > > HTTPS ensures encryption so the content, including the Basic Auth > > username and password, is secret for any external observer. > > > > But it is *not* secret for the receiver (the server): if it was > > compromised an adversary will have access to your password. It is much > > easier to print a captured password than cracking the hashes. > > > > Other authentication mechanisms exist, like OAuth, which are more > > "secure". OAuth is "an /authorization protocol/, rather than an /authentication protocol/" [Wikipedia]. > If your server is compromised in that way, *all is lost*. If "you" are the service provider, yes. but if "you" are the user, no. From a user's perspective "all" is much more than the data (including username and password) associated with that particular service. So if one service is compromised, not all is lost, but only a bit (of course, depending on the importance of the service, that bit may be little or big; a random web forum probably doesn't matter. Your bank account probably does). So assuming that many people reuse passwords (which of course they shouldn't and thanks to password is becoming rarer, but is still distressingly common), there are three levels of security (from highest to lowest) in this scenario: 1: The secret known to the user is never transmitted to the server at all, the client only proves that the secret is known. This is the case for TLS client authentication (which AFAIK all browsers support but is a real pain in the ass to set up, so it's basically never used) and for SCRAM (which isn't part of HTTP(S) but could be implemented in JavaScript). 2: The secret is transmitted on login but never stored. This limits the damage to users who logged in while the server was compromised. This is the case for Basic Authentication combined with a probperly salted hashed storage. 3: The secret is stored on the server. When the server is compromised, all user's passwords are known. This is (AFAIK) the case for Digest and NTLM. So given the choice between Basic Auth and Digest or NTLM (over HTTPS in all cases) I would prefer Basic Auth. Ideally I would use SCRAM or a public key method, but I admit that my security requirements were never high enough to actually bother to do that (actually, I used SSL client side auth once, 20 years ago, ...). hp -- _ | Peter J. Holzer| Story must make more sense than reality. |_|_) || | | | h...@hjp.at |-- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" signature.asc Description: PGP signature -- https://mail.python.org/mailman/listinfo/python-list
Re: basic auth request
On Sun, Aug 22, 2021 at 6:45 PM Peter J. Holzer wrote: > > On 2021-08-22 05:04:43 +1000, Chris Angelico wrote: > > On Sun, Aug 22, 2021 at 4:55 AM Martin Di Paola > > wrote: > > > HTTPS ensures encryption so the content, including the Basic Auth > > > username and password, is secret for any external observer. > > > > > > But it is *not* secret for the receiver (the server): if it was > > > compromised an adversary will have access to your password. It is much > > > easier to print a captured password than cracking the hashes. > > > > > > Other authentication mechanisms exist, like OAuth, which are more > > > "secure". > > OAuth is "an /authorization protocol/, rather than an /authentication > protocol/" [Wikipedia]. > > > If your server is compromised in that way, *all is lost*. > > If "you" are the service provider, yes. but if "you" are the user, no. If "your server" is compromised, then you are the service provider, are you not? I'm not sure what "your server" would mean if "you" are the user. But okay. Suppose I log in to Random Service 1, using a user name and password, and also to Random Service 2, using OAuth. What happens if those servers get compromised? 1) Someone knows the login credentials that I created for that service. If I've used the same password that I also use at my bank, then I am in big trouble. It is, largely, my fault. 2) Someone has access to my login token and the client ID/secret associated with it. That attacker can now impersonate me to the OAuth provider, to the exact extent that the scopes permit. At absolute least, the attacker gets to know a lot about who I am on some entirely separate service. I'm talking here about a complete and utter compromise, the sort where neither SSL encryption nor proper password hashing would protect my details, since that's what was being claimed. Which is actually worse? Is it as clear-cut? > From a user's perspective "all" is much more than the data (including > username and password) associated with that particular service. So if > one service is compromised, not all is lost, but only a bit (of course, > depending on the importance of the service, that bit may be little or > big; a random web forum probably doesn't matter. Your bank account > probably does). > > So assuming that many people reuse passwords (which of course they > shouldn't and thanks to password is becoming rarer, but is still > distressingly common), True, but reuse of passwords is something under the user's control. OAuth scope selection is partly under the service's control, and partly under the provider's (some providers have extremely coarse scopes, widening the attack). > there are three levels of security (from highest > to lowest) in this scenario: > > 1: The secret known to the user is never transmitted to the server at >all, the client only proves that the secret is known. This is the >case for TLS client authentication (which AFAIK all browsers support >but is a real pain in the ass to set up, so it's basically never >used) and for SCRAM (which isn't part of HTTP(S) but could be >implemented in JavaScript). This would be great, if nobody minded (a) setting up a unique client certificate for every site, or (b) allowing the ultimate in remote tracking cookie whereby any server could recognize you by your TLS certificate. > 2: The secret is transmitted on login but never stored. This limits the >damage to users who logged in while the server was compromised. This >is the case for Basic Authentication combined with a probperly salted >hashed storage. Current best prac, and what I'd generally recommend to most people. > 3: The secret is stored on the server. When the server is compromised, >all user's passwords are known. This is (AFAIK) the case for Digest >and NTLM. I'm not sure what the effects of wide-spread Digest/NTLM usage would have on password managers and the risks of compromise to them, but the way things currently are, I would prefer salted/hashed passwords, such that a data breach doesn't mean compromise of all historical data. > So given the choice between Basic Auth and Digest or NTLM (over HTTPS in > all cases) I would prefer Basic Auth. Ideally I would use SCRAM or a > public key method, but I admit that my security requirements were never > high enough to actually bother to do that (actually, I used SSL client > side auth once, 20 years ago, ...). > I would, of course, prefer something like form fill-out over Basic, but that's due to UI concerns rather than security ones. SCRAM seems tempting, but in a context of web browsers, I'm not sure that it would be worth the hassle. When it comes to security, one thing I'm very curious about is why we don't have any sort of certificate renewal verification. My browser could retain the certificates of some web site (or of all web sites, even - they're not THAT large), and if the site presents a different cert, it could show the previously retained one
Re: basic auth request
> On 22 Aug 2021, at 10:37, Chris Angelico wrote: > > When it comes to security, one thing I'm very curious about is why we > don't have any sort of certificate renewal verification. My browser > could retain the certificates of some web site (or of all web sites, > even - they're not THAT large), and if the site presents a different > cert, it could show the previously retained one and challenge the > server "prove that you're the same guy". This proof would consist of > the latest cert, signed by the older cert's key (or possibly a chain > that can construct such a proof, which would allow the server to > simply retain each new cert signed by the one previous cert, forming a > line - or a tree if necessary). My suspicion is that it'd add little > above simply having a valid cert, but if people are paranoid, surely > that's a better place to look? The web site proves it owners the hostname and/or IP address using its certificate. You use your trust store to show that you can trust that certificate. The fact that a certificate changes is not a reason to stop trusting a site. So it does not add anything. The pain point in PKI is revocation. The gold standard is for a web site to use OCSP stapling. But that is rare sadly. And because of issues with revocation lists, (privacy, latency, need to fail open on failiure, DoD vector, etc) this is where the paranoid should look. Barry -- https://mail.python.org/mailman/listinfo/python-list
from foo import bar and the ast module
In 'from foo import bar': With the ast module, I see how to get bar, but I do not yet see how to get the foo. There are clearly ast.Import and ast.ImportFrom, but I do not see the foo part in ast.ImportFrom. ? Thanks! -- https://mail.python.org/mailman/listinfo/python-list
Re: from foo import bar and the ast module
On Mon, Aug 23, 2021 at 12:08 AM Dan Stromberg wrote: > > In 'from foo import bar': > > With the ast module, I see how to get bar, but I do not yet see how to get > the foo. > > There are clearly ast.Import and ast.ImportFrom, but I do not see the foo > part in ast.ImportFrom. > > ? >>> import ast >>> ast.dump(ast.parse("from foo import bar")) "Module(body=[ImportFrom(module='foo', names=[alias(name='bar')], level=0)], type_ignores=[])" >>> ast.parse("from foo import bar").body[0].module 'foo' ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: from foo import bar and the ast module
On Sun, Aug 22, 2021 at 7:14 AM Chris Angelico wrote: > On Mon, Aug 23, 2021 at 12:08 AM Dan Stromberg > wrote: > > > > In 'from foo import bar': > > > > With the ast module, I see how to get bar, but I do not yet see how to > get > > the foo. > > > > There are clearly ast.Import and ast.ImportFrom, but I do not see the foo > > part in ast.ImportFrom. > > > > ? > > >>> import ast > >>> ast.dump(ast.parse("from foo import bar")) > "Module(body=[ImportFrom(module='foo', names=[alias(name='bar')], > level=0)], type_ignores=[])" > >>> ast.parse("from foo import bar").body[0].module > 'foo' > With 'from . import bar', I get a module of None. Does this seem strange? -- https://mail.python.org/mailman/listinfo/python-list
Re: from foo import bar and the ast module
On Mon, Aug 23, 2021 at 12:26 AM Dan Stromberg wrote: > > > On Sun, Aug 22, 2021 at 7:14 AM Chris Angelico wrote: >> >> On Mon, Aug 23, 2021 at 12:08 AM Dan Stromberg wrote: >> > >> > In 'from foo import bar': >> > >> > With the ast module, I see how to get bar, but I do not yet see how to get >> > the foo. >> > >> > There are clearly ast.Import and ast.ImportFrom, but I do not see the foo >> > part in ast.ImportFrom. >> > >> > ? >> >> >>> import ast >> >>> ast.dump(ast.parse("from foo import bar")) >> "Module(body=[ImportFrom(module='foo', names=[alias(name='bar')], >> level=0)], type_ignores=[])" >> >>> ast.parse("from foo import bar").body[0].module >> 'foo' > > > With 'from . import bar', I get a module of None. > > Does this seem strange? > No; it's just the AST so it can't bring in any additional information. To distinguish package-relative imports, use the level attribute: >>> ast.dump(ast.parse("from . import bar").body[0]) "ImportFrom(names=[alias(name='bar')], level=1)" >>> ast.dump(ast.parse("from .foo import bar").body[0]) "ImportFrom(module='foo', names=[alias(name='bar')], level=1)" >>> ast.dump(ast.parse("from foo.bar import bar").body[0]) "ImportFrom(module='foo.bar', names=[alias(name='bar')], level=0)" >>> ast.dump(ast.parse("from .foo.bar import bar").body[0]) "ImportFrom(module='foo.bar', names=[alias(name='bar')], level=1)" >>> ast.dump(ast.parse("from ..foo.bar import bar").body[0]) "ImportFrom(module='foo.bar', names=[alias(name='bar')], level=2)" ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: on perhaps unloading modules?
Hope Rouselle writes: > Chris Angelico writes: > >> On Tue, Aug 17, 2021 at 4:02 AM Greg Ewing >> wrote: >>> The second best way would be to not use import_module, but to >>> exec() the student's code. That way you don't create an entry in >>> sys.modules and don't have to worry about somehow unloading the >>> module. >> >> I would agree with this. If you need to mess around with modules and >> you don't want them to be cached, avoid the normal "import" mechanism, >> and just exec yourself a module's worth of code. > > Sounds like a plan. Busy, haven't been able to try it out. But I will. > Soon. Thank you! Just to close off this thread, let me share a bit of what I wrote. The result is a lot better. Thanks for all the help! I exec the student's code into a dictionary g. --8<---cut here---start->8--- def fs_read(fname): with open(fname, "r") as f: return f.read() def get_student_module_exec(fname): g = {} try: student_code = fs_read(fname) student = exec(student_code, g) except Exception as e: return False, str(e) return True, g def get_student_module(fname): return get_student_module_exec(fname) --8<---cut here---end--->8--- And now write the test's key as if I were a student and named my test as "test_key.py". --8<---cut here---start->8--- def get_key(): okay, k = get_student_module("test_key.py") if not okay: # Stop everything. ... return g --8<---cut here---end--->8--- The procedure for grading a question consumes the student's code as a dictionary /s/, grabs the key as /k/ and checks whether the procedures are the same. So, suppose I want to check whether a certain function /fn/ written in the student's dictionary-code /s/ matches the key's. Then I invoke check_student_procedure(k, s, fn). --8<---cut here---start->8--- def check_student_procedure(k, s, fn, args = [], wrap = identity): return check_functions_equal(g[fn], s.get(fn, None), args, wrap) --8<---cut here---end--->8--- For completeness, here's check_functions_equal. --8<---cut here---start->8--- def check_functions_equal(fn_original, fn_candidate, args = [], wrap = identity): flag, e = is_function_executable(fn_candidate, args) if not flag: return False, "runtime", e # run original and student's code, then compare them answer_correct = fn_original(*args) answer_student = wrap(fn_candidate(*args)) if answer_correct != answer_student: return False, None, str(answer_student) return True, None, None def identity(x): return x --8<---cut here---end--->8--- To explain my extra complication there: sometimes I'm permissive with student's answers. Suppose a question requires a float as an answer but in some cases the answer is a whole number --- such as 1.0. If the student ends up producing an int, the student gets that case right: I wrap the student's answer in a float() and the check turns out successful. I probably don't need to check whether a procedure is executable first, but I decided to break the procedure into two such steps. --8<---cut here---start->8--- def is_function_executable(f, args = []): try: f(*args) except Exception as e: return False, str(e) return True, None --8<---cut here---end--->8--- -- https://mail.python.org/mailman/listinfo/python-list
Re: basic auth request
On Sun, Aug 22, 2021 at 8:30 PM Barry Scott wrote: > > > > On 22 Aug 2021, at 10:37, Chris Angelico wrote: > > When it comes to security, one thing I'm very curious about is why we > don't have any sort of certificate renewal verification. My browser > could retain the certificates of some web site (or of all web sites, > even - they're not THAT large), and if the site presents a different > cert, it could show the previously retained one and challenge the > server "prove that you're the same guy". This proof would consist of > the latest cert, signed by the older cert's key (or possibly a chain > that can construct such a proof, which would allow the server to > simply retain each new cert signed by the one previous cert, forming a > line - or a tree if necessary). My suspicion is that it'd add little > above simply having a valid cert, but if people are paranoid, surely > that's a better place to look? > > > The web site proves it owners the hostname and/or IP address using its > certificate. > You use your trust store to show that you can trust that certificate. > > The fact that a certificate changes is not a reason to stop trusting a site. > > So it does not add anything. > > The pain point in PKI is revocation. The gold standard is for a web site to > use OCSP stapling. > But that is rare sadly. And because of issues with revocation lists, > (privacy, latency, need to > fail open on failiure, DoD vector, etc) this is where the paranoid should > look. > Fair point. Let me give you a bit of context. Recently, the owner/operator of a site (I'll call it https://demo.example/ ) died. Other people, who have been using the site extensively, wish for it to continue. If the domain registration expires, anyone can reregister it, and can then generate a completely new certificate for the common name "demo.example", and web browsers will accept that. The old cert may or may not have expired, but it won't be revoked. As far as I can tell, a web browser with default settings will happily accept the change of ownership. It won't care that the IP address, certificate, etc, have all changed. It just acknowledges that some CA has signed some certificate with the right common name. And therein is the vulnerability. (NOTE: I'm not saying that this is a real and practical vulnerability - this is theoretical only, and a focus for the paranoid.) This is true even if the old cert were one of those enhanced certificates that some CAs try to upsell you to ("Extended Validation" and friends). Even if, in the past, your bank was secured by one of those certs, your browser will still accept a perfectly standard cert next time. Which, in my opinion, renders those (quite pricey) certificates no more secure than something from Let's Encrypt that has no validation beyond ownership of DNS. Of course, you can pin a certificate. You can ask your browser to warn you if it's changed *at all*. But since certs expire, that's highly impractical, hence wondering why we don't have a system for using the old cert to prove ownership of the new one. So how is a web browser supposed to distinguish between (a) normal operation in which certs expire and are replaced, and (b) legit or non-legit ownership changes? (Of course the browser can't tell you whether the ownership change is legit, but out-of-band info can help with that.) Or does it really matter that little? ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: on perhaps unloading modules?
On Sat, 21 Aug 2021 17:15:14 -0300, Hope Rouselle declaimed the following: >write some PHP precisely because it looked so much more cryptic than >Allaire ColdFusion. Then C looked even more cryptic, so I fell in love >with C. > Try APL then... (I suspect this will get garbaged in processing...) 4 5 ? 20 ? 52 (it did... the first ? [in my display] is Greek lower case rho, the second question mark is... a question mark). 4 5 $RHO 20 ? 52 Generate 20 random numbers in the range 1..52, no duplicates, reshape the vector into a 4x5 matrix. That just "dealt" four poker hands (needs logic to translate integer 1..52 into suit/rank). -- Wulfraed Dennis Lee Bieber AF6VN wlfr...@ix.netcom.comhttp://wlfraed.microdiversity.freeddns.org/ -- https://mail.python.org/mailman/listinfo/python-list
PyQt5 is not recognized from python 3.8 installation in python 3.10
Hi guys, I have on my laptop the python installation 3.8 and newly I installed newest version 3.10 as well on my laptop. Now I have two IDLEs for both of the installations. When I rund some *.py file, having PyQt5 module, on the 3.8 version, it works as before without any problems. But whenn I run the same file on IDLE with 3.10 installation, it crashes and says that PyQt5 is not known. I tried to install this package with"pip install pyqt5" or with "py -3 -m pip install pyqt5", it brings lots of error messages (long long) as the lines below (they are only the beginning of the messages): == C:\Users\Mohsen>py -3 -m pip install pyqt5 Collecting pyqt5 Using cached PyQt5-5.15.4.tar.gz (3.3 MB) Installing build dependencies ... done Getting requirements to build wheel ... done Preparing wheel metadata ... error ERROR: Command errored out with exit status 1: command: 'C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\python.exe' 'C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py' prepare_metadata_for_build_wheel 'C:\Users\Mohsen\AppData\Local\Temp\tmprax0esmt' cwd: C:\Users\Mohsen\AppData\Local\Temp\pip-install-wl_b58e9\pyqt5_1cbd1bab46fa4abaad34b55514561ce6 Complete output (33 lines): Querying qmake about your Qt installation... C:\Qt\4.7.4\bin\qmake.exe -query Traceback (most recent call last): File "C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py", line 143, in prepare_metadata_for_build_wheel hook = backend.prepare_metadata_for_build_wheel AttributeError: module 'sipbuild.api' has no attribute 'prepare_metadata_for_build_wheel' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py", line 349, in main() File "C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py", line 331, in main json_out['return_val'] = hook(**hook_input['kwargs']) == It begins with "PyQt5-5.15.4.tar.gz" and goes down "PyQt5-5.15.3.tar.gz" and so on, after it cannot install that version. After it reaches the "PyQt5-5.14.0.tar.gz" it breaks the downloading and bring this message == WARNING: Discarding https://files.pythonhosted.org/packages/3a/fb/eb51731f2dc7c22d8e1a63ba88fb702727b324c6352183a32f27f73b8116/PyQt5-5.14.1.tar.gz#sha256=2f230f2dbd767099de7a0cb915abdf0cbc3256a0b5bb910eb09b99117db7a65b (from https://pypi.org/simple/pyqt5/) (requires-python:>=3.5). Command errored out with exit status 1: 'C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\python.exe' 'C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py' prepare_metadata_for_build_wheel 'C:\Users\Mohsen\AppData\Local\Temp\tmp6t_i9jm7' Check the logs for full command output. Downloading PyQt5-5.14.0.tar.gz (3.2 MB) || 3.2 MB 3.3 MB/s ERROR: pyqt5 from https://files.pythonhosted.org/packages/7c/5b/e760ec4f868cb77cee45b4554bf15d3fe6972176e89c4e3faac941213694/PyQt5-5.14.0.tar.gz#sha256=0145a6b7de15756366decb736c349a0cb510d706c83fda5b8cd9e0557bc1da72 has a pyproject.toml file that does not comply with PEP 518: 'build-system.requires' contains an invalid requirement: 'sip >=5.0.1 <6' == What is wrong with my installations. How can I get all the packages available in 3.8 version also available for 3.10 version without any new installation in 3.10 for each all already existing packages? Thanks a lot in advance for you contributions. Mohsen -- https://mail.python.org/mailman/listinfo/python-list
Re: on perhaps unloading modules?
On 2021-08-22 17:18, Dennis Lee Bieber wrote: On Sat, 21 Aug 2021 17:15:14 -0300, Hope Rouselle declaimed the following: write some PHP precisely because it looked so much more cryptic than Allaire ColdFusion. Then C looked even more cryptic, so I fell in love with C. Try APL then... (I suspect this will get garbaged in processing...) 4 5 ? 20 ? 52 4 5 ρ 20 ? 52 (it did... the first ? [in my display] is Greek lower case rho, the second question mark is... a question mark). The headers say that the encoding is ASCII. 4 5 $RHO 20 ? 52 Generate 20 random numbers in the range 1..52, no duplicates, reshape the vector into a 4x5 matrix. That just "dealt" four poker hands (needs logic to translate integer 1..52 into suit/rank). -- https://mail.python.org/mailman/listinfo/python-list
Re: PyQt5 is not recognized from python 3.8 installation in python 3.10
On Mon, Aug 23, 2021 at 4:31 AM Mohsen Owzar wrote: > How can I get all the packages available in 3.8 version also available for > 3.10 version without any new installation in 3.10 for each all already > existing packages? > You can't. With compiled binaries, especially, it's important to install into each version separately - there can be minor differences which will be taken care of by the installer. Normally, that's not a problem, other than that you have to install each one again; the best way would be to keep track of your package dependencies in a file called requirements.txt, and then you can simply install from that (python3 -m pip install -r requirements.txt) into the new version. As to PyQt5 specifically, though I don't know what the issue here is, but I tried it on my system and it successfully installed version 5.15.4. Are you using the latest version of pip? There might be some other requirements. Alternatively, I'm seeing a potential red flag from this line: > C:\Qt\4.7.4\bin\qmake.exe -query You're trying to install Qt5, but maybe it's coming across a Qt4 installation? Not sure if that's significant or not. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: PyQt5 is not recognized from python 3.8 installation in python 3.10
On 8/22/21 7:04 AM, Mohsen Owzar wrote: Hi guys, I have on my laptop the python installation 3.8 and newly I installed newest version 3.10 as well on my laptop. Now I have two IDLEs for both of the installations. When I rund some *.py file, having PyQt5 module, on the 3.8 version, it works as before without any problems. But whenn I run the same file on IDLE with 3.10 installation, it crashes and says that PyQt5 is not known. I tried to install this package with"pip install pyqt5" or with "py -3 -m pip install pyqt5", it brings lots of error messages (long long) as the lines below (they are only the beginning of the messages): make sure you're getting the right Python by doing py -3.10 -m pip install pyqt5 (the fact you're getting the build error below indicates you _are_ getting the right one, but it's good to be explicit anyway, just so you're sure). == C:\Users\Mohsen>py -3 -m pip install pyqt5 Collecting pyqt5 Using cached PyQt5-5.15.4.tar.gz (3.3 MB) Installing build dependencies ... done Getting requirements to build wheel ... done Preparing wheel metadata ... error ERROR: Command errored out with exit status 1: command: 'C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\python.exe' 'C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py' prepare_metadata_for_build_wheel 'C:\Users\Mohsen\AppData\Local\Temp\tmprax0esmt' cwd: C:\Users\Mohsen\AppData\Local\Temp\pip-install-wl_b58e9\pyqt5_1cbd1bab46fa4abaad34b55514561ce6 Complete output (33 lines): Querying qmake about your Qt installation... C:\Qt\4.7.4\bin\qmake.exe -query Traceback (most recent call last): File "C:\Users\Mohsen\AppData\Local\Programs\Python\Python310\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py", line 143, in prepare_metadata_for_build_wheel hook = backend.prepare_metadata_for_build_wheel AttributeError: module 'sipbuild.api' has no attribute 'prepare_metadata_for_build_wheel' Your problem here is that there's no released binary wheel for PyQt5, since Py 3.10 isn't released (there's been some recent chatter about encouraging projects to make builds for new Python versions available early, e.g. once a Python version hits release candidate state, but that's just that - chatter - for now). In theory your system should be able to build it, but my experience is that unless you're an active Python developer on Windows and already have the right working setup, it pretty much always fails. These are the perils of trying to use a pre-release... That error suggests there's something different going on than usual (which has to do with the MSVC compiler suite not being set up the way the package expects): there looks like a version mismatch - it looks like it's finding qmake for Qt4, not Qt5. Maybe you can make some progress by adjusting some paths? Many people go here to get early-access, albeit unofficial, binary wheels: https://www.lfd.uci.edu/~gohlke/pythonlibs Unfortunately, PyQt5 is not available from there (as listed in the section at the very bottom) -- https://mail.python.org/mailman/listinfo/python-list