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

Windows pathlib.Path.glob(pattern) fixed part of the pattern changed to lowercase whereas it should be unchanged. #75385

Closed
brice-gros mannequin opened this issue Aug 14, 2017 · 8 comments
Labels
3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes OS-windows stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@brice-gros
Copy link
Mannequin

brice-gros mannequin commented Aug 14, 2017

BPO 31202
Nosy @pfmoore, @tjguk, @zware, @serhiy-storchaka, @zooba, @brice-gros, @miss-islington, @iritkatriel
PRs
  • bpo-31202: Windows pathlib.Path.glob(pattern) fixed part of the pattern changed to lowercase whereas it should be unchanged. #3087
  • bpo-31202: Preserve case of literal parts in Path.glob() on Windows. #16860
  • [3.7] bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860) #16874
  • [3.8] bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860) #16875
  • 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-10-17.00:11:35.555>
    created_at = <Date 2017-08-14.13:57:31.993>
    labels = ['type-bug', '3.8', '3.9', '3.7', 'library', 'OS-windows']
    title = 'Windows pathlib.Path.glob(pattern) fixed part of the pattern changed to lowercase whereas it should be unchanged.'
    updated_at = <Date 2020-10-17.00:11:35.552>
    user = 'https://github.com/brice-gros'

    bugs.python.org fields:

    activity = <Date 2020-10-17.00:11:35.552>
    actor = 'steve.dower'
    assignee = 'none'
    closed = True
    closed_date = <Date 2020-10-17.00:11:35.555>
    closer = 'steve.dower'
    components = ['Library (Lib)', 'Windows']
    creation = <Date 2017-08-14.13:57:31.993>
    creator = 'brice.gros'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 31202
    keywords = ['patch']
    message_count = 8.0
    messages = ['300245', '354976', '355087', '355093', '355095', '378786', '378792', '378794']
    nosy_count = 8.0
    nosy_names = ['paul.moore', 'tim.golden', 'zach.ware', 'serhiy.storchaka', 'steve.dower', 'brice.gros', 'miss-islington', 'iritkatriel']
    pr_nums = ['3087', '16860', '16874', '16875']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue31202'
    versions = ['Python 3.7', 'Python 3.8', 'Python 3.9']

    @brice-gros
    Copy link
    Mannequin Author

    brice-gros mannequin commented Aug 14, 2017

    Windows pathlib.Path.glob(pattern) fixed part of the pattern to lowercase whereas it should be unchanged.
    Note that this issue is different from http://bugs.python.org/issue26655 : "pathlib glob case sensitivity issue on Windows" where it was asked to get the actual case of the folder from the file system.

    Assuming a directory contains a folder named 'Folder'.
    On Windows, calling pathlib.Path().glob('Folder') gives 'folder', but 'Folde?' will return 'Folder'
    This is an issue for instance if trying to glob files to put them in an archive to be sent to a case sensitive platform.
    glob.glob() does behave properly though, Windows pathlib.Path is the only platform which has such a behavior.

    I would expect Path.glob to output the same as glob.glob() for each platform.
    From comments on http://bugs.python.org/issue19718 : "Path.glob() on case-insensitive Posix filesystems" it sounds that it should even match the native shell behavior.
    And it looks like it is the case for linux and macOS, I tested that with the following script, whose results on win32, darwin and linux platforms follow:

    #!/usr/bin/env python3.6
    # Let's say this path exists : ./Folder/file
    from pathlib import Path
    import glob
    import os
    import sys
    import subprocess
    
    def ls(pattern):
        if sys.platform in ('win32', 'win64'):
            process = subprocess.run(['powershell', '-Command', f'dir {pattern}'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=os.getcwd(), encoding='utf-8')
            if process.returncode:
                return []
            # expected output:
            # 
            # 
            #     Directory: C:\path_to\Folder
            # 
            # 
            # Mode                LastWriteTime         Length Name
            # ----                -------------         ------ ----
            # -a----       2017-08-14     10:16              0 file
            lines = process.stdout.splitlines()
            folder = os.path.basename(lines[2].split()[-1])
            file = lines[7].split()[-1]
            result = f"{folder}{os.path.sep}{file}"
            return [result]
        else:
            cmd = ['ls', f'{pattern}']
            process = subprocess.run(' '.join(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=os.getcwd(), encoding='utf-8', shell=True)
            if process.returncode:
                return []
            return [process.stdout.strip()]
    
    def main():
        print(sys.platform)
        p = Path('.')
        tests = ['Folder/*', 'FOlder/*', 'F?lder/*', 'FOlde?/*', 'folder/*', 'f?lder/*']
        for t in tests:
            print(f'{t}:')
            print(f'    Path.glob():  {[str(f) for f in p.glob(t)]}')
            print(f'    glob.glob():  {[f for f in glob.glob(str(p/t))]}')
            print(f'    shell:        {ls(str(p/t))}')
    
    if __name__ == '__main__':
        main()
    
    Output:
            win32                                            darwin                                        linux
    1:      Folder/*:                                        Folder/*:                                     Folder/*:
    1a:         Path.glob():  ['folder\\file']                   Path.glob():  ['Folder/file']                 Path.glob():  ['Folder/file']
    1b:         glob.glob():  ['Folder\\file']                   glob.glob():  ['Folder/file']                 glob.glob():  ['Folder/file']
    1c:         shell:        ['Folder\\file']                   shell:        ['Folder/file']                 shell:        ['Folder/file']
    2:      FOlder/*:                                        FOlder/*:                                     FOlder/*:
    2a:         Path.glob():  ['folder\\file']                   Path.glob():  ['FOlder/file']                 Path.glob():  []
    2b:         glob.glob():  ['FOlder\\file']                   glob.glob():  ['FOlder/file']                 glob.glob():  []
    2c:         shell:        ['FOlder\\file']                   shell:        ['FOlder/file']                 shell:        []
    3:      F?lder/*:                                        F?lder/*:                                     F?lder/*:
    3a:         Path.glob():  ['Folder\\file']                   Path.glob():  ['Folder/file']                 Path.glob():  ['Folder/file']
    3b:         glob.glob():  ['Folder\\file']                   glob.glob():  ['Folder/file']                 glob.glob():  ['Folder/file']
    3c:         shell:        ['Folder\\file']                   shell:        ['Folder/file']                 shell:        ['Folder/file']
    4:      FOlde?/*:                                        FOlde?/*:                                     FOlde?/*:
    4a:         Path.glob():  ['Folder\\file']                   Path.glob():  []                              Path.glob():  []
    4b:         glob.glob():  ['Folder\\file']                   glob.glob():  []                              glob.glob():  []
    4c:         shell:        ['Folder\\file']                   shell:        []                              shell:        []
    5:      folder/*:                                        folder/*:                                     folder/*:
    5a:         Path.glob():  ['folder\\file']                   Path.glob():  ['folder/file']                 Path.glob():  []
    5b:         glob.glob():  ['folder\\file']                   glob.glob():  ['folder/file']                 glob.glob():  []
    5c:         shell:        ['folder\\file']                   shell:        ['folder/file']                 shell:        []
    6:      f?lder/*:                                        f?lder/*:                                     f?lder/*:
    6a:         Path.glob():  ['Folder\\file']                   Path.glob():  []                              Path.glob():  []
    6b:         glob.glob():  ['Folder\\file']                   glob.glob():  []                              glob.glob():  []
    6c:         shell:        ['Folder\\file']                   shell:        []                              shell:        []
    

    @brice-gros brice-gros mannequin added 3.7 (EOL) end of life stdlib Python modules in the Lib dir OS-windows type-bug An unexpected behavior, bug, or error labels Aug 14, 2017
    @ned-deily ned-deily added the 3.8 only security fixes label Jun 7, 2018
    @zooba
    Copy link
    Member

    zooba commented Oct 19, 2019

    Bumping this - it's bitten me a couple of times as one of the build/release scripts relies on Path.glob().

    @zooba zooba added the 3.9 only security fixes label Oct 19, 2019
    @serhiy-storchaka
    Copy link
    Member

    New changeset 10ecbad by Serhiy Storchaka in branch 'master':
    bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860)
    10ecbad

    @miss-islington
    Copy link
    Contributor

    New changeset 175abcc by Miss Skeleton (bot) in branch '3.7':
    bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860)
    175abcc

    @miss-islington
    Copy link
    Contributor

    New changeset 2f8d4f0 by Miss Skeleton (bot) in branch '3.8':
    bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860)
    2f8d4f0

    @iritkatriel
    Copy link
    Member

    Can this be closed?

    @brice-gros
    Copy link
    Mannequin Author

    brice-gros mannequin commented Oct 16, 2020

    I think so, the original PR has been ported to 3.9, 3.8, 3.7, and all the PRs were merged.

    @zooba
    Copy link
    Member

    zooba commented Oct 17, 2020

    Yeah, looks done.

    @zooba zooba closed this as completed Oct 17, 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.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes 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