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

[Bug]: Rename PDF Sheets not working #2273

Open
5 tasks done
countdookuw opened this issue May 29, 2024 · 4 comments
Open
5 tasks done

[Bug]: Rename PDF Sheets not working #2273

countdookuw opened this issue May 29, 2024 · 4 comments
Labels
Bug Bug that stops user from using the tool or a major portion of pyRevit functionality [class] Extension Commands Issues related to pyRevit extension commands [subsystem] Good First Issue Bug or feature with trivial solution that awaits you to be fixed!

Comments

@countdookuw
Copy link

✈ Pre-Flight checks

  • I don't have SentinelOne antivirus installed (see above for the solution)
  • I have searched in the issues (open and closed) but couldn't find a similar issue
  • I have searched in the pyRevit Forum for similar issues
  • I already followed the installation troubleshooting guide thoroughly
  • I am using the latest pyRevit Version

🐞 Describe the bug

Rename PDF Sheets does not work

⌨ Error/Debug Message

IronPython Traceback:
Traceback (most recent call last):
 File "C:\Program Files\pyRevit-Master\extensions\pyRevitTools.extension\pyRevit.tab\Drawing Set.panel\Sheets.pulldown\Rename PDF Sheets.pushbutton\script.py", line 35, in <module>
 File "C:\Program Files\pyRevit-Master\extensions\pyRevitTools.extension\pyRevit.tab\Drawing Set.panel\Sheets.pulldown\Rename PDF Sheets.pushbutton\script.py", line 20, in renamePDF
IndexError: index out of range: 0


Script Executor Traceback:
System.IndexOutOfRangeException: index out of range: 0
 at IronPython.Runtime.Operations.PythonOps.FixIndex(Int32 v, Int32 len)
 at IronPython.Runtime.List.get_Item(Int32 index)
 at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
 at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
 at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
 at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
 at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
 at Microsoft.Scripting.Interpreter.DynamicInstruction`4.Run(InterpretedFrame frame)
 at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
 at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
 at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
 at PyRevitLabs.PyRevit.Runtime.IronPythonEngine.Execute(ScriptRuntime& runtime)

♻️ To Reproduce

  1. Go to "Rename PDF Sheets"
  2. Browse to folder
  3. Crash occurs after hitting ok

⏲️ Expected behavior

Rename PDF tool to work

🖥️ Hardware and Software Setup (please complete the following information)

==> Registered Clones (full git repos)
==> Registered Clones (deployed from archive/image)
master | Deploy: "basepublic" | Branch: "master" | Version: "4.8.16.24121+2117" | Path: "C:\Users\ptomfohrde\AppData\Roaming\pyRevit-Master"
==> Attachments
Unnamed-363FBF8 | Product: "Autodesk Revit 2024" | Engine: IPY277 (277) | Path: "C:\Program Files\pyRevit-Master" | AllUsers
Unnamed-363FBF8 | Product: "Autodesk Revit 2023" | Engine: IPY277 (277) | Path: "C:\Program Files\pyRevit-Master" | AllUsers
Unnamed-363FBF8 | Product: "2022.1" | Engine: IPY277 (277) | Path: "C:\Program Files\pyRevit-Master" | AllUsers
Unnamed-363FBF8 | Product: "Autodesk Revit 2021" | Engine: IPY277 (277) | Path: "C:\Program Files\pyRevit-Master" | AllUsers
Unnamed-363FBF8 | Product: "2020.2.0" | Engine: IPY277 (277) | Path: "C:\Program Files\pyRevit-Master" | AllUsers
==> Installed Extensions
==> Default Extension Search Path
C:\Users\ptomfohrde\AppData\Roaming\pyRevit\Extensions
==> Extension Search Paths
==> Extension Sources - Default
https://github.com/eirannejad/pyRevit/raw/master/extensions/extensions.json
==> Extension Sources - Additional
==> Installed Revits
Autodesk Revit 2024 | Version: 24.2.0.63 | Build: 20231029_1515(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2024\"
Autodesk Revit 2023 | Version: 23.1.20.70 | Build: 20230510_1100(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2023\"
2022.1 | Version: 22.1.1.516 | Build: 20210921_1515(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2022\"
Autodesk Revit 2021 | Version: 21.1.21.45 | Build: 20201116_1100(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2021\"
2020.2.0 | Version: 20.2.90.12 | Build: 20220517_1515(x64) | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2020\"
==> Running Revit Instances
Error: Object reference not set to an instance of an object.
Run with "--debug" option to see debug messages

Additional context

Running Windows 11 Pro on Lenovo Thinkpad , Revit 2024

@countdookuw countdookuw added the Bug Bug that stops user from using the tool or a major portion of pyRevit functionality [class] label May 29, 2024
@sanzoghenzo
Copy link
Contributor

Hi @countdookuw, sorry for being so late in replying!

Do you by any chance still have the list of PDF file names?

The script expects that the file is named like <zero or more chars>Sheet - <name to use>.

The error you see is because one of the file in the chosen directory has "Sheet" in it, so it passes the first test

but it doesn't contain "Sheet - " (with space, hyphen and space after the word) as checked with the regular expression here:

This bug can be resolved in 2 ways: checking the presence of the entire "Sheet - " text from the start, or use a better code for the renamePDF function: it uses the findall method to then pick the first result, so it might be better use match and then check if the returning value is not None

@sanzoghenzo sanzoghenzo added Extension Commands Issues related to pyRevit extension commands [subsystem] Good First Issue Bug or feature with trivial solution that awaits you to be fixed! labels Aug 23, 2024
@Malouche-git
Copy link
Contributor

Hello everyone !
it's my first comment and futur commit to Pyrevit !

i have tried différent méthode to solve this issus and test run time, it's not so much but i thing it's faster without regex :

runtime-regex-vs-string

if it's ok i will also add a subfolder option with a form

#Include sub Folder or not
subfolders = forms.alert("Do you want to include subfolders?", yes=True, no=True)

@Malouche-git
Copy link
Contributor

I experimented with both functions in regex and normal string.
As I said, it's a bit faster with a normal string; however, regex allows for much better handling of various edge cases, with improved management of spaces between hyphens.
So I think it’s best to stick with regex

Here is what I came up with in regex :

def rename_pdf_re(old_name):
    try:
        # Step 1: Delete everything before and including "Sheet -", with space management
        new_name = re.sub(r"^.*?Sheet\s*-\s*", "", old_name)
        # Step 2: Make the part after the last hyphen before the period capitalized
        new_name = re.sub(r"\s*-\s*(.*)\.", lambda m: "-{}.".format(m.group(1).upper()), new_name)
        # Step 3: Normalize all other hyphens surrounded by spaces to single hyphens with no spaces (Optional)
        new_name = re.sub(r"\s*-\s*", "-", new_name)
    except:
        return False
    # Test new_name validity
    if new_name == old_name or new_name == "":
        return False
    else:
        return new_name

Here is what I came up with normal string (does include step 3, which replaces all spaces and hyphens with just a hyphen) :

def rename_pdf_str(old_name):
    #The non regex fonction may be litle bite faster It is more complex to manage the different cases with or without spaces
    try:
        index_sheet = old_name.find("Sheet - ")
        if index_sheet != -1:
            new_name = old_name[index_sheet + len("Sheet - "):]
            new_name = new_name[:new_name.find("-")+1] + " " + new_name[new_name.find("-") + 1:].strip().upper()
        else:
            return False
    except:
        return False
    if new_name == old_name or new_name == "":
        return False
    else:
        return new_name

As I mentioned, I added the option to also handle subfolders.

if not forms.alert("Do you want to include subfolders?", yes=True, no=True):
    #No sub Folder treatment proced for basefolder
    sheetcount = sheetcount + process_folder(basefolder)
else:
    # Search for pdf files in base folder and sub folder, add folder who have any in the list
    folders_to_process = []
    for root, dirs, files in os.walk(basefolder):
        if any(f.lower().endswith(".pdf") for f in files):
            folders_to_process.append(root)
    if not folders_to_process:
        forms.alert("No .pdf file found in these folder")
    #list not empty proced for each folder
    else:
        for folder in folders_to_process:
            sheetcount = sheetcount + process_folder(folder)

# let user know how many sheets have been renames
forms.alert("{0} FILES RENAMED.".format(sheetcount))

I don't know yet how to push or propose a modification in the project code !?
I will search for it and commit next month !

Happy New Year and enjoy your holidays if you have some ! 🎉✨🎄

Thanks, everyone, for the effort you put in !

@sanzoghenzo
Copy link
Contributor

sanzoghenzo commented Dec 19, 2024

Hi @Malouche-git , thank you for the contribution!

Indeed the regex way is slower, but it can be optimized by compiling the patterns with re.compile as stated in the documentation:

using re.compile() and saving the resulting regular expression object for reuse is more efficient when the expression will be used several times in a single program.

prefix_stripper = re.compile(r"^.*?Sheet\s*-\s*")
capitalizer = re.compile(r"\s*-\s*(.*)\.")
normalizer = re.compile("\s*-\s*")

def capitalizer_repl(match):
    return  "-{}.".format(m.group(1).upper())

def rename_pdf(old_name):
    new_name = prefix_stripper.sub("", old_name)
    new_name = capitalizer.sub(capitalizer_repl, new_name)
    return normalizer.sub("-", new_name)

I'm against returning False in the function on an error or no substitution; here we are in a self contained script at it doesn't matter that much, but still: it's a bad practice to return different types and having the caller figure out why a "rename_pdf" function returned False instead of a string as it would expect.
just move the try/except and the last checks outside of the function.
we can keep the empty new_name check inside the function and return a ValueError

def rename_pdf(old_name):
    new_name = prefix_stripper.sub("", old_name)
    new_name = capitalizer.sub(capitalizer_repl, new_name)
    new_name = normalizer.sub("-", new_name)
    if not new_name:
        raise ValueError("Renaming results in an empty string.")
    return new_name

Also, the file operations can be simplified with pathlib; it is a python 3 library, but it has been ported to python 2.7 and is available in pyrevit.

from pathlib import Path

# ...

dir_pattern = "**/" if forms.alert("Do you want to include subfolders?", yes=True, no=True) else ""
for pdf_file in Path(basefolder).glob("{}*.pdf".format(dir_pattern)):
    try:
        new_name = rename_pdf(pdf_file.stem)
    except (ValueError, re.error):
        continue
    new_path = pdf_file.with_name("{}.pdf".format(new_name))
    pdf_file.rename(new_path)

Finally, to send the proposed changes you have to:

  • fork this repository (in the start page of the repo you'll se a "Fork" button)
  • since this is a single-file modification, you can just use the web editor to change the contents of the scripts and commit them
  • once the commit has been created, you'll see a "Contribute" button, click it and select "Open a pull request".

You can read the official github documentation, if you want to do the "full-contributor" way and work on a local copy synced to your repository

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Bug that stops user from using the tool or a major portion of pyRevit functionality [class] Extension Commands Issues related to pyRevit extension commands [subsystem] Good First Issue Bug or feature with trivial solution that awaits you to be fixed!
Projects
None yet
Development

No branches or pull requests

3 participants