Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unix-only crypt should not be present on Windows. #69359

Closed
terryjreedy opened this issue Sep 19, 2015 · 40 comments
Closed

Unix-only crypt should not be present on Windows. #69359

terryjreedy opened this issue Sep 19, 2015 · 40 comments
Labels
3.8 only security fixes 3.9 only security fixes easy OS-windows stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@terryjreedy
Copy link
Member

BPO 25172
Nosy @terryjreedy, @pfmoore, @tjguk, @zware, @zooba, @miss-islington, @shireenrao
PRs
  • bpo-25172: Raise appropriate ImportError msg when crypt module used on Windows #15149
  • [3.8] bpo-25172: Raise appropriate ImportError msg when crypt module used on Windows (GH-15149) #15182
  • bpo-25172: Add test for crypt ImportError msg for Windows #15252
  • [3.8] bpo-25172: Add test for crypt ImportError on Windows (GH-15252) #15263
  • bpo-25172: Reduce scope of crypt import tests #17881
  • [3.8] bpo-25172: Reduce scope of crypt import tests (GH-17881) #17922
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2020-01-09.17:40:12.788>
    created_at = <Date 2015-09-19.00:49:31.196>
    labels = ['easy', 'type-bug', '3.8', '3.9', 'library', 'OS-windows']
    title = 'Unix-only crypt should not be present on Windows.'
    updated_at = <Date 2020-01-09.17:40:12.788>
    user = 'https://github.com/terryjreedy'

    bugs.python.org fields:

    activity = <Date 2020-01-09.17:40:12.788>
    actor = 'steve.dower'
    assignee = 'none'
    closed = True
    closed_date = <Date 2020-01-09.17:40:12.788>
    closer = 'steve.dower'
    components = ['Library (Lib)', 'Windows']
    creation = <Date 2015-09-19.00:49:31.196>
    creator = 'terry.reedy'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 25172
    keywords = ['patch', 'easy', 'newcomer friendly']
    message_count = 40.0
    messages = ['251046', '348935', '349097', '349111', '349114', '349115', '349116', '349117', '349118', '349125', '349129', '349130', '349138', '349143', '349251', '349252', '349253', '349254', '349256', '349257', '349258', '349259', '349262', '349265', '349275', '349566', '349568', '349569', '349615', '349619', '349620', '349621', '349623', '349624', '356914', '358170', '359467', '359469', '359686', '359688']
    nosy_count = 8.0
    nosy_names = ['terry.reedy', 'paul.moore', 'jafo', 'tim.golden', 'zach.ware', 'steve.dower', 'miss-islington', 'shireenrao']
    pr_nums = ['15149', '15182', '15252', '15263', '17881', '17922']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue25172'
    versions = ['Python 3.8', 'Python 3.9']

    @terryjreedy
    Copy link
    Member Author

    Except for crypt, all the modules labeled 'Unix' or 'Linux' on the module index https://docs.python.org/3/py-modindex.html are absent from /Lib on Windows. 'import xyz' fails with "ImportError: no module named 'zyz'". (I presume the same is true on unix for Windows-only modules.)

    However, crypt is present, and 'import crypt' fails with "...'_crypt'", leading one to think that the C accelerator should be present but is not. Assuming that _crypt should (cannot) not be present, please add crypt to the list of modules omitted from the Windows installer, however this is done. And if 'unix-only' is obsolete and _crypt should be present, please fix this instead. ;-)

    This is 3.x issue only, as crypt is not present in my Windows 2.7.10 /Lib. The fact that is was somehow added to some 3.x prompted me to look and see if there is anything useful without _crypt present. I think not.

    @terryjreedy terryjreedy added stdlib Python modules in the Lib dir OS-windows labels Sep 19, 2015
    @serhiy-storchaka serhiy-storchaka added 3.7 (EOL) end of life type-bug An unexpected behavior, bug, or error labels Oct 24, 2017
    @zooba
    Copy link
    Member

    zooba commented Aug 2, 2019

    Marking this easy/newcomer friendly.

    This should catch the ModuleNotFoundError raised when _crypt is missing and raise a more informative ImportError saying that crypt is unsupported.

    All the other modules that are missing are native extension modules that are not built - this is the only one that is a .py file. We don't exclude any other Lib\*.py files from the distribution.

    @zooba zooba added easy 3.8 only security fixes 3.9 only security fixes and removed 3.7 (EOL) end of life labels Aug 2, 2019
    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 6, 2019

    Hello
    I would like to work on this issue. First time contributor here. Would putting the import _crypt statement on line 3 in crypt.py inside a try/except block and checking to see if platform is windows then give an appropriate message be a good fix?

    Thank you
    -Srinivas

    @zooba
    Copy link
    Member

    zooba commented Aug 6, 2019

    That sounds good to me, though you may want to propose the error message here first so we can get the wording right - probably not everyone will be watching github PR.

    It probably makes sense to raise a different error message on platforms where we do expect it to have been built - the same confusion could arise there.

    Some starting points (that will likely need improvement):

    win32: raise ImportError("The crypt module is not supported on Windows")

    not win32: raise ImportError("The required _crypt module was not built as part of CPython")

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 6, 2019

    What is the recommended way to check for platform in cpython? Is it using the sys module or os module? As for the error messages I couldn't think of anything better then what you suggested :).

    win32: raise ImportError("The crypt module is not supported on Windows")

    not win32: raise ImportError("The required _crypt module was not built as part of CPython")

    @zooba
    Copy link
    Member

    zooba commented Aug 6, 2019

    sys.platform is the value that reflects how Python was compiled - sys.platform == 'win32' means compiled for Windows. And since this issue is related to compilation, it makes the most sense to use sys.

    (os.name is also based on compilation, but it really only reflects the POSIX implementation in use, which is why sys is better.)

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 6, 2019

    Sounds good. Can I submit my PR now?

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 6, 2019

    I forgot to ask about tests? I see there is test_crypt.py under Lib\test. Do you have any thoughts on how to test this?

    @zooba
    Copy link
    Member

    zooba commented Aug 6, 2019

    Can I submit my PR now?

    Sure, though if others want to weigh in on wording they should feel free to do it here.

    I forgot to ask about tests? I see there is test_crypt.py under Lib\test. Do you have any thoughts on how to test this?

    It should continue to "successfully" skip tests when _crypt isn't built. So as long as you raise ImportError, this should be fine.

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 6, 2019

    The proposed wording seems good to me.

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 6, 2019

    Sorry, I should have waited 1 day after submitting the CLA before submitting the PR. The system is waiting for my CLA to be cleared.

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 6, 2019

    It might be worth adding a test (running only on Windows) to confirm that if you try to import crypt you get an import error with a message that includes the phrase "not supported". That will ensure that we don't get regressions here in future, while still not tying us too strictly to the exact wording.

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 6, 2019

    How do I write tests which only run for a given platform? Looking at test_crypt.py, I see that the crypt module is imported using test.support module so the exception will be raised even before the tests run. Is there a way to test imports?

    @terryjreedy
    Copy link
    Member Author

    I agree with Paul about the wording. Note that the proposed platform-specific catch and raise are for crypt.py, not test_crypt.py.

    If a test module should be skipped entirely, import_module is correct. For more refinement, test_idle has, for example,

    tk = import_module('tkinter')  # Also imports _tkinter.
    if tk.TkVersion < 8.5:
        raise unittest.SkipTest("IDLE requires tk 8.5 or later.")

    Testing only continues if tkinter and _tkinter and tk >= 8.5.

    I presume that crypt = import_module('crypt') will only continue if crypt and _crypt, which is what you want. It is apparently not an error for _crypt to be missing on unix, just an inconvenience for people who expect it.

    FYI, Individual test classes and methods can be skipped with
    @unittest.skipIf(condition, message) # example
    @unittest.skipIf(sys.platform != 'darwin', 'test macOS-only code')
    See the unittest doc for more, though apparently not needed here.

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 8, 2019

    New changeset f4e725f by Paul Moore (shireenrao) in branch 'master':
    bpo-25172: Raise appropriate ImportError msg when crypt module used on Windows (GH-15149)
    f4e725f

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 8, 2019

    On reflection, adding a test for the Windows-specific behaviour looks like it could be more complex than I'd anticipated, so I'm happy for this to go in without an extra test. I'll look at adding a test in a follow-up PR (or if someone else wants to, that's fine as well).

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 8, 2019

    I am curious how one would create a test for this? Would this be a new test script? The new script would skip if platform not win32 and the test case would be to import the crypt module and check for "not supported" string in the ImportError?

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 8, 2019

    That's where I decided it was too complex for now :-)

    The whole test_crypt.py file is skipped if you can't import crypt, via the use of the test.support.import_module() function. To be able to write a test for a platform where the whole point is that you can't import crypt, you'd have to rewrite that. So you'd get something like

    try:
    import crypt
    except ImportError as e:
    if sys.platform == "win32":
    assert "not supported" in e.msg
    raise unittest.SkipTest("crypt is not present on this platform")

    But you can't use "assert" like that in top-level code (or at least I don't think you can - I'm not that familiar with unittest, but I think assertions have to live in classes in unittest).

    At this point I gave up. It starts to be quite a big rewrite for a relatively minor benefit.

    The alternative would be, if there was a "Windows-specific tests" test module, we could have put a test for this situation in there. But I don't think there is such a module.

    @zooba
    Copy link
    Member

    zooba commented Aug 8, 2019

    The alternative would be, if there was a "Windows-specific tests" test module, we could have put a test for this situation in there

    Maybe test___all__?

    @zooba
    Copy link
    Member

    zooba commented Aug 8, 2019

    Or better yet (since my last suggestion was bad), add a second test class to test_crypt

    try:
    import crypt
    IMPORT_ERROR = None
    except ImportError as ex:
    crypt = None
    IMPORT_ERROR = str(ex)

    @skipIf(crypt)
    class TestWhyCryptDidNotImport(TestCase):
        ...
    
    @skipUnless(crypt)
    class CryptTestCase(TestCase):
        ...

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 8, 2019

    Are you suggesting using the try/except block instead of import_module in test_crypt.py

    @zooba
    Copy link
    Member

    zooba commented Aug 8, 2019

    Yes. support.import_module is going to raise a skip when the module can't be imported, but we want to handle ImportError differently.

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 8, 2019

    Can I have a go at it? Do I need to open a new issue to post a new PR?

    @zooba
    Copy link
    Member

    zooba commented Aug 8, 2019

    Sure. You can post a new PR with the same bug number (and it won't need a NEWS file this time).

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 9, 2019

    When I try to put the skipUnless decorator on CryptTestCase, I am still seeing a failure when I try to run this. The error is -
    File "C:\Users\srao\projects\cpython\lib\test\test_crypt.py", line 59, in CryptTestCase
    @unittest.skipUnless(crypt.METHOD_SHA256 in crypt.methods or
    AttributeError: 'NoneType' object has no attribute 'METHOD_SHA256'

    Line 59 is the following decorator and method -
    @unittest.skipUnless(crypt.METHOD_SHA256 in crypt.methods or
    crypt.METHOD_SHA512 in crypt.methods,
    'requires support of SHA-2')
    def test_sha2_rounds(self):

    I tried a simple @Skip decorator and that too fails on the same error. The class level skip is not helping here. Does it make sense to create a different test file for windows?

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 13, 2019

    I submitted a new PR for the Windows test case. Please take a look. Also how do I attach the label "skip news" to this new PR?

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 13, 2019

    I added the label for you.

    @pfmoore
    Copy link
    Member

    pfmoore commented Aug 13, 2019

    To clarify, I think adding the label needs core dev (or maybe triager) rights on github, so I don't think it's something you can do yourself.

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 13, 2019

    Thank you @paul.moore

    @miss-islington
    Copy link
    Contributor

    New changeset 7f7f747 by Miss Islington (bot) in branch '3.8':
    bpo-25172: Raise appropriate ImportError msg when crypt module used on Windows (GH-15149)
    7f7f747

    @zooba
    Copy link
    Member

    zooba commented Aug 13, 2019

    New changeset 243a73d by Steve Dower (shireenrao) in branch 'master':
    bpo-25172: Add test for crypt ImportError on Windows (GH-15252)
    243a73d

    @zooba
    Copy link
    Member

    zooba commented Aug 13, 2019

    Thanks for the patches, Srinivas!

    @zooba zooba closed this as completed Aug 13, 2019
    @miss-islington
    Copy link
    Contributor

    New changeset e7ec9e0 by Miss Islington (bot) in branch '3.8':
    bpo-25172: Add test for crypt ImportError on Windows (GH-15252)
    e7ec9e0

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Aug 13, 2019

    Thank you Steve for accepting my pull requests.

    I was surprised to see the methods in the class and its decorators getting evaluated and causing the failures initially, but I then realized that the code is parsed before execution and that's when I was seeing the failure.

    @xdegaye
    Copy link
    Mannequin

    xdegaye mannequin commented Nov 18, 2019

    test_crypt fails on android following last changes made at 243a73d.
    The android libc does not have a crypt() function and the _crypt module is not built.

    generic_x86_64:/data/local/tmp/python $ python
    Python 3.9.0a0 (heads/abifa-dirty:cf805c25e6, Nov 18 2019, 16:40:26)
    [Clang 8.0.2 (https://android.googlesource.com/toolchain/clang 40173bab62ec7462 on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import crypt
    Traceback (most recent call last):
      File "/data/local/tmp/python/lib/python3.9/crypt.py", line 6, in <module>
        import _crypt
    ModuleNotFoundError: No module named '_crypt'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/data/local/tmp/python/lib/python3.9/crypt.py", line 11, in <module>
        raise ImportError("The required _crypt module was not built as part of CPython")
    ImportError: The required _crypt module was not built as part of CPython
    >>>

    generic_x86_64:/data/local/tmp/python $ python -m test -v test_crypt
    == CPython 3.9.0a0 (heads/abifa-dirty:cf805c25e6, Nov 18 2019, 16:40:26) [Clang 8.0.2 (https://andro
    id.googlesource.com/toolchain/clang 40173bab62ec7462
    == Linux-3.10.0+-x86_64-with-libc little-endian
    == cwd: /data/local/tmp/python/tmp/test_python_3523
    == CPU count: 2
    == encodings: locale=UTF-8, FS=utf-8
    0:00:00 Run tests sequentially
    0:00:00 [1/1] test_crypt
    test_blowfish_rounds (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_crypt (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_invalid_rounds (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_methods (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_salt (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_saltedcrypt (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_sha2_rounds (test.test_crypt.CryptTestCase) ... skipped 'Not supported on Windows'
    test_failure_only_for_windows (test.test_crypt.TestWhyCryptDidNotImport) ... FAIL
    test_import_failure_message (test.test_crypt.TestWhyCryptDidNotImport) ... FAIL

    ======================================================================
    FAIL: test_failure_only_for_windows (test.test_crypt.TestWhyCryptDidNotImport)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "/data/local/tmp/python/lib/python3.9/test/test_crypt.py", line 16, in test_failure_only_for_
    windows
        self.assertEqual(sys.platform, 'win32')
    AssertionError: 'linux' != 'win32'
    - linux
    + win32

    ======================================================================
    FAIL: test_import_failure_message (test.test_crypt.TestWhyCryptDidNotImport)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "/data/local/tmp/python/lib/python3.9/test/test_crypt.py", line 19, in test_import_failure_message
        self.assertIn('not supported', IMPORT_ERROR)
    AssertionError: 'not supported' not found in 'The required _crypt module was not built as part of CPython'

    Ran 9 tests in 0.008s

    FAILED (failures=2, skipped=7)
    test test_crypt failed
    test_crypt failed

    == Tests result: FAILURE ==

    1 test failed:
    test_crypt

    Total duration: 165 ms
    Tests result: FAILURE

    @xdegaye xdegaye mannequin reopened this Nov 19, 2019
    @xdegaye
    Copy link
    Mannequin

    xdegaye mannequin commented Dec 10, 2019

    Not interested anymore in android stuff.

    @shireenrao
    Copy link
    Mannequin

    shireenrao mannequin commented Jan 6, 2020

    @steve.dower - Does this fix need more work for android? @xdegaye says he does not need this for android anymore.

    @zooba
    Copy link
    Member

    zooba commented Jan 6, 2020

    I started creating an example of improving the skip cases, and ended up just making a PR. It should:

    • expect a helpful error on Windows
    • work fine on other platforms with crypt
    • skip all tests on other platforms without crypt

    @zooba
    Copy link
    Member

    zooba commented Jan 9, 2020

    New changeset ed36781 by Steve Dower in branch 'master':
    bpo-25172: Reduce scope of crypt import tests (GH-17881)
    ed36781

    @miss-islington
    Copy link
    Contributor

    New changeset 8c08518 by Miss Islington (bot) in branch '3.8':
    bpo-25172: Reduce scope of crypt import tests (GH-17881)
    8c08518

    @zooba zooba closed this as completed Jan 9, 2020
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 only security fixes 3.9 only security fixes easy OS-windows stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants