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

ModuleNotFoundError: No module named 'string_utils_py' #3

Closed
andry81 opened this issue Aug 6, 2022 · 11 comments
Closed

ModuleNotFoundError: No module named 'string_utils_py' #3

andry81 opened this issue Aug 6, 2022 · 11 comments

Comments

@andry81
Copy link

andry81 commented Aug 6, 2022

c:\Work\OpenSource\lnk_parser\master>c:\python\x64\310\python lnk_parser.py
Traceback (most recent call last):
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser.py", line 8, in <module>
    from string_utils_py import text_align_delimiter, underline
ModuleNotFoundError: No module named 'string_utils_py'
@vphpersson
Copy link
Owner

vphpersson commented Aug 6, 2022

Hi! Did you install the dependencies from requirements.txt?

@vphpersson vphpersson reopened this Aug 6, 2022
@andry81
Copy link
Author

andry81 commented Aug 6, 2022

I've tried to install. Several dependencies has failed to install:

Removing c:\python\x64\310\lib\site-packages\msdsalgs-0.11-py3.10.egg
error: [WinError 32] Процесс не может получить доступ к файлу, так как этот файл занят другим процессом: 'c:\\python\\x64\\310\\lib\\site-packages\\msdsalgs-0.11-py3.10.egg'

@vphpersson
Copy link
Owner

vphpersson commented Aug 6, 2022

Even when translating the error message, I do not understand how the code could cause it. Do you have anything else running simultaneously that has access to the files?

Admittedly, I haven't tried running this code on Windows. I just ran it successfully on Linux with the following commands:

$ git clone [email protected]:vphpersson/lnk_parser.git
$ cd lnk_parser
$ python -m venv venv
$ source ./venv/bin/activate
$ pip install -r requirements.txt
$ ./lnk_parser.py --help

As a last resort, If you really want this to run on Windows, maybe you could try running it in the Windows Subsystem for Linux.

@andry81
Copy link
Author

andry81 commented Aug 7, 2022

Thx for answer. I've tried to install it manually using requirements.txt and got this.

If try to use the command:

C:\Work\OpenSource\lnk_parser\master>c:\python\x64\310\python -m pip install -r requirements.txt

It reports another error:

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
lnk-parser 0.1 requires strings_utils_py@ git+https://github.com/vphpersson/string_utils_py.git#egg=string_utils_py, which is not installed.

But it somehow installed and if run:

c:\Work\OpenSource\lnk_parser\master>c:\python\x64\310\python lnk_parser.py d:\1.txt.lnk
Traceback (most recent call last):
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser.py", line 40, in <module>
    main()
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser.py", line 26, in main
    text='\n\n'.join(
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser.py", line 29, in <genexpr>
    f'{ShellLink.from_bytes(data=lnk_file.read())}'
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser\structures\shell_link.py", line 54, in from_bytes
    link_info = LinkInfo.from_bytes(data=data, base_offset=offset)
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser\structures\link_info.py", line 72, in from_bytes
    local_base_path=_read_null_terminated_string(
  File "c:\Work\OpenSource\lnk_parser\master\lnk_parser\utils.py", line 35, in _read_null_terminated_string
    bytes(data[offset:offset + num_string_bytes]).decode(encoding=('utf-16-le' if is_unicode else 'ascii')),
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf6 in position 3: ordinal not in range(128)

This error already known from another app: strayge/pylnk#20 (comment)

I just searching a solution for this.

@vphpersson
Copy link
Owner

vphpersson commented Aug 7, 2022

Glad that it is running, and thanks for the additional info.

The code is having a problem reading the local base path of the LinkInfo structure (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/6813269d-0cc8-4be2-933f-e96e8e3412dc). In the file that you provided, LinkInfoHeaderSize is 0x0000001C, which according to the documentation indicates that the optional field LocalBasePathOffsetUnicode is not specified. This entails that the bytes that constitute the local base path are not Unicode-encoded.

When debugging, I can see that the local base path bytes are extracted correctly:

> data[offset:offset+num_string_bytes].tobytes()
b'D:\\\xf6\xf6\xf6\\1.txt'

Now for the cause of the problem: When attempting to decode bytes that are not Unicode-encoded, I have defaulted to using ascii. That is probably not correct. It seems that one should use "the system default code page" in such cases.

Maybe you could help me figure how to obtain that value? When making whatever call for it, you should probably receive something other than utf-8 and ascii. Maybe locale.getpreferredencoding()? (https://docs.python.org/3/library/locale.html#locale.getpreferredencoding)

@andry81
Copy link
Author

andry81 commented Aug 7, 2022

Maybe you could help me figure how to obtain that value?

May be these help.

https://serverfault.com/questions/80635/how-can-i-manually-determine-the-codepage-and-locale-of-the-current-os/836221#836221

A registry-based method that also works on older systems down to Windows XP:

# Get the code pages:
Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Nls\CodePage | 
     Select-Object OEMCP, ACP

On a US-English system, the above yields:

OEMCP ACP 
----- --- 
 437   1252

https://stackoverflow.com/questions/3425294/how-to-detect-the-os-default-language-in-python/25691701#25691701

But if you want getting the windows language identifier, i recommend to use instead GetUserDefaultUILanguage(), because as stated en MSDN, will search recursively until reaches the language:

"Returns the language identifier for the user UI language for the current user. If the current user has not set a language, GetUserDefaultUILanguage returns the preferred language set for the system. If there is no preferred language set for the system, then the system default UI language (also known as "install language") is returned. For more information about the user UI language, see User Interface Language Management."

Code:

import locale
locale.getdefaultlocale()
('es_ES', 'cp1252')            # <------------- Bad! I'm on english OS.
import ctypes
windll = ctypes.windll.kernel32
windll.GetUserDefaultUILanguage()
1033
locale.windows_locale[ windll.GetUserDefaultUILanguage() ]
'en_US'          # <----------- Good work

Also the explicit way I think would be as good too:

You can create the --chcp <str> parameter or something for that. And add --ignore-decode-errors to call decode(..., errors='ignore') instead.

@vphpersson
Copy link
Owner

vphpersson commented Aug 7, 2022

Thanks! As indicated in the thread of the issue you referred to, cp1252 is the encoding value that is needed to decode the problematic bytes correctly:

> data[offset:offset+num_string_bytes].tobytes().decode(encoding='cp1252')
'D:\\ööö\\1.txt'

Using locale.getdefaultlocale() seems like the best alternative as it is system-independent. I will implement its use and make a commit to the repository today, alright?

When setting the encoding to cp1252 instead of ascii explicitly, the code runs successfully with your file:

lnk_files/1_buggy.txt.lnk
=========================
General
-------
            Link target: D:\E81B~1\1.txt
              Arguments: None
            Name string: None
          Relative path: .\ööö\1.txt
            Working dir: D:\ööö
          Icon location: None
Header
------
             Link flags: <LinkFlags.EnableTargetMetadata|IsUnicode|HasWorkingDir|HasRelativePath|HasLinkInfo|HasLinkTargetIDList: 524443>
        File attributes: <FileAttributesFlag.FILE_ATTRIBUTE_ARCHIVE: 32>
          Creation time: 2022-07-30 17:51:27.142681+00:00
            Access time: 2022-07-30 17:51:27.142681+00:00
             Write time: 2022-07-30 17:51:00.750172+00:00
              File size: 0
             Icon index: 0
           Show command: SW_SHOWNORMAL
                Hot key: None
Link target IDs
---------------
                   Type: RootFolderShellItem
             Sort index: 80
Shell folder identifier: 20d04fe0-3aea-1069-a2d8-08002b30309d

                   Type: VolumeShellItem
                   Name: D:\
                  Flags: <VolumeShellItemFlags.UNKNOWN_2|UNKNOWN_1|HAS_NAME: 7>

                   Type: FileEntryShellItem
           Primary name: E81B~1
                  Flags: <FileEntryShellItemFlags.IS_DIRECTORY: 1>
              File size: None
        File attributes: <FileAttributesFlag.FILE_ATTRIBUTE_DIRECTORY: 16>
          Last modified: 2022-07-30 17:51:28

                   Type: FileEntryShellItem
           Primary name: 1.txt
                  Flags: <FileEntryShellItemFlags.IS_FILE: 2>
              File size: None
        File attributes: <FileAttributesFlag.FILE_ATTRIBUTE_ARCHIVE: 32>
          Last modified: 2022-07-30 17:51:02
Extra data
----------
                   Type: PropertyStoreDataBlock
           Storage size: 161
                Version: 0x53505331
              Format ID: b725f130-47ef-101a-a5f1-02608c9eebac
             Value size: 29
               Value ID: 10
             Value type: 0x1f
                  Value: 1.txt
             Value size: 41
               Value ID: 4
             Value type: 0x1f
                  Value: Файл "TXT"
             Value size: 21
               Value ID: 15
             Value type: 0x40
                  Value: b'\x00\x10^\xfe<\xa4\xd8\x01'
             Value size: 21
               Value ID: 12
             Value type: 0x15
                  Value: b'\x00\x00\x00\x00\x00\x00\x00\x00'
             Value size: 21
               Value ID: 14
             Value type: 0x40
                  Value: b'\x00\xc7\xde\xee<\xa4\xd8\x01'
           Storage size: 61
                Version: 0x53505331
              Format ID: e3e0584c-b788-4a5a-bb20-7f5a44c9acdd
             Value size: 33
               Value ID: 6
             Value type: 0x1f
                  Value: D:\ööö
           Storage size: 73
                Version: 0x53505331
              Format ID: 28636aa6-953d-11d2-b5d6-00c04fd918d0
             Value size: 45
               Value ID: 30
             Value type: 0x1f
                  Value: D:\ööö\1.txt

@vphpersson
Copy link
Owner

Sorry, I thought the output of locale.getdefaultlocale() in your reply was yours. Could you try running it yourself?

import locale
locale.getdefaultlocale()

@andry81
Copy link
Author

andry81 commented Aug 7, 2022

import locale
locale.getdefaultlocale()

('ru_RU', 'cp1251')

@vphpersson
Copy link
Owner

I have updated the repository. If you run the latest version, I believe it will run successfully with your file.

@vphpersson
Copy link
Owner

I am closing this issue as I believe the problem alluded to is solved. I will re-open it if there are any indications that it is not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants