248
pyRevit Documentation Release 4.5 eirannejad Jan 20, 2019

pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

  • Upload
    lelien

  • View
    387

  • Download
    5

Embed Size (px)

Citation preview

Page 1: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit DocumentationRelease 4.5

eirannejad

Jan 20, 2019

Page 2: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface
Page 3: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

Getting Started

1 Anatomy of a pyRevit Script 31.1 Script Metadata Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 pyrevit.script Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.3 Appendix A: Builtin Parameters Provided by pyRevit Engine . . . . . . . . . . . . . . . . . . . . . 81.4 Appendix B: System Category Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2 Effective Output/Input 152.1 Clickable Element Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.2 Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.3 Code Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.4 Progress bars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.5 Standard Prompts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.6 Standard Dialogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222.7 Base Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312.8 Graphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3 Keyboard Shortcuts 413.1 Shift-Click: Alternate/Config Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413.2 Ctrl-Click: Debug Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413.3 Alt-Click: Show Script file in Explorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423.4 Ctrl-Shift-Alt-Click: Reload Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423.5 Shift-Win-Click: pyRevit Button Context Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

4 Extensions and Commmands 434.1 Why do I need an Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434.2 Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434.3 Command Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444.4 Group Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454.5 Advanced Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474.6 Other Extension Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

5 pyRevit Configuration 51

6 Usage Logger 53

7 pyRevit Installer 55

i

Page 4: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

8 Load Sequence, Step 1: Revit Addon 578.1 The Complex Relationship of a C# Addin and a Python Script . . . . . . . . . . . . . . . . . . . . . 578.2 pyRevit loader script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578.3 pyRevitLoader Addin Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

9 Load Sequence, Step 2: IronPython Module 59

10 pyrevit 6110.1 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

11 pyrevit.api 7511.1 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

12 pyrevit.compat 7712.1 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

13 pyrevit.forms 7913.1 pyrevit.forms.utils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9413.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

14 pyrevit.framework 13314.1 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

15 pyrevit.script 13715.1 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

16 pyrevit.userconfig 15316.1 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155

17 pyrevit.coreutils 16317.1 pyrevit.coreutils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16317.2 pyrevit.coreutils.envvars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20017.3 pyrevit.coreutils.appdata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20217.4 pyrevit.coreutils.pyutils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20917.5 pyrevit.coreutils.mathnet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21417.6 pyrevit.coreutils.moduleutils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

18 pyrevit.output 21718.1 pyrevit.output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21718.2 pyrevit.output.linkmaker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

Python Module Index 237

ii

Page 5: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Note: This documentation is a work-in-progress. Thanks for your patience.

Getting Started

I suggest reading this section completely as it provides 99% of what you will need to know for developing scripts inpyRevit environment. Other sections dive deeper into pyRevit inner workings.

• Anatomy of a pyRevit Script

• Effective Output/Input

• Keyboard Shortcuts

• Extensions and Commmands

• pyRevit Configuration

• Usage Logger

• pyRevit Installer

Getting Started 1

Page 6: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2 Getting Started

Page 7: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 1

Anatomy of a pyRevit Script

pyRevit provides a few basic services to python scripts that use its engine. These fuctionalities are accessible througha few high level modules. This article is a quick look at these services and their associated python modules.

1.1 Script Metadata Variables

pyRevit looks for certain global scope variables in each scripts that provide metadata about the script and follow the__<name>__ format.

1.1.1 __title__

Button Title: When using the bundle name as the button name in Revit UI is not desired, or you want to add anewline character to the command name to better display the butonn name inside Revit UI Panel, you can define the__title__ variable in your script and set it to the desired button title.

__title__ = 'Sample\\nCommand'

3

Page 8: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

1.1.2 __doc__

Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface. You can define the tooltip for ascript using the doscstring at the top of the script or by explicitly defining __doc__ metadata variable.

# defining tooltip as the script docstring"""You can place the docstring (tooltip) at the top of the script file.This serves both as python docstring and also button tooltip in pyRevit.You should use triple quotes for standard python docstrings."""

# defining tooltip by setting metadata variable__doc__ = 'This is the text for the button tooltip associated with this→˓script.'

1.1.3 __author__

Script Author: You can define the script author as shown below. This will show up on the button tooltip.

__author__ = 'Ehsan Iran-Nejad'

1.1.4 __helpurl__

F1 Shortcut Help Url: xx

1.1.5 __min_revit_ver__

Min Revit Version Required: xx

1.1.6 __max_revit_ver__

Max Revit Version Supported: xx

1.1.7 __beta__

Script In Beta: xx

4 Chapter 1. Anatomy of a pyRevit Script

Page 9: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

1.1.8 __context__

Command Availability: Revit commands use standard IExternalCommandAvailability class to let Revitknow if they are available in different contexts. For example, if a command needs to work on a set of elements, it cantell Revit to deactivate the button unless the user has selected one or more elements.

In pyRevit, command availability is set through the __context__ variable. Currently, pyRevit support three typesof command availability types.

# Tool activates when at least one element is selected__context__ = 'Selection'

# Tools are active even when there are no documents available/open in Revit__context__ = 'zerodoc'

# Tool activates when all selected elements are of the given category or categories__context__ = '<Element Category>'__context__ = ['<Element Category>', '<Element Category>']

<Element Category> can be any of the standard Revit element categories. See Appendix B: System CategoryNames for a full list of system categories. You can use the List tool under pyRevit > Spy and list the standardcategories.

Here are a few examples:

# Tool activates when all selected elements are of the given category

__context__ = 'Doors'__context__ = 'Walls'__context__ = 'Floors'__context__ = ['Space Tags', 'Spaces']

1.2 pyrevit.script Module

All pyRevit scripts should use the pyrevit.scriptmodule to access pyRevit functionality unless listed otherwise.pyRevit internals are subject to changes and accessing them directly is not suggested.

Here is a list of supported modules for pyRevit scripts. Examples of using the functionality in these modules areprovided on this page.

pyrevit.script

This module provides access to output window (pyrevit.output), logging (pyrevit.coreutils.logger), temporary files (pyrevit.coreutils.appdata), and other misc fea-tures. See the module page for usage examples and full documentation of all available functions.

1.2.1 Logging

You can get the default logger for the script using pyrevit.script.get_logger().

from pyrevt import script

logger = script.get_logger()

logger.info('Test Log Level :ok_hand_sign:')

(continues on next page)

1.2. pyrevit.script Module 5

Page 10: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

logger.warning('Test Log Level')

logger.critical('Test Log Level')

Critical and warning messages are printed in color for clarity. Normally debug messages are not printed. you can holdCTRL and click on a command button to put that command in DEBUG mode and see all its debug messages

logger.debug('Yesss! Here is the debug message')

1.2.2 Controlling Output Window

Each script can control its own output window:

from pyrevit import script

output = script.get_output()

output.set_height(600)output.get_title()output.set_title('More control please!')

See Effective Output/Input for more info.

1.2.3 Script Config

Each script can save and load configuration pyRevit’s user configuration file:

See pyrevit.output for more examples.

See pyrevit.script.get_config() and pyrevit.script.save_config() for the individual func-tions used here.

from pyrevit import script

config = script.get_config()

# set a new config parameter: firstparamconfig.firstparam = True

# saving configurationsscript.save_config()

# read the config parameter valueif config.firstparam:

do_task_A()

1.2.4 Logging Results

pyRevit has a usage logging system that can record all tool usages to either a json file or to a web server. Scripts canreturn custom data to this logging system.

In example below, the script reports the amount of time it saved to the logging system:

6 Chapter 1. Anatomy of a pyRevit Script

Page 11: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

from pyrevit import script

results = script.get_results()results.timesaved = 10

1.2.5 Using Temporary Files

Scripts can create 3 different types of data files:

• Universal files

These files are not marked by host Revit version and could be shared between all Revit versions andinstances. These data files are saved in pyRevit’s appdata directory and are NOT cleaned up at Revitrestarts.

See pyrevit.script.get_universal_data_file()

Note: Script should take care of cleaning up these data files.

# provide a unique file id and file extension# Method will return full path of the data filefrom pyrevit import scriptscript.get_universal_data_file(file_id, file_ext)

• Data files

These files are marked by host Revit version and could be shared between instances of host Revitversion Data files are saved in pyRevit’s appdata directory and are NOT cleaned up when Revitrestarts.

See pyrevit.script.get_data_file()

Note: Script should take care of cleaning up these data files.

# provide a unique file id and file extension# Method will return full path of the data filefrom pyrevit import scriptscript.get_data_file(file_id, file_ext)

• Instance Data files

These files are marked by host Revit version and process Id and are only available to current Revitinstance. This avoids any conflicts between similar scripts running under two or more Revit instances.Data files are saved in pyRevit’s appdata directory (with extension .tmp) and ARE cleaned up whenRevit restarts.

See pyrevit.script.get_instance_data_file()

# provide a unique file id and file extension# Method will return full path of the data filefrom pyrevit import scriptscript.get_instance_data_file(file_id)

• Document Data files

1.2. pyrevit.script Module 7

Page 12: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(Shared only between instances of host Revit version): These files are marked by host Revit versionand name of Active Project and could be shared between instances of host Revit version. Data filesare saved in pyRevit’s appdata directory and are NOT cleaned up when Revit restarts.

See pyrevit.script.get_document_data_file()

Note: Script should take care of cleaning up these data files.

# provide a unique file id and file extension# Method will return full path of the data filefrom pyrevit import scriptscript.get_document_data_file(file_id, file_ext)

# You can also pass a document object to get a data file for that# document (use document name in file naming)script.get_document_data_file(file_id, file_ext, doc)

1.3 Appendix A: Builtin Parameters Provided by pyRevit Engine

Variables listed below are provided for every script in pyRevit.

Note: It’s strongly advised not to read or write values from these variables unless necessary. The pyrevit moduleprovides wrappers around these variables that are safe to use.

# Revit UIApplication is accessible through:__revit__

# Command data provided to this command by Revit is accessible through:__commandData__

# selection of elements provided to this command by Revit__elements__

# pyRevit engine manager that is managing this engine__ipyenginemanager__

# This variable is True if command is being run in a cached engine__cachedengine__

# pyRevit external command object wrapping the command being run__externalcommand__

# information about the pyrevit command being run__commandpath__ # main script path__alternatecommandpath__ # alternate script path__commandname__ # command name__commandbundle__ # command bundle name__commandextension__ # command extension name__commanduniqueid__ # command unique id

# This variable is True if user CTRL-Clicks the button__forceddebugmode__

(continues on next page)

8 Chapter 1. Anatomy of a pyRevit Script

Page 13: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# This variable is True if user SHIFT-Clicks the button__shiftclick__

# results dictionary__result__

1.4 Appendix B: System Category Names

Adaptive PointsAir Terminal TagsAir TerminalsAnalysis Display StyleAnalysis ResultsAnalytical Beam TagsAnalytical BeamsAnalytical Brace TagsAnalytical BracesAnalytical Column TagsAnalytical ColumnsAnalytical Floor TagsAnalytical FloorsAnalytical Foundation SlabsAnalytical Isolated Foundation TagsAnalytical Isolated FoundationsAnalytical Link TagsAnalytical LinksAnalytical Node TagsAnalytical NodesAnalytical Slab Foundation TagsAnalytical SpacesAnalytical SurfacesAnalytical Wall Foundation TagsAnalytical Wall FoundationsAnalytical Wall TagsAnalytical WallsAnnotation Crop BoundaryArea Load TagsArea TagsAreasAssembliesAssembly TagsBoundary ConditionsBrace in Plan View SymbolsCable Tray Fitting TagsCable Tray FittingsCable Tray RunsCable Tray TagsCable TraysCallout BoundaryCallout HeadsCalloutsCamerasCasework

(continues on next page)

1.4. Appendix B: System Category Names 9

Page 14: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Casework TagsCeiling TagsCeilingsColor Fill LegendsColumnsCommunication Device TagsCommunication DevicesConduit Fitting TagsConduit FittingsConduit RunsConduit TagsConduitsConnection SymbolsContour LabelsCrop BoundariesCurtain GridsCurtain Panel TagsCurtain PanelsCurtain System TagsCurtain SystemsCurtain Wall MullionsData Device TagsData DevicesDetail Item TagsDetail ItemsDimensionsDisplacement PathDoor TagsDoorsDuct AccessoriesDuct Accessory TagsDuct Color FillDuct Color Fill LegendsDuct Fitting TagsDuct FittingsDuct Insulation TagsDuct InsulationsDuct Lining TagsDuct LiningsDuct PlaceholdersDuct SystemsDuct TagsDuctsElectrical CircuitsElectrical EquipmentElectrical Equipment TagsElectrical Fixture TagsElectrical FixturesElectrical Spare/Space CircuitsElevation MarksElevationsEntourageFilled regionFire Alarm Device TagsFire Alarm DevicesFlex Duct TagsFlex Ducts

(continues on next page)

10 Chapter 1. Anatomy of a pyRevit Script

Page 15: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Flex Pipe TagsFlex PipesFloor TagsFloorsFoundation Span Direction SymbolFurnitureFurniture System TagsFurniture SystemsFurniture TagsGeneric AnnotationsGeneric Model TagsGeneric ModelsGrid HeadsGridsGuide GridHVAC ZonesImports in FamiliesInternal Area Load TagsInternal Line Load TagsInternal Point Load TagsKeynote TagsLevel HeadsLevelsLighting Device TagsLighting DevicesLighting Fixture TagsLighting FixturesLine Load TagsLinesMasking RegionMassMass Floor TagsMass TagsMatchlineMaterial TagsMaterialsMechanical EquipmentMechanical Equipment TagsMEP Fabrication ContainmentMEP Fabrication Containment TagsMEP Fabrication DuctworkMEP Fabrication Ductwork TagsMEP Fabrication Hanger TagsMEP Fabrication HangersMEP Fabrication PipeworkMEP Fabrication Pipework TagsMulti-Category TagsMulti-Rebar AnnotationsNurse Call Device TagsNurse Call DevicesPanel Schedule GraphicsParkingParking TagsPart TagsPartsPipe AccessoriesPipe Accessory Tags

(continues on next page)

1.4. Appendix B: System Category Names 11

Page 16: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Pipe Color FillPipe Color Fill LegendsPipe Fitting TagsPipe FittingsPipe Insulation TagsPipe InsulationsPipe PlaceholdersPipe SegmentsPipe TagsPipesPiping SystemsPlan RegionPlantingPlanting TagsPlumbing Fixture TagsPlumbing FixturesPoint CloudsPoint Load TagsProject InformationProperty Line Segment TagsProperty TagsRailing TagsRailingsRampsRaster ImagesRebar Cover ReferencesRebar Set ToggleRebar ShapeReference LinesReference PlanesReference PointsRender RegionsRevision Cloud TagsRevision CloudsRoadsRoof TagsRoofsRoom TagsRoomsRouting PreferencesSchedule GraphicsScope BoxesSection BoxesSection LineSection MarksSectionsSecurity Device TagsSecurity DevicesShaft OpeningsSheetsSiteSite TagsSpace TagsSpacesSpan Direction SymbolSpecialty EquipmentSpecialty Equipment Tags

(continues on next page)

12 Chapter 1. Anatomy of a pyRevit Script

Page 17: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Spot CoordinatesSpot Elevation SymbolsSpot ElevationsSpot SlopesSprinkler TagsSprinklersStair Landing TagsStair PathsStair Run TagsStair Support TagsStair TagsStair Tread/Riser NumbersStairsStructural AnnotationsStructural Area ReinforcementStructural Area Reinforcement SymbolsStructural Area Reinforcement TagsStructural Beam System TagsStructural Beam SystemsStructural Column TagsStructural ColumnsStructural Connection TagsStructural ConnectionsStructural Fabric AreasStructural Fabric ReinforcementStructural Fabric Reinforcement SymbolsStructural Fabric Reinforcement TagsStructural Foundation TagsStructural FoundationsStructural FramingStructural Framing TagsStructural Internal LoadsStructural Load CasesStructural LoadsStructural Path ReinforcementStructural Path Reinforcement SymbolsStructural Path Reinforcement TagsStructural RebarStructural Rebar Coupler TagsStructural Rebar CouplersStructural Rebar TagsStructural Stiffener TagsStructural StiffenersStructural Truss TagsStructural TrussesSwitch SystemTelephone Device TagsTelephone DevicesText NotesTitle BlocksTopographyView ReferenceView TitlesViewportsViewsWall TagsWalls

(continues on next page)

1.4. Appendix B: System Category Names 13

Page 18: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Window TagsWindowsWire TagsWiresZone Tags

14 Chapter 1. Anatomy of a pyRevit Script

Page 19: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 2

Effective Output/Input

2.1 Clickable Element Links

work in progress

15

Page 20: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.2 Tables

work in progress

16 Chapter 2. Effective Output/Input

Page 21: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.3 Code Output

work in progress

2.4 Progress bars

work in progress

2.3. Code Output 17

Page 22: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.5 Standard Prompts

2.5.1 Alerts

pyrevit.forms.alert(msg, title=None, sub_msg=None, expanded=None, footer=”, ok=True, can-cel=False, yes=False, no=False, retry=False, warn_icon=True, options=None,exitscript=False)

Show a task dialog with given message.

Parameters

• msg (str) – message to be displayed

• title (str, optional) – task dialog title

• ok (bool, optional) – show OK button, defaults to True

• cancel (bool, optional) – show Cancel button, defaults to False

• yes (bool, optional) – show Yes button, defaults to False

• no (bool, optional) – show NO button, defaults to False

• retry (bool, optional) – show Retry button, defaults to False

• options (list[str], optional) – list of command link titles in order

• exitscript (bool, optional) – exit if cancel or no, defaults to False

Returns True if okay, yes, or retry, otherwise False

Return type bool

Example

>>> from pyrevit import forms>>> forms.alert('Are you sure?',... ok=False, yes=True, no=True, exitscript=True)

18 Chapter 2. Effective Output/Input

Page 23: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.forms.check_workshared(doc=None, message=’Model is not workshared.’)Verify if model is workshared and notify user if not.

Parameters

• doc (DB.Document) – target document, current of not provided

• message (str) – prompt message if returning False

Returns True if doc is workshared

Return type bool

class pyrevit.forms.WarningBar(height=32, **kwargs)Show warning bar at the top of Revit window.

Parameters title (string) – warning bar text

Example

>>> with WarningBar(title='my warning'):... # do stuff

2.5. Standard Prompts 19

Page 24: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.5.2 Command Options

class pyrevit.forms.CommandSwitchWindow(context, title, width, height, **kwargs)Standard form to select from a list of command options.

Parameters

• context (list[str]) – list of command options to choose from

• switches (list[str]) – list of on/off switches

• message (str) – window title message

• config (dict) – dictionary of config dicts for options or switches

Returns name of selected option

Return type str

Returns if switches option is used, returns a tuple of selection option name and dict of switches

Return type tuple(str, dict)

Example

This is an example with series of command options:

>>> from pyrevit import forms>>> ops = ['option1', 'option2', 'option3', 'option4']>>> forms.CommandSwitchWindow.show(ops, message='Select Option')'option2'

A more advanced example of combining command options, on/off switches, and option or switch configurationoptions:

>>> from pyrevit import forms>>> ops = ['option1', 'option2', 'option3', 'option4']>>> switches = ['switch1', 'switch2']>>> cfgs = {'option1': { 'background': '0xFF55FF'}}>>> rops, rswitches = forms.CommandSwitchWindow.show(... ops,... switches=switches... message='Select Option',... config=cfgs... )>>> rops'option2'

(continues on next page)

20 Chapter 2. Effective Output/Input

Page 25: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

>>> rswitches{'switch1': False, 'switch2': True}

2.5.3 Showing Progress

class pyrevit.forms.ProgressBar(height=32, **kwargs)Show progress bar at the top of Revit window.

Parameters

• title (string) – progress bar text, defaults to 0/100 progress format

• indeterminate (bool) – create indeterminate progress bar

• cancellable (bool) – add cancel button to progress bar

• step (int) – update progress intervals

Example

>>> from pyrevit import forms>>> count = 1>>> with forms.ProgressBar(title='my command progress message') as pb:... # do stuff... pb.update_progress(count, 100)... count += 1

Progress bar title could also be customized to show the current and total progress values. In example below, theprogress bar message will be in format “0 of 100”

>>> with forms.ProgressBar(title='{value} of {max_value}') as pb:

By default progress bar updates the progress every time the .update_progress method is called. For operationswith a large number of max steps, the gui update process time will have a significate effect on the overall

2.5. Standard Prompts 21

Page 26: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

execution time of the command. In these cases, set the value of step argument to something larger than 1. Inexample below, the progress bar updates once per every 10 units of progress.

>>> with forms.ProgressBar(title='message', steps=10):

Progress bar could also be set to indeterminate for operations of unknown length. In this case, the progress barwill show an infinitely running ribbon:

>>> with forms.ProgressBar(title='message', indeterminate=True):

if cancellable is set on the object, a cancel button will show on the progress bar and .cancelled attribute will beset on the ProgressBar instance if users clicks on cancel button:

>>> with forms.ProgressBar(title='message',... cancellable=True) as pb:... # do stuff... if pb.cancelled:... # wrap up and cancel operation

2.6 Standard Dialogs

2.6.1 Pick File

pyrevit.forms.pick_file(file_ext=”, files_filter=”, init_dir=”, restore_dir=True, multi_file=False,unc_paths=False)

Pick file dialog to select a destination file.

22 Chapter 2. Effective Output/Input

Page 27: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters

• file_ext (str) – file extension

• files_filter (str) – file filter

• init_dir (str) – initial directory

• restore_dir (bool) – restore last directory

• multi_file (bool) – allow select multiple files

• unc_paths (bool) – return unc paths

Returns file path or list of file paths if multi_file=True

Return type str or list[str]

Example

>>> from pyrevit import forms>>> forms.pick_file(file_ext='csv')... r'C:\output\somefile.csv'

>>> forms.pick_file(file_ext='csv', multi_file=True)... [r'C:\output\somefile1.csv', r'C:\output\somefile2.csv']

>>> forms.pick_file(files_filter='All Files (*.*)|*.*|''Excel Workbook (*.xlsx)|*.xlsx|''Excel 97-2003 Workbook|*.xls',

multi_file=True)... [r'C:\output\somefile1.xlsx', r'C:\output\somefile2.xls']

pyrevit.forms.save_file(file_ext=”, files_filter=”, init_dir=”, default_name=”, restore_dir=True,unc_paths=False)

Save file dialog to select a destination file for data.

Parameters

• file_ext (str) – file extension

• files_filter (str) – file filter

• init_dir (str) – initial directory

• default_name (str) – default file name

• restore_dir (bool) – restore last directory

• unc_paths (bool) – return unc paths

Returns file path

Return type str

Example

>>> from pyrevit import forms>>> forms.save_file(file_ext='csv')... r'C:\output\somefile.csv'

2.6. Standard Dialogs 23

Page 28: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.6.2 Pick Folder

pyrevit.forms.pick_folder(title=None)Show standard windows pick folder dialog.

Parameters title (str, optional) – title for the window

Returns folder path

Return type str

24 Chapter 2. Effective Output/Input

Page 29: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.6.3 Select Views

pyrevit.forms.select_views(title=’Select Views’, button_name=’Select’, width=500, multi-ple=True, filterfunc=None, doc=None)

Standard form for selecting views.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

• doc (DB.Document, optional) – source document for views; defaults to active doc-ument

Returns list of selected views

Return type list[DB.View]

Example

>>> from pyrevit import forms>>> forms.select_views()

(continues on next page)

2.6. Standard Dialogs 25

Page 30: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

... [<Autodesk.Revit.DB.View object>,

... <Autodesk.Revit.DB.View object>]

2.6.4 Select Sheets

pyrevit.forms.select_sheets(title=’Select Sheets’, button_name=’Select’, width=500, multi-ple=True, filterfunc=None, doc=None)

Standard form for selecting sheets.

Sheets are grouped into sheet sets and sheet set can be selected from a drop down box at the top of window.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

• doc (DB.Document, optional) – source document for sheets; defaults to active doc-ument

Returns list of selected sheets

Return type list[DB.ViewSheet]

26 Chapter 2. Effective Output/Input

Page 31: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit import forms>>> forms.select_sheets()... [<Autodesk.Revit.DB.ViewSheet object>,... <Autodesk.Revit.DB.ViewSheet object>]

2.6.5 Select Revisions

pyrevit.forms.select_revisions(title=’Select Revision’, button_name=’Select’, width=500, mul-tiple=True, filterfunc=None, doc=None)

Standard form for selecting revisions.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

• doc (DB.Document, optional) – source document for revisions; defaults to activedocument

Returns list of selected revisions

2.6. Standard Dialogs 27

Page 32: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Return type list[DB.Revision]

Example

>>> from pyrevit import forms>>> forms.select_revisions()... [<Autodesk.Revit.DB.Revision object>,... <Autodesk.Revit.DB.Revision object>]

2.6.6 Select From Open Documents

pyrevit.forms.select_open_docs(title=’Select Open Documents’, button_name=’OK’, width=500,multiple=True, filterfunc=None)

Standard form for selecting open documents.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

Returns list of selected documents

28 Chapter 2. Effective Output/Input

Page 33: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Return type list[DB.Document]

Example

>>> from pyrevit import forms>>> forms.select_open_docs()... [<Autodesk.Revit.DB.Document object>,... <Autodesk.Revit.DB.Document object>]

2.6.7 Select From List (Single, Multiple)

2.6. Standard Dialogs 29

Page 34: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

class pyrevit.forms.SelectFromList(context, title, width, height, **kwargs)Standard form to select from a list of items.

Any object can be passed in a list to the context argument. This class wraps the objects passed to context,in TemplateListItem. This class provides the necessary mechanism to make this form work both forselecting items from a list, and from a list of checkboxes. See the list of arguments below for additional optionsand features.

Parameters

• context (list[str] or dict[list[str]]) – list of items to be selected fromOR dict of list of items to be selected from. use dict when input items need to be groupede.g. List of sheets grouped by sheet set.

• title (str, optional) – window title. see super class for defaults.

• width (int, optional) – window width. see super class for defaults.

• height (int, optional) – window height. see super class for defaults.

• button_name (str, optional) – name of select button. defaults to ‘Select’

• name_attr (str, optional) – object attribute that should be read as item name.

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto False

• return_all (bool, optional) – return all items. This is handly when some inputitems have states and the script needs to check the state changes on all items. This optionsworks in multiselect mode only. defaults to False

• filterfunc (function) – filter function to be applied to context items.

• group_selector_title (str) – title for list group selector. defaults to ‘List Group’

30 Chapter 2. Effective Output/Input

Page 35: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• default_group (str) – name of defautl group to be selected

Example

>>> from pyrevit import forms>>> items = ['item1', 'item2', 'item3']>>> forms.SelectFromList.show(items, button_name='Select Item')>>> ['item1']

>>> from pyrevit import forms>>> ops = [viewsheet1, viewsheet2, viewsheet3]>>> res = forms.SelectFromList.show(ops,... multiselect=False,... name_attr='Name',... button_name='Select Sheet')

>>> from pyrevit import forms>>> ops = {'Sheet Set A': [viewsheet1, viewsheet2, viewsheet3],... 'Sheet Set B': [viewsheet4, viewsheet5, viewsheet6]}>>> res = forms.SelectFromList.show(ops,... multiselect=True,... name_attr='Name',... group_selector_title='Sheet Sets',... button_name='Select Sheets')

This module also provides a wrapper base class TemplateListItem for when the checkbox option is wrap-ping another element, e.g. a Revit ViewSheet. Derive from this base class and define the name property tocustomize how the checkbox is named on the dialog.

>>> from pyrevit import forms>>> class MyOption(forms.TemplateListItem)... @property... def name(self):... return '{} - {}{}'.format(self.item.SheetNumber,... self.item.SheetNumber)>>> ops = [MyOption('op1'), MyOption('op2', True), MyOption('op3')]>>> res = forms.SelectFromList.show(ops,... multiselect=True,... button_name='Select Item')>>> [bool(x) for x in res] # or [x.state for x in res][True, False, True]

class pyrevit.forms.TemplateListItem(orig_item, checkable=True, name_attr=None)Base class for checkbox option wrapping another object.

2.7 Base Forms

2.7.1 Input Dialog for pyRevit Search

2.7. Base Forms 31

Page 36: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.forms.SearchPrompt(search_db, width, height, **kwargs)Standard prompt for pyRevit search.

Parameters

• search_db (list) – list of possible search targets

• search_tip (str) – text to show in grayscale when search box is empty

• switches (str) – list of switches

• width (int) – width of search prompt window

• height (int) – height of search prompt window

Returns matched strings, and dict of switches if provided str: matched string if switches are notprovided.

Return type str, dict

Example

>>> from pyrevit import forms>>> # assume search input of '/switch1 target1'>>> matched_str, args, switches = forms.SearchPrompt.show(... search_db=['target1', 'target2', 'target3', 'target4'],... switches=['/switch1', '/switch2'],... search_tip='pyRevit Search'... )... matched_str'target1'... args['--help', '--branch', 'branchname']... switches{'/switch1': True, '/switch2': False}

2.7.2 Generic Forms

class pyrevit.forms.TemplatePromptBar(height=32, **kwargs)Template context-manager class for creating prompt bars.

Prompt bars are show at the top of the active Revit window and are designed for better prompt visibility.

Parameters

• height (int) – window height

• **kwargs – other arguments to be passed to _setup()

class pyrevit.forms.TemplateUserInputWindow(context, title, width, height, **kwargs)Base class for pyRevit user input standard forms.

Parameters

• context (any) – window context element(s)

• title (str) – window title

• width (int) – window width

• height (int) – window height

32 Chapter 2. Effective Output/Input

Page 37: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• **kwargs – other arguments to be passed to _setup()

class pyrevit.forms.WPFWindow(xaml_source, literal_string=False, handle_esc=True)WPF Window base class for all pyRevit forms.

Parameters

• xaml_source (str) – xaml source filepath or xaml content

• literal_string (bool) – xaml_source contains xaml content, not filepath

• handle_esc (bool) – handle Escape button and close the window

Example

>>> from pyrevit import forms>>> layout = '<Window ShowInTaskbar="False" ResizeMode="NoResize" ' \>>> 'WindowStartupLocation="CenterScreen" ' \>>> 'HorizontalContentAlignment="Center">' \>>> '</Window>'>>> w = forms.WPFWindow(layout, literal_string=True)>>> w.show()

2.8 Graphs

Step 1: Create a chart object for the chart type that you want. We’ll add data to this later. . .

from pyrevit import script

output = script.get_output()

# Line chartchart = output.make_line_chart()# Bar chartchart = output.make_bar_chart()# Bubble chartchart = output.make_bubble_chart()# Radar chartchart = output.make_radar_chart()# Polar chartchart = output.make_polar_chart()# Pie chartchart = output.make_pie_chart()# Doughnut chartchart = output.make_doughnut_chart()

Step 1-a: Optional: Setup the chart title, and other options. the full list of options for every chart is available onCharts.js Documentation page. Some of the properties have their own sub-properties, for example the title optionfor the charts has multiple sub-properties as shown below. The value for these type of properties should be a dictionaryof the sub-properties you’d like to set. All this is explained clearly in the Charts.js Documentation

chart.set_style('height:150px')

chart.options.title = {'display': True,'text':'Chart Title',

(continues on next page)

2.8. Graphs 33

Page 38: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

'fontSize': 18,'fontColor': '#000','fontStyle': 'bold'}

Step 2: Now let’s add data to the chart. Every chart object has a data property chart.data that we can interactwith to add datasets to the chart. Different types of charts need different types of data sets in terms of how data isorganized, so the chart can present multiple data sets correctly. I’m providing two examples here, one for a simple linechart (showing 3 different data sets) and another for a radial chart (also showing 3 different data sets within the samechart). They’re all very similar to each other though.

# setting the charts x line data labelschart.data.labels = ['Monday', 'Tuesday',

'Wednesday', 'Thursday','Friday', 'Saturday', 'Sunday']

# Let's add the first dataset to the chart object# we'll give it a name: set_aset_a = chart.data.new_dataset('set_a')# And let's add data to it.# These are the data for the Y axis of the graph# The data length should match the length of data for the X axisset_a.data = [12, 19, 3, 17, 6, 3, 7]# Set the color for this graphset_a.set_color(0xFF, 0x8C, 0x8D, 0.8)

Step 3: The last step is to ask the chart object to draw itself.

# Before drawing the chart you can randomize the colors# if you have not added any color to the datasets.chart.randomize_colors()

# Finally let's draw the chartchart.draw()

2.8.1 Line charts

See the comments in the script for more info

# get line chart objectchart = output.make_line_chart()

# this is a list of labels for the X axis of the line graphchart.data.labels = ['Monday', 'Tuesday',

'Wednesday', 'Thursday','Friday', 'Saturday', 'Sunday']

# Let's add the first dataset to the chart object# we'll give it a name: set_aset_a = chart.data.new_dataset('set_a')# And let's add data to it.# These are the data for the Y axis of the graph# The data length should match the length of data for the X axisset_a.data = [12, 19, 3, 17, 6, 3, 7]# Set the color for this graph

(continues on next page)

34 Chapter 2. Effective Output/Input

Page 39: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

set_a.set_color(0xFF, 0x8C, 0x8D, 0.8)# You can also set custom options for this graph# See the Charts.js documentation for all the optionsset_b.fill = False

# Same as above for a new data set: set_bset_b = chart.data.new_dataset('set_b')# Obviously a different set of data and a different colorset_b.data = [2, 29, 5, 5, 2, 3, 10]set_b.set_color(0xFF, 0xCE, 0x56, 0.8)

# Same as above for a new data set: set_cset_c = chart.data.new_dataset('set_c')# Obviously a different set of data and a different colorset_c.data = [55, 12, 2, 20,→˓18, 6, 22]set_c.set_color(0x36, 0xA2, 0xEB, 0.8)

And here is the result:

2.8.2 Pie charts

See the comments in the script for more info

# get pie chart objectchart = output.make_pie_chart()

# Set the labels for the circumference axischart.data.labels = ['A', 'B', 'C']

# Create new data setsset_a = chart.data.new_dataset('set_a')set_a.data = [100, 20, 50]# You can set a different color for each pie of the chart

(continues on next page)

2.8. Graphs 35

Page 40: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

set_a.backgroundColor = ["#560764", "#1F6CB0", "#F98B60"]

set_b = chart.data.new_dataset('set_b')set_b.data = [50, 30, 80]set_b.backgroundColor = ["#913175", "#70A3C4", "#FFC057"]

set_c = chart.data.new_dataset('set_c')set_c.data = [40, 20, 10]set_c.backgroundColor = ["#DD5B82", "#E7E8F5", "#FFE084"]

And here is the result:

2.8.3 Bar charts

See the comments in the script for more info

# get bar chart objectchart = output.make_bar_chart()

And here is the result:

36 Chapter 2. Effective Output/Input

Page 41: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.8.4 Bubble charts

See the comments in the script for more info

# get bubble chart objectchart = output.make_bubble_chart()

And here is the result:

2.8.5 Radar charts

See the comments in the script for more info

2.8. Graphs 37

Page 42: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

# get radar chart objectchart = output.make_radar_chart()

And here is the result:

2.8.6 Polar Area charts

See the comments in the script for more info

# get polar chart objectchart = output.make_polar_chart()

And here is the result:

38 Chapter 2. Effective Output/Input

Page 43: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.8.7 Doghnut charts

See the comments in the script for more info

# get doughnut chart objectchart = output.make_doughnut_chart()

And here is the result:

2.8. Graphs 39

Page 44: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

2.8.8 Charts engine

Here is a little info on how the charts engine works: the pyRevit charts module is pyrevit.coreutils.charts.This is the module that the output window interacts with to create the charts.

The charts module provides the chart object and handles the creation of datasets. The first thing it does when drawingthe graph is to create a html <canvas> element and assign a unique id to it:

<canvas id="chart123456"></canvas>

Then it parses the input data and creates a JSON representation of the data. The JSON string (json_data) will beinserted into a template javascript. This javascript creates a Chart object from the Chart.js library:

var ctx = document.getElementById('{}').getContext('2d');var chart = new Chart(ctx, json_data);

and finally, the pyRevit chart object, injects this dynamically created javascript into the <head> of the output windowWebBrowser component:

output.inject_script(js_code)

40 Chapter 2. Effective Output/Input

Page 45: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 3

Keyboard Shortcuts

3.1 Shift-Click: Alternate/Config Script

Each pyRevit command bundle can contain two scripts:

*script.py is the main script.

*config.py is the Alternale/Config script.

SHIFT-clicking on a ui button will run the alternate/config script. This alternate script is generally used to configurethe main tool. Try Shift clicking on the Match tool in pyRevit > Modify panel and see the configuration window. Thentry Shift clicking on the Settings tool in pyRevit panel slide-out and see what it does.

If you don’t define the configuration script, you can check the value of __shiftclick__ in your scripts to changescript behaviour. This is the method that the Settings command is using to open the config file location in explorer:

if __shiftclick__:do_task_A()

else:do_task_B()

3.2 Ctrl-Click: Debug Mode

CTRL-clicking on a ui button will run the script in DEBUG mode and will allow the script to print all debug messages.You can check the value of __forceddebugmode__ variable to see if the script is running in Debug mode to changescript behaviour if neccessary.

if __forceddebugmode__:do_task_A()

else:do_task_B()

41

Page 46: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

3.3 Alt-Click: Show Script file in Explorer

ALT-clicking on a ui button will show the associated script file in windows explorer.

3.4 Ctrl-Shift-Alt-Click: Reload Engine

If you’re using pyRevit Rocket mode, this keyboard combination will force pyRevit to discard the cached engine forthis command and use a new fresh engine. If you are developing scripts for pyRevit and using external modules, you’llneed to use this keyboard combination after changes to the imported module source codes. Since the modules arealready imported in the cached engine, you’d need a new fresh engine to reload the modules.

3.5 Shift-Win-Click: pyRevit Button Context Menu

Shows the context menu for the pyRevit command. See image below:

42 Chapter 3. Keyboard Shortcuts

Page 47: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 4

Extensions and Commmands

4.1 Why do I need an Extension

pyRevit’s extensions system has evolved again to be more flexible and easier to work with. We’ll dive right into howyou can add your own extension, but first let’s answer one important question:

Q: Why would I need to create a separate extension? Why Can’t I just add my scripts to the current pyRevit tools?

A: Because pyRevit is a git repository and the real benefit of that is that you can keep it always updated without theneed to unsinstall and install the newer versions. To keep this system running without issues, I highly recommendnot to mess with the pyRevit git repository folders and contents and pyRevit makes it really easy to add your ownextensions. You can even add tools to the standard pyRevit tab in your own extensions. I’ll show you how.

Besides, by creating a separate extension, you’ll have all your precious scripts and tools in a safe place and away fromthe changes being made to the core pyRevit. They can even live somewhere on your company shared drives and beshared between your teams.

4.2 Extensions

Each extension is a group of tools, organized in bundles to be easily accessible through the user interface.

Extensions are organized in a folder bundle with .extension postfix.

Like this one:

43

Page 48: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

There are two steps that you need to follow to create your own extensions:

• Setup external extension folder:

First, is to create a separate folder for all your custom extensions and tell pyRevit to load yourextensions from this folder. This is done in the Settings window, under the Custom Extension folderssection. This way your precious extensions will stay out of the pyRevit installation and are safe.

• Create custom extension bundle:

Next, create your <your extension name>.extension folder under your custom exten-sions folder. Read the sections below on how to create bundles for your commands and the userinterface.

4.3 Command Bundles

A bundle is a folder named in the format bundle_name.bundle_type.

Like these:

44 Chapter 4. Extensions and Commmands

Page 49: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

The most basic bundle is a command bundle. There are more than one type of command bundles but a .pushbuttonbundle explained here covers 90% of the use cases.

4.3.1 Pushbutton Bundle

Each command bundle needs to include a script either in python or C#:

script.py:

The first script file under the bundle that ends with script.py will be used as the script for this com-mand bundle.

Examples: BuildWall_script.py Analyse-script.py

config.py:

This for python commands configuration. If this script is provided then Shift-Clicking on the button willrun this command instead. Also a black dot will be added to the button name in the user interface to showthat this command has a custom configuration tool. See Shift-Click: Alternate/Config Script

script.cs:

This for C# commands and works similarly to python scripts. This C# script will be compiled in runtime.

icon.png:

Command bundles can include an icon for their user interface.

lib/:

Bundles can define a python library (a sub-folder named lib inside the bundle will do). This library willbe accessible to the python script in this bundle. This organizes all the python modules that are necessaryfor this python script to work into one folder.

This is how a command bundle looks like:

And this is a more advanced command bundle with a configuration script and configuration window definition file:

4.4 Group Bundles

Now that we have explained the command bundles, we need a way to organize these commands into a user-friendlyinterface. Let’s introduce Group Bundles

A group bundle is a bundle that can contain command bundles and other group bundles. They come in all differentshapes and sizes but they have a few features in common:

• They can contain command bundles and other group bundles. (But I’ve already said that)

4.4. Group Bundles 45

Page 50: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• icon.png: Bundle can include an icon for their user interface.

• lib/: The can define a python library (a sub-folder named lib inside the bundle will do). This library will beaccessible to all the commands in this bundle and other child group bundles. This folder can contain all thepython modules that are being shared between the child commands.

• _layout: This is a text file inside the bundle that defines the order in which the bundle contents should be createdin the user interface. The contents of this file should be the names of the component in the order that they shouldbe created in the user interface.

Here is _layout file example. This is a layout file for a Group Bundle that has a series of push buttons and othergroup bundles under itself:

PushButton APushButton BPullDown A---PullDown BStack3 A>>>PushButton CPullDown C

Oh, and also:

• --- This line will add a separator to the interface (You can use more than 3 - characters. For example---------- still works as a separator)

• >>> Any bundle after this line will be created inside a slide-out. This works for panel bundles only. (You canuse more than 3 > characters. For example >>>>>>>>> still works as a slide-out)

And this is how a typical Group Bundle looks like:

Now let’s talk about the different Group Bundles:

4.4.1 Tab Bundle

This bundle creates a Tab in the Ribbon with the bundle name.

Example Can ContainpyRevit.tab Only .panel Group Bundles.

46 Chapter 4. Extensions and Commmands

Page 51: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

4.4.2 Panel Bundle

This bundle creates a Panel in a Ribbon Tab with the bundle name.

Example Can ContainpyRevit.panel Any other bundle type

4.4.3 PullDown Bundle

This bundle creates a Pulldown Button in a Ribbon Panel or a Stack, with the bundle name and icon.

Example Can ContainpyRevit.pulldown Only command bundles

4.4.4 SplitButton Bundle

This bundle creates a Split Button button in a Ribbon Panel or a Stack, with the bundle name and icon.

Example Can ContainpyRevit.splitbutton Only command bundles

4.4.5 SplitPushButton Bundle

This bundle creates a Split Push Button button (The sticky split button) in a Ribbon Panel or a Stack, with the bundlename and icon.

Example Can ContainpyRevit.splitpushbutton Only command bundles

4.4.6 Stack Bundle: Two Buttons

This bundle creates a stack of 2 buttons in a panel.

Example Can ContainpyRevit.stack2 Can contain: .pulldown .splitbutton .splitpushbutton

4.4.7 Stack Bundle: Three Buttons

Just like the .stack2 bundle but with 3 buttons instead.

4.5 Advanced Bundles

There are a few more advanced bundle types in pyRevit as well. Here is some quick intro on these bundles.

4.5. Advanced Bundles 47

Page 52: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

4.5.1 Smart Button Bundle

ExamplepyRevit.smartbutton

Smart buttons are python scripts that are written like modules. They should define __selfinit__ function asshown below. This function gets executed at startup time to give a chance to the button to initialize itself (e.g set itsicon based on its state).

The __selfinit__ must return True if the initialization is successful and False if it is not. pyRevit will notcreate the button if the initialization returns False and is unsuccessful.

def __selfinit__(script_cmp, ui_button_cmp, __rvt__):"""Args:

script_cmp: script component that contains info on this scriptui_button_cmp: this is the UI button component__rvt__: Revit UIApplication

Returns:bool: Return True if successful, False if not

"""

run_self_initialization()

4.5.2 No Button Bundle

ExamplepyRevit.nobutton

No-Button bundles are just like Pushbutton bundles except that they will never show up inside Revit UI and thus don’tneed any icons. The only method to run these commands is through pyRevit Search tool. These commands are meantfor more advanced commands that not every user needs.

4.5.3 Panel Button Bundle

ExamplepyRevit.panelbutton

Panle Button bundles are just like Pushbutton bundles except that they will be set as the panel configuration button(small arrow at the corner of UI Panels). These bundles do not need to have an icon as the standard Small arrow iconis used for panel configuration buttons by default. These commands work just like any pyRevit command but theirprimary purpose should be to configure set of related tools in a panel.

4.5.4 Link Button Bundle

ExamplepyRevit.linkbutton

48 Chapter 4. Extensions and Commmands

Page 53: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Link buttons can call a function from another Addin. To make a link button define the parameters below in the bundlesscript.py:

Note: For this button to work properly, the target addin must be already loaded when this button is being created,otherwise Revit can not tie the UI button to an assembly that is not loaded.

__assembly__ = 'Addin assembly name'__commandclass__ = 'Class name for the command'

For example to call the Interactive Python Shell from RevitPythonShell addin:

__assembly__ = 'RevitPythonShell'__commandclass__ = 'IronPythonConsoleCommand'

4.6 Other Extension Types

4.6.1 Library Extensions

Library extensions are created to share IronPython modules between all extensions. They’re in essence IronPythonmodule packages. Some users might decide to develop an IronPython library (e.g. RevitPythonWrapper Library) thatother users can use in their tools and benefit from.

Library extensions are identified by .lib postfix. The library extension folder address will be added to the sys.path of all the other extensions by the loader.

4.6. Other Extension Types 49

Page 54: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

50 Chapter 4. Extensions and Commmands

Page 55: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 5

pyRevit Configuration

work in progress

51

Page 56: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

52 Chapter 5. pyRevit Configuration

Page 57: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 6

Usage Logger

work in progress

53

Page 58: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

54 Chapter 6. Usage Logger

Page 59: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 7

pyRevit Installer

work in progress

pyRevit Core

• Load Sequence, Step 1: Revit Addon

• Load Sequence, Step 2: IronPython Module

55

Page 60: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

56 Chapter 7. pyRevit Installer

Page 61: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 8

Load Sequence, Step 1: Revit Addon

8.1 The Complex Relationship of a C# Addin and a Python Script

Let’s talk basics:

• Revit Addons are written in C# and are windows .dll files.

• pyRevit is written as an IronPython module. (actually a bit more complex than that)

• Revit doesn’t have an option to run external python scripts.

Thus, we need a way to teach Revit how to run a python script when it’s starting up.

The solution was to create a custom C# addin to create a python engine and run a script. We’ll call this addinpyRevitLoader.dll. I wanted to keep this addin as simple as possible since it’s the only statically-compiledpiece of code in this project. The rest of the task of loading pyRevit were assigned to a loader python script that isbeing run by the loader addin.

So:

• pyRevitLoader.dll is a simple C# addin for Revit that runs python scripts

• pyRevitLoader.dll loads pyRevitLoader.py at startup.

• pyRevitLoader.py sets up the environment and loads pyRevit.

It’s that simple really. See the sources below.

From here on, the documentation page for the pyrevit.loader module will take you through all the steps of parsingextensions, making dll assemblies and creating the user interface for the parsed extensions.

8.2 pyRevit loader script

Here is the full source of pyRevitLoader.py. The docstring explains how it works.

57

Page 62: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

# -*- coding: utf-8 -*-#pylint: disable=C0103,W1401,E0401,E0602"""

This is the starting point for pyRevit. At Revit loads the PyRevitLoader.dlladdon at startup. This dll then creates an ironpython engine and runspyRevitLoader.py (this script). It's the job of this script to setup theenvironment for the pyrevit module (pyrevitlib\pyrevit) and load a new pyRevitsession. This script needs to add the directory path of the pyrevit lib folderso the pyrevit module can be imported and used.

"""

import sysimport os.path as op

# add the library location to the system search pathsrepo_path = op.dirname(op.dirname(op.dirname(__file__)))sys.path.append(op.join(repo_path, 'pyrevitlib'))

# now pyrevit can be importedfrom pyrevit.loader import sessionmgr

# ask sessionmgr to start a new sessionsessionmgr.load_session()

8.3 pyRevitLoader Addin Source

The source code for pyRevitLoader addin is under: pyrevitlib/pyrevit/addin/<loader version>/Source

58 Chapter 8. Load Sequence, Step 1: Revit Addon

Page 63: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 9

Load Sequence, Step 2: IronPython Module

work in progress

Modules

• pyrevit

• pyrevit.api

• pyrevit.compat

• pyrevit.forms

• pyrevit.framework

• pyrevit.script

• pyrevit.userconfig

• pyrevit.coreutils

• pyrevit.output

59

Page 64: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

60 Chapter 9. Load Sequence, Step 2: IronPython Module

Page 65: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 10

pyrevit

pyRevit root level config for all pyrevit sub-modules.

Examples

>>> from pyrevit import DB, UI>>> from pyrevit import PyRevitException, PyRevitIOError

>>> # pyrevit module has global instance of the>>> # _HostAppPostableCommand and _ExecutorParams classes already created>>> # import and use them like below>>> from pyrevit import HOST_APP>>> from pyrevit import EXEC_PARAMS

class pyrevit.PyRevitExceptionBase class for all pyRevit Exceptions.

Parameters args and message are derived from Exception class.

class pyrevit.PyRevitIOErrorGeneric IO error in pyRevit.

class pyrevit._HostAppPostableCommand(name, key, id, rvtobj)Private namedtuple for passing information about a PostableCommand

namestr – Postable command name

keystr – Postable command key string

idint – Postable command id

rvtobjRevitCommandId – Postable command Id Object

61

Page 66: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

class pyrevit._HostApplication(host_uiapp)Private Wrapper for Current Instance of Revit.

Provides version info and comparison functionality, alongside providing info on the active screen, active docu-ment and ui-document, available postable commands, and other functionality.

Parameters host_uiapp (UIApplication) – Instance of running host.

Example

>>> hostapp = _HostApplication(__revit__)>>> hostapp.is_newer_than(2017)

activeviewReturn view that is active (UIDocument.ActiveView).

appReturn Application provided to the running command.

available_serversReturn list of available Revit server names.

buildstr – Return build number (e.g. ‘20170927_1515(x64)’).

docReturn active Document.

docsReturn list of open Document objects.

get_postable_commands()Return list of postable commands.

Returns list of _HostAppPostableCommand

is_exactly(version)bool: Return True if host app is equal to provided version.

Parameters version (str or int) – version to check against.

is_newer_than(version, or_equal=False)bool: Return True if host app is newer than provided version.

Parameters version (str or int) – version to check against.

is_older_than(version)bool: Return True if host app is older than provided version.

Parameters version (str or int) – version to check against.

procSystem.Diagnostics.Process – Return current process object.

proc_idint – Return current process id.

proc_namestr – Return current process name.

proc_pathstr – Return file path for the current process main module.

62 Chapter 10. pyrevit

Page 67: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

proc_screenintptr – Return handle to screen hosting current process.

proc_screen_scalefactorfloat – Return scaling for screen hosting current process.

proc_screen_workareaSystem.Drawing.Rectangle – Return screen working area.

subversionstr – Return subversion number (e.g. ‘2018.3’).

uiappReturn UIApplication provided to the running command.

uidocReturn active UIDocument.

usernamestr – Return the username from Revit API (Application.Username).

versionstr – Return version number (e.g. ‘2018’).

version_namestr – Return version name (e.g. ‘Autodesk Revit 2018’).

class pyrevit._ExecutorParamsPrivate Wrapper that provides runtime environment info.

command_alt_pathstr – Return current command alternate script path.

command_bundlestr – Return current command bundle name.

command_dataExternalCommandData – Return current command data.

command_extensionstr – Return current command extension name.

command_modebool – Check if pyrevit is running in pyrevit command context.

command_namestr – Return current command name.

command_pathstr – Return current command path.

command_uniqueidstr – Return current command unique id.

doc_modebool – Check if pyrevit is running by doc generator.

engine_mgrPyRevitBaseClasses.EngineManager – Return engine manager.

engine_verstr – Return PyRevitLoader.ScriptExecutor hardcoded version.

63

Page 68: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

executed_from_uibool – Check if command was executed from ui.

first_loadbool – Check whether pyrevit is not running in pyrevit command.

forced_debug_modebool – Check if command is in debug mode.

pyrevit_commandPyRevitBaseClasses.PyRevitCommandRuntime – Return command.

result_dictDictionary<String, String> – Return results dict for logging.

window_handlePyRevitBaseClasses.ScriptOutput – Return output window.

10.1 Implementation

"""pyRevit root level config for all pyrevit sub-modules.

Examples:>>> from pyrevit import DB, UI>>> from pyrevit import PyRevitException, PyRevitIOError

>>> # pyrevit module has global instance of the>>> # _HostAppPostableCommand and _ExecutorParams classes already created>>> # import and use them like below>>> from pyrevit import HOST_APP>>> from pyrevit import EXEC_PARAMS

"""#pylint: disable=W0703,C0302,C0103,C0413import sysimport osimport os.path as opfrom collections import namedtupleimport tracebackimport clr #pylint: disable=E0401

try:clr.AddReference('PyRevitLoader')

except Exception:# probably older IronPython engine not being able to# resolve to an already loaded assembly.# PyRevitLoader is executing this script so it should be referabe.pass

try:import PyRevitLoader

except ImportError:# this means that pyRevit is _not_ being loaded from a pyRevit engine# e.g. when importing from RevitPythonShellPyRevitLoader = None

(continues on next page)

64 Chapter 10. pyrevit

Page 69: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

PYREVIT_ADDON_NAME = 'pyRevit'VERSION_MAJOR = 4VERSION_MINOR = 6BUILD_METADATA = '.12'

# -----------------------------------------------------------------------------# config environment paths# -----------------------------------------------------------------------------# main pyrevit repo foldertry:

# 3 steps back for <home>/Lib/pyrevitHOME_DIR = op.dirname(op.dirname(op.dirname(__file__)))

except NameError:raise Exception('Critical Error. Can not find home directory.')

# BIN directoryBIN_DIR = op.join(HOME_DIR, 'bin')

# main pyrevit lib foldersMAIN_LIB_DIR = op.join(HOME_DIR, 'pyrevitlib')MISC_LIB_DIR = op.join(HOME_DIR, 'site-packages')

# path to pyrevit moduleMODULE_DIR = op.join(MAIN_LIB_DIR, 'pyrevit')

# loader directoryLOADER_DIR = op.join(MODULE_DIR, 'loader')

# addin directoryADDIN_DIR = op.join(LOADER_DIR, 'addin')

# if loader module is available means pyRevit is being executed by Revit.if PyRevitLoader:

ENGINES_DIR = \op.join(BIN_DIR, 'engines', PyRevitLoader.ScriptExecutor.EngineVersion)

ADDIN_RESOURCE_DIR = op.join(BIN_DIR, 'engines','Source', 'pyRevitLoader', 'Resources')

# otherwise it might be under test, or documentation processing.# so let's keep the symbols but set to None (fake the symbols)else:

ENGINES_DIR = ADDIN_RESOURCE_DIR = None

# add the framework dll path to the search pathssys.path.append(BIN_DIR)sys.path.append(ADDIN_DIR)sys.path.append(ENGINES_DIR)

# now we can start importing stufffrom pyrevit.compat import safe_strtypefrom pyrevit.framework import Processfrom pyrevit.framework import Windowsfrom pyrevit.framework import Formsfrom pyrevit.api import DB, UI

# -----------------------------------------------------------------------------# Base Exceptions

(continues on next page)

10.1. Implementation 65

Page 70: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# -----------------------------------------------------------------------------TRACEBACK_TITLE = 'Traceback:'

# General Exceptionsclass PyRevitException(Exception):

"""Base class for all pyRevit Exceptions.

Parameters args and message are derived from Exception class."""

@propertydef msg(self):

"""Return exception message."""if self.args:

return self.args[0] #pylint: disable=E1136else:

return ''

def __str__(self):"""Process stack trace and prepare report for output window."""sys.exc_type, sys.exc_value, sys.exc_traceback = sys.exc_info()try:

tb_report = traceback.format_tb(sys.exc_traceback)[0]if self.msg:

return '{}\n\n{}\n{}'.format(self.msg,TRACEBACK_TITLE,tb_report)

else:return '{}\n{}'.format(TRACEBACK_TITLE, tb_report)

except Exception:return Exception.__str__(self)

class PyRevitIOError(PyRevitException):"""Generic IO error in pyRevit."""

pass

# -----------------------------------------------------------------------------# Wrapper for __revit__ builtin parameter set in scope by C# Script Executor# -----------------------------------------------------------------------------# namedtuple for passing information about a PostableCommand_HostAppPostableCommand = namedtuple('_HostAppPostableCommand',

['name', 'key', 'id', 'rvtobj'])"""Private namedtuple for passing information about a PostableCommand

Attributes:name (str): Postable command namekey (str): Postable command key stringid (int): Postable command idrvtobj (``RevitCommandId``): Postable command Id Object

"""

class _HostApplication(object):(continues on next page)

66 Chapter 10. pyrevit

Page 71: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Private Wrapper for Current Instance of Revit.

Provides version info and comparison functionality, alongside providinginfo on the active screen, active document and ui-document, availablepostable commands, and other functionality.

Args:host_uiapp (``UIApplication``): Instance of running host.

Example:>>> hostapp = _HostApplication(__revit__)>>> hostapp.is_newer_than(2017)

"""

def __init__(self, host_uiapp):self._uiapp = host_uiappself._postable_cmds = []

@propertydef uiapp(self):

"""Return UIApplication provided to the running command."""return self._uiapp

@propertydef app(self):

"""Return Application provided to the running command."""return self.uiapp.Application

@propertydef uidoc(self):

"""Return active UIDocument."""return getattr(self.uiapp, 'ActiveUIDocument', None)

@propertydef doc(self):

"""Return active Document."""return getattr(self.uidoc, 'Document', None)

@propertydef activeview(self):

"""Return view that is active (UIDocument.ActiveView)."""return getattr(self.uidoc, 'ActiveView', None)

@activeview.setterdef activeview(self, value):

"""Set the active view in user interface."""setattr(self.uidoc, 'ActiveView', value)

@propertydef docs(self):

"""Return :obj:`list` of open :obj:`Document` objects."""return getattr(self.app, 'Documents', None)

@propertydef available_servers(self):

"""Return :obj:`list` of available Revit server names."""return list(self.app.GetRevitServerNetworkHosts())

(continues on next page)

10.1. Implementation 67

Page 72: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

@propertydef version(self):

"""str: Return version number (e.g. '2018')."""return self.app.VersionNumber

@propertydef subversion(self):

"""str: Return subversion number (e.g. '2018.3')."""return self.app.SubVersionNumber

@propertydef version_name(self):

"""str: Return version name (e.g. 'Autodesk Revit 2018')."""return self.app.VersionName

@propertydef build(self):

"""str: Return build number (e.g. '20170927_1515(x64)')."""return self.app.VersionBuild

@propertydef username(self):

"""str: Return the username from Revit API (Application.Username)."""uname = self.app.Usernameuname = uname.split('@')[0] # if username is email# removing dots since username will be used in file naminguname = uname.replace('.', '')return uname

@propertydef proc(self):

"""System.Diagnostics.Process: Return current process object."""return Process.GetCurrentProcess()

@propertydef proc_id(self):

"""int: Return current process id."""return Process.GetCurrentProcess().Id

@propertydef proc_name(self):

"""str: Return current process name."""return Process.GetCurrentProcess().ProcessName

@propertydef proc_path(self):

"""str: Return file path for the current process main module."""return Process.GetCurrentProcess().MainModule.FileName

@propertydef proc_screen(self):

"""``intptr``: Return handle to screen hosting current process."""return Forms.Screen.FromHandle(

Process.GetCurrentProcess().MainWindowHandle)

@property(continues on next page)

68 Chapter 10. pyrevit

Page 73: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def proc_screen_workarea(self):"""``System.Drawing.Rectangle``: Return screen working area."""screen = HOST_APP.proc_screenif screen:

return screen.WorkingArea

@propertydef proc_screen_scalefactor(self):

"""float: Return scaling for screen hosting current process."""screen = HOST_APP.proc_screenif screen:

actual_wdith = Windows.SystemParameters.PrimaryScreenWidthscaled_width = screen.PrimaryScreen.WorkingArea.Widthreturn abs(scaled_width / actual_wdith)

def is_newer_than(self, version, or_equal=False):"""bool: Return True if host app is newer than provided version.

Args:version (str or int): version to check against.

"""if or_equal:

return int(self.version) >= int(version)else:

return int(self.version) > int(version)

def is_older_than(self, version):"""bool: Return True if host app is older than provided version.

Args:version (str or int): version to check against.

"""return int(self.version) < int(version)

def is_exactly(self, version):"""bool: Return True if host app is equal to provided version.

Args:version (str or int): version to check against.

"""return int(self.version) == int(version)

def get_postable_commands(self):"""Return list of postable commands.

Returns::obj:`list` of :obj:`_HostAppPostableCommand`

"""# if list of postable commands is _not_ already created# make the list and store in instance parameterif not self._postable_cmds:

for pc in UI.PostableCommand.GetValues(UI.PostableCommand):try:

rcid = UI.RevitCommandId.LookupPostableCommandId(pc)self._postable_cmds.append(

# wrap postable command info in custom namedtuple_HostAppPostableCommand(name=safe_strtype(pc),

(continues on next page)

10.1. Implementation 69

Page 74: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

key=rcid.Name,id=rcid.Id,rvtobj=rcid)

)except Exception:

# if any error occured when querying postable command# or its info, pass silentlypass

return self._postable_cmds

try:# Create an intance of host application wrapper# making sure __revit__ is availableHOST_APP = _HostApplication(__revit__) #pylint: disable=E0602

except Exception:raise Exception('Critical Error: Host software is not supported. '

'(__revit__ handle is not available)')

# -----------------------------------------------------------------------------# Wrapper to access builtin parameters set in scope by C# Script Executor# -----------------------------------------------------------------------------class _ExecutorParams(object):

"""Private Wrapper that provides runtime environment info."""

@property # read-onlydef engine_mgr(self):

"""``PyRevitBaseClasses.EngineManager``: Return engine manager."""try:

return __ipyenginemanager__except NameError:

raise AttributeError()

@property # read-onlydef engine_ver(self):

"""str: Return PyRevitLoader.ScriptExecutor hardcoded version."""if PyRevitLoader:

return PyRevitLoader.ScriptExecutor.EngineVersion

@property # read-onlydef first_load(self):

"""bool: Check whether pyrevit is not running in pyrevit command."""# if no output window is set by the executor, it means that pyRevit# is loading at Revit startup (not reloading)return True if EXEC_PARAMS.window_handle is None else False

@property # read-onlydef pyrevit_command(self):

"""``PyRevitBaseClasses.PyRevitCommandRuntime``: Return command."""try:

return __externalcommand__except NameError:

return None

@property # read-only(continues on next page)

70 Chapter 10. pyrevit

Page 75: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def forced_debug_mode(self):"""bool: Check if command is in debug mode."""if self.pyrevit_command:

return self.pyrevit_command.DebugModeelse:

return False

@property # read-onlydef executed_from_ui(self):

"""bool: Check if command was executed from ui."""if self.pyrevit_command:

return self.pyrevit_command.ExecutedFromUIelse:

return False

@property # readdef window_handle(self):

"""``PyRevitBaseClasses.ScriptOutput``: Return output window."""if self.pyrevit_command:

return self.pyrevit_command.OutputWindow

@property # read-onlydef command_path(self):

"""str: Return current command path."""if '__commandpath__' in __builtins__ \

and __builtins__['__commandpath__']:return __builtins__['__commandpath__']

elif self.pyrevit_command:return op.dirname(self.pyrevit_command.ScriptSourceFile)

@property # read-onlydef command_alt_path(self):

"""str: Return current command alternate script path."""if '__alternatecommandpath__' in __builtins__ \

and __builtins__['__alternatecommandpath__']:return __builtins__['__alternatecommandpath__']

elif self.pyrevit_command:return op.dirname(self.pyrevit_command.AlternateScriptSourceFile)

@property # read-onlydef command_name(self):

"""str: Return current command name."""if '__commandname__' in __builtins__ \

and __builtins__['__commandname__']:return __builtins__['__commandname__']

elif self.pyrevit_command:return self.pyrevit_command.CommandName

@property # read-onlydef command_bundle(self):

"""str: Return current command bundle name."""if '__commandbundle__' in __builtins__ \

and __builtins__['__commandbundle__']:return __builtins__['__commandbundle__']

elif self.pyrevit_command:return self.pyrevit_command.CommandBundle

(continues on next page)

10.1. Implementation 71

Page 76: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

@property # read-onlydef command_extension(self):

"""str: Return current command extension name."""if '__commandextension__' in __builtins__ \

and __builtins__['__commandextension__']:return __builtins__['__commandextension__']

elif self.pyrevit_command:return self.pyrevit_command.CommandExtension

@property # read-onlydef command_uniqueid(self):

"""str: Return current command unique id."""if '__commanduniqueid__' in __builtins__ \

and __builtins__['__commanduniqueid__']:return __builtins__['__commanduniqueid__']

elif self.pyrevit_command:return self.pyrevit_command.CommandUniqueId

@propertydef command_data(self):

"""``ExternalCommandData``: Return current command data."""if self.pyrevit_command:

return self.pyrevit_command.CommandData

@propertydef doc_mode(self):

"""bool: Check if pyrevit is running by doc generator."""try:

return __sphinx__except NameError:

return False

@propertydef command_mode(self):

"""bool: Check if pyrevit is running in pyrevit command context."""return self.pyrevit_command is not None

@propertydef result_dict(self):

"""``Dictionary<String, String>``: Return results dict for logging."""if self.pyrevit_command:

return self.pyrevit_command.GetResultsDictionary()

# create an instance of _ExecutorParams wrapping current runtime.EXEC_PARAMS = _ExecutorParams()

# -----------------------------------------------------------------------------# config user environment paths# -----------------------------------------------------------------------------# user env pathsif EXEC_PARAMS.doc_mode:

ALLUSER_PROGRAMDATA = USER_ROAMING_DIR = USER_SYS_TEMP = USER_DESKTOP = \EXTENSIONS_DEFAULT_DIR = THIRDPARTY_EXTENSIONS_DEFAULT_DIR = ' '

else:ALLUSER_PROGRAMDATA = os.getenv('programdata')

(continues on next page)

72 Chapter 10. pyrevit

Page 77: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

USER_ROAMING_DIR = os.getenv('appdata')USER_SYS_TEMP = os.getenv('temp')USER_DESKTOP = op.expandvars('%userprofile%\\desktop')

# verify directory per issue #369if not USER_DESKTOP or not op.exists(USER_DESKTOP):

USER_DESKTOP = USER_SYS_TEMP

# default extensions directoryEXTENSIONS_DEFAULT_DIR = op.join(HOME_DIR, 'extensions')THIRDPARTY_EXTENSIONS_DEFAULT_DIR = \

op.join(USER_ROAMING_DIR, PYREVIT_ADDON_NAME, 'Extensions')

# create paths for pyrevit filesif EXEC_PARAMS.doc_mode:

PYREVIT_ALLUSER_APP_DIR = PYREVIT_APP_DIR = PYREVIT_VERSION_APP_DIR = ' 'else:

# pyrevit file directoryPYREVIT_ALLUSER_APP_DIR = op.join(ALLUSER_PROGRAMDATA, PYREVIT_ADDON_NAME)PYREVIT_APP_DIR = op.join(USER_ROAMING_DIR, PYREVIT_ADDON_NAME)PYREVIT_VERSION_APP_DIR = op.join(PYREVIT_APP_DIR, HOST_APP.version)

# add runtime paths to sys.paths# this will allow importing any dynamically compiled DLLs that# would be placed under this paths.for pyrvt_app_dir in [PYREVIT_APP_DIR,

PYREVIT_VERSION_APP_DIR,THIRDPARTY_EXTENSIONS_DEFAULT_DIR]:

if not op.isdir(pyrvt_app_dir):try:

os.mkdir(pyrvt_app_dir)sys.path.append(pyrvt_app_dir)

except Exception as err:raise PyRevitException('Can not access pyRevit '

'folder at: {} | {}'.format(pyrvt_app_dir, err))

else:sys.path.append(pyrvt_app_dir)

# -----------------------------------------------------------------------------# standard prefixes for naming pyrevit files (config, appdata and temp files)# -----------------------------------------------------------------------------if EXEC_PARAMS.doc_mode:

PYREVIT_FILE_PREFIX_UNIVERSAL = PYREVIT_FILE_PREFIX = \PYREVIT_FILE_PREFIX_STAMPED = None

PYREVIT_FILE_PREFIX_UNIVERSAL_USER = PYREVIT_FILE_PREFIX_USER = \PYREVIT_FILE_PREFIX_STAMPED_USER = None

else:# e.g. pyRevit_PYREVIT_FILE_PREFIX_UNIVERSAL = '{}_'.format(PYREVIT_ADDON_NAME)PYREVIT_FILE_PREFIX_UNIVERSAL_REGEX = \

r'^' + PYREVIT_ADDON_NAME + r'_(?P<fname>.+)'

# e.g. pyRevit_2018_PYREVIT_FILE_PREFIX = '{}_{}_'.format(PYREVIT_ADDON_NAME,

HOST_APP.version)(continues on next page)

10.1. Implementation 73

Page 78: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

PYREVIT_FILE_PREFIX_REGEX = \r'^' + PYREVIT_ADDON_NAME + r'_(?P<version>\d{4})_(?P<fname>.+)'

# e.g. pyRevit_2018_14422_PYREVIT_FILE_PREFIX_STAMPED = '{}_{}_{}_'.format(PYREVIT_ADDON_NAME,

HOST_APP.version,HOST_APP.proc_id)

PYREVIT_FILE_PREFIX_STAMPED_REGEX = \r'^' + PYREVIT_ADDON_NAME \+ r'_(?P<version>\d{4})_(?P<pid>\d+)_(?P<fname>.+)'

# e.g. pyRevit_eirannejad_PYREVIT_FILE_PREFIX_UNIVERSAL_USER = '{}_{}_'.format(PYREVIT_ADDON_NAME,

HOST_APP.username)PYREVIT_FILE_PREFIX_UNIVERSAL_USER_REGEX = \

r'^' + PYREVIT_ADDON_NAME + r'_(?P<user>.+)_(?P<fname>.+)'

# e.g. pyRevit_2018_eirannejad_PYREVIT_FILE_PREFIX_USER = '{}_{}_{}_'.format(PYREVIT_ADDON_NAME,

HOST_APP.version,HOST_APP.username)

PYREVIT_FILE_PREFIX_USER_REGEX = \r'^' + PYREVIT_ADDON_NAME \+ r'_(?P<version>\d{4})_(?P<user>.+)_(?P<fname>.+)'

# e.g. pyRevit_2018_eirannejad_14422_PYREVIT_FILE_PREFIX_STAMPED_USER = '{}_{}_{}_{}_'.format(PYREVIT_ADDON_NAME,

HOST_APP.version,HOST_APP.username,HOST_APP.proc_id)

PYREVIT_FILE_PREFIX_STAMPED_USER_REGEX = \r'^' + PYREVIT_ADDON_NAME \+ r'_(?P<version>\d{4})_(?P<user>.+)_(?P<pid>\d+)_(?P<fname>.+)'

74 Chapter 10. pyrevit

Page 79: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 11

pyrevit.api

Provide access to Revit API.

Example

>>> from pyrevit.api import AdWindows>>> from pyrevit.api import NSJson

11.1 Implementation

"""Provide access to Revit API.

Example:>>> from pyrevit.api import AdWindows>>> from pyrevit.api import NSJson

"""

#pylint: disable=E0401,W0611,W0703,C0413from pyrevit.framework import clr

clr.AddReference('RevitAPI')clr.AddReference('RevitAPIUI')clr.AddReference('AdWindows')clr.AddReference('UIFramework')clr.AddReference('UIFrameworkServices')

import UIFrameworkimport UIFrameworkServices

import Autodesk.Internal as AdInternalimport Autodesk.Private as AdPrivate

(continues on next page)

75

Page 80: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

import Autodesk.Windows as AdWindows

from Autodesk.Revit import Attributesfrom Autodesk.Revit import DBfrom Autodesk.Revit import UI

# try loading some utility modules shipped with revittry:

clr.AddReference('Newtonsoft.Json')import Newtonsoft.Json as NSJson

except Exception:pass

76 Chapter 11. pyrevit.api

Page 81: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 12

pyrevit.compat

python engine compatibility module.

Example

>>> from pyrevit.compat import IRONPY277>>> from pyrevit.compat import safe_strtype

12.1 Implementation

"""python engine compatibility module.

Example:>>> from pyrevit.compat import IRONPY277>>> from pyrevit.compat import safe_strtype

"""

import sys

PY2 = sys.version_info[0] == 2PY3 = sys.version_info[0] == 3IRONPY273 = sys.version_info[:3] == (2, 7, 3)IRONPY277 = sys.version_info[:3] == (2, 7, 7)

#pylint: disable=C0103safe_strtype = str

if PY2:safe_strtype = unicode #pylint: disable=E0602

77

Page 82: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

78 Chapter 12. pyrevit.compat

Page 83: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 13

pyrevit.forms

Reusable WPF forms for pyRevit.

Example

>>> from pyrevit.forms import WPFWindow

class pyrevit.forms.CommandSwitchWindow(context, title, width, height, **kwargs)Standard form to select from a list of command options.

Parameters

• context (list[str]) – list of command options to choose from

• switches (list[str]) – list of on/off switches

• message (str) – window title message

• config (dict) – dictionary of config dicts for options or switches

Returns name of selected option

Return type str

Returns if switches option is used, returns a tuple of selection option name and dict of switches

Return type tuple(str, dict)

Example

This is an example with series of command options:

>>> from pyrevit import forms>>> ops = ['option1', 'option2', 'option3', 'option4']>>> forms.CommandSwitchWindow.show(ops, message='Select Option')'option2'

79

Page 84: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

A more advanced example of combining command options, on/off switches, and option or switch configurationoptions:

>>> from pyrevit import forms>>> ops = ['option1', 'option2', 'option3', 'option4']>>> switches = ['switch1', 'switch2']>>> cfgs = {'option1': { 'background': '0xFF55FF'}}>>> rops, rswitches = forms.CommandSwitchWindow.show(... ops,... switches=switches... message='Select Option',... config=cfgs... )>>> rops'option2'>>> rswitches{'switch1': False, 'switch2': True}

_setup(**kwargs)Private method to be overriden by subclasses for window setup.

handle_click(sender, args)Handle mouse click.

handle_input_key(sender, args)Handle keyboard inputs.

process_option(sender, args)Handle click on command option button.

search_txt_changed(sender, args)Handle text change in search box.

class pyrevit.forms.GetValueWindow(context, title, width, height, **kwargs)Standard form to get simple values from user.

Args:

Example

>>> from pyrevit import forms>>> items = ['item1', 'item2', 'item3']>>> forms.SelectFromList.show(items, button_name='Select Item')>>> ['item1']

_setup(**kwargs)Private method to be overriden by subclasses for window setup.

class pyrevit.forms.ProgressBar(height=32, **kwargs)Show progress bar at the top of Revit window.

Parameters

• title (string) – progress bar text, defaults to 0/100 progress format

• indeterminate (bool) – create indeterminate progress bar

• cancellable (bool) – add cancel button to progress bar

• step (int) – update progress intervals

80 Chapter 13. pyrevit.forms

Page 85: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit import forms>>> count = 1>>> with forms.ProgressBar(title='my command progress message') as pb:... # do stuff... pb.update_progress(count, 100)... count += 1

Progress bar title could also be customized to show the current and total progress values. In example below, theprogress bar message will be in format “0 of 100”

>>> with forms.ProgressBar(title='{value} of {max_value}') as pb:

By default progress bar updates the progress every time the .update_progress method is called. For operationswith a large number of max steps, the gui update process time will have a significate effect on the overallexecution time of the command. In these cases, set the value of step argument to something larger than 1. Inexample below, the progress bar updates once per every 10 units of progress.

>>> with forms.ProgressBar(title='message', steps=10):

Progress bar could also be set to indeterminate for operations of unknown length. In this case, the progress barwill show an infinitely running ribbon:

>>> with forms.ProgressBar(title='message', indeterminate=True):

if cancellable is set on the object, a cancel button will show on the progress bar and .cancelled attribute will beset on the ProgressBar instance if users clicks on cancel button:

>>> with forms.ProgressBar(title='message',... cancellable=True) as pb:... # do stuff... if pb.cancelled:... # wrap up and cancel operation

_setup(**kwargs)Private method to be overriden by subclasses for prompt setup.

clicked_cancel(sender, args)Handler for cancel button clicked event.

indeterminateProgress bar indeterminate state.

reset()Reset progress value to 0.

titleProgress bar title.

update_progress(new_value, max_value=1)Update progress bar state with given min, max values.

Parameters

• new_value (float) – current progress value

• max_value (float) – total progress value

81

Page 86: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

wait_async(func, args=())Call a method asynchronosely and show progress.

class pyrevit.forms.RevisionOption(revision_element)Revision wrapper for select_revisions().

nameRevision name (description).

class pyrevit.forms.SearchPrompt(search_db, width, height, **kwargs)Standard prompt for pyRevit search.

Parameters

• search_db (list) – list of possible search targets

• search_tip (str) – text to show in grayscale when search box is empty

• switches (str) – list of switches

• width (int) – width of search prompt window

• height (int) – height of search prompt window

Returns matched strings, and dict of switches if provided str: matched string if switches are notprovided.

Return type str, dict

Example

>>> from pyrevit import forms>>> # assume search input of '/switch1 target1'>>> matched_str, args, switches = forms.SearchPrompt.show(... search_db=['target1', 'target2', 'target3', 'target4'],... switches=['/switch1', '/switch2'],... search_tip='pyRevit Search'... )... matched_str'target1'... args['--help', '--branch', 'branchname']... switches{'/switch1': True, '/switch2': False}

find_direct_match(input_text)Find direct text matches in search term.

find_word_match(input_text)Find direct word matches in search term.

handle_kb_key(sender, args)Handle keyboard input event.

search_inputCurrent search input.

search_input_partsCurrent cleaned up search term.

search_matchesList of matches for the given search term.

82 Chapter 13. pyrevit.forms

Page 87: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

search_termCurrent cleaned up search term.

search_term_argsFind arguments in search term.

search_term_mainCurrent cleaned up search term without the listed switches.

search_term_switchesFind matching switches in search term.

search_txt_changed(sender, args)Handle text changed event.

set_search_results(*args)Set search results for returning.

classmethod show(search_db, width=600, height=100, **kwargs)Show search prompt.

update_results_display(fill_match=False)Update search prompt results based on current input text.

class pyrevit.forms.SelectFromList(context, title, width, height, **kwargs)Standard form to select from a list of items.

Any object can be passed in a list to the context argument. This class wraps the objects passed to context,in TemplateListItem. This class provides the necessary mechanism to make this form work both forselecting items from a list, and from a list of checkboxes. See the list of arguments below for additional optionsand features.

Parameters

• context (list[str] or dict[list[str]]) – list of items to be selected fromOR dict of list of items to be selected from. use dict when input items need to be groupede.g. List of sheets grouped by sheet set.

• title (str, optional) – window title. see super class for defaults.

• width (int, optional) – window width. see super class for defaults.

• height (int, optional) – window height. see super class for defaults.

• button_name (str, optional) – name of select button. defaults to ‘Select’

• name_attr (str, optional) – object attribute that should be read as item name.

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto False

• return_all (bool, optional) – return all items. This is handly when some inputitems have states and the script needs to check the state changes on all items. This optionsworks in multiselect mode only. defaults to False

• filterfunc (function) – filter function to be applied to context items.

• group_selector_title (str) – title for list group selector. defaults to ‘List Group’

• default_group (str) – name of defautl group to be selected

83

Page 88: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit import forms>>> items = ['item1', 'item2', 'item3']>>> forms.SelectFromList.show(items, button_name='Select Item')>>> ['item1']

>>> from pyrevit import forms>>> ops = [viewsheet1, viewsheet2, viewsheet3]>>> res = forms.SelectFromList.show(ops,... multiselect=False,... name_attr='Name',... button_name='Select Sheet')

>>> from pyrevit import forms>>> ops = {'Sheet Set A': [viewsheet1, viewsheet2, viewsheet3],... 'Sheet Set B': [viewsheet4, viewsheet5, viewsheet6]}>>> res = forms.SelectFromList.show(ops,... multiselect=True,... name_attr='Name',... group_selector_title='Sheet Sets',... button_name='Select Sheets')

This module also provides a wrapper base class TemplateListItem for when the checkbox option is wrap-ping another element, e.g. a Revit ViewSheet. Derive from this base class and define the name property tocustomize how the checkbox is named on the dialog.

>>> from pyrevit import forms>>> class MyOption(forms.TemplateListItem)... @property... def name(self):... return '{} - {}{}'.format(self.item.SheetNumber,... self.item.SheetNumber)>>> ops = [MyOption('op1'), MyOption('op2', True), MyOption('op3')]>>> res = forms.SelectFromList.show(ops,... multiselect=True,... button_name='Select Item')>>> [bool(x) for x in res] # or [x.state for x in res][True, False, True]

_setup(**kwargs)Private method to be overriden by subclasses for window setup.

button_select(sender, args)Handle select button click.

check_all(sender, args)Handle check all button to mark all check boxes as checked.

check_selected(sender, args)Mark selected checkboxes as checked.

clear_search(sender, args)Clear search box.

search_txt_changed(sender, args)Handle text change in search box.

84 Chapter 13. pyrevit.forms

Page 89: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

toggle_all(sender, args)Handle toggle all button to toggle state of all check boxes.

uncheck_all(sender, args)Handle uncheck all button to mark all check boxes as un-checked.

uncheck_selected(sender, args)Mark selected checkboxes as unchecked.

class pyrevit.forms.SheetOption(sheet_element)Sheet wrapper for select_sheets().

nameSheet name.

numberSheet number.

class pyrevit.forms.TemplateListItem(orig_item, checkable=True, name_attr=None)Base class for checkbox option wrapping another object.

checkableList Item CheckBox Visibility.

classmethod is_checkbox(item)Check if the object has all necessary attribs for a checkbox.

nameName property.

unwrap()Unwrap and return wrapped object.

class pyrevit.forms.TemplatePromptBar(height=32, **kwargs)Template context-manager class for creating prompt bars.

Prompt bars are show at the top of the active Revit window and are designed for better prompt visibility.

Parameters

• height (int) – window height

• **kwargs – other arguments to be passed to _setup()

_setup(**kwargs)Private method to be overriden by subclasses for prompt setup.

update_window()Update the prompt bar to match Revit window.

class pyrevit.forms.TemplateUserInputWindow(context, title, width, height, **kwargs)Base class for pyRevit user input standard forms.

Parameters

• context (any) – window context element(s)

• title (str) – window title

• width (int) – window width

• height (int) – window height

• **kwargs – other arguments to be passed to _setup()

85

Page 90: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

_setup(**kwargs)Private method to be overriden by subclasses for window setup.

classmethod show(context, title=’User Input’, width=500, height=400, **kwargs)Show user input window.

Parameters

• context (any) – window context element(s)

• title (str) – window title

• width (str) – window width

• height (str) – window height

• **kwargs (any) – other arguments to be passed to window

class pyrevit.forms.ViewOption(view_element)View wrapper for select_views().

nameView name.

class pyrevit.forms.WPFWindow(xaml_source, literal_string=False, handle_esc=True)WPF Window base class for all pyRevit forms.

Parameters

• xaml_source (str) – xaml source filepath or xaml content

• literal_string (bool) – xaml_source contains xaml content, not filepath

• handle_esc (bool) – handle Escape button and close the window

Example

>>> from pyrevit import forms>>> layout = '<Window ShowInTaskbar="False" ResizeMode="NoResize" ' \>>> 'WindowStartupLocation="CenterScreen" ' \>>> 'HorizontalContentAlignment="Center">' \>>> '</Window>'>>> w = forms.WPFWindow(layout, literal_string=True)>>> w.show()

static disable_element(*wpf_elements)Enable elements.

Parameters *wpf_elements – WPF framework elements to be enabled

static enable_element(*wpf_elements)Enable elements.

Parameters *wpf_elements – WPF framework elements to be enabled

handle_input_key(sender, args)Handle keyboard input and close the window on Escape.

static hide_element(*wpf_elements)Collapse elements.

Parameters *wpf_elements – WPF framework elements to be collaped

86 Chapter 13. pyrevit.forms

Page 91: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

set_image_source(wpf_element, image_file)Set source file for image element.

Parameters

• element_name (System.Windows.Controls.Image) – xaml image element

• image_file (str) – image file path

setup_icon()Setup default window icon.

show(modal=False)Show window.

show_dialog()Show modal window.

static show_element(*wpf_elements)Show collapsed elements.

Parameters *wpf_elements – WPF framework elements to be set to visible.

static toggle_element(*wpf_elements)Toggle visibility of elements.

Parameters *wpf_elements – WPF framework elements to be toggled.

class pyrevit.forms.WarningBar(height=32, **kwargs)Show warning bar at the top of Revit window.

Parameters title (string) – warning bar text

Example

>>> with WarningBar(title='my warning'):... # do stuff

_setup(**kwargs)Private method to be overriden by subclasses for prompt setup.

pyrevit.forms.alert(msg, title=None, sub_msg=None, expanded=None, footer=”, ok=True, can-cel=False, yes=False, no=False, retry=False, warn_icon=True, options=None,exitscript=False)

Show a task dialog with given message.

Parameters

• msg (str) – message to be displayed

• title (str, optional) – task dialog title

• ok (bool, optional) – show OK button, defaults to True

• cancel (bool, optional) – show Cancel button, defaults to False

• yes (bool, optional) – show Yes button, defaults to False

• no (bool, optional) – show NO button, defaults to False

• retry (bool, optional) – show Retry button, defaults to False

• options (list[str], optional) – list of command link titles in order

87

Page 92: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• exitscript (bool, optional) – exit if cancel or no, defaults to False

Returns True if okay, yes, or retry, otherwise False

Return type bool

Example

>>> from pyrevit import forms>>> forms.alert('Are you sure?',... ok=False, yes=True, no=True, exitscript=True)

pyrevit.forms.alert_ifnot(condition, msg, *args, **kwargs)Show a task dialog with given message if condition is NOT met.

Parameters

• condition (bool) – condition to test

• msg (str) – message to be displayed

• title (str, optional) – task dialog title

• ok (bool, optional) – show OK button, defaults to True

• cancel (bool, optional) – show Cancel button, defaults to False

• yes (bool, optional) – show Yes button, defaults to False

• no (bool, optional) – show NO button, defaults to False

• retry (bool, optional) – show Retry button, defaults to False

• exitscript (bool, optional) – exit if cancel or no, defaults to False

Returns True if okay, yes, or retry, otherwise False

Return type bool

Example

>>> from pyrevit import forms>>> forms.alert_ifnot(value > 12,... 'Are you sure?',... ok=False, yes=True, no=True, exitscript=True)

pyrevit.forms.check_familydoc(doc=None, family_cat=None, exitscript=False)Verify document is a Family and notify user of not.

Parameters

• doc (DB.Document) – target document, current of not provided

• family_cat (str) – family category name

• exitscript (bool) – exit script if returning False

Returns True if doc is a Family and of provided category

Return type bool

88 Chapter 13. pyrevit.forms

Page 93: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit import forms>>> forms.check_familydoc(doc=revit.doc, family_cat='Data Devices')... True

pyrevit.forms.check_selection(exitscript=False, message=’At least one element must be se-lected.’)

Verify if selection is not empty notify user if it is.

Parameters

• exitscript (bool) – exit script if returning False

• message (str) – prompt message if returning False

Returns True if selection has at least one item

Return type bool

pyrevit.forms.check_workshared(doc=None, message=’Model is not workshared.’)Verify if model is workshared and notify user if not.

Parameters

• doc (DB.Document) – target document, current of not provided

• message (str) – prompt message if returning False

Returns True if doc is workshared

Return type bool

pyrevit.forms.pick_excel_file(save=False)File pick/save dialog for an excel file.

Parameters save (bool) – show file save dialog, instead of file pick dialog

Returns file path

Return type str

pyrevit.forms.pick_file(file_ext=”, files_filter=”, init_dir=”, restore_dir=True, multi_file=False,unc_paths=False)

Pick file dialog to select a destination file.

Parameters

• file_ext (str) – file extension

• files_filter (str) – file filter

• init_dir (str) – initial directory

• restore_dir (bool) – restore last directory

• multi_file (bool) – allow select multiple files

• unc_paths (bool) – return unc paths

Returns file path or list of file paths if multi_file=True

Return type str or list[str]

89

Page 94: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit import forms>>> forms.pick_file(file_ext='csv')... r'C:\output\somefile.csv'

>>> forms.pick_file(file_ext='csv', multi_file=True)... [r'C:\output\somefile1.csv', r'C:\output\somefile2.csv']

>>> forms.pick_file(files_filter='All Files (*.*)|*.*|''Excel Workbook (*.xlsx)|*.xlsx|''Excel 97-2003 Workbook|*.xls',

multi_file=True)... [r'C:\output\somefile1.xlsx', r'C:\output\somefile2.xls']

pyrevit.forms.pick_folder(title=None)Show standard windows pick folder dialog.

Parameters title (str, optional) – title for the window

Returns folder path

Return type str

pyrevit.forms.save_excel_file()File save dialog for an excel file.

Returns file path

Return type str

pyrevit.forms.save_file(file_ext=”, files_filter=”, init_dir=”, default_name=”, restore_dir=True,unc_paths=False)

Save file dialog to select a destination file for data.

Parameters

• file_ext (str) – file extension

• files_filter (str) – file filter

• init_dir (str) – initial directory

• default_name (str) – default file name

• restore_dir (bool) – restore last directory

• unc_paths (bool) – return unc paths

Returns file path

Return type str

Example

>>> from pyrevit import forms>>> forms.save_file(file_ext='csv')... r'C:\output\somefile.csv'

pyrevit.forms.select_image(images, title=’Select Image’, button_name=’Select’)Standard form for selecting an image.

90 Chapter 13. pyrevit.forms

Page 95: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters

• images (list[str] | list[framework.Imaging.BitmapImage]) – list ofimage file paths or bitmaps

• title (str, optional) – swatch list window title

• button_name (str, optional) – swatch list window button caption

Returns path of the selected image

Return type str

Example

>>> from pyrevit import forms>>> forms.select_image(['C:/path/to/image1.png',

'C:/path/to/image2.png'],title="Select Variation")

... 'C:/path/to/image1.png'

pyrevit.forms.select_open_docs(title=’Select Open Documents’, button_name=’OK’, width=500,multiple=True, filterfunc=None)

Standard form for selecting open documents.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

Returns list of selected documents

Return type list[DB.Document]

Example

>>> from pyrevit import forms>>> forms.select_open_docs()... [<Autodesk.Revit.DB.Document object>,... <Autodesk.Revit.DB.Document object>]

pyrevit.forms.select_revisions(title=’Select Revision’, button_name=’Select’, width=500, mul-tiple=True, filterfunc=None, doc=None)

Standard form for selecting revisions.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

91

Page 96: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

• doc (DB.Document, optional) – source document for revisions; defaults to activedocument

Returns list of selected revisions

Return type list[DB.Revision]

Example

>>> from pyrevit import forms>>> forms.select_revisions()... [<Autodesk.Revit.DB.Revision object>,... <Autodesk.Revit.DB.Revision object>]

pyrevit.forms.select_sheets(title=’Select Sheets’, button_name=’Select’, width=500, multi-ple=True, filterfunc=None, doc=None)

Standard form for selecting sheets.

Sheets are grouped into sheet sets and sheet set can be selected from a drop down box at the top of window.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

• doc (DB.Document, optional) – source document for sheets; defaults to active doc-ument

Returns list of selected sheets

Return type list[DB.ViewSheet]

Example

>>> from pyrevit import forms>>> forms.select_sheets()... [<Autodesk.Revit.DB.ViewSheet object>,... <Autodesk.Revit.DB.ViewSheet object>]

pyrevit.forms.select_swatch(title=’Select Color Swatch’, button_name=’Select’)Standard form for selecting a color swatch.

Parameters

• title (str, optional) – swatch list window title

• button_name (str, optional) – swatch list window button caption

92 Chapter 13. pyrevit.forms

Page 97: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Returns rgb color

Return type pyrevit.coreutils.colors.RGB

Example

>>> from pyrevit import forms>>> forms.select_swatch(title="Select Text Color")... <RGB #CD8800>

pyrevit.forms.select_titleblocks(title=’Select Titleblock’, button_name=’Select’,no_tb_option=’No Title Block’, width=500, multiple=False,filterfunc=None, doc=None)

Standard form for selecting a titleblock.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• no_tb_option (str, optional) – name of option for no title block

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

• doc (DB.Document, optional) – source document for titleblocks; defaults to activedocument

Returns selected titleblock id.

Return type DB.ElementId

Example

>>> from pyrevit import forms>>> forms.select_titleblocks()... <Autodesk.Revit.DB.ElementId object>

pyrevit.forms.select_views(title=’Select Views’, button_name=’Select’, width=500, multi-ple=True, filterfunc=None, doc=None)

Standard form for selecting views.

Parameters

• title (str, optional) – list window title

• button_name (str, optional) – list window button caption

• width (int, optional) – width of list window

• multiselect (bool, optional) – allow multi-selection (uses check boxes). defaultsto True

• filterfunc (function) – filter function to be applied to context items.

93

Page 98: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• doc (DB.Document, optional) – source document for views; defaults to active doc-ument

Returns list of selected views

Return type list[DB.View]

Example

>>> from pyrevit import forms>>> forms.select_views()... [<Autodesk.Revit.DB.View object>,... <Autodesk.Revit.DB.View object>]

pyrevit.forms.toast(message, title=’pyRevit’, appid=’pyRevit’, icon=None, click=None, ac-tions=None)

Show a Windows 10 notification.

Parameters

• message (str) – notification message

• title (str) – notification title

• appid (str) – app name (will show under message)

• icon (str) – file path to icon .ico file (defaults to pyRevit icon)

• click (str) – click action commands string

• actions (dict) – dictionary of button names and action strings

Example

>>> script.toast("Hello World!",... title="My Script",... appid="MyAPP",... click="https://eirannejad.github.io/pyRevit/",... actions={... "Open Google":"https://google.com",... "Open Toast64":"https://github.com/go-toast/toast"... })

13.1 pyrevit.forms.utils

Utility functions to support forms module.

pyrevit.forms.utils.bitmap_from_file(bitmap_file)Create BitmapImage from a bitmap file.

Parameters bitmap_file (str) – path to bitmap file

Returns bitmap image object

Return type BitmapImage

94 Chapter 13. pyrevit.forms

Page 99: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

13.2 Implementation

"""Reusable WPF forms for pyRevit.

Example:>>> from pyrevit.forms import WPFWindow

"""

import sysimport osimport os.path as opimport stringfrom collections import OrderedDictimport threadingfrom functools import wrapsimport datetime

from pyrevit import HOST_APP, EXEC_PARAMS, BIN_DIRfrom pyrevit.compat import safe_strtypefrom pyrevit import coreutilsfrom pyrevit.coreutils.logger import get_loggerfrom pyrevit.coreutils import colorsfrom pyrevit import frameworkfrom pyrevit.framework import Systemfrom pyrevit.framework import Threadingfrom pyrevit.framework import Interopfrom pyrevit.framework import Inputfrom pyrevit.framework import wpf, Forms, Controls, Mediafrom pyrevit.api import AdWindowsfrom pyrevit import revit, UI, DBfrom pyrevit.forms import utilsfrom pyrevit.forms import toasterfrom pyrevit import versionmgr

#pylint: disable=W0703,C0302,C0103mlogger = get_logger(__name__)

DEFAULT_CMDSWITCHWND_WIDTH = 600DEFAULT_SEARCHWND_WIDTH = 600DEFAULT_SEARCHWND_HEIGHT = 100DEFAULT_INPUTWINDOW_WIDTH = 500DEFAULT_INPUTWINDOW_HEIGHT = 400

WPF_HIDDEN = framework.Windows.Visibility.HiddenWPF_COLLAPSED = framework.Windows.Visibility.CollapsedWPF_VISIBLE = framework.Windows.Visibility.Visible

class WPFWindow(framework.Windows.Window):r"""WPF Window base class for all pyRevit forms.

Args:xaml_source (str): xaml source filepath or xaml contentliteral_string (bool): xaml_source contains xaml content, not filepath

(continues on next page)

13.2. Implementation 95

Page 100: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

handle_esc (bool): handle Escape button and close the window

Example:>>> from pyrevit import forms>>> layout = '<Window ShowInTaskbar="False" ResizeMode="NoResize" ' \>>> 'WindowStartupLocation="CenterScreen" ' \>>> 'HorizontalContentAlignment="Center">' \>>> '</Window>'>>> w = forms.WPFWindow(layout, literal_string=True)>>> w.show()

"""

def __init__(self, xaml_source, literal_string=False, handle_esc=True):"""Initialize WPF window and resources."""# self.Parent = selfwih = Interop.WindowInteropHelper(self)wih.Owner = AdWindows.ComponentManager.ApplicationWindow

if not literal_string:if not op.exists(xaml_source):

wpf.LoadComponent(self,os.path.join(EXEC_PARAMS.command_path,

xaml_source))

else:wpf.LoadComponent(self, xaml_source)

else:wpf.LoadComponent(self, framework.StringReader(xaml_source))

if handle_esc:self.PreviewKeyDown += self.handle_input_key #pylint: disable=E1101

self.setup_icon()

#2c3e50self.Resources['pyRevitDarkColor'] = \

Media.Color.FromArgb(0xFF, 0x2c, 0x3e, 0x50)

#23303dself.Resources['pyRevitDarkerDarkColor'] = \

Media.Color.FromArgb(0xFF, 0x23, 0x30, 0x3d)

#ffffffself.Resources['pyRevitButtonColor'] = \

Media.Color.FromArgb(0xFF, 0xff, 0xff, 0xff)

#f39c12self.Resources['pyRevitAccentColor'] = \

Media.Color.FromArgb(0xFF, 0xf3, 0x9c, 0x12)

self.Resources['pyRevitDarkBrush'] = \Media.SolidColorBrush(self.Resources['pyRevitDarkColor'])

self.Resources['pyRevitAccentBrush'] = \Media.SolidColorBrush(self.Resources['pyRevitAccentColor'])

self.Resources['pyRevitDarkerDarkBrush'] = \Media.SolidColorBrush(self.Resources['pyRevitDarkerDarkColor'])

(continues on next page)

96 Chapter 13. pyrevit.forms

Page 101: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

self.Resources['pyRevitButtonForgroundBrush'] = \Media.SolidColorBrush(self.Resources['pyRevitButtonColor'])

def handle_input_key(self, sender, args): #pylint: disable=W0613"""Handle keyboard input and close the window on Escape."""if args.Key == Input.Key.Escape:

self.Close()

def setup_icon(self):"""Setup default window icon."""iconpath = op.join(BIN_DIR, 'window_icon.png')self.Icon = utils.bitmap_from_file(iconpath)

def show(self, modal=False):"""Show window."""if modal:

return self.ShowDialog()self.Show()

def show_dialog(self):"""Show modal window."""return self.ShowDialog()

def set_image_source(self, wpf_element, image_file):"""Set source file for image element.

Args:element_name (System.Windows.Controls.Image): xaml image elementimage_file (str): image file path

"""if not op.exists(image_file):

wpf_element.Source = \utils.bitmap_from_file(

os.path.join(EXEC_PARAMS.command_path,image_file)

)else:

wpf_element.Source = utils.bitmap_from_file(image_file)

@propertydef pyrevit_version(self):

return 'pyRevit {}'.format(versionmgr.get_pyrevit_version().get_formatted())

@staticmethoddef hide_element(*wpf_elements):

"""Collapse elements.

Args:

*wpf_elements: WPF framework elements to be collaped"""for wpfel in wpf_elements:

wpfel.Visibility = WPF_COLLAPSED

@staticmethod(continues on next page)

13.2. Implementation 97

Page 102: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def show_element(*wpf_elements):"""Show collapsed elements.

Args:

*wpf_elements: WPF framework elements to be set to visible."""for wpfel in wpf_elements:

wpfel.Visibility = WPF_VISIBLE

@staticmethoddef toggle_element(*wpf_elements):

"""Toggle visibility of elements.

Args:

*wpf_elements: WPF framework elements to be toggled."""for wpfel in wpf_elements:

if wpfel.Visibility == WPF_VISIBLE:WPFWindow.hide_element(wpfel)

elif wpfel.Visibility == WPF_COLLAPSED:WPFWindow.show_element(wpfel)

@staticmethoddef disable_element(*wpf_elements):

"""Enable elements.

Args:

*wpf_elements: WPF framework elements to be enabled"""for wpfel in wpf_elements:

wpfel.IsEnabled = False

@staticmethoddef enable_element(*wpf_elements):

"""Enable elements.

Args:

*wpf_elements: WPF framework elements to be enabled"""for wpfel in wpf_elements:

wpfel.IsEnabled = True

class TemplateUserInputWindow(WPFWindow):"""Base class for pyRevit user input standard forms.

Args:context (any): window context element(s)title (str): window titlewidth (int): window widthheight (int): window height

**kwargs: other arguments to be passed to :func:`_setup`"""

xaml_source = 'BaseWindow.xaml'

def __init__(self, context, title, width, height, **kwargs):(continues on next page)

98 Chapter 13. pyrevit.forms

Page 103: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Initialize user input window."""WPFWindow.__init__(self,

op.join(op.dirname(__file__), self.xaml_source),handle_esc=True)

self.Title = title or 'pyRevit'self.Width = widthself.Height = height

self._context = contextself.response = None

# parent window?owner = kwargs.get('owner', None)if owner:

# set wpf windows directlyself.Owner = ownerself.WindowStartupLocation = \

framework.Windows.WindowStartupLocation.CenterOwner

self._setup(**kwargs)

def _setup(self, **kwargs):"""Private method to be overriden by subclasses for window setup."""pass

@classmethoddef show(cls, context, #pylint: disable=W0221

title='User Input',width=DEFAULT_INPUTWINDOW_WIDTH,height=DEFAULT_INPUTWINDOW_HEIGHT, **kwargs):

"""Show user input window.

Args:context (any): window context element(s)title (str): window titlewidth (str): window widthheight (str): window height

**kwargs (any): other arguments to be passed to window"""dlg = cls(context, title, width, height, **kwargs)dlg.ShowDialog()return dlg.response

class TemplateListItem(object):"""Base class for checkbox option wrapping another object."""

def __init__(self, orig_item, checkable=True, name_attr=None):"""Initialize the checkbox option and wrap given obj.

Args:orig_item (any): Object to wrap (must have name property

or be convertable to string with str()checkable (bool): Use checkbox for itemsname_attr (str): Get this attribute of wrapped object as name

"""self.item = orig_item

(continues on next page)

13.2. Implementation 99

Page 104: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

self.state = Falseself._nameattr = name_attrself._checkable = checkable

def __nonzero__(self):return self.state

def __str__(self):return self.name or str(self.item)

def __contains__(self, value):return value in self.name

def __getattr__(self, param_name):return getattr(self.item, param_name)

@propertydef name(self):

"""Name property."""# get custom attr, or name or just str reprif self._nameattr:

return str(getattr(self.item, self._nameattr))elif hasattr(self.item, 'name'):

return getattr(self.item, 'name', '')else:

return safe_strtype(self.item)

def unwrap(self):"""Unwrap and return wrapped object."""return self.item

@propertydef checkable(self):

"""List Item CheckBox Visibility."""return WPF_VISIBLE if self._checkable \

else WPF_COLLAPSED

@checkable.setterdef checkable(self, value):

self._checkable = value

@classmethoddef is_checkbox(cls, item):

"""Check if the object has all necessary attribs for a checkbox."""return isinstance(item, TemplateListItem)

class SelectFromList(TemplateUserInputWindow):"""Standard form to select from a list of items.

Any object can be passed in a list to the ``context`` argument. This classwraps the objects passed to context, in :obj:`TemplateListItem`.This class provides the necessary mechanism to make this form work bothfor selecting items from a list, and from a list of checkboxes. See thelist of arguments below for additional options and features.

Args:(continues on next page)

100 Chapter 13. pyrevit.forms

Page 105: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

context (list[str] or dict[list[str]]):list of items to be selected fromORdict of list of items to be selected from.use dict when input items need to be groupede.g. List of sheets grouped by sheet set.

title (str, optional): window title. see super class for defaults.width (int, optional): window width. see super class for defaults.height (int, optional): window height. see super class for defaults.button_name (str, optional):

name of select button. defaults to 'Select'name_attr (str, optional):

object attribute that should be read as item name.multiselect (bool, optional):

allow multi-selection (uses check boxes). defaults to Falsereturn_all (bool, optional):

return all items. This is handly when some input items have statesand the script needs to check the state changes on all items.This options works in multiselect mode only. defaults to False

filterfunc (function):filter function to be applied to context items.

group_selector_title (str):title for list group selector. defaults to 'List Group'

default_group (str): name of defautl group to be selected

Example:>>> from pyrevit import forms>>> items = ['item1', 'item2', 'item3']>>> forms.SelectFromList.show(items, button_name='Select Item')>>> ['item1']

>>> from pyrevit import forms>>> ops = [viewsheet1, viewsheet2, viewsheet3]>>> res = forms.SelectFromList.show(ops,... multiselect=False,... name_attr='Name',... button_name='Select Sheet')

>>> from pyrevit import forms>>> ops = {'Sheet Set A': [viewsheet1, viewsheet2, viewsheet3],... 'Sheet Set B': [viewsheet4, viewsheet5, viewsheet6]}>>> res = forms.SelectFromList.show(ops,... multiselect=True,... name_attr='Name',... group_selector_title='Sheet Sets',... button_name='Select Sheets')

This module also provides a wrapper base class :obj:`TemplateListItem`for when the checkbox option is wrapping another element,e.g. a Revit ViewSheet. Derive from this base class and define thename property to customize how the checkbox is named on the dialog.

>>> from pyrevit import forms>>> class MyOption(forms.TemplateListItem)... @property... def name(self):

(continues on next page)

13.2. Implementation 101

Page 106: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

... return '{} - {}{}'.format(self.item.SheetNumber,

... self.item.SheetNumber)>>> ops = [MyOption('op1'), MyOption('op2', True), MyOption('op3')]>>> res = forms.SelectFromList.show(ops,... multiselect=True,... button_name='Select Item')>>> [bool(x) for x in res] # or [x.state for x in res][True, False, True]

"""

xaml_source = 'SelectFromList.xaml'

def _setup(self, **kwargs):# custom button name?button_name = kwargs.get('button_name', 'Select')if button_name:

self.select_b.Content = button_name

# attribute to use as name?self._nameattr = kwargs.get('name_attr', None)

# multiselect?if kwargs.get('multiselect', False):

self.multiselect = Trueself.list_lb.SelectionMode = Controls.SelectionMode.Extendedself.show_element(self.checkboxbuttons_g)

else:self.multiselect = Falseself.list_lb.SelectionMode = Controls.SelectionMode.Singleself.hide_element(self.checkboxbuttons_g)

# return checked items only?self.return_all = kwargs.get('return_all', False)

# filter function?self.filter_func = kwargs.get('filterfunc', None)

# context group title?self.ctx_groups_title = \

kwargs.get('group_selector_title', 'List Group')self.ctx_groups_title_tb.Text = self.ctx_groups_title

self.ctx_groups_active = kwargs.get('default_group', None)

# check for custom templatesitems_panel_template = kwargs.get('items_panel_template', None)if items_panel_template:

self.Resources["ItemsPanelTemplate"] = items_panel_template

item_container_template = kwargs.get('item_container_template', None)if item_container_template:

self.Resources["ItemContainerTemplate"] = item_container_template

item_template = kwargs.get('item_template', None)if item_template:

self.Resources["ItemTemplate"] = \(continues on next page)

102 Chapter 13. pyrevit.forms

Page 107: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

item_template

# nicely wrap and prepare context for presentation, then presentself._prepare_context()

# list options nowself._list_options()

# setup search and filter fieldsself.hide_element(self.clrsearch_b)self.clear_search(None, None)

def _prepare_context_items(self, ctx_items):new_ctx = []# filter context if necessaryif self.filter_func:

ctx_items = filter(self.filter_func, ctx_items)

for item in ctx_items:if TemplateListItem.is_checkbox(item):

item.checkable = self.multiselectnew_ctx.append(item)

else:new_ctx.append(

TemplateListItem(item,checkable=self.multiselect,name_attr=self._nameattr)

)

return new_ctx

def _prepare_context(self):if isinstance(self._context, dict) and self._context.keys():

self._update_ctx_groups(self._context.keys())new_ctx = {}for ctx_grp, ctx_items in self._context.items():

new_ctx[ctx_grp] = self._prepare_context_items(ctx_items)else:

new_ctx = self._prepare_context_items(self._context)

self._context = new_ctx

def _update_ctx_groups(self, ctx_group_names):self.show_element(self.ctx_groups_dock)self.ctx_groups_selector_cb.ItemsSource = ctx_group_namesif self.ctx_groups_active in ctx_group_names:

self.ctx_groups_selector_cb.SelectedIndex = \ctx_group_names.index(self.ctx_groups_active)

else:self.ctx_groups_selector_cb.SelectedIndex = 0

def _get_active_ctx_group(self):return self.ctx_groups_selector_cb.SelectedItem

def _get_active_ctx(self):if isinstance(self._context, dict):

return self._context[self._get_active_ctx_group()](continues on next page)

13.2. Implementation 103

Page 108: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

else:return self._context

def _list_options(self, option_filter=None):if option_filter:

self.checkall_b.Content = 'Check'self.uncheckall_b.Content = 'Uncheck'self.toggleall_b.Content = 'Toggle'# get a match score for every item and sort high to lowfuzzy_matches = sorted(

[(x, coreutils.fuzzy_search_ratio(x.name, option_filter))for x in self._get_active_ctx()],

key=lambda x: x[1],reverse=True)

# filter out any match with score less than 80self.list_lb.ItemsSource = \

[x[0] for x in fuzzy_matches if x[1] >= 80]else:

self.checkall_b.Content = 'Check All'self.uncheckall_b.Content = 'Uncheck All'self.toggleall_b.Content = 'Toggle All'self.list_lb.ItemsSource = [x for x in self._get_active_ctx()]

@staticmethoddef _unwrap_options(options):

unwrapped = []for optn in options:

if isinstance(optn, TemplateListItem):unwrapped.append(optn.unwrap())

else:unwrapped.append(optn)

return unwrapped

def _get_options(self):if self.multiselect:

if self.return_all:return [x for x in self._get_active_ctx()]

else:return self._unwrap_options(

[x for x in self._get_active_ctx()if x.state or x in self.list_lb.SelectedItems]

)else:

return self._unwrap_options([self.list_lb.SelectedItem])[0]

def _set_states(self, state=True, flip=False, selected=False):all_items = self.list_lb.ItemsSourceif selected:

current_list = self.list_lb.SelectedItemselse:

current_list = self.list_lb.ItemsSourcefor checkbox in current_list:

if flip:checkbox.state = not checkbox.state

else:checkbox.state = state

(continues on next page)

104 Chapter 13. pyrevit.forms

Page 109: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# push list view to redrawself.list_lb.ItemsSource = Noneself.list_lb.ItemsSource = all_items

def toggle_all(self, sender, args): #pylint: disable=W0613"""Handle toggle all button to toggle state of all check boxes."""self._set_states(flip=True)

def check_all(self, sender, args): #pylint: disable=W0613"""Handle check all button to mark all check boxes as checked."""self._set_states(state=True)

def uncheck_all(self, sender, args): #pylint: disable=W0613"""Handle uncheck all button to mark all check boxes as un-checked."""self._set_states(state=False)

def check_selected(self, sender, args): #pylint: disable=W0613"""Mark selected checkboxes as checked."""self._set_states(state=True, selected=True)

def uncheck_selected(self, sender, args): #pylint: disable=W0613"""Mark selected checkboxes as unchecked."""self._set_states(state=False, selected=True)

def button_select(self, sender, args): #pylint: disable=W0613"""Handle select button click."""self.response = self._get_options()self.Close()

def search_txt_changed(self, sender, args): #pylint: disable=W0613"""Handle text change in search box."""if self.search_tb.Text == '':

self.hide_element(self.clrsearch_b)else:

self.show_element(self.clrsearch_b)

self._list_options(option_filter=self.search_tb.Text)

def clear_search(self, sender, args): #pylint: disable=W0613"""Clear search box."""self.search_tb.Text = ' 'self.search_tb.Clear()self.search_tb.Focus()

class CommandSwitchWindow(TemplateUserInputWindow):"""Standard form to select from a list of command options.

Args:context (list[str]): list of command options to choose fromswitches (list[str]): list of on/off switchesmessage (str): window title messageconfig (dict): dictionary of config dicts for options or switches

Returns:str: name of selected option

(continues on next page)

13.2. Implementation 105

Page 110: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Returns:tuple(str, dict): if ``switches`` option is used, returns a tupleof selection option name and dict of switches

Example:This is an example with series of command options:

>>> from pyrevit import forms>>> ops = ['option1', 'option2', 'option3', 'option4']>>> forms.CommandSwitchWindow.show(ops, message='Select Option')'option2'

A more advanced example of combining command options, on/off switches,and option or switch configuration options:

>>> from pyrevit import forms>>> ops = ['option1', 'option2', 'option3', 'option4']>>> switches = ['switch1', 'switch2']>>> cfgs = {'option1': { 'background': '0xFF55FF'}}>>> rops, rswitches = forms.CommandSwitchWindow.show(... ops,... switches=switches... message='Select Option',... config=cfgs... )>>> rops'option2'>>> rswitches{'switch1': False, 'switch2': True}

"""

xaml_source = 'CommandSwitchWindow.xaml'

def _setup(self, **kwargs):self.selected_switch = ''self.Width = DEFAULT_CMDSWITCHWND_WIDTHself.Title = 'Command Options'

message = kwargs.get('message', None)self._switches = kwargs.get('switches', [])if not isinstance(self._switches, dict):

self._switches = dict.fromkeys(self._switches)

configs = kwargs.get('config', None)

self.message_label.Content = \message if message else 'Pick a command option:'

# creates the switches firstfor switch, state in self._switches.items():

my_togglebutton = framework.Controls.Primitives.ToggleButton()my_togglebutton.Content = switchmy_togglebutton.IsChecked = state if state else Falseif configs and 'option' in configs:

self._set_config(my_togglebutton, configs[switch])self.button_list.Children.Add(my_togglebutton)

(continues on next page)

106 Chapter 13. pyrevit.forms

Page 111: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

for option in self._context:my_button = framework.Controls.Button()my_button.Content = optionmy_button.Click += self.process_optionif configs and option in configs:

self._set_config(my_button, configs[option])self.button_list.Children.Add(my_button)

self._setup_response()self.search_tb.Focus()self._filter_options()

@staticmethoddef _set_config(item, config_dict):

bg = config_dict.get('background', None)if bg:

bg = bg.replace('0x', '#')item.Background = Media.BrushConverter().ConvertFrom(bg)

def _setup_response(self, response=None):if self._switches:

switches = [x for x in self.button_list.Childrenif hasattr(x, 'IsChecked')]

self.response = response, {x.Content: x.IsCheckedfor x in switches}

else:self.response = response

def _filter_options(self, option_filter=None):if option_filter:

self.search_tb.Tag = ''option_filter = option_filter.lower()for button in self.button_list.Children:

if option_filter not in button.Content.lower():button.Visibility = WPF_COLLAPSED

else:button.Visibility = WPF_VISIBLE

else:self.search_tb.Tag = \

'Type to Filter / Tab to Select / Enter or Click to Run'for button in self.button_list.Children:

button.Visibility = WPF_VISIBLE

def _get_active_button(self):buttons = []for button in self.button_list.Children:

if button.Visibility == WPF_VISIBLE:buttons.append(button)

if len(buttons) == 1:return buttons[0]

else:for x in buttons:

if x.IsFocused:return x

def handle_click(self, sender, args): #pylint: disable=W0613(continues on next page)

13.2. Implementation 107

Page 112: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Handle mouse click."""self.Close()

def handle_input_key(self, sender, args):"""Handle keyboard inputs."""if args.Key == Input.Key.Escape:

if self.search_tb.Text:self.search_tb.Text = ''

else:self.Close()

elif args.Key == Input.Key.Enter:self.process_option(self._get_active_button(), None)

elif args.Key != Input.Key.Tab \and args.Key != Input.Key.Space\and args.Key != Input.Key.LeftShift\and args.Key != Input.Key.RightShift:

self.search_tb.Focus()

def search_txt_changed(self, sender, args): #pylint: disable=W0613"""Handle text change in search box."""self._filter_options(option_filter=self.search_tb.Text)

def process_option(self, sender, args): #pylint: disable=W0613"""Handle click on command option button."""self.Close()if sender:

self._setup_response(response=sender.Content)

class GetValueWindow(TemplateUserInputWindow):"""Standard form to get simple values from user.

Args:

Example:>>> from pyrevit import forms>>> items = ['item1', 'item2', 'item3']>>> forms.SelectFromList.show(items, button_name='Select Item')>>> ['item1']

"""

xaml_source = 'GetValueWindow.xaml'

def _setup(self, **kwargs):self.Width = 400# determine value typeself.value_type = kwargs.get('value_type', 'string')value_prompt = kwargs.get('prompt', None)value_default = kwargs.get('default', None)self.reserved_values = kwargs.get('reserved_values', [])

# customize window based on typeif self.value_type == 'string':

self.show_element(self.stringPanel_dp)self.stringValue_tb.Text = value_default if value_default else ''self.stringValue_tb.Focus()

(continues on next page)

108 Chapter 13. pyrevit.forms

Page 113: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

self.stringValue_tb.SelectAll()self.stringPrompt.Text = \

value_prompt if value_prompt else 'Enter string:'if self.reserved_values:

self.string_value_changed(None, None)elif self.value_type == 'dropdown':

self.show_element(self.dropdownPanel_db)self.dropdownPrompt.Text = \

value_prompt if value_prompt else 'Pick one value:'self.dropdown_cb.ItemsSource = self._contextif value_default:

self.dropdown_cb.SelectedItem = value_defaultelif self.value_type == 'date':

self.show_element(self.datePanel_dp)self.datePrompt.Text = \

value_prompt if value_prompt else 'Pick date:'

def string_value_changed(self, sender, args):filtered_rvalues = \

sorted([x for x in self.reserved_valuesif self.stringValue_tb.Text in str(x)],reverse=True)

if filtered_rvalues:self.reservedValuesList.ItemsSource = filtered_rvaluesself.show_element(self.reservedValuesListPanel)self.okayButton.IsEnabled = \

self.stringValue_tb.Text not in filtered_rvalueselse:

self.reservedValuesList.ItemsSource = []self.hide_element(self.reservedValuesListPanel)self.okayButton.IsEnabled = True

def select(self, sender, args): #pylint: disable=W0613self.Close()if self.value_type == 'string':

self.response = self.stringValue_tb.Textelif self.value_type == 'dropdown':

self.response = self.dropdown_cb.SelectedItemelif self.value_type == 'date':

if self.datePicker.SelectedDate:datestr = self.datePicker.SelectedDate.ToString("MM/dd/yyyy")self.response = datetime.datetime.strptime(datestr, r'%m/%d/%Y')

else:self.response = None

class TemplatePromptBar(WPFWindow):"""Template context-manager class for creating prompt bars.

Prompt bars are show at the top of the active Revit window and aredesigned for better prompt visibility.

Args:height (int): window height

**kwargs: other arguments to be passed to :func:`_setup`"""

(continues on next page)

13.2. Implementation 109

Page 114: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

xaml_source = 'TemplatePromptBar.xaml'

def __init__(self, height=32, **kwargs):"""Initialize user prompt window."""WPFWindow.__init__(self,

op.join(op.dirname(__file__), self.xaml_source))

self.user_height = heightself.update_window()self._setup(**kwargs)

def update_window(self):"""Update the prompt bar to match Revit window."""screen_area = HOST_APP.proc_screen_workareascale_factor = 1.0 / HOST_APP.proc_screen_scalefactortop = left = width = height = 0

window_rect = revit.get_window_rectangle()

# set width and heightwidth = window_rect.Right - window_rect.Leftheight = self.user_height

top = window_rect.Top# in maximized window, the top might be off the active screen# due to windows thicker window frames# lets cut the height and re-adjust the toptop_diff = abs(screen_area.Top - top)if 10 > top_diff > 0 and top_diff < height:

height -= top_difftop = screen_area.Top

left = window_rect.Left# in maximized window, Left also might be off the active screen# due to windows thicker window frames# let's fix the width to accomodate the extra pixels as wellleft_diff = abs(screen_area.Left - left)if 10 > left_diff > 0 and left_diff < width:

# deduct two times the left negative offset since this extra# offset happens on both left and right sidewidth -= left_diff * 2left = screen_area.Left

self.Top = top * scale_factorself.Left = left * scale_factorself.Width = width * scale_factorself.Height = height

def _setup(self, **kwargs):"""Private method to be overriden by subclasses for prompt setup."""pass

def __enter__(self):self.Show()return self

def __exit__(self, exception, exception_value, traceback):(continues on next page)

110 Chapter 13. pyrevit.forms

Page 115: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

self.Close()

class WarningBar(TemplatePromptBar):"""Show warning bar at the top of Revit window.

Args:title (string): warning bar text

Example:>>> with WarningBar(title='my warning'):... # do stuff

"""

xaml_source = 'WarningBar.xaml'

def _setup(self, **kwargs):self.message_tb.Text = kwargs.get('title', '')

class ProgressBar(TemplatePromptBar):"""Show progress bar at the top of Revit window.

Args:title (string): progress bar text, defaults to 0/100 progress formatindeterminate (bool): create indeterminate progress barcancellable (bool): add cancel button to progress barstep (int): update progress intervals

Example:>>> from pyrevit import forms>>> count = 1>>> with forms.ProgressBar(title='my command progress message') as pb:... # do stuff... pb.update_progress(count, 100)... count += 1

Progress bar title could also be customized to show the current andtotal progress values. In example below, the progress bar messagewill be in format "0 of 100"

>>> with forms.ProgressBar(title='{value} of {max_value}') as pb:

By default progress bar updates the progress every time the.update_progress method is called. For operations with a large numberof max steps, the gui update process time will have a significateeffect on the overall execution time of the command. In these cases,set the value of step argument to something larger than 1. In examplebelow, the progress bar updates once per every 10 units of progress.

>>> with forms.ProgressBar(title='message', steps=10):

Progress bar could also be set to indeterminate for operations ofunknown length. In this case, the progress bar will show an infinitelyrunning ribbon:

>>> with forms.ProgressBar(title='message', indeterminate=True):(continues on next page)

13.2. Implementation 111

Page 116: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

if cancellable is set on the object, a cancel button will show on theprogress bar and .cancelled attribute will be set on the ProgressBarinstance if users clicks on cancel button:

>>> with forms.ProgressBar(title='message',... cancellable=True) as pb:... # do stuff... if pb.cancelled:... # wrap up and cancel operation

"""

xaml_source = 'ProgressBar.xaml'

def _setup(self, **kwargs):self.max_value = 1self.new_value = 0self.step = kwargs.get('step', 0)

self.cancelled = Falsehas_cancel = kwargs.get('cancellable', False)if has_cancel:

self.show_element(self.cancel_b)

self.pbar.IsIndeterminate = kwargs.get('indeterminate', False)self._title = kwargs.get('title', '{value}/{max_value}')

def _update_pbar(self):self.update_window()self.pbar.Maximum = self.max_valueself.pbar.Value = self.new_value

# updating titletitle_text = \

string.Formatter().vformat(self._title,(),coreutils.SafeDict(

{'value': self.new_value,'max_value': self.max_value}

))

self.pbar_text.Text = title_text

def _donothing(self):pass

def _dispatch_updater(self):# ask WPF dispatcher for gui updateself.pbar.Dispatcher.Invoke(System.Action(self._update_pbar),

Threading.DispatcherPriority.Background)# give it a little free time to update uiself.pbar.Dispatcher.Invoke(System.Action(self._donothing),

Threading.DispatcherPriority.Background)

@staticmethoddef _make_return_getter(f, ret):

# WIP(continues on next page)

112 Chapter 13. pyrevit.forms

Page 117: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

@wraps(f)def wrapped_f(*args, **kwargs):

ret.append(f(*args, **kwargs))return wrapped_f

@propertydef title(self):

"""Progress bar title."""return self._title

@title.setterdef title(self, value):

if isinstance(value, str):self._title = value #pylint: disable=W0201

@propertydef indeterminate(self):

"""Progress bar indeterminate state."""return self.pbar.IsIndeterminate

@indeterminate.setterdef indeterminate(self, value):

self.pbar.IsIndeterminate = value

def clicked_cancel(self, sender, args): #pylint: disable=W0613"""Handler for cancel button clicked event."""self.cancel_b.Content = 'Cancelling...'self.cancelled = True #pylint: disable=W0201

def wait_async(self, func, args=()):"""Call a method asynchronosely and show progress."""returns = []self.indeterminate = Truergfunc = self._make_return_getter(func, returns)t = threading.Thread(target=rgfunc, args=args)t.start()while t.is_alive():

self._dispatch_updater()

return returns[0] if returns else None

def reset(self):"""Reset progress value to 0."""self.update_progress(0, 1)

def update_progress(self, new_value, max_value=1):"""Update progress bar state with given min, max values.

Args:new_value (float): current progress valuemax_value (float): total progress value

"""self.max_value = max_value #pylint: disable=W0201self.new_value = new_value #pylint: disable=W0201if self.new_value == 0:

self._dispatch_updater()elif self.step > 0:

(continues on next page)

13.2. Implementation 113

Page 118: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

if self.new_value % self.step == 0:self._dispatch_updater()

else:self._dispatch_updater()

class SearchPrompt(WPFWindow):"""Standard prompt for pyRevit search.

Args:search_db (list): list of possible search targetssearch_tip (str): text to show in grayscale when search box is emptyswitches (str): list of switcheswidth (int): width of search prompt windowheight (int): height of search prompt window

Returns:str, dict: matched strings, and dict of switches if providedstr: matched string if switches are not provided.

Example:>>> from pyrevit import forms>>> # assume search input of '/switch1 target1'>>> matched_str, args, switches = forms.SearchPrompt.show(... search_db=['target1', 'target2', 'target3', 'target4'],... switches=['/switch1', '/switch2'],... search_tip='pyRevit Search'... )... matched_str'target1'... args['--help', '--branch', 'branchname']... switches{'/switch1': True, '/switch2': False}

"""def __init__(self, search_db, width, height, **kwargs):

"""Initialize search prompt window."""WPFWindow.__init__(self,

op.join(op.dirname(__file__), 'SearchPrompt.xaml'))self.Width = widthself.MinWidth = self.Widthself.Height = height

self.search_tip = kwargs.get('search_tip', '')

self._search_db = sorted(search_db)self._switches = kwargs.get('switches', [])self._setup_response()

self.search_tb.Focus()self.hide_element(self.tab_icon)self.hide_element(self.return_icon)self.search_tb.Text = ''self.set_search_results()

def _setup_response(self, response=None):switch_dict = dict.fromkeys(self._switches)

(continues on next page)

114 Chapter 13. pyrevit.forms

Page 119: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

for switch in self.search_term_switches:switch_dict[switch] = True

arguments = self.search_term_args# remove first arg which is command nameif len(arguments) >= 1:

arguments = arguments[1:]

self.response = response, arguments, switch_dict

@propertydef search_input(self):

"""Current search input."""return self.search_tb.Text

@search_input.setterdef search_input(self, value):

self.search_tb.Text = valueself.search_tb.CaretIndex = len(value)

@propertydef search_input_parts(self):

"""Current cleaned up search term."""return self.search_input.strip().split()

@propertydef search_term(self):

"""Current cleaned up search term."""return self.search_input.lower().strip()

@propertydef search_term_switches(self):

"""Find matching switches in search term."""switches = set()for stpart in self.search_input_parts:

if stpart.lower() in self._switches:switches.add(stpart)

return switches

@propertydef search_term_args(self):

"""Find arguments in search term."""args = []switches = self.search_term_switchesfor spart in self.search_input_parts:

if spart.lower() not in switches:args.append(spart)

return args

@propertydef search_term_main(self):

"""Current cleaned up search term without the listed switches."""if len(self.search_term_args) >= 1:

return self.search_term_args[0]else:

return ''

@property(continues on next page)

13.2. Implementation 115

Page 120: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def search_matches(self):"""List of matches for the given search term."""# remove duplicates while keeping order# results = list(set(self._search_results))return OrderedDict.fromkeys(self._search_results).keys()

def update_results_display(self, fill_match=False):"""Update search prompt results based on current input text."""self.directmatch_tb.Text = ''self.wordsmatch_tb.Text = ''

results = self.search_matchesres_cout = len(results)

mlogger.debug('unique results count: %s', res_cout)mlogger.debug('unique results: %s', results)

if res_cout > 1:self.show_element(self.tab_icon)self.hide_element(self.return_icon)

elif res_cout == 1:self.hide_element(self.tab_icon)self.show_element(self.return_icon)

else:self.hide_element(self.tab_icon)self.hide_element(self.return_icon)

if self._result_index >= res_cout:self._result_index = 0 #pylint: disable=W0201

if self._result_index < 0:self._result_index = res_cout - 1 #pylint: disable=W0201

if not self.search_input:self.directmatch_tb.Text = self.search_tipreturn

if results:input_term = self.search_termcur_res = results[self._result_index]mlogger.debug('current result: %s', cur_res)if fill_match:

self.search_input = cur_reselse:

if cur_res.lower().startswith(input_term):self.directmatch_tb.Text = \

self.search_input + cur_res[len(input_term):]mlogger.debug('directmatch_tb.Text: %s',

self.directmatch_tb.Text)else:

self.wordsmatch_tb.Text = '- {}'.format(cur_res)mlogger.debug('wordsmatch_tb.Text: %s',

self.wordsmatch_tb.Text)

self._setup_response(response=cur_res)return True

(continues on next page)

116 Chapter 13. pyrevit.forms

Page 121: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

self._setup_response()return False

def set_search_results(self, *args):"""Set search results for returning."""self._result_index = 0self._search_results = []

mlogger.debug('search input: %s', self.search_input)mlogger.debug('search term: %s', self.search_term)mlogger.debug('search term (main): %s', self.search_term_main)mlogger.debug('search term (parts): %s', self.search_input_parts)mlogger.debug('search term (args): %s', self.search_term_args)mlogger.debug('search term (switches): %s', self.search_term_switches)

for resultset in args:mlogger.debug('result set: %s}', resultset)self._search_results.extend(sorted(resultset))

mlogger.debug('results: %s', self._search_results)

def find_direct_match(self, input_text):"""Find direct text matches in search term."""results = []if input_text:

for cmd_name in self._search_db:if cmd_name.lower().startswith(input_text):

results.append(cmd_name)

return results

def find_word_match(self, input_text):"""Find direct word matches in search term."""results = []if input_text:

cur_words = input_text.split(' ')for cmd_name in self._search_db:

if all([x in cmd_name.lower() for x in cur_words]):results.append(cmd_name)

return results

def search_txt_changed(self, sender, args): #pylint: disable=W0613"""Handle text changed event."""input_term = self.search_term_maindmresults = self.find_direct_match(input_term)wordresults = self.find_word_match(input_term)self.set_search_results(dmresults, wordresults)self.update_results_display()

def handle_kb_key(self, sender, args): #pylint: disable=W0613"""Handle keyboard input event."""shiftdown = Input.Keyboard.IsKeyDown(Input.Key.LeftShift) \

or Input.Keyboard.IsKeyDown(Input.Key.RightShift)# Escape: set response to none and closeif args.Key == Input.Key.Escape:

self._setup_response()(continues on next page)

13.2. Implementation 117

Page 122: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

self.Close()# Enter: close, returns matched response automaticallyelif args.Key == Input.Key.Enter:

self.Close()# Shift+Tab, Tab: Cycle through matcheselif args.Key == Input.Key.Tab and shiftdown:

self._result_index -= 1self.update_results_display()

elif args.Key == Input.Key.Tab:self._result_index += 1self.update_results_display()

# Up, Down: Cycle through matcheselif args.Key == Input.Key.Up:

self._result_index -= 1self.update_results_display()

elif args.Key == Input.Key.Down:self._result_index += 1self.update_results_display()

# Right, End: Autocomplete with displayed matchelif args.Key in [Input.Key.Right,

Input.Key.End]:self.update_results_display(fill_match=True)

@classmethoddef show(cls, search_db, #pylint: disable=W0221

width=DEFAULT_SEARCHWND_WIDTH,height=DEFAULT_SEARCHWND_HEIGHT, **kwargs):

"""Show search prompt."""dlg = cls(search_db, width, height, **kwargs)dlg.ShowDialog()return dlg.response

class RevisionOption(TemplateListItem):"""Revision wrapper for :func:`select_revisions`."""def __init__(self, revision_element):

super(RevisionOption, self).__init__(revision_element)

@propertydef name(self):

"""Revision name (description)."""revnum = self.item.SequenceNumberif hasattr(self.item, 'RevisionNumber'):

revnum = self.item.RevisionNumberreturn '{}-{}-{}'.format(revnum,

self.item.Description,self.item.RevisionDate)

class SheetOption(TemplateListItem):"""Sheet wrapper for :func:`select_sheets`."""def __init__(self, sheet_element):

super(SheetOption, self).__init__(sheet_element)

@propertydef name(self):

"""Sheet name."""(continues on next page)

118 Chapter 13. pyrevit.forms

Page 123: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

return '{} - {}{}' \.format(self.item.SheetNumber,

self.item.Name,' (placeholder)' if self.item.IsPlaceholder else '')

@propertydef number(self):

"""Sheet number."""return self.item.SheetNumber

class ViewOption(TemplateListItem):"""View wrapper for :func:`select_views`."""def __init__(self, view_element):

super(ViewOption, self).__init__(view_element)

@propertydef name(self):

"""View name."""return '{} ({})'.format(revit.query.get_name(self.item),

self.item.ViewType)

def select_revisions(title='Select Revision',button_name='Select',width=DEFAULT_INPUTWINDOW_WIDTH,multiple=True,filterfunc=None,doc=None):

"""Standard form for selecting revisions.

Args:title (str, optional): list window titlebutton_name (str, optional): list window button captionwidth (int, optional): width of list windowmultiselect (bool, optional):

allow multi-selection (uses check boxes). defaults to Truefilterfunc (function):

filter function to be applied to context items.doc (DB.Document, optional):

source document for revisions; defaults to active document

Returns:list[DB.Revision]: list of selected revisions

Example:>>> from pyrevit import forms>>> forms.select_revisions()... [<Autodesk.Revit.DB.Revision object>,... <Autodesk.Revit.DB.Revision object>]

"""revisions = sorted(revit.query.get_revisions(doc=doc),

key=lambda x: x.SequenceNumber)

if filterfunc:revisions = filter(filterfunc, revisions)

(continues on next page)

13.2. Implementation 119

Page 124: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# ask user for revisionsselected_revs = SelectFromList.show(

[RevisionOption(x) for x in revisions],title=title,button_name=button_name,width=width,multiselect=multiple,checked_only=True)

return selected_revs

def select_sheets(title='Select Sheets',button_name='Select',width=DEFAULT_INPUTWINDOW_WIDTH,multiple=True,filterfunc=None,doc=None):

"""Standard form for selecting sheets.

Sheets are grouped into sheet sets and sheet set can be selected froma drop down box at the top of window.

Args:title (str, optional): list window titlebutton_name (str, optional): list window button captionwidth (int, optional): width of list windowmultiselect (bool, optional):

allow multi-selection (uses check boxes). defaults to Truefilterfunc (function):

filter function to be applied to context items.doc (DB.Document, optional):

source document for sheets; defaults to active document

Returns:list[DB.ViewSheet]: list of selected sheets

Example:>>> from pyrevit import forms>>> forms.select_sheets()... [<Autodesk.Revit.DB.ViewSheet object>,... <Autodesk.Revit.DB.ViewSheet object>]

"""doc = doc or HOST_APP.docall_ops = {}all_sheets = DB.FilteredElementCollector(doc) \

.OfClass(DB.ViewSheet) \

.WhereElementIsNotElementType() \

.ToElements()

if filterfunc:all_sheets = filter(filterfunc, all_sheets)

all_sheets_ops = sorted([SheetOption(x) for x in all_sheets],key=lambda x: x.number)

all_ops['All Sheets'] = all_sheets_ops(continues on next page)

120 Chapter 13. pyrevit.forms

Page 125: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

sheetsets = revit.query.get_sheet_sets(doc)for sheetset in sheetsets:

sheetset_sheets = \[x for x in sheetset.Views if isinstance(x, DB.ViewSheet)]

if filterfunc:sheetset_sheets = filter(filterfunc, sheetset_sheets)

sheetset_ops = sorted([SheetOption(x) for x in sheetset_sheets],key=lambda x: x.number)

all_ops[sheetset.Name] = sheetset_ops

# ask user for multiple sheetsselected_sheets = SelectFromList.show(

all_ops,title=title,group_selector_title='Sheet Sets:',button_name=button_name,width=width,multiselect=multiple,checked_only=True)

return selected_sheets

def select_views(title='Select Views',button_name='Select',width=DEFAULT_INPUTWINDOW_WIDTH,multiple=True,filterfunc=None,doc=None):

"""Standard form for selecting views.

Args:title (str, optional): list window titlebutton_name (str, optional): list window button captionwidth (int, optional): width of list windowmultiselect (bool, optional):

allow multi-selection (uses check boxes). defaults to Truefilterfunc (function):

filter function to be applied to context items.doc (DB.Document, optional):

source document for views; defaults to active document

Returns:list[DB.View]: list of selected views

Example:>>> from pyrevit import forms>>> forms.select_views()... [<Autodesk.Revit.DB.View object>,... <Autodesk.Revit.DB.View object>]

"""all_graphviews = revit.query.get_all_views(doc=doc)

if filterfunc:all_graphviews = filter(filterfunc, all_graphviews)

(continues on next page)

13.2. Implementation 121

Page 126: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

selected_views = SelectFromList.show(sorted([ViewOption(x) for x in all_graphviews],

key=lambda x: x.name),title=title,button_name=button_name,width=width,multiselect=multiple,checked_only=True)

return selected_views

def select_open_docs(title='Select Open Documents',button_name='OK',width=DEFAULT_INPUTWINDOW_WIDTH, #pylint: disable=W0613multiple=True,filterfunc=None):

"""Standard form for selecting open documents.

Args:title (str, optional): list window titlebutton_name (str, optional): list window button captionwidth (int, optional): width of list windowmultiselect (bool, optional):

allow multi-selection (uses check boxes). defaults to Truefilterfunc (function):

filter function to be applied to context items.

Returns:list[DB.Document]: list of selected documents

Example:>>> from pyrevit import forms>>> forms.select_open_docs()... [<Autodesk.Revit.DB.Document object>,... <Autodesk.Revit.DB.Document object>]

"""# find open documents other than the active docopen_docs = [d for d in revit.docs if not d.IsLinked] #pylint: disable=E1101open_docs.remove(revit.doc) #pylint: disable=E1101

if not open_docs:alert('Only one active document is found. '

'At least two documents must be open. ''Operation cancelled.')

return

return SelectFromList.show(open_docs,name_attr='Title',multiselect=multiple,title=title,button_name=button_name,filterfunc=filterfunc)

(continues on next page)

122 Chapter 13. pyrevit.forms

Page 127: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def select_titleblocks(title='Select Titleblock',button_name='Select',no_tb_option='No Title Block',width=DEFAULT_INPUTWINDOW_WIDTH,multiple=False,filterfunc=None,doc=None):

"""Standard form for selecting a titleblock.

Args:title (str, optional): list window titlebutton_name (str, optional): list window button captionno_tb_option (str, optional): name of option for no title blockwidth (int, optional): width of list windowmultiselect (bool, optional):

allow multi-selection (uses check boxes). defaults to Truefilterfunc (function):

filter function to be applied to context items.doc (DB.Document, optional):

source document for titleblocks; defaults to active document

Returns:DB.ElementId: selected titleblock id.

Example:>>> from pyrevit import forms>>> forms.select_titleblocks()... <Autodesk.Revit.DB.ElementId object>

"""doc = doc or HOST_APP.doctitleblocks = DB.FilteredElementCollector(doc)\

.OfCategory(DB.BuiltInCategory.OST_TitleBlocks)\

.WhereElementIsElementType()\

.ToElements()

tblock_dict = {'{}: {}'.format(tb.FamilyName,revit.query.get_name(tb)): tb.Id

for tb in titleblocks}tblock_dict[no_tb_option] = DB.ElementId.InvalidElementIdselected_titleblocks = SelectFromList.show(sorted(tblock_dict.keys()),

title=title,button_name=button_name,width=width,multiselect=multiple,filterfunc=filterfunc)

if selected_titleblocks:if multiple:

return [tblock_dict[x] for x in selected_titleblocks]else:

return tblock_dict[selected_titleblocks]

def select_swatch(title='Select Color Swatch', button_name='Select'):"""Standard form for selecting a color swatch.

(continues on next page)

13.2. Implementation 123

Page 128: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Args:title (str, optional): swatch list window titlebutton_name (str, optional): swatch list window button caption

Returns:pyrevit.coreutils.colors.RGB: rgb color

Example:>>> from pyrevit import forms>>> forms.select_swatch(title="Select Text Color")... <RGB #CD8800>

"""itemplate_xaml_file = \

os.path.join(op.dirname(__file__), "SwatchContainerStyle.xaml")itemplate = \

wpf.LoadComponent(Controls.ControlTemplate(), itemplate_xaml_file)swatch = SelectFromList.show(

colors.COLORS.values(),title=title,button_name=button_name,width=300,multiselect=False,item_template=itemplate)

return swatch

def select_image(images, title='Select Image', button_name='Select'):"""Standard form for selecting an image.

Args:images (list[str] | list[framework.Imaging.BitmapImage]):

list of image file paths or bitmapstitle (str, optional): swatch list window titlebutton_name (str, optional): swatch list window button caption

Returns:str : path of the selected image

Example:>>> from pyrevit import forms>>> forms.select_image(['C:/path/to/image1.png',

'C:/path/to/image2.png'],title="Select Variation")

... 'C:/path/to/image1.png'"""ptemplate_xaml_file = \

os.path.join(op.dirname(__file__), "ImageListPanelStyle.xaml")ptemplate = \

wpf.LoadComponent(Controls.ItemsPanelTemplate(), ptemplate_xaml_file)

itemplate_xaml_file = \os.path.join(op.dirname(__file__), "ImageListContainerStyle.xaml")

itemplate = \wpf.LoadComponent(Controls.ControlTemplate(), itemplate_xaml_file)

(continues on next page)

124 Chapter 13. pyrevit.forms

Page 129: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

bitmap_images = {}for imageobj in images:

if isinstance(imageobj, str):img = utils.bitmap_from_file(imageobj)if img:

bitmap_images[img] = imageobjelif isinstance(imageobj, framework.Imaging.BitmapImage):

bitmap_images[imageobj] = imageobj

selected_image = SelectFromList.show(sorted(bitmap_images.keys(), key=lambda x: x.UriSource.AbsolutePath),title=title,button_name=button_name,width=500,multiselect=False,item_template=itemplate,items_panel_template=ptemplate)

return bitmap_images.get(selected_image, None)

def alert(msg, title=None, sub_msg=None, expanded=None, footer='',ok=True, cancel=False, yes=False, no=False, retry=False,warn_icon=True, options=None, exitscript=False):

"""Show a task dialog with given message.

Args:msg (str): message to be displayedtitle (str, optional): task dialog titleok (bool, optional): show OK button, defaults to Truecancel (bool, optional): show Cancel button, defaults to Falseyes (bool, optional): show Yes button, defaults to Falseno (bool, optional): show NO button, defaults to Falseretry (bool, optional): show Retry button, defaults to Falseoptions(list[str], optional): list of command link titles in orderexitscript (bool, optional): exit if cancel or no, defaults to False

Returns:bool: True if okay, yes, or retry, otherwise False

Example:>>> from pyrevit import forms>>> forms.alert('Are you sure?',... ok=False, yes=True, no=True, exitscript=True)

"""# BUILD DIALOGcmd_name = EXEC_PARAMS.command_nameif not title:

title = cmd_name if cmd_name else 'pyRevit'tdlg = UI.TaskDialog(title)

options = options or []# add command links if anyif options:

clinks = coreutils.get_enum_values(UI.TaskDialogCommandLinkId)max_clinks = len(clinks)

(continues on next page)

13.2. Implementation 125

Page 130: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

for idx, cmd in enumerate(options):if idx < max_clinks:

tdlg.AddCommandLink(clinks[idx], cmd)# otherwise add buttonselse:

buttons = coreutils.get_enum_none(UI.TaskDialogCommonButtons)if yes:

buttons |= UI.TaskDialogCommonButtons.Yeselif ok:

buttons |= UI.TaskDialogCommonButtons.Ok

if cancel:buttons |= UI.TaskDialogCommonButtons.Cancel

if no:buttons |= UI.TaskDialogCommonButtons.No

if retry:buttons |= UI.TaskDialogCommonButtons.Retry

tdlg.CommonButtons = buttons

# set textstdlg.MainInstruction = msgtdlg.MainContent = sub_msgtdlg.ExpandedContent = expandedif footer:

footer = footer.strip() + '\n'tdlg.FooterText = footer + 'pyRevit {}'.format(

versionmgr.get_pyrevit_version().get_formatted())

tdlg.TitleAutoPrefix = False

# set icontdlg.MainIcon = \

UI.TaskDialogIcon.TaskDialogIconWarning \if warn_icon else UI.TaskDialogIcon.TaskDialogIconNone

# tdlg.VerificationText = 'verif'

# SHOW DIALOGres = tdlg.Show()

# PROCESS REPONSES# positive responseif res == UI.TaskDialogResult.Ok \

or res == UI.TaskDialogResult.Yes \or res == UI.TaskDialogResult.Retry:

if not exitscript:return True

else:sys.exit()

# negative responseelif res == coreutils.get_enum_none(UI.TaskDialogResult) \

or res == UI.TaskDialogResult.Cancel \or res == UI.TaskDialogResult.No:

if not exitscript:return False

else:sys.exit()

(continues on next page)

126 Chapter 13. pyrevit.forms

Page 131: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# command link responseelif 'CommandLink' in str(res):

tdresults = sorted([x for x in coreutils.get_enum_values(UI.TaskDialogResult)if 'CommandLink' in str(x)]

)residx = tdresults.index(res)return options[residx]

else:if not exitscript:

return Falseelse:

sys.exit()

def alert_ifnot(condition, msg, *args, **kwargs):"""Show a task dialog with given message if condition is NOT met.

Args:condition (bool): condition to testmsg (str): message to be displayedtitle (str, optional): task dialog titleok (bool, optional): show OK button, defaults to Truecancel (bool, optional): show Cancel button, defaults to Falseyes (bool, optional): show Yes button, defaults to Falseno (bool, optional): show NO button, defaults to Falseretry (bool, optional): show Retry button, defaults to Falseexitscript (bool, optional): exit if cancel or no, defaults to False

Returns:bool: True if okay, yes, or retry, otherwise False

Example:>>> from pyrevit import forms>>> forms.alert_ifnot(value > 12,... 'Are you sure?',... ok=False, yes=True, no=True, exitscript=True)

"""if not condition:

return alert(msg, *args, **kwargs)

def pick_folder(title=None):"""Show standard windows pick folder dialog.

Args:title (str, optional): title for the window

Returns:str: folder path

"""fb_dlg = Forms.FolderBrowserDialog()if title:

fb_dlg.Description = titleif fb_dlg.ShowDialog() == Forms.DialogResult.OK:

return fb_dlg.SelectedPath

(continues on next page)

13.2. Implementation 127

Page 132: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def pick_file(file_ext='', files_filter='', init_dir='',restore_dir=True, multi_file=False, unc_paths=False):

r"""Pick file dialog to select a destination file.

Args:file_ext (str): file extensionfiles_filter (str): file filterinit_dir (str): initial directoryrestore_dir (bool): restore last directorymulti_file (bool): allow select multiple filesunc_paths (bool): return unc paths

Returns:str or list[str]: file path or list of file paths if multi_file=True

Example:>>> from pyrevit import forms>>> forms.pick_file(file_ext='csv')... r'C:\output\somefile.csv'

>>> forms.pick_file(file_ext='csv', multi_file=True)... [r'C:\output\somefile1.csv', r'C:\output\somefile2.csv']

>>> forms.pick_file(files_filter='All Files (*.*)|*.*|''Excel Workbook (*.xlsx)|*.xlsx|''Excel 97-2003 Workbook|*.xls',

multi_file=True)... [r'C:\output\somefile1.xlsx', r'C:\output\somefile2.xls']

"""of_dlg = Forms.OpenFileDialog()if files_filter:

of_dlg.Filter = files_filterelse:

of_dlg.Filter = '|*.{}'.format(file_ext)of_dlg.RestoreDirectory = restore_dirof_dlg.Multiselect = multi_fileif init_dir:

of_dlg.InitialDirectory = init_dirif of_dlg.ShowDialog() == Forms.DialogResult.OK:

if multi_file:if unc_paths:

return [coreutils.dletter_to_unc(x)for x in of_dlg.FileNames]

return of_dlg.FileNameselse:

if unc_paths:return coreutils.dletter_to_unc(of_dlg.FileName)

return of_dlg.FileName

def save_file(file_ext='', files_filter='', init_dir='', default_name='',restore_dir=True, unc_paths=False):

r"""Save file dialog to select a destination file for data.

Args:file_ext (str): file extension

(continues on next page)

128 Chapter 13. pyrevit.forms

Page 133: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

files_filter (str): file filterinit_dir (str): initial directorydefault_name (str): default file namerestore_dir (bool): restore last directoryunc_paths (bool): return unc paths

Returns:str: file path

Example:>>> from pyrevit import forms>>> forms.save_file(file_ext='csv')... r'C:\output\somefile.csv'

"""sf_dlg = Forms.SaveFileDialog()if files_filter:

sf_dlg.Filter = files_filterelse:

sf_dlg.Filter = '|*.{}'.format(file_ext)sf_dlg.RestoreDirectory = restore_dirif init_dir:

sf_dlg.InitialDirectory = init_dir

# setting default filenamesf_dlg.FileName = default_name

if sf_dlg.ShowDialog() == Forms.DialogResult.OK:if unc_paths:

return coreutils.dletter_to_unc(sf_dlg.FileName)return sf_dlg.FileName

def pick_excel_file(save=False):"""File pick/save dialog for an excel file.

Args:save (bool): show file save dialog, instead of file pick dialog

Returns:str: file path

"""if save:

return save_file(file_ext='xlsx')return pick_file(files_filter='All Files (*.*)|*.*|'

'Excel Workbook (*.xlsx)|*.xlsx|''Excel 97-2003 Workbook|*.xls')

def save_excel_file():"""File save dialog for an excel file.

Returns:str: file path

"""return pick_excel_file(save=True)

(continues on next page)

13.2. Implementation 129

Page 134: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def check_workshared(doc=None, message='Model is not workshared.'):"""Verify if model is workshared and notify user if not.

Args:doc (DB.Document): target document, current of not providedmessage (str): prompt message if returning False

Returns:bool: True if doc is workshared

"""doc = doc or HOST_APP.docif not doc.IsWorkshared:

alert(message, warn_icon=True)return False

return True

def check_selection(exitscript=False,message='At least one element must be selected.'):

"""Verify if selection is not empty notify user if it is.

Args:exitscript (bool): exit script if returning Falsemessage (str): prompt message if returning False

Returns:bool: True if selection has at least one item

"""if revit.get_selection().is_empty:

alert(message, exitscript=exitscript)return False

return True

def check_familydoc(doc=None, family_cat=None, exitscript=False):"""Verify document is a Family and notify user of not.

Args:doc (DB.Document): target document, current of not providedfamily_cat (str): family category nameexitscript (bool): exit script if returning False

Returns:bool: True if doc is a Family and of provided category

Example:>>> from pyrevit import forms>>> forms.check_familydoc(doc=revit.doc, family_cat='Data Devices')... True

"""doc = doc or HOST_APP.docfamily_cat = revit.query.get_category(family_cat)if doc.IsFamilyDocument and family_cat:

if doc.OwnerFamily.FamilyCategory.Id == family_cat.Id:return True

elif doc.IsFamilyDocument and not family_cat:return True

(continues on next page)

130 Chapter 13. pyrevit.forms

Page 135: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

family_type_msg = ' of type {}'\.format(family_cat.Name) if family_cat else''

alert('Active document must be a Family document{}.'.format(family_type_msg), exitscript=exitscript)

return False

def toast(message, title='pyRevit', appid='pyRevit',icon=None, click=None, actions=None):

"""Show a Windows 10 notification.

Args:message (str): notification messagetitle (str): notification titleappid (str): app name (will show under message)icon (str): file path to icon .ico file (defaults to pyRevit icon)click (str): click action commands stringactions (dict): dictionary of button names and action strings

Example:>>> script.toast("Hello World!",... title="My Script",... appid="MyAPP",... click="https://eirannejad.github.io/pyRevit/",... actions={... "Open Google":"https://google.com",... "Open Toast64":"https://github.com/go-toast/toast"... })

"""toaster.send_toast(

message,title=title,appid=appid,icon=icon,click=click,actions=actions)

def ask_for_string(default=None, prompt=None, title=None, **kwargs):return GetValueWindow.show(

None,value_type='string',default=default,prompt=prompt,title=title,

**kwargs)

def ask_for_unique_string(reserved_values,default=None, prompt=None, title=None, **kwargs):

return GetValueWindow.show(None,value_type='string',default=default,prompt=prompt,

(continues on next page)

13.2. Implementation 131

Page 136: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

title=title,reserved_values=reserved_values,

**kwargs)

def ask_for_one_item(items, default=None, prompt=None, title=None, **kwargs):return GetValueWindow.show(

items,value_type='dropdown',default=default,prompt=prompt,title=title,

**kwargs)

def ask_for_date(default=None, prompt=None, title=None, **kwargs):return GetValueWindow.show(

None,value_type='date',default=default,prompt=prompt,title=title,

**kwargs)

def inform_wip():alert("Work in progress.", exitscript=True)

132 Chapter 13. pyrevit.forms

Page 137: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 14

pyrevit.framework

Provide access to DotNet Framework.

Example

>>> from pyrevit.framework import Assembly, Windows

pyrevit.framework.get_dll_file(assembly_name)Return path to given assembly name.

pyrevit.framework.get_type(fw_object)Return CLR type of an object.

Parameters fw_object – Dotnet Framework Object Instance

14.1 Implementation

"""Provide access to DotNet Framework.

Example:>>> from pyrevit.framework import Assembly, Windows

"""

#pylint: disable=W0703,C0302,C0103,W0614,E0401,W0611,C0413import os.path as op

import clrimport System

clr.AddReference("System.Core")clr.AddReference('System.Management')

(continues on next page)

133

Page 138: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

clr.AddReferenceByPartialName('System.Windows.Forms')clr.AddReferenceByPartialName('System.Drawing')clr.AddReference('PresentationCore')clr.AddReference('PresentationFramework')clr.AddReference('System.Xml.Linq')clr.AddReferenceByPartialName('WindowsBase')

# add linq extensions?clr.ImportExtensions(System.Linq)

from System import AppDomain, Versionfrom System import Typefrom System import Uri, Guidfrom System import EventHandlerfrom System import Array, IntPtr, Enumfrom System import Convertfrom System.Text import Encodingfrom System.Collections import IEnumerator, IEnumerablefrom System.Collections.Generic import List, Dictionaryfrom System import DateTime, DateTimeOffset

from System import Diagnosticsfrom System.Diagnostics import Processfrom System.Diagnostics import Stopwatch

from System import Reflectionfrom System.Reflection import Assembly, AssemblyNamefrom System.Reflection import TypeAttributes, MethodAttributesfrom System.Reflection import CallingConventionsfrom System.Reflection import BindingFlagsfrom System.Reflection.Emit import AssemblyBuilderAccessfrom System.Reflection.Emit import CustomAttributeBuilder, OpCodes

from System import IOfrom System.IO import IOException, DriveInfo, Path, StringReader

from System import Netfrom System.Net import WebClient, WebRequest, WebProxy

from System import ComponentModelfrom System import Drawingfrom System import Windowsfrom System.Windows import Formsfrom System.Windows.Forms import Clipboardfrom System.Windows import Controlsfrom System.Windows import Mediafrom System.Windows import Threadingfrom System.Windows import Interopfrom System.Windows import Inputfrom System.Windows.Media import Imaging, SolidColorBrush, Colorfrom System import Mathfrom System.CodeDom import Compilerfrom System.Management import ManagementObjectSearcherfrom System.Runtime.Serialization import FormatterServices

from Microsoft.CSharp import CSharpCodeProvider

(continues on next page)

134 Chapter 14. pyrevit.framework

Page 139: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

clr.AddReference('IronPython.Wpf')import wpf

from pyrevit import BIN_DIR

def get_type(fw_object):"""Return CLR type of an object.

Args:fw_object: Dotnet Framework Object Instance

"""return clr.GetClrType(fw_object)

def get_dll_file(assembly_name):"""Return path to given assembly name."""addin_file = op.join(BIN_DIR, assembly_name + '.dll')if op.exists(addin_file):

return addin_file

14.1. Implementation 135

Page 140: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

136 Chapter 14. pyrevit.framework

Page 141: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 15

pyrevit.script

See pyrevit.script Module

Provide basic utilities for pyRevit scripts.

Example

>>> from pyrevit import script>>> script.clipboard_copy('some text')>>> data = script.journal_read('data-key')>>> script.exit()

pyrevit.script.clipboard_copy(string_to_copy)Copy string to Windows Clipboard.

pyrevit.script.exit()Stop the script execution and exit.

pyrevit.script.get_all_buttons()Find and return all ui buttons matching current script command name.

Sometimes tools are duplicated across extensions for user access control so this would help smart buttons to findall the loaded buttons and make icon adjustments.

Returns list of ui button objects

Return type list(pyrevit.coreutils.ribbon._PyRevitRibbonButton)

pyrevit.script.get_alt_script_path()Return alternate script path of the current pyRevit command.

Returns alternate script path

Return type str

pyrevit.script.get_bundle_file(file_name)Return full path to file under current script bundle.

137

Page 142: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters file_name (str) – bundle file name

Returns full bundle file path

Return type str

pyrevit.script.get_bundle_files(sub_path=None)Return full path to all file under current script bundle.

Returns list of bundle file paths

Return type list[str]

pyrevit.script.get_bundle_name()Return bundle name of the current pyRevit command.

Returns bundle name (e.g. MyButton.pushbutton)

Return type str

pyrevit.script.get_button()Find and return current script ui button.

Returns ui button object

Return type pyrevit.coreutils.ribbon._PyRevitRibbonButton

pyrevit.script.get_config(section=None)Create and return config section parser object for current script.

Parameters section (str, optional) – config section name

Returns Config section parser object

Return type pyrevit.coreutils.configparser.PyRevitConfigSectionParser

pyrevit.script.get_data_file(file_id, file_ext, add_cmd_name=False)Return filename to be used by a user script to store data.

File name is generated in this format: pyRevit_{Revit Version}_{file_id}.{file_ext}

Example

>>> script.get_data_file('mydata', 'data')'.../pyRevit_2018_mydata.data'>>> script.get_data_file('mydata', 'data', add_cmd_name=True)'.../pyRevit_2018_Command Name_mydata.data'

Data files are not cleaned up at pyRevit startup. Script should manage cleaning up these files.

Parameters

• file_id (str) – unique id for the filename

• file_ext (str) – file extension

• add_cmd_name (bool, optional) – add command name to file name

Returns full file path

Return type str

138 Chapter 15. pyrevit.script

Page 143: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.script.get_document_data_file(file_id, file_ext, add_cmd_name=False)Return filename to be used by a user script to store data.

File name is generated in this format: pyRevit_{Revit Version}_{file_id}_{Project Name}.{file_ext}

Example

>>> script.get_document_data_file('mydata', 'data')'.../pyRevit_2018_mydata_Project1.data'>>> script.get_document_data_file('mydata', 'data', add_cmd_name=True)'.../pyRevit_2018_Command Name_mydata_Project1.data'

Document data files are not cleaned up at pyRevit startup. Script should manage cleaning up these files.

Parameters

• file_id (str) – unique id for the filename

• file_ext (str) – file extension

• add_cmd_name (bool, optional) – add command name to file name

Returns full file path

Return type str

pyrevit.script.get_envvar(envvar)Return value of give pyRevit environment variable.

The environment variable system is used to retain small values in memory between script runs (e.g. ac-tive/inactive state for toggle tools). Do not store large objects in memory using this method. List of currentlyset environment variables could be sees in pyRevit settings window.

Parameters envvar (str) – name of environment variable

Returns type of object stored in environment variable

Return type any

Example

>>> script.get_envvar('ToolActiveState')True

pyrevit.script.get_extension_name()Return extension name of the current pyRevit command.

Returns extension name (e.g. MyExtension.extension)

Return type str

pyrevit.script.get_info()Return info on current pyRevit command.

Returns Command info object

Return type pyrevit.extensions.genericcomps.GenericUICommand

139

Page 144: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.script.get_instance_data_file(file_id, add_cmd_name=False)Return filename to be used by a user script to store data.

File name is generated in this format: pyRevit_{Revit Version}_{Process Id}_{file_id}.{file_ext}

Example

>>> script.get_instance_data_file('mydata')'.../pyRevit_2018_6684_mydata.tmp'>>> script.get_instance_data_file('mydata', add_cmd_name=True)'.../pyRevit_2018_6684_Command Name_mydata.tmp'

Instance data files are cleaned up at pyRevit startup.

Parameters

• file_id (str) – unique id for the filename

• add_cmd_name (bool, optional) – add command name to file name

Returns full file path

Return type str

pyrevit.script.get_logger()Create and return logger named for current script.

Returns Logger object

Return type pyrevit.coreutils.logger.LoggerWrapper

pyrevit.script.get_output()Return object wrapping output window for current script.

Returns Output wrapper object

Return type pyrevit.output.PyRevitOutputWindow

pyrevit.script.get_pyrevit_version()Return pyRevit version.

Returns pyRevit version provider

Return type pyrevit.versionmgr.PyRevitVersion

pyrevit.script.get_results()Return command results dictionary for logging.

Returns Command results dict

Return type pyrevit.usagelog.record.CommandCustomResults

pyrevit.script.get_script_path()Return script path of the current pyRevit command.

Returns script path

Return type str

pyrevit.script.get_unique_id()Return unique id of the current pyRevit command.

Returns command unique id

140 Chapter 15. pyrevit.script

Page 145: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Return type str

pyrevit.script.get_universal_data_file(file_id, file_ext, add_cmd_name=False)Return filename to be used by a user script to store data.

File name is generated in this format: pyRevit_{file_id}.{file_ext}

Example

>>> script.get_universal_data_file('mydata', 'data')'.../pyRevit_mydata.data'>>> script.get_universal_data_file('mydata', 'data', add_cmd_name=True)'.../pyRevit_Command Name_mydata.data'

Universal data files are not cleaned up at pyRevit startup. Script should manage cleaning up these files.

Parameters

• file_id (str) – unique id for the filename

• file_ext (str) – file extension

• add_cmd_name (bool, optional) – add command name to file name

Returns full file path

Return type str

pyrevit.script.journal_read(data_key)Read value for provided key from active Revit journal.

Parameters data_key (str) – data key

Returns data value string

Return type str

pyrevit.script.journal_write(data_key, msg)Write key and value to active Revit journal for current command.

Parameters

• data_key (str) – data key

• msg (str) – data value string

pyrevit.script.load_index(index_file=’index.html’)Load html file into output window.

This method expects index.html file in the current command bundle, unless full path to an html file is provided.

Parameters index_file (str, optional) – full path of html file.

pyrevit.script.open_url(url)Open url in a new tab in default webbrowser.

pyrevit.script.reset_config(section=None)Reset pyRevit config.

Script should call this to reset any save configuration by removing section related to current script.

Parameters section (str, optional) – config section name

141

Page 146: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.script.save_config()Save pyRevit config.

Scripts should call this to save any changes they have done to their config section object received fromscript.get_config() method.

pyrevit.script.set_envvar(envvar, value)Set value of give pyRevit environment variable.

The environment variable system is used to retain small values in memory between script runs (e.g. ac-tive/inactive state for toggle tools). Do not store large objects in memory using this method. List of currentlyset environment variables could be sees in pyRevit settings window.

Parameters

• envvar (str) – name of environment variable

• value (any) – value of environment variable

Example

>>> script.set_envvar('ToolActiveState', False)>>> script.get_envvar('ToolActiveState')False

pyrevit.script.show_file_in_explorer(file_path)Show file in Windows Explorer.

pyrevit.script.toggle_icon(new_state, on_icon_path=None, off_icon_path=None)Set the state of button icon (on or off).

This method expects on.png and off.png in command bundle for on and off icon states, unless full path of iconstates are provided.

Parameters

• new_state (bool) – state of the ui button icon.

• on_icon_path (str, optional) – full path of icon for on state. default=’on.png’

• off_icon_path (str, optional) – full path of icon for off state. default=’off.png’

15.1 Implementation

"""Provide basic utilities for pyRevit scripts.

Example:>>> from pyrevit import script>>> script.clipboard_copy('some text')>>> data = script.journal_read('data-key')>>> script.exit()

"""

import sysimport osimport os.path as opimport warnings

(continues on next page)

142 Chapter 15. pyrevit.script

Page 147: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

from pyrevit import EXEC_PARAMS, PyRevitExceptionfrom pyrevit.coreutils import loggerfrom pyrevit.coreutils import appdatafrom pyrevit.coreutils import envvarsfrom pyrevit import frameworkfrom pyrevit import revitfrom pyrevit import outputfrom pyrevit import versionmgrfrom pyrevit.labs import TargetApps

# suppress any warning generated by native or third-party moduleswarnings.filterwarnings("ignore")

#pylint: disable=W0703,C0302,C0103,W0614mlogger = logger.get_logger(__name__)

def get_info():"""Return info on current pyRevit command.

Returns::obj:`pyrevit.extensions.genericcomps.GenericUICommand`:

Command info object"""from pyrevit.extensions.extensionmgr import get_command_from_pathreturn get_command_from_path(EXEC_PARAMS.command_path)

def get_script_path():"""Return script path of the current pyRevit command.

Returns:str: script path

"""return EXEC_PARAMS.command_path

def get_alt_script_path():"""Return alternate script path of the current pyRevit command.

Returns:str: alternate script path

"""return EXEC_PARAMS.command_alt_path

def get_bundle_name():"""Return bundle name of the current pyRevit command.

Returns:str: bundle name (e.g. MyButton.pushbutton)

"""return EXEC_PARAMS.command_bundle

(continues on next page)

15.1. Implementation 143

Page 148: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def get_extension_name():"""Return extension name of the current pyRevit command.

Returns:str: extension name (e.g. MyExtension.extension)

"""return EXEC_PARAMS.command_extension

def get_unique_id():"""Return unique id of the current pyRevit command.

Returns:str: command unique id

"""return EXEC_PARAMS.command_uniqueid

def get_results():"""Return command results dictionary for logging.

Returns::obj:`pyrevit.usagelog.record.CommandCustomResults`:

Command results dict"""from pyrevit.usagelog.record import CommandCustomResultsreturn CommandCustomResults()

def get_pyrevit_version():"""Return pyRevit version.

Returns::obj:`pyrevit.versionmgr.PyRevitVersion`: pyRevit version provider

"""return versionmgr.get_pyrevit_version()

def get_logger():"""Create and return logger named for current script.

Returns::obj:`pyrevit.coreutils.logger.LoggerWrapper`: Logger object

"""return logger.get_logger(EXEC_PARAMS.command_name)

def get_output():"""Return object wrapping output window for current script.

Returns::obj:`pyrevit.output.PyRevitOutputWindow`: Output wrapper object

"""return output.get_output()

def get_config(section=None):(continues on next page)

144 Chapter 15. pyrevit.script

Page 149: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Create and return config section parser object for current script.

Args:section (str, optional): config section name

Returns::obj:`pyrevit.coreutils.configparser.PyRevitConfigSectionParser`:

Config section parser object"""from pyrevit.userconfig import user_configif not section:

script_cfg_postfix = 'config'section = EXEC_PARAMS.command_name + script_cfg_postfix

try:return user_config.get_section(section)

except Exception:return user_config.add_section(section)

def save_config():"""Save pyRevit config.

Scripts should call this to save any changes they have done to theirconfig section object received from script.get_config() method."""from pyrevit.userconfig import user_configuser_config.save_changes()

def reset_config(section=None):"""Reset pyRevit config.

Script should call this to reset any save configuration by removingsection related to current script.

Args:section (str, optional): config section name

"""from pyrevit.userconfig import user_configif not section:

script_cfg_postfix = 'config'section = EXEC_PARAMS.command_name + script_cfg_postfix

elif section in [TargetApps.Revit.PyRevitConsts.ConfigsCoreSection]:raise PyRevitException('Can not remove internal config section: {}'

.format(section))

try:user_config.remove_section(section)user_config.save_changes()

except Exception:mlogger.debug('Failed resetting config for %s (%s)',

EXEC_PARAMS.command_name, section)

def get_universal_data_file(file_id, file_ext, add_cmd_name=False):"""Return filename to be used by a user script to store data.

(continues on next page)

15.1. Implementation 145

Page 150: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

File name is generated in this format:``pyRevit_{file_id}.{file_ext}``

Example:>>> script.get_universal_data_file('mydata', 'data')'.../pyRevit_mydata.data'>>> script.get_universal_data_file('mydata', 'data', add_cmd_name=True)'.../pyRevit_Command Name_mydata.data'

Universal data files are not cleaned up at pyRevit startup.Script should manage cleaning up these files.

Args:file_id (str): unique id for the filenamefile_ext (str): file extensionadd_cmd_name (bool, optional): add command name to file name

Returns:str: full file path

"""if add_cmd_name:

script_file_id = '{}_{}'.format(EXEC_PARAMS.command_name, file_id)else:

script_file_id = file_id

return appdata.get_universal_data_file(script_file_id, file_ext)

def get_data_file(file_id, file_ext, add_cmd_name=False):"""Return filename to be used by a user script to store data.

File name is generated in this format:``pyRevit_{Revit Version}_{file_id}.{file_ext}``

Example:>>> script.get_data_file('mydata', 'data')'.../pyRevit_2018_mydata.data'>>> script.get_data_file('mydata', 'data', add_cmd_name=True)'.../pyRevit_2018_Command Name_mydata.data'

Data files are not cleaned up at pyRevit startup.Script should manage cleaning up these files.

Args:file_id (str): unique id for the filenamefile_ext (str): file extensionadd_cmd_name (bool, optional): add command name to file name

Returns:str: full file path

"""if add_cmd_name:

script_file_id = '{}_{}'.format(EXEC_PARAMS.command_name, file_id)else:

script_file_id = file_id

(continues on next page)

146 Chapter 15. pyrevit.script

Page 151: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

return appdata.get_data_file(script_file_id, file_ext)

def get_instance_data_file(file_id, add_cmd_name=False):"""Return filename to be used by a user script to store data.

File name is generated in this format:``pyRevit_{Revit Version}_{Process Id}_{file_id}.{file_ext}``

Example:>>> script.get_instance_data_file('mydata')'.../pyRevit_2018_6684_mydata.tmp'>>> script.get_instance_data_file('mydata', add_cmd_name=True)'.../pyRevit_2018_6684_Command Name_mydata.tmp'

Instance data files are cleaned up at pyRevit startup.

Args:file_id (str): unique id for the filenameadd_cmd_name (bool, optional): add command name to file name

Returns:str: full file path

"""if add_cmd_name:

script_file_id = '{}_{}'.format(EXEC_PARAMS.command_name, file_id)else:

script_file_id = file_id

return appdata.get_instance_data_file(script_file_id)

def get_document_data_file(file_id, file_ext, add_cmd_name=False):"""Return filename to be used by a user script to store data.

File name is generated in this format:``pyRevit_{Revit Version}_{file_id}_{Project Name}.{file_ext}``

Example:>>> script.get_document_data_file('mydata', 'data')'.../pyRevit_2018_mydata_Project1.data'>>> script.get_document_data_file('mydata', 'data', add_cmd_name=True)'.../pyRevit_2018_Command Name_mydata_Project1.data'

Document data files are not cleaned up at pyRevit startup.Script should manage cleaning up these files.

Args:file_id (str): unique id for the filenamefile_ext (str): file extensionadd_cmd_name (bool, optional): add command name to file name

Returns:str: full file path

"""proj_info = revit.query.get_project_info()

(continues on next page)

15.1. Implementation 147

Page 152: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

if add_cmd_name:script_file_id = '{}_{}_{}'.format(EXEC_PARAMS.command_name,

file_id,proj_info.filenameor proj_info.name)

else:script_file_id = '{}_{}'.format(file_id,

proj_info.filenameor proj_info.name)

return appdata.get_data_file(script_file_id, file_ext)

def get_bundle_file(file_name):"""Return full path to file under current script bundle.

Args:file_name (str): bundle file name

Returns:str: full bundle file path

"""return op.join(EXEC_PARAMS.command_path, file_name)

def get_bundle_files(sub_path=None):"""Return full path to all file under current script bundle.

Returns:list[str]: list of bundle file paths

"""if sub_path:

command_path = op.join(EXEC_PARAMS.command_path, sub_path)else:

command_path = EXEC_PARAMS.command_pathreturn [op.join(command_path, x) for x in os.listdir(command_path)]

def journal_write(data_key, msg):"""Write key and value to active Revit journal for current command.

Args:data_key (str): data keymsg (str): data value string

"""# Get the StringStringMap class which can write data into.data_map = EXEC_PARAMS.command_data.JournalDatadata_map.Clear()

# Begin to add the support datadata_map.Add(data_key, msg)

def journal_read(data_key):"""Read value for provided key from active Revit journal.

Args:(continues on next page)

148 Chapter 15. pyrevit.script

Page 153: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

data_key (str): data key

Returns:str: data value string

"""# Get the StringStringMap class which can write data into.data_map = EXEC_PARAMS.command_data.JournalData

# Begin to get the support datareturn data_map[data_key]

def get_button():"""Find and return current script ui button.

Returns::obj:`pyrevit.coreutils.ribbon._PyRevitRibbonButton`: ui button object

"""from pyrevit.coreutils.ribbon import get_current_uipyrvt_tabs = get_current_ui().get_pyrevit_tabs()for tab in pyrvt_tabs:

button = tab.find_child(EXEC_PARAMS.command_name)if button:

return buttonreturn None

def get_all_buttons():"""Find and return all ui buttons matching current script command name.

Sometimes tools are duplicated across extensions for user access controlso this would help smart buttons to find all the loaded buttons and makeicon adjustments.

Returns::obj:`list(pyrevit.coreutils.ribbon._PyRevitRibbonButton)`:

list of ui button objects"""from pyrevit.coreutils.ribbon import get_current_uipyrvt_tabs = get_current_ui().get_pyrevit_tabs()buttons = []for tab in pyrvt_tabs:

button = tab.find_child(EXEC_PARAMS.command_name)if button:

buttons.append(button)return buttons

def toggle_icon(new_state, on_icon_path=None, off_icon_path=None):"""Set the state of button icon (on or off).

This method expects on.png and off.png in command bundle for on and officon states, unless full path of icon states are provided.

Args:new_state (bool): state of the ui button icon.on_icon_path (str, optional): full path of icon for on state.

(continues on next page)

15.1. Implementation 149

Page 154: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

default='on.png'off_icon_path (str, optional): full path of icon for off state.

default='off.png'"""# find the ui buttonuibuttons = get_all_buttons()if not uibuttons:

mlogger.debug('Can not find ui button.')return

# get icon for on stateif not on_icon_path:

on_icon_path = get_bundle_file('on.png')if not on_icon_path:

mlogger.debug('Script does not have icon for on state.')return

# get icon for off stateif not off_icon_path:

off_icon_path = get_bundle_file('off.png')if not off_icon_path:

mlogger.debug('Script does not have icon for on state.')return

icon_path = on_icon_path if new_state else off_icon_pathmlogger.debug('Setting icon state to: %s (%s)',

new_state, icon_path)

for uibutton in uibuttons:uibutton.set_icon(icon_path)

def exit(): #pylint: disable=W0622"""Stop the script execution and exit."""sys.exit()

def show_file_in_explorer(file_path):"""Show file in Windows Explorer."""import subprocesssubprocess.Popen(r'explorer /select,"{}"'

.format(os.path.normpath(file_path)))

def open_url(url):"""Open url in a new tab in default webbrowser."""import webbrowserreturn webbrowser.open_new_tab(url)

def clipboard_copy(string_to_copy):"""Copy string to Windows Clipboard."""framework.Clipboard.SetText(string_to_copy)

def load_index(index_file='index.html'):"""Load html file into output window.

(continues on next page)

150 Chapter 15. pyrevit.script

Page 155: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

This method expects index.html file in the current command bundle,unless full path to an html file is provided.

Args:index_file (str, optional): full path of html file.

"""outputwindow = get_output()if not op.isfile(index_file):

index_file = get_bundle_file(index_file)outputwindow.open_page(index_file)

def get_envvar(envvar):"""Return value of give pyRevit environment variable.

The environment variable system is used to retain small values in memorybetween script runs (e.g. active/inactive state for toggle tools). Do notstore large objects in memory using this method. List of currently setenvironment variables could be sees in pyRevit settings window.

Args:envvar (str): name of environment variable

Returns:any: type of object stored in environment variable

Example:>>> script.get_envvar('ToolActiveState')True

"""return envvars.get_pyrevit_env_var(envvar)

def set_envvar(envvar, value):"""Set value of give pyRevit environment variable.

The environment variable system is used to retain small values in memorybetween script runs (e.g. active/inactive state for toggle tools). Do notstore large objects in memory using this method. List of currently setenvironment variables could be sees in pyRevit settings window.

Args:envvar (str): name of environment variablevalue (any): value of environment variable

Example:>>> script.set_envvar('ToolActiveState', False)>>> script.get_envvar('ToolActiveState')False

"""return envvars.set_pyrevit_env_var(envvar, value)

15.1. Implementation 151

Page 156: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

152 Chapter 15. pyrevit.script

Page 157: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 16

pyrevit.userconfig

Handle reading and parsing, writin and saving of all user configurations.

This module handles the reading and writing of the pyRevit configuration files. It’s been used extensively by pyRevitsub-modules. user_config is set up automatically in the global scope by this module and can be imported intoscripts and other modules to access the default configurations.

All other modules use this module to query user config.

Example

>>> from pyrevit.userconfig import user_config>>> user_config.add_section('newsection')>>> user_config.newsection.property = value>>> user_config.newsection.get('property', default_value)>>> user_config.save_changes()

The user_config object is also the destination for reading and writing configuration by pyRevit scripts throughget_config() of pyrevit.script module. Here is the function source:

def get_config(section=None):"""Create and return config section parser object for current script.

Args:section (str, optional): config section name

Returns::obj:`pyrevit.coreutils.configparser.PyRevitConfigSectionParser`:

Config section parser object"""from pyrevit.userconfig import user_configif not section:

script_cfg_postfix = 'config'section = EXEC_PARAMS.command_name + script_cfg_postfix

(continues on next page)

153

Page 158: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

try:return user_config.get_section(section)

except Exception:return user_config.add_section(section)

Example

>>> from pyrevit import script>>> cfg = script.get_config()>>> cfg.property = value>>> cfg.get('property', default_value)>>> script.save_config()

class pyrevit.userconfig.PyRevitConfig(cfg_file_path=None, config_type=’Unknown’)Provide read/write access to pyRevit configuration.

Parameters

• cfg_file_path (str) – full path to config file to be used.

• config_type (str) – type of config file

Example

>>> cfg = PyRevitConfig(cfg_file_path)>>> cfg.add_section('sectionname')>>> cfg.sectionname.property = value>>> cfg.sectionname.get('property', default_value)>>> cfg.save_changes()

config_fileCurrent config file path.

get_config_version()Return version of config file used for change detection.

get_ext_root_dirs()Return a list of all extension directories.

Returns list of strings. user extension directories.

Return type list

get_thirdparty_ext_root_dirs(include_default=True)Return a list of external extension directories set by the user.

Returns list of strings. External user extension directories.

Return type list

save_changes()Save user config into associated config file.

set_thirdparty_ext_root_dirs(path_list)Updates list of external extension directories in config file

154 Chapter 16. pyrevit.userconfig

Page 159: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters path_list (list[str]) – list of external extension paths

pyrevit.userconfig.find_config_file(target_path)Find config file in target path.

pyrevit.userconfig.verify_configs(config_file_path=None)Create a user settings file.

if config_file_path is not provided, configs will be in memory only

Parameters config_file_path (str, optional) – config file full name and path

Returns pyRevit config file handler

Return type pyrevit.userconfig.PyRevitConfig

16.1 Implementation

"""Handle reading and parsing, writin and saving of all user configurations.

This module handles the reading and writing of the pyRevit configuration files.It's been used extensively by pyRevit sub-modules. :obj:`user_config` isset up automatically in the global scope by this module and can be importedinto scripts and other modules to access the default configurations.

All other modules use this module to query user config.

Example:

>>> from pyrevit.userconfig import user_config>>> user_config.add_section('newsection')>>> user_config.newsection.property = value>>> user_config.newsection.get('property', default_value)>>> user_config.save_changes()

The :obj:`user_config` object is also the destination for reading and writingconfiguration by pyRevit scripts through :func:`get_config` of:mod:`pyrevit.script` module. Here is the function source:

.. literalinclude:: ../../pyrevitlib/pyrevit/script.py:pyobject: get_config

Example:

>>> from pyrevit import script>>> cfg = script.get_config()>>> cfg.property = value>>> cfg.get('property', default_value)>>> script.save_config()

"""#pylint: disable=C0103,C0413,W0703import osimport os.path as op

from pyrevit import EXEC_PARAMS, HOME_DIRfrom pyrevit import EXTENSIONS_DEFAULT_DIR, THIRDPARTY_EXTENSIONS_DEFAULT_DIRfrom pyrevit import PYREVIT_ALLUSER_APP_DIR, PYREVIT_APP_DIR

(continues on next page)

16.1. Implementation 155

Page 160: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

from pyrevit.labs import TargetApps

from pyrevit.coreutils import touchfrom pyrevit.coreutils import appdatafrom pyrevit.coreutils import configparserfrom pyrevit.coreutils import loggerfrom pyrevit.versionmgr import upgrade

mlogger = logger.get_logger(__name__)

# =============================================================================# fix obsolete config file naming# config file (and all appdata files) used to include username in the filename# this fixes the existing config file with obsolete naming, to new format# from pyrevit import PYREVIT_APP_DIR, PYREVIT_FILE_PREFIX_UNIVERSAL_USER

# OBSOLETE_CONFIG_FILENAME = '{}_{}'.format(PYREVIT_FILE_PREFIX_UNIVERSAL_USER,# 'config.ini')# OBSOLETE_CONFIG_FILEPATH = op.join(PYREVIT_APP_DIR, OBSOLETE_CONFIG_FILENAME)

# if op.exists(OBSOLETE_CONFIG_FILEPATH):# try:# os.rename(OBSOLETE_CONFIG_FILEPATH, CONFIG_FILE)# except Exception as rename_err:# mlogger.error('Failed to update the config file name to new format. '# 'A new configuration file has been created for you '# 'under \n{}'# '\nYour previous pyRevit configuration file still '# 'existing under the same folder. Please close Revit, '# 'open both configuration files and copy and paste '# 'settings from the old config file to new config file. '# 'Then you can remove the old config file as pyRevit '# 'will not be using that anymore. | {}'# .format(CONFIG_FILE, rename_err))# end fix obsolete config file naming# =============================================================================

class PyRevitConfig(configparser.PyRevitConfigParser):"""Provide read/write access to pyRevit configuration.

Args:cfg_file_path (str): full path to config file to be used.config_type (str): type of config file

Example:>>> cfg = PyRevitConfig(cfg_file_path)>>> cfg.add_section('sectionname')>>> cfg.sectionname.property = value>>> cfg.sectionname.get('property', default_value)>>> cfg.save_changes()

"""

def __init__(self, cfg_file_path=None, config_type='Unknown'):(continues on next page)

156 Chapter 16. pyrevit.userconfig

Page 161: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Load settings from provided config file and setup parser."""# try opening and reading config file in order.super(PyRevitConfig, self).__init__(cfg_file_path=cfg_file_path)

# set log mode on the logger module based on# user settings (overriding the defaults)self._update_env()self._admin = config_type == 'Admin'self.config_type = config_type

def _update_env(self):# update the debug level based on user configmlogger.reset_level()

try:# first check to see if command is not in forced debug modeif not EXEC_PARAMS.forced_debug_mode:

if self.core.debug:mlogger.set_debug_mode()mlogger.debug('Debug mode is enabled in user settings.')

elif self.core.verbose:mlogger.set_verbose_mode()

logger.set_file_logging(self.core.filelogging)except Exception as env_update_err:

mlogger.debug('Error updating env variable per user config. | %s',env_update_err)

@propertydef config_file(self):

"""Current config file path."""return self._cfg_file_path

def get_config_version(self):"""Return version of config file used for change detection."""return self.get_config_file_hash()

def get_ext_root_dirs(self):"""Return a list of all extension directories.

Returns::obj:`list`: list of strings. user extension directories.

"""dir_list = []dir_list.append(EXTENSIONS_DEFAULT_DIR)dir_list.extend(self.get_thirdparty_ext_root_dirs())return dir_list

def get_thirdparty_ext_root_dirs(self, include_default=True):"""Return a list of external extension directories set by the user.

Returns::obj:`list`: list of strings. External user extension directories.

"""dir_list = []if include_default:

(continues on next page)

16.1. Implementation 157

Page 162: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# add default ext pathdir_list.append(THIRDPARTY_EXTENSIONS_DEFAULT_DIR)

try:dir_list.extend([

op.expandvars(op.normpath(x.encode('string-escape')))for x in self.core.userextensions])

except Exception as read_err:mlogger.error('Error reading list of user extension folders. | %s',

read_err)

return dir_list

def set_thirdparty_ext_root_dirs(self, path_list):"""Updates list of external extension directories in config file

Args:path_list (list[str]): list of external extension paths

"""try:

self.core.userextensions = \[op.normpath(x) for x in path_list]

except Exception as write_err:mlogger.error('Error setting list of user extension folders. | %s',

write_err)

def save_changes(self):"""Save user config into associated config file."""if not self._admin:

try:super(PyRevitConfig, self).save()

except Exception as save_err:mlogger.error('Can not save user config to: %s | %s',

self.config_file, save_err)

# adjust environment per user configurationsself._update_env()

else:mlogger.debug('Config is in admin mode. Skipping save.')

def find_config_file(target_path):"""Find config file in target path."""return TargetApps.Revit.PyRevit.FindConfigFileInDirectory(target_path)

def verify_configs(config_file_path=None):"""Create a user settings file.

if config_file_path is not provided, configs will be in memory only

Args:config_file_path (str, optional): config file full name and path

Returns::obj:`pyrevit.userconfig.PyRevitConfig`: pyRevit config file handler

"""(continues on next page)

158 Chapter 16. pyrevit.userconfig

Page 163: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

if config_file_path:mlogger.debug('Creating default config file at: %s', config_file_path)touch(config_file_path)

try:parser = PyRevitConfig(cfg_file_path=config_file_path)

except Exception as read_err:# can not create default user config file under appdata foldermlogger.warning('Can not create config file under: %s | %s',

config_file_path, read_err)parser = PyRevitConfig()

# set hard-coded valuesconsts = TargetApps.Revit.PyRevitConsts# core sectionif not parser.has_section(consts.ConfigsCoreSection):

parser.add_section(consts.ConfigsCoreSection)# checkupatesif not parser.core.has_option(consts.ConfigsCheckUpdatesKey):

parser.core.set_option(consts.ConfigsCheckUpdatesKey, False)# autoupdateif not parser.core.has_option(consts.ConfigsAutoUpdateKey):

parser.core.set_option(consts.ConfigsAutoUpdateKey, False)# verboseif not parser.core.has_option(consts.ConfigsVerboseKey):

parser.core.set_option(consts.ConfigsVerboseKey, True)# debugif not parser.core.has_option(consts.ConfigsDebugKey):

parser.core.set_option(consts.ConfigsDebugKey, False)# fileloggingif not parser.core.has_option(consts.ConfigsFileLoggingKey):

parser.core.set_option(consts.ConfigsFileLoggingKey, False)# startuplogtimeoutif not parser.core.has_option(consts.ConfigsStartupLogTimeoutKey):

parser.core.set_option(consts.ConfigsStartupLogTimeoutKey, 10)# userextensionsif not parser.core.has_option(consts.ConfigsUserExtensionsKey):

parser.core.set_option(consts.ConfigsUserExtensionsKey, [])# compilecsharpif not parser.core.has_option(consts.ConfigsCompileCSharpKey):

parser.core.set_option(consts.ConfigsCompileCSharpKey, True)# compilevbif not parser.core.has_option(consts.ConfigsCompileVBKey):

parser.core.set_option(consts.ConfigsCompileVBKey, True)# loadbetaif not parser.core.has_option(consts.ConfigsLoadBetaKey):

parser.core.set_option(consts.ConfigsLoadBetaKey, False)# rocketmodeif not parser.core.has_option(consts.ConfigsRocketModeKey):

parser.core.set_option(consts.ConfigsRocketModeKey, True)# bincacheif not parser.core.has_option(consts.ConfigsBinaryCacheKey):

parser.core.set_option(consts.ConfigsBinaryCacheKey, True)# usercanupdateif not parser.core.has_option(consts.ConfigsUserCanUpdateKey):

parser.core.set_option(consts.ConfigsUserCanUpdateKey, True)# usercanextend

(continues on next page)

16.1. Implementation 159

Page 164: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

if not parser.core.has_option(consts.ConfigsUserCanExtendKey):parser.core.set_option(consts.ConfigsUserCanExtendKey, True)

# usercanconfigif not parser.core.has_option(consts.ConfigsUserCanConfigKey):

parser.core.set_option(consts.ConfigsUserCanConfigKey, True)

# usagelogging sectionif not parser.has_section(consts.ConfigsUsageLoggingSection):

parser.add_section(consts.ConfigsUsageLoggingSection)# usagelogging activeif not parser.usagelogging.has_option(consts.ConfigsUsageLoggingStatusKey):

parser.usagelogging.set_option(consts.ConfigsUsageLoggingStatusKey, False)

# usagelogging fileif not parser.usagelogging.has_option(consts.ConfigsUsageLogFilePathKey):

parser.usagelogging.set_option(consts.ConfigsUsageLogFilePathKey, "")# usagelogging serverif not parser.usagelogging.has_option(consts.ConfigsUsageLogServerUrlKey):

parser.usagelogging.set_option(consts.ConfigsUsageLogServerUrlKey, "")

# save config into config fileif config_file_path:

parser.save_changes()mlogger.debug('Default config saved to: %s', config_file_path)

return parser

LOCAL_CONFIG_FILE = ADMIN_CONFIG_FILE = USER_CONFIG_FILE = CONFIG_FILE = ''user_config = None

# location for default pyRevit config filesif not EXEC_PARAMS.doc_mode:

LOCAL_CONFIG_FILE = find_config_file(HOME_DIR)ADMIN_CONFIG_FILE = find_config_file(PYREVIT_ALLUSER_APP_DIR)USER_CONFIG_FILE = find_config_file(PYREVIT_APP_DIR)

# decide which config file to use# check if a config file is inside the repo. for developers config overrideif LOCAL_CONFIG_FILE:

CONFIG_TYPE = 'Local'CONFIG_FILE = LOCAL_CONFIG_FILE

# check to see if there is any config file provided by adminelif ADMIN_CONFIG_FILE:

# if yes, copy that and use as defaultif os.access(ADMIN_CONFIG_FILE, os.W_OK):

CONFIG_TYPE = 'Seed'TargetApps.Revit.PyRevit.SeedConfig(False, ADMIN_CONFIG_FILE)CONFIG_FILE = find_config_file(PYREVIT_APP_DIR)

# unless it's locked. then read that config file and set admin-modeelse:

CONFIG_TYPE = 'Admin'CONFIG_FILE = ADMIN_CONFIG_FILE

# if a config file is available for user use thatelif USER_CONFIG_FILE:

CONFIG_TYPE = 'User'(continues on next page)

160 Chapter 16. pyrevit.userconfig

Page 165: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

CONFIG_FILE = USER_CONFIG_FILE# if nothing can be found, make oneelse:

CONFIG_TYPE = 'New'# setup config file name and pathCONFIG_FILE = appdata.get_universal_data_file(file_id='config',

file_ext='ini')

mlogger.debug('Using %s config file: %s', CONFIG_TYPE, CONFIG_FILE)

# read config, or setup default config file if not available# this pushes reading settings at first import of this module.try:

verify_configs(CONFIG_FILE)user_config = PyRevitConfig(cfg_file_path=CONFIG_FILE,

config_type=CONFIG_TYPE)upgrade.upgrade_user_config(user_config)

except Exception as cfg_err:mlogger.debug('Can not read confing file at: %s | %s',

CONFIG_FILE, cfg_err)mlogger.debug('Using configs in memory...')user_config = verify_configs()

16.1. Implementation 161

Page 166: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

162 Chapter 16. pyrevit.userconfig

Page 167: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 17

pyrevit.coreutils

Misc Helper functions for pyRevit.

17.1 pyrevit.coreutils

Misc Helper functions for pyRevit.

Example

>>> from pyrevit import coreutils>>> coreutils.cleanup_string('some string')

class pyrevit.coreutils.FileWatcher(filepath)Simple file version watcher.

This is a simple utility class to look for changes in a file based on its timestamp.

Example

>>> watcher = FileWatcher('/path/to/file.ext')>>> watcher.has_changedTrue

has_changedCompare current file timestamp to the cached timestamp.

update_tstamp()Update the cached timestamp for later comparison.

163

Page 168: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

class pyrevit.coreutils.SafeDictDictionary that does not fail on any key.

This is a dictionary subclass to help with string formatting with unknown key values.

Example

>>> string = '{target} {attr} is {color}.'>>> safedict = SafeDict({'target': 'Apple',... 'attr': 'Color'})>>> string.format(safedict) # will not fail with missing 'color' key'Apple Color is {color}.'

class pyrevit.coreutils.ScriptFileParser(file_address)Parse python script to extract variables and docstrings.

Primarily designed to assist pyRevit in determining script configurations but can work for any python script.

Example

>>> finder = ScriptFileParser('/path/to/coreutils/__init__.py')>>> finder.docstring()... "Misc Helper functions for pyRevit.">>> finder.extract_param('SomeValue', [])[]

extract_param(param_name, default_value=None)Find variable and extract its value.

Parameters

• param_name (str) – variable name

• default_value (any) – default value to be returned if variable does not exist

Returns value of the variable or None

Return type any

get_docstring()Get global docstring.

class pyrevit.coreutils.TimerTimer class using python native time module.

Example

>>> timer = Timer()>>> timer.get_time()12

get_time()Get Elapsed Time.

restart()Restart Timer.

164 Chapter 17. pyrevit.coreutils

Page 169: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.coreutils.calculate_dir_hash(dir_path, dir_filter, file_filter)Create a unique hash to represent state of directory.

Parameters

• dir_path (str) – target directory

• dir_filter (str) – exclude directories matching this regex

• file_filter (str) – exclude files matching this regex

Returns hash value as string

Return type str

Example

>>> calculate_dir_hash(source_path, '\.extension', '\.json')"1a885a0cae99f53d6088b9f7cee3bf4d"

pyrevit.coreutils.can_access_url(url_to_open, timeout=1000)Check if url is accessible within timeout.

Parameters

• url_to_open (str) – url to check access for

• timeout (int) – timeout in milliseconds

Returns true if accessible

Return type bool

pyrevit.coreutils.check_internet_connection(timeout=1000)Check if internet connection is available.

Pings a few well-known websites to check if internet connection is present.

Parameters timeout (int) – timeout in milliseconds

Returns url if internet connection is present, None if no internet.

pyrevit.coreutils.check_revittxt_encoding(filename)Check if given file is in UTF-16 (UCS-2 LE) encoding.

Parameters filename (str) – file path

pyrevit.coreutils.check_utf8bom_encoding(filename)Check if given file is in UTF-8 encoding.

Parameters filename (str) – file path

pyrevit.coreutils.cleanup_filename(file_name)Cleanup file name from special characters.

Parameters file_name (str) – file name

Returns cleaned up file name

Return type str

17.1. pyrevit.coreutils 165

Page 170: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> cleanup_filename('Myfile-(3).txt')"Myfile3.txt"

pyrevit.coreutils.cleanup_string(input_str)Replace special characters in string with another string.

This function was created to help cleanup pyRevit command unique names from any special characters so C#class names can be created based on those unique names.

coreutils.SPECIAL_CHARS is the conversion table for this function.

Parameters input_str (str) – input string to be cleaned

Example

>>> src_str = 'TEST@Some*<value>'>>> cleanup_string(src_str)"TESTATSomeSTARvalue"

pyrevit.coreutils.correct_revittxt_encoding(filename)Convert encoding of text file generated by Revit to UTF-8.

Parameters filename (str) – file path

pyrevit.coreutils.create_ext_command_attrs()Create dotnet attributes for Revit extenrnal commads.

This method is used in creating custom dotnet types for pyRevit commands and compiling them into aDLL assembly. Current implementation sets RegenerationOption.Manual and TransactionMode.Manual

Returns list of CustomAttributeBuilder for RegenerationOption andTransactionMode attributes.

Return type list

pyrevit.coreutils.create_type(modulebuilder, type_class, class_name, custom_attr_list, *args)Create a dotnet type for a pyRevit command.

See baseclasses.cs code for the template pyRevit command dotnet type and its constructor default argu-ments that must be provided here.

Parameters

• modulebuilder (ModuleBuilder) – dotnet module builder

• type_class (type) – source dotnet type for the command

• class_name (str) – name for the new type

• custom_attr_list (list) – list of dotnet attributes for the type

• *args – list of arguments to be used with type constructor

Returns returns created dotnet type

Return type type

166 Chapter 17. pyrevit.coreutils

Page 171: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> asm_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(... win_asm_name, AssemblyBuilderAccess.RunAndSave, filepath... )>>> module_builder = asm_builder.DefineDynamicModule(... ext_asm_file_name, ext_asm_full_file_name... )>>> create_type(... module_builder,... PyRevitCommand,... "PyRevitSomeCommandUniqueName",... coreutils.create_ext_command_attrs(),... [scriptpath, atlscriptpath, searchpath, helpurl, name,... bundle, extension, uniquename, False, False])<type PyRevitSomeCommandUniqueName>

pyrevit.coreutils.current_date()Return formatted current date.

Current implementation uses %Y-%m-%d to format date.

Returns formatted current date.

Return type str

Example

>>> current_date()'2018-01-03'

pyrevit.coreutils.current_time()Return formatted current time.

Current implementation uses %H:%M:%S to format time.

Returns formatted current time.

Return type str

Example

>>> current_time()'07:50:53'

pyrevit.coreutils.decrement_str(input_str, step)Decrement identifier.

Parameters

• input_str (str) – identifier e.g. A310a

• step (int) – number of steps to change the identifier

Returns modified identifier

Return type str

17.1. pyrevit.coreutils 167

Page 172: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> decrement_str('A310a')'A309z'

pyrevit.coreutils.dletter_to_unc(dletter_path)Convert drive letter path into UNC path of that drive.

Parameters dletter_path (str) – drive letter path

Returns UNC path

Return type str

Example

>>> # assuming J: is mapped to //filestore/server/jdrive>>> dletter_to_unc('J:/somefile.txt')'//filestore/server/jdrive/somefile.txt'

pyrevit.coreutils.extract_guid(source_str)Extract GUID number from a string.

pyrevit.coreutils.extract_range(formatted_str, max_range=500)Extract range from formatted string.

String must be formatted as below A103 No range A103-A106 A103 to A106 A103:A106 A103 to A106A103,A105a A103 and A105a A103;A105a A103 and A105a

Parameters formatted_str (str) – string specifying range

Returns list of names in the specified range

Return type list

Example

>>> exract_range('A103:A106')['A103', 'A104', 'A105', 'A106']>>> exract_range('S203-S206')['S203', 'S204', 'S205', 'S206']>>> exract_range('M00A,M00B')['M00A', 'M00B']

pyrevit.coreutils.filter_null_items(src_list)Remove None items in the given list.

Parameters src_list (list) – list of any items

Returns cleaned list

Return type list

pyrevit.coreutils.find_loaded_asm(asm_info, by_partial_name=False, by_location=False)Find loaded assembly based on name, partial name, or location.

Parameters

• asm_info (str) – name or location of the assembly

168 Chapter 17. pyrevit.coreutils

Page 173: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

• by_partial_name (bool) – returns all assemblies that has the asm_info

• by_location (bool) – returns all assemblies matching location

Returns List of all loaded assemblies matching the provided info If only one assembly has beenfound, it returns the assembly. None will be returned if assembly is not loaded.

Return type list

pyrevit.coreutils.find_type_by_name(assembly, type_name)Find type by name in assembly.

Parameters

• assembly (Assembly) – assembly to find the type in

• type_name (str) – type name

Returns returns the type if found.

Raises PyRevitException if type not found.

pyrevit.coreutils.format_hex_rgb(rgb_value)Formats rgb value as #RGB value string.

pyrevit.coreutils.fully_remove_dir(dir_path)Remove directory recursively.

Parameters dir_path (str) – directory path

pyrevit.coreutils.fuzzy_search_ratio(target_string, sfilter)Match target string against the filter and return a match ratio.

pyrevit.coreutils.get_all_subclasses(parent_classes)Return all subclasses of a python class.

Parameters parent_classes (list) – list of python classes

Returns list of python subclasses

Return type list

pyrevit.coreutils.get_canonical_parts(canonical_string)Splots argument using dot, returning all composing parts.

Parameters canonical_string (str) – Source string e.g. “Config.SubConfig”

Returns list of composing parts

Return type list[str]

Example

>>> get_canonical_parts("Config.SubConfig")['Config', 'SubConfig']

pyrevit.coreutils.get_enum_none(enum_type)Returns the None value in given Enum.

pyrevit.coreutils.get_enum_value(enum_type, value_string)Return enum value matching given value string (case insensitive)

pyrevit.coreutils.get_enum_values(enum_type)Returns enum values.

17.1. pyrevit.coreutils 169

Page 174: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.coreutils.get_file_name(file_path)Return file basename of the given file.

Parameters file_path (str) – file path

pyrevit.coreutils.get_mapped_drives_dict()Return a dictionary of currently mapped network drives.

pyrevit.coreutils.get_revit_instance_count()Return number of open host app instances.

Returns number of open host app instances.

Return type int

pyrevit.coreutils.get_str_hash(source_str)Calculate hash value of given string.

Current implementation uses hashlib.md5() hash function.

Parameters source_str (str) – source str

Returns hash value as string

Return type str

pyrevit.coreutils.get_sub_folders(search_folder)Get a list of all subfolders directly inside provided folder.

Parameters search_folder (str) – folder path

Returns list of subfolder names

Return type list

pyrevit.coreutils.has_nonprintable(input_str)Check input string for non-printable characters.

Parameters input_str (str) – input string

Returns True if contains non-printable characters

Return type bool

pyrevit.coreutils.increment_str(input_str, step)Incremenet identifier.

Parameters

• input_str (str) – identifier e.g. A310a

• step (int) – number of steps to change the identifier

Returns modified identifier

Return type str

Example

>>> increment_str('A319z')'A320a'

pyrevit.coreutils.inspect_calling_scope_global_var(variable_name)Trace back the stack to find the variable in the caller global stack.

170 Chapter 17. pyrevit.coreutils

Page 175: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters variable_name (str) – variable name to look up in caller global scope

pyrevit.coreutils.inspect_calling_scope_local_var(variable_name)Trace back the stack to find the variable in the caller local stack.

PyRevitLoader defines __revit__ in builtins and __window__ in locals. Thus, modules have access to __revit__but not to __window__. This function is used to find __window__ in the caller stack.

Parameters variable_name (str) – variable name to look up in caller local scope

pyrevit.coreutils.is_blank(input_string)Check if input string is blank (multiple white spaces is blank).

Parameters input_string (str) – input string

Returns True if string is blank

Return type bool

Example

>>> is_blank(' ')True

pyrevit.coreutils.is_box_visible_on_screens(left, top, width, height)Check if given box is visible on any screen.

pyrevit.coreutils.is_url_valid(url_string)Check if given URL is in valid format.

Parameters url_string (str) – URL string

Returns True if URL is in valid format

Return type bool

Example

>>> is_url_valid('https://www.google.com')True

pyrevit.coreutils.join_strings(str_list, separator=’;’)Join strings using provided separator.

Parameters

• str_list (list) – list of string values

• separator (str) – single separator character, defaults to DEFAULT_SEPARATOR

Returns joined string

Return type str

pyrevit.coreutils.load_asm(asm_name)Load assembly by name into current domain.

Parameters asm_name (str) – assembly name

Returns returns the loaded assembly, None if not loaded.

17.1. pyrevit.coreutils 171

Page 176: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.coreutils.load_asm_file(asm_file)Load assembly by file into current domain.

Parameters asm_file (str) – assembly file path

Returns returns the loaded assembly, None if not loaded.

pyrevit.coreutils.make_canonical_name(*args)Join arguments with dot creating a unique id.

Parameters *args – Variable length argument list of type str

Returns dot separated unique name

Return type str

Example

>>> make_canonical_name('somename', 'someid', 'txt')"somename.someid.txt"

pyrevit.coreutils.new_uuid()Create a new UUID (using dotnet Guid.NewGuid)

pyrevit.coreutils.open_folder_in_explorer(folder_path)Open given folder in Windows Explorer.

Parameters folder_path (str) – directory path

pyrevit.coreutils.prepare_html_str(input_string)Reformat html string and prepare for pyRevit output window.

pyRevit output window renders html content. But this means that < and > characters in outputs from python(e.g. <class at xxx>) will be treated as html tags. To avoid this, all <> characters that are defining html contentneed to be replaced with special phrases. pyRevit output later translates these phrases back in to < and >. Thatis how pyRevit ditinquishes between <> printed from python and <> that define html.

Parameters input_string (str) – input html string

Example

>>> prepare_html_str('<p>Some text</p>')"&clt;p&cgt;Some text&clt;/p&cgt;"

pyrevit.coreutils.random_alpha()Return a random alpha value (between 0 and 1.00).

pyrevit.coreutils.random_color()Return a random color channel value (between 0 and 255).

pyrevit.coreutils.random_hex_color()Return a random color in hex format.

Example

>>> random_hex_color()'#FF0000'

172 Chapter 17. pyrevit.coreutils

Page 177: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.coreutils.random_rgb_color()Return a random color in rgb format.

Example

>>> random_rgb_color()'rgb(255, 0, 0)'

pyrevit.coreutils.random_rgba_color()Return a random color in rgba format.

Example

>>> random_rgba_color()'rgba(255, 0, 0, 0.5)'

pyrevit.coreutils.read_source_file(source_file_path)Read text file and return contents.

Parameters source_file_path (str) – target file path

Returns file contents

Return type str

Raises PyRevitException on read error

pyrevit.coreutils.reformat_string(orig_str, orig_format, new_format)Reformat a string into a new format.

Extracts information from a string based on a given pattern, and recreates a new string based on the given newpattern.

Parameters

• orig_str (str) – Original string to be reformatted

• orig_format (str) – Pattern of the original str (data to be extracted)

• new_format (str) – New pattern (how to recompose the data)

Returns Reformatted string

Return type str

Example

>>> reformat_string('150 - FLOOR/CEILING - WD - 1 HR - FLOOR ASSEMBLY','{section} - {loc} - {mat} - {rating} - {name}','{section}:{mat}:{rating} - {name} ({loc})'))

'150:WD:1 HR - FLOOR ASSEMBLY (FLOOR/CEILING)'

pyrevit.coreutils.reverse_dict(input_dict)Reverse the key, value pairs.

Parameters input_dict (dict) – source ordered dict

Returns reversed dictionary

17.1. pyrevit.coreutils 173

Page 178: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Return type defaultdict

Example

>>> reverse_dict({1: 2, 3: 4})defaultdict(<type 'list'>, {2: [1], 4: [3]})

pyrevit.coreutils.reverse_html(input_html)Reformat codified pyRevit output html string back to normal html.

pyRevit output window renders html content. But this means that < and > characters in outputs from python(e.g. <class at xxx>) will be treated as html tags. To avoid this, all <> characters that are defining html contentneed to be replaced with special phrases. pyRevit output later translates these phrases back in to < and >. Thatis how pyRevit ditinquishes between <> printed from python and <> that define html.

Parameters input_html (str) – input codified html string

Example

>>> prepare_html_str('&clt;p&cgt;Some text&clt;/p&cgt;')"<p>Some text</p>"

pyrevit.coreutils.run_process(proc, cwd=”)Run shell process silently.

Parameters

• proc (str) – process executive name

• cwd (str) – current working directory

Exmaple:

>>> run_process('notepad.exe', 'c:/')

pyrevit.coreutils.show_entry_in_explorer(entry_path)Show given entry in Windows Explorer.

Parameters entry_path (str) – directory or file path

pyrevit.coreutils.timestamp()Return timestamp for current time.

Returns timestamp in string format

Return type str

Example

>>> timestamp()'01003075032506808'

pyrevit.coreutils.touch(fname, times=None)Update the timestamp on the given file.

174 Chapter 17. pyrevit.coreutils

Page 179: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters

• fname (str) – target file path

• times (int) – number of times to touch the file

pyrevit.coreutils.unc_to_dletter(unc_path)Convert UNC path into drive letter path.

Parameters unc_path (str) – UNC path

Returns drive letter path

Return type str

Example

>>> # assuming J: is mapped to //filestore/server/jdrive>>> unc_to_dletter('//filestore/server/jdrive/somefile.txt')'J:/somefile.txt'

pyrevit.coreutils.verify_directory(folder)Check if the folder exists and if not create the folder.

Parameters folder (str) – path of folder to verify

Returns path of verified folder, equals to provided folder

Return type str

Raises OSError on folder creation error.

17.1.1 Implementation

"""Misc Helper functions for pyRevit.

Example:>>> from pyrevit import coreutils>>> coreutils.cleanup_string('some string')

"""

import osimport os.path as opimport reimport astimport hashlibimport timeimport datetimeimport shutilimport randomimport statimport codecsimport mathfrom collections import defaultdict

#pylint: disable=E0401from pyrevit import HOST_APP, PyRevitExceptionfrom pyrevit.compat import safe_strtype

(continues on next page)

17.1. pyrevit.coreutils 175

Page 180: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

from pyrevit import frameworkfrom pyrevit import api

# RE: https://github.com/eirannejad/pyRevit/issues/413# import uuidfrom System import Guid

#pylint: disable=W0703,C0302DEFAULT_SEPARATOR = ';'

# extracted from# https://www.fileformat.info/info/unicode/block/general_punctuation/images.htmUNICODE_NONPRINTABLE_CHARS = [

u'\u2000', u'\u2001', u'\u2002', u'\u2003', u'\u2004', u'\u2005', u'\u2006',u'\u2007', u'\u2008', u'\u2009', u'\u200A', u'\u200B', u'\u200C', u'\u200D',u'\u200E', u'\u200F',u'\u2028', u'\u2029', u'\u202A', u'\u202B', u'\u202C', u'\u202D', u'\u202E',u'\u202F',u'\u205F', u'\u2060',u'\u2066', u'\u2067', u'\u2068', u'\u2069', u'\u206A', u'\u206B', u'\u206C'u'\u206D', u'\u206E', u'\u206F']

class Timer:"""Timer class using python native time module.

Example:>>> timer = Timer()>>> timer.get_time()12

"""

def __init__(self):"""Initialize and Start Timer."""self.start = time.time()

def restart(self):"""Restart Timer."""self.start = time.time()

def get_time(self):"""Get Elapsed Time."""return time.time() - self.start

class ScriptFileParser:"""Parse python script to extract variables and docstrings.

Primarily designed to assist pyRevit in determining script configurationsbut can work for any python script.

Example:>>> finder = ScriptFileParser('/path/to/coreutils/__init__.py')>>> finder.docstring()

(continues on next page)

176 Chapter 17. pyrevit.coreutils

Page 181: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

... "Misc Helper functions for pyRevit.">>> finder.extract_param('SomeValue', [])[]

"""

def __init__(self, file_address):"""Initialize and read provided python script.

Args:file_address (str): python script file path

"""self.file_addr = file_addresswith open(file_address, 'r') as source_file:

self.ast_tree = ast.parse(source_file.read())

def get_docstring(self):"""Get global docstring."""doc_str = ast.get_docstring(self.ast_tree)if doc_str:

return doc_str.decode('utf-8')return None

def extract_param(self, param_name, default_value=None):"""Find variable and extract its value.

Args:param_name (str): variable namedefault_value (any):

default value to be returned if variable does not exist

Returns:any: value of the variable or :obj:`None`

"""try:

for child in ast.iter_child_nodes(self.ast_tree):if hasattr(child, 'targets'):

for target in child.targets:if hasattr(target, 'id') and target.id == param_name:

param_value = ast.literal_eval(child.value)if isinstance(param_value, str):

param_value = param_value.decode('utf-8')return param_value

except Exception as err:raise PyRevitException('Error parsing parameter: {} '

'in script file for : {} | {}'.format(param_name, self.file_addr, err))

return default_value

class FileWatcher(object):"""Simple file version watcher.

This is a simple utility class to look for changes in a file based onits timestamp.

Example:(continues on next page)

17.1. pyrevit.coreutils 177

Page 182: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

>>> watcher = FileWatcher('/path/to/file.ext')>>> watcher.has_changedTrue

"""

def __init__(self, filepath):"""Initialize and read timestamp of provided file.

Args:filepath (str): file path

"""self._cached_stamp = 0self._filepath = filepathself.update_tstamp()

def update_tstamp(self):"""Update the cached timestamp for later comparison."""self._cached_stamp = os.stat(self._filepath).st_mtime

@propertydef has_changed(self):

"""Compare current file timestamp to the cached timestamp."""return os.stat(self._filepath).st_mtime != self._cached_stamp

class SafeDict(dict):"""Dictionary that does not fail on any key.

This is a dictionary subclass to help with string formatting with unknownkey values.

Example:>>> string = '{target} {attr} is {color}.'>>> safedict = SafeDict({'target': 'Apple',... 'attr': 'Color'})>>> string.format(safedict) # will not fail with missing 'color' key'Apple Color is {color}.'

"""

def __missing__(self, key):return '{' + key + '}'

def get_all_subclasses(parent_classes):"""Return all subclasses of a python class.

Args:parent_classes (list): list of python classes

Returns:list: list of python subclasses

"""sub_classes = []# if super-class, get a list of sub-classes.# Otherwise use component_class to create objects.for parent_class in parent_classes:

try:(continues on next page)

178 Chapter 17. pyrevit.coreutils

Page 183: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

derived_classes = parent_class.__subclasses__()if not derived_classes:

sub_classes.append(parent_class)else:

sub_classes.extend(derived_classes)except AttributeError:

sub_classes.append(parent_class)return sub_classes

def get_sub_folders(search_folder):"""Get a list of all subfolders directly inside provided folder.

Args:search_folder (str): folder path

Returns:list: list of subfolder names

"""sub_folders = []for sub_folder in os.listdir(search_folder):

if op.isdir(op.join(search_folder, sub_folder)):sub_folders.append(sub_folder)

return sub_folders

def verify_directory(folder):"""Check if the folder exists and if not create the folder.

Args:folder (str): path of folder to verify

Returns:str: path of verified folder, equals to provided folder

Raises:OSError on folder creation error.

"""if not op.exists(folder):

try:os.makedirs(folder)

except OSError as err:raise err

return folder

def join_strings(str_list, separator=DEFAULT_SEPARATOR):"""Join strings using provided separator.

Args:str_list (list): list of string valuesseparator (str): single separator character,

defaults to DEFAULT_SEPARATOR

Returns:str: joined string

"""(continues on next page)

17.1. pyrevit.coreutils 179

Page 184: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

if str_list:return separator.join(str_list)

return ''

# character replacement list for cleaning up file namesSPECIAL_CHARS = {' ': '',

'~': '','!': 'EXCLAM','@': 'AT','#': 'SHARP','$': 'DOLLAR','%': 'PERCENT','^': '','&': 'AND','*': 'STAR','+': 'PLUS',';': '', ':': '', ',': '', '\"': '','{': '', '}': '', '[': '', ']': '', r'\(': '', r'\)': '','-': 'MINUS','=': 'EQUALS','<': '', '>': '','?': 'QMARK','.': 'DOT','_': 'UNDERS','|': 'VERT',r'\/': '', '\\': ''}

def cleanup_string(input_str):"""Replace special characters in string with another string.

This function was created to help cleanup pyRevit command unique names fromany special characters so C# class names can be created based on thoseunique names.

``coreutils.SPECIAL_CHARS`` is the conversion table for this function.

Args:input_str (str): input string to be cleaned

Example:>>> src_str = 'TEST@Some*<value>'>>> cleanup_string(src_str)"TESTATSomeSTARvalue"

"""# remove spaces and special characters from stringsfor char, repl in SPECIAL_CHARS.items():

input_str = input_str.replace(char, repl)

return input_str

def get_revit_instance_count():"""Return number of open host app instances.

Returns:(continues on next page)

180 Chapter 17. pyrevit.coreutils

Page 185: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

int: number of open host app instances."""return len(list(framework.Process.GetProcessesByName(HOST_APP.proc_name)))

def run_process(proc, cwd=''):"""Run shell process silently.

Args:proc (str): process executive namecwd (str): current working directory

Exmaple:>>> run_process('notepad.exe', 'c:/')

"""import subprocessreturn subprocess.Popen(proc,

stdout=subprocess.PIPE, stderr=subprocess.PIPE,cwd=cwd, shell=True)

def inspect_calling_scope_local_var(variable_name):"""Trace back the stack to find the variable in the caller local stack.

PyRevitLoader defines __revit__ in builtins and __window__ in locals.Thus, modules have access to __revit__ but not to __window__.This function is used to find __window__ in the caller stack.

Args:variable_name (str): variable name to look up in caller local scope

"""import inspect

frame = inspect.stack()[1][0]while variable_name not in frame.f_locals:

frame = frame.f_backif frame is None:

return Nonereturn frame.f_locals[variable_name]

def inspect_calling_scope_global_var(variable_name):"""Trace back the stack to find the variable in the caller global stack.

Args:variable_name (str): variable name to look up in caller global scope

"""import inspect

frame = inspect.stack()[1][0]while variable_name not in frame.f_globals:

frame = frame.f_backif frame is None:

return Nonereturn frame.f_locals[variable_name]

(continues on next page)

17.1. pyrevit.coreutils 181

Page 186: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def find_loaded_asm(asm_info, by_partial_name=False, by_location=False):"""Find loaded assembly based on name, partial name, or location.

Args:asm_info (str): name or location of the assemblyby_partial_name (bool): returns all assemblies that has the asm_infoby_location (bool): returns all assemblies matching location

Returns:list: List of all loaded assemblies matching the provided infoIf only one assembly has been found, it returns the assembly.:obj:`None` will be returned if assembly is not loaded.

"""loaded_asm_list = []for loaded_assembly in framework.AppDomain.CurrentDomain.GetAssemblies():

if by_partial_name:if asm_info.lower() in \

safe_strtype(loaded_assembly.GetName().Name).lower():loaded_asm_list.append(loaded_assembly)

elif by_location:try:

if op.normpath(loaded_assembly.Location) == \op.normpath(asm_info):

loaded_asm_list.append(loaded_assembly)except Exception:

continueelif asm_info.lower() == \

safe_strtype(loaded_assembly.GetName().Name).lower():loaded_asm_list.append(loaded_assembly)

return loaded_asm_list

def load_asm(asm_name):"""Load assembly by name into current domain.

Args:asm_name (str): assembly name

Returns:returns the loaded assembly, None if not loaded.

"""return framework.AppDomain.CurrentDomain.Load(asm_name)

def load_asm_file(asm_file):"""Load assembly by file into current domain.

Args:asm_file (str): assembly file path

Returns:returns the loaded assembly, None if not loaded.

"""try:

return framework.Assembly.LoadFrom(asm_file)except Exception:

(continues on next page)

182 Chapter 17. pyrevit.coreutils

Page 187: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

return None

def find_type_by_name(assembly, type_name):"""Find type by name in assembly.

Args:assembly (:obj:`Assembly`): assembly to find the type intype_name (str): type name

Returns:returns the type if found.

Raises::obj:`PyRevitException` if type not found.

"""base_class = assembly.GetType(type_name)if base_class is not None:

return base_classelse:

raise PyRevitException('Can not find base class type: {}'.format(type_name))

def make_canonical_name(*args):"""Join arguments with dot creating a unique id.

Args:

*args: Variable length argument list of type :obj:`str`

Returns:str: dot separated unique name

Example:>>> make_canonical_name('somename', 'someid', 'txt')"somename.someid.txt"

"""return '.'.join(args)

def get_canonical_parts(canonical_string):"""Splots argument using dot, returning all composing parts.

Args:canonical_string(:obj:`str`): Source string e.g. "Config.SubConfig"

Returns:list[:obj:`str`]: list of composing parts

Example:>>> get_canonical_parts("Config.SubConfig")['Config', 'SubConfig']

"""return canonical_string.split('.')

def get_file_name(file_path):(continues on next page)

17.1. pyrevit.coreutils 183

Page 188: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Return file basename of the given file.

Args:file_path (str): file path

"""return op.splitext(op.basename(file_path))[0]

def get_str_hash(source_str):"""Calculate hash value of given string.

Current implementation uses :func:`hashlib.md5` hash function.

Args:source_str (str): source str

Returns:str: hash value as string

"""return hashlib.md5(source_str.encode('utf-8', 'ignore')).hexdigest()

def calculate_dir_hash(dir_path, dir_filter, file_filter):r"""Create a unique hash to represent state of directory.

Args:dir_path (str): target directorydir_filter (str): exclude directories matching this regexfile_filter (str): exclude files matching this regex

Returns:str: hash value as string

Example:>>> calculate_dir_hash(source_path, '\.extension', '\.json')"1a885a0cae99f53d6088b9f7cee3bf4d"

"""mtime_sum = 0for root, dirs, files in os.walk(dir_path): #pylint: disable=W0612

if re.search(dir_filter, op.basename(root), flags=re.IGNORECASE):mtime_sum += op.getmtime(root)for filename in files:

if re.search(file_filter, filename, flags=re.IGNORECASE):modtime = op.getmtime(op.join(root, filename))mtime_sum += modtime

return get_str_hash(safe_strtype(mtime_sum))

def prepare_html_str(input_string):"""Reformat html string and prepare for pyRevit output window.

pyRevit output window renders html content. But this means that < and >characters in outputs from python (e.g. <class at xxx>) will be treatedas html tags. To avoid this, all <> characters that are defininghtml content need to be replaced with special phrases. pyRevit outputlater translates these phrases back in to < and >. That is how pyRevitditinquishes between <> printed from python and <> that define html.

(continues on next page)

184 Chapter 17. pyrevit.coreutils

Page 189: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Args:input_string (str): input html string

Example:>>> prepare_html_str('<p>Some text</p>')"&clt;p&cgt;Some text&clt;/p&cgt;"

"""return input_string.replace('<', '&clt;').replace('>', '&cgt;')

def reverse_html(input_html):"""Reformat codified pyRevit output html string back to normal html.

pyRevit output window renders html content. But this means that < and >characters in outputs from python (e.g. <class at xxx>) will be treatedas html tags. To avoid this, all <> characters that are defininghtml content need to be replaced with special phrases. pyRevit outputlater translates these phrases back in to < and >. That is how pyRevitditinquishes between <> printed from python and <> that define html.

Args:input_html (str): input codified html string

Example:>>> prepare_html_str('&clt;p&cgt;Some text&clt;/p&cgt;')"<p>Some text</p>"

"""return input_html.replace('&clt;', '<').replace('&cgt;', '>')

# def check_internet_connection():# client = framework.WebClient()# try:# client.OpenRead("http://www.google.com")# return True# except:# return False#

# def check_internet_connection():# import urllib2## def internet_on():# try:# urllib2.urlopen('http://216.58.192.142', timeout=1)# return True# except urllib2.URLError as err:# return False

def can_access_url(url_to_open, timeout=1000):"""Check if url is accessible within timeout.

Args:url_to_open (str): url to check access for

(continues on next page)

17.1. pyrevit.coreutils 185

Page 190: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

timeout (int): timeout in milliseconds

Returns:bool: true if accessible

"""try:

client = framework.WebRequest.Create(url_to_open)client.Method = "HEAD"client.Timeout = timeoutclient.Proxy = framework.WebProxy.GetDefaultProxy()response = client.GetResponse()response.GetResponseStream()return True

except Exception:return False

def check_internet_connection(timeout=1000):"""Check if internet connection is available.

Pings a few well-known websites to check if internet connection is present.

Args:timeout (int): timeout in milliseconds

Returns:url if internet connection is present, None if no internet.

"""solid_urls = ["http://google.com/",

"http://github.com/","http://bitbucket.com/","http://airtable.com/","http://todoist.com/","http://stackoverflow.com/","http://twitter.com/","http://youtube.com/"]

random.shuffle(solid_urls)for url in solid_urls:

if can_access_url(url, timeout):return url

return None

def touch(fname, times=None):"""Update the timestamp on the given file.

Args:fname (str): target file pathtimes (int): number of times to touch the file

"""with open(fname, 'a'):

os.utime(fname, times)

def read_source_file(source_file_path):"""Read text file and return contents.

(continues on next page)

186 Chapter 17. pyrevit.coreutils

Page 191: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Args:source_file_path (str): target file path

Returns:str: file contents

Raises::obj:`PyRevitException` on read error

"""try:

with open(source_file_path, 'r') as code_file:return code_file.read()

except Exception as read_err:raise PyRevitException('Error reading source file: {} | {}'

.format(source_file_path, read_err))

def create_ext_command_attrs():"""Create dotnet attributes for Revit extenrnal commads.

This method is used in creating custom dotnet types for pyRevit commandsand compiling them into a DLL assembly. Current implementation sets``RegenerationOption.Manual`` and ``TransactionMode.Manual``

Returns:list: list of :obj:`CustomAttributeBuilder` for:obj:`RegenerationOption` and :obj:`TransactionMode` attributes.

"""regen_const_info = \

framework.clr.GetClrType(api.Attributes.RegenerationAttribute) \.GetConstructor(

framework.Array[framework.Type]((api.Attributes.RegenerationOption,)))

regen_attr_builder = \framework.CustomAttributeBuilder(

regen_const_info,framework.Array[object](

(api.Attributes.RegenerationOption.Manual,)))

# add TransactionAttribute to framework.Typetrans_constructor_info = \

framework.clr.GetClrType(api.Attributes.TransactionAttribute) \.GetConstructor(

framework.Array[framework.Type]((api.Attributes.TransactionMode,))

)

trans_attrib_builder = \framework.CustomAttributeBuilder(

trans_constructor_info,framework.Array[object](

(api.Attributes.TransactionMode.Manual,)(continues on next page)

17.1. pyrevit.coreutils 187

Page 192: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

))

return [regen_attr_builder, trans_attrib_builder]

def create_type(modulebuilder,type_class, class_name, custom_attr_list, *args):

"""Create a dotnet type for a pyRevit command.

See ``baseclasses.cs`` code for the template pyRevit command dotnet typeand its constructor default arguments that must be provided here.

Args:modulebuilder (:obj:`ModuleBuilder`): dotnet module buildertype_class (type): source dotnet type for the commandclass_name (str): name for the new typecustom_attr_list (:obj:`list`): list of dotnet attributes for the type

*args: list of arguments to be used with type constructor

Returns:type: returns created dotnet type

Example:>>> asm_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(... win_asm_name, AssemblyBuilderAccess.RunAndSave, filepath... )>>> module_builder = asm_builder.DefineDynamicModule(... ext_asm_file_name, ext_asm_full_file_name... )>>> create_type(... module_builder,... PyRevitCommand,... "PyRevitSomeCommandUniqueName",... coreutils.create_ext_command_attrs(),... [scriptpath, atlscriptpath, searchpath, helpurl, name,... bundle, extension, uniquename, False, False])<type PyRevitSomeCommandUniqueName>

"""# create type buildertype_builder = \

modulebuilder.DefineType(class_name,framework.TypeAttributes.Class | framework.TypeAttributes.Public,type_class)

for custom_attr in custom_attr_list:type_builder.SetCustomAttribute(custom_attr)

# prepare a list of input param types to find the matching constructortype_list = []param_list = []for param in args:

if isinstance(param, str) \or isinstance(param, int):

type_list.append(type(param))(continues on next page)

188 Chapter 17. pyrevit.coreutils

Page 193: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

param_list.append(param)

# call base constructorconstructor = \

type_class.GetConstructor(framework.Array[framework.Type](type_list))# create class constructor builderconst_builder = \

type_builder.DefineConstructor(framework.MethodAttributes.Public,framework.CallingConventions.Standard,framework.Array[framework.Type](()))

# add constructor parameters to stackgen = const_builder.GetILGenerator()gen.Emit(framework.OpCodes.Ldarg_0) # Load "this" onto eval stack

# add constructor input params to the stackfor param_type, param in zip(type_list, param_list):

if param_type == str:gen.Emit(framework.OpCodes.Ldstr, param)

elif param_type == int:gen.Emit(framework.OpCodes.Ldc_I4, param)

# call base constructor (consumes "this" and the created stack)gen.Emit(framework.OpCodes.Call, constructor)# Fill some space - this is how it is generated for equivalent C# codegen.Emit(framework.OpCodes.Nop)gen.Emit(framework.OpCodes.Nop)gen.Emit(framework.OpCodes.Nop)gen.Emit(framework.OpCodes.Ret)return type_builder.CreateType()

def open_folder_in_explorer(folder_path):"""Open given folder in Windows Explorer.

Args:folder_path (str): directory path

"""import subprocesssubprocess.Popen(r'explorer /open,"{}"'

.format(os.path.normpath(folder_path)))

def show_entry_in_explorer(entry_path):"""Show given entry in Windows Explorer.

Args:entry_path (str): directory or file path

"""import subprocesssubprocess.Popen(r'explorer /select,"{}"'

.format(os.path.normpath(entry_path)))

def fully_remove_dir(dir_path):"""Remove directory recursively.

Args:(continues on next page)

17.1. pyrevit.coreutils 189

Page 194: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

dir_path (str): directory path"""def del_rw(action, name, exc): #pylint: disable=W0613

os.chmod(name, stat.S_IWRITE)os.remove(name)

shutil.rmtree(dir_path, onerror=del_rw)

def cleanup_filename(file_name):"""Cleanup file name from special characters.

Args:file_name (str): file name

Returns:str: cleaned up file name

Example:>>> cleanup_filename('Myfile-(3).txt')"Myfile3.txt"

"""return re.sub(r'[^\w_.)( -]', '', file_name)

def _inc_or_dec_string(str_id, shift):"""Increment or decrement identifier.

Args:str_id (str): identifier e.g. A310ashift (int): number of steps to change the identifier

Returns:str: modified identifier

Example:>>> _inc_or_dec_string('A319z')'A320a'

"""next_str = ""index = len(str_id) - 1carry = shift

while index >= 0:if str_id[index].isalpha():

if str_id[index].islower():reset_a = 'a'reset_z = 'z'

else:reset_a = 'A'reset_z = 'Z'

curr_digit = (ord(str_id[index]) + carry)if curr_digit < ord(reset_a):

curr_digit = ord(reset_z) - ((ord(reset_a) - curr_digit) - 1)carry = shift

elif curr_digit > ord(reset_z):(continues on next page)

190 Chapter 17. pyrevit.coreutils

Page 195: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

curr_digit = ord(reset_a) + ((curr_digit - ord(reset_z)) - 1)carry = shift

else:carry = 0

curr_digit = chr(curr_digit)next_str += curr_digit

elif str_id[index].isdigit():

curr_digit = int(str_id[index]) + carryif curr_digit > 9:

curr_digit = 0 + ((curr_digit - 9)-1)carry = shift

elif curr_digit < 0:curr_digit = 9 - ((0 - curr_digit)-1)carry = shift

else:carry = 0

next_str += safe_strtype(curr_digit)

else:next_str += str_id[index]

index -= 1

return next_str[::-1]

def increment_str(input_str, step):"""Incremenet identifier.

Args:input_str (str): identifier e.g. A310astep (int): number of steps to change the identifier

Returns:str: modified identifier

Example:>>> increment_str('A319z')'A320a'

"""return _inc_or_dec_string(input_str, abs(step))

def decrement_str(input_str, step):"""Decrement identifier.

Args:input_str (str): identifier e.g. A310astep (int): number of steps to change the identifier

Returns:str: modified identifier

Example:(continues on next page)

17.1. pyrevit.coreutils 191

Page 196: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

>>> decrement_str('A310a')'A309z'

"""return _inc_or_dec_string(input_str, -abs(step))

def filter_null_items(src_list):"""Remove None items in the given list.

Args:src_list (:obj:`list`): list of any items

Returns::obj:`list`: cleaned list

"""return list(filter(bool, src_list))

def reverse_dict(input_dict):"""Reverse the key, value pairs.

Args:input_dict (:obj:`dict`): source ordered dict

Returns::obj:`defaultdict`: reversed dictionary

Example:>>> reverse_dict({1: 2, 3: 4})defaultdict(<type 'list'>, {2: [1], 4: [3]})

"""output_dict = defaultdict(list)for key, value in input_dict.items():

output_dict[value].append(key)return output_dict

def timestamp():"""Return timestamp for current time.

Returns:str: timestamp in string format

Example:>>> timestamp()'01003075032506808'

"""return datetime.datetime.now().strftime("%m%j%H%M%S%f")

def current_time():"""Return formatted current time.

Current implementation uses %H:%M:%S to format time.

Returns:str: formatted current time.

(continues on next page)

192 Chapter 17. pyrevit.coreutils

Page 197: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Example:>>> current_time()'07:50:53'

"""return datetime.datetime.now().strftime("%H:%M:%S")

def current_date():"""Return formatted current date.

Current implementation uses %Y-%m-%d to format date.

Returns:str: formatted current date.

Example:>>> current_date()'2018-01-03'

"""return datetime.datetime.now().strftime("%Y-%m-%d")

def is_blank(input_string):"""Check if input string is blank (multiple white spaces is blank).

Args:input_string (str): input string

Returns:bool: True if string is blank

Example:>>> is_blank(' ')True

"""if input_string and input_string.strip():

return Falsereturn True

def is_url_valid(url_string):"""Check if given URL is in valid format.

Args:url_string (str): URL string

Returns:bool: True if URL is in valid format

Example:>>> is_url_valid('https://www.google.com')True

"""regex = re.compile(

r'^(?:http|ftp)s?://' # http:// or https://r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+'

(continues on next page)

17.1. pyrevit.coreutils 193

Page 198: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...r'localhost|' # localhost...r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ipr'(?::\d+)?' # optional portr'(?:/?|[/?]\S+)$', re.IGNORECASE)

return regex.match(url_string)

def reformat_string(orig_str, orig_format, new_format):"""Reformat a string into a new format.

Extracts information from a string based on a given pattern,and recreates a new string based on the given new pattern.

Args:orig_str (str): Original string to be reformattedorig_format (str): Pattern of the original str (data to be extracted)new_format (str): New pattern (how to recompose the data)

Returns:str: Reformatted string

Example:>>> reformat_string('150 - FLOOR/CEILING - WD - 1 HR - FLOOR ASSEMBLY',

'{section} - {loc} - {mat} - {rating} - {name}','{section}:{mat}:{rating} - {name} ({loc})'))

'150:WD:1 HR - FLOOR ASSEMBLY (FLOOR/CEILING)'"""# find the tagstag_extractor = re.compile('{(.+?)}')tags = tag_extractor.findall(orig_format)

# replace the tags with regex patterns# to create a regex pattern that finds valuestag_replacer = re.compile('{.+?}')value_extractor_pattern = tag_replacer.sub('(.+)', orig_format)# find all valuesvalue_extractor = re.compile(value_extractor_pattern)match = value_extractor.match(orig_str)values = match.groups()

# create a dictionary of tags and valuesreformat_dict = {}for key, value in zip(tags, values):

reformat_dict[key] = value

# use dictionary to reformat the string into newreturn new_format.format(**reformat_dict)

def get_mapped_drives_dict():"""Return a dictionary of currently mapped network drives."""searcher = framework.ManagementObjectSearcher(

"root\\CIMV2","SELECT * FROM Win32_MappedLogicalDisk")

(continues on next page)

194 Chapter 17. pyrevit.coreutils

Page 199: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

return {x['DeviceID']: x['ProviderName'] for x in searcher.Get()}

def dletter_to_unc(dletter_path):"""Convert drive letter path into UNC path of that drive.

Args:dletter_path (str): drive letter path

Returns:str: UNC path

Example:>>> # assuming J: is mapped to //filestore/server/jdrive>>> dletter_to_unc('J:/somefile.txt')'//filestore/server/jdrive/somefile.txt'

"""drives = get_mapped_drives_dict()dletter = dletter_path[:2]for mapped_drive, server_path in drives.items():

if dletter.lower() == mapped_drive.lower():return dletter_path.replace(dletter, server_path)

def unc_to_dletter(unc_path):"""Convert UNC path into drive letter path.

Args:unc_path (str): UNC path

Returns:str: drive letter path

Example:>>> # assuming J: is mapped to //filestore/server/jdrive>>> unc_to_dletter('//filestore/server/jdrive/somefile.txt')'J:/somefile.txt'

"""drives = get_mapped_drives_dict()for mapped_drive, server_path in drives.items():

if server_path in unc_path:return unc_path.replace(server_path, mapped_drive)

def random_color():"""Return a random color channel value (between 0 and 255)."""return random.randint(0, 255)

def random_alpha():"""Return a random alpha value (between 0 and 1.00)."""return round(random.random(), 2)

def random_hex_color():"""Return a random color in hex format.

(continues on next page)

17.1. pyrevit.coreutils 195

Page 200: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Example:>>> random_hex_color()'#FF0000'

"""return '#%02X%02X%02X' % (random_color(),

random_color(),random_color())

def random_rgb_color():"""Return a random color in rgb format.

Example:>>> random_rgb_color()'rgb(255, 0, 0)'

"""return 'rgb(%d, %d, %d)' % (random_color(),

random_color(),random_color())

def random_rgba_color():"""Return a random color in rgba format.

Example:>>> random_rgba_color()'rgba(255, 0, 0, 0.5)'

"""return 'rgba(%d, %d, %d, %.2f)' % (random_color(),

random_color(),random_color(),random_alpha())

def extract_range(formatted_str, max_range=500):"""Extract range from formatted string.

String must be formatted as belowA103 No rangeA103-A106 A103 to A106A103:A106 A103 to A106A103,A105a A103 and A105aA103;A105a A103 and A105a

Args:formatted_str (str): string specifying range

Returns:list: list of names in the specified range

Example:>>> exract_range('A103:A106')['A103', 'A104', 'A105', 'A106']>>> exract_range('S203-S206')['S203', 'S204', 'S205', 'S206']>>> exract_range('M00A,M00B')

(continues on next page)

196 Chapter 17. pyrevit.coreutils

Page 201: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

['M00A', 'M00B']"""for rchar, rchartype in {'::': 'range', '--': 'range',

',': 'list', ';': 'list'}.items():if rchar in formatted_str:

if rchartype == 'range' \and formatted_str.count(rchar) == 1:

items = []start, end = formatted_str.split(rchar)assert len(start) == len(end), \

'Range start and end must have same length'items.append(start)item = increment_str(start, 1)safe_counter = 0while item != end:

items.append(item)item = increment_str(item, 1)safe_counter += 1assert safe_counter < max_range, 'Max range reached.'

items.append(end)return items

elif rchartype == 'list':return [x.strip() for x in formatted_str.split(rchar)]

return [formatted_str]

def correct_revittxt_encoding(filename):"""Convert encoding of text file generated by Revit to UTF-8.

Args:filename (str): file path

"""with codecs.open(filename, 'r', 'utf_16_le') as oldf:

fcontent = oldf.readlines()with codecs.open(filename, 'w', 'utf-8') as newf:

newf.writelines(fcontent)

def check_revittxt_encoding(filename):"""Check if given file is in UTF-16 (UCS-2 LE) encoding.

Args:filename (str): file path

"""with open(filename, 'rb') as rtfile:

return rtfile.read()[:2] == codecs.BOM_UTF16

def check_utf8bom_encoding(filename):"""Check if given file is in UTF-8 encoding.

Args:filename (str): file path

"""with open(filename, 'rb') as rtfile:

return rtfile.read()[:3] == codecs.BOM_UTF8

(continues on next page)

17.1. pyrevit.coreutils 197

Page 202: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def has_nonprintable(input_str):"""Check input string for non-printable characters.

Args:input_str (str): input string

Returns:bool: True if contains non-printable characters

"""return any([x in input_str for x in UNICODE_NONPRINTABLE_CHARS])

def get_enum_values(enum_type):"""Returns enum values."""return framework.Enum.GetValues(enum_type)

def get_enum_value(enum_type, value_string):"""Return enum value matching given value string (case insensitive)"""for ftype in get_enum_values(enum_type):

if str(ftype).lower() == value_string.lower():return ftype

def get_enum_none(enum_type):"""Returns the None value in given Enum."""for val in get_enum_values(enum_type):

if str(val) == 'None':return val

def extract_guid(source_str):"""Extract GUID number from a string."""guid_match = re.match(".*([0-9A-Fa-f]{8}"

"[-][0-9A-Fa-f]{4}""[-][0-9A-Fa-f]{4}""[-][0-9A-Fa-f]{4}""[-][0-9A-Fa-f]{12}).*", source_str)

if guid_match:return guid_match.groups()[0]

def format_hex_rgb(rgb_value):"""Formats rgb value as #RGB value string."""if isinstance(rgb_value, str):

if not rgb_value.startswith('#'):return '#%s' % rgb_value

else:return rgb_value

elif isinstance(rgb_value, int):return '#%x' % rgb_value

def new_uuid():"""Create a new UUID (using dotnet Guid.NewGuid)"""# RE: https://github.com/eirannejad/pyRevit/issues/413

(continues on next page)

198 Chapter 17. pyrevit.coreutils

Page 203: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# return uuid.uuid1()return str(Guid.NewGuid())

def is_box_visible_on_screens(left, top, width, height):"""Check if given box is visible on any screen."""bounds = \

framework.Drawing.Rectangle(framework.Convert.ToInt32(0 if math.isnan(left) else left),framework.Convert.ToInt32(0 if math.isnan(top) else top),framework.Convert.ToInt32(0 if math.isnan(width) else width),framework.Convert.ToInt32(0 if math.isnan(height) else height))

for scr in framework.Forms.Screen.AllScreens:if bounds.IntersectsWith(scr.Bounds):

return Truereturn False

def fuzzy_search_ratio(target_string, sfilter):"""Match target string against the filter and return a match ratio."""tstring = target_string# 100 for identical matchesif sfilter == tstring:

return 100

# 98 to 99 reserved (2 scores)

# 97 for identical non-case-sensitive matcheslower_tstring = tstring.lower()lower_sfilter_str = sfilter.lower()if lower_sfilter_str == lower_tstring:

return 97

# 95 to 96 reserved (2 scores)

# 93 to 94 for inclusion matchesif sfilter in tstring:

return 94if lower_sfilter_str in lower_tstring:

return 93

# 91 to 92 reserved (2 scores)

## 80 to 90 for parts matcheststring_parts = tstring.split()sfilter_parts = sfilter.split()if all(x in tstring_parts for x in sfilter_parts):

return 90

# 88 to 89 reserved (2 scores)

lower_tstring_parts = [x.lower() for x in tstring_parts]lower_sfilter_parts = [x.lower() for x in sfilter_parts]if all(x in lower_tstring_parts for x in lower_sfilter_parts):

return 87

(continues on next page)

17.1. pyrevit.coreutils 199

Page 204: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

# 85 to 86 reserved (2 scores)

if all(x in tstring for x in sfilter_parts):return 84

# 82 to 83 reserved (2 scores)

if all(x in lower_tstring for x in lower_sfilter_parts):return 81

# 80 reserved

return 0

17.2 pyrevit.coreutils.envvars

pyRevit managed environment variables framework.

pyRevit provides the environment variables framework to the pyRevit core and all pyRevit tools so they can storearbitary data withing the running host session and share small data quickly between script runs.

Some settings needs to be set for the current session and might need to affect the behaviour of all individual scriptsinside the extensions. (e.g. If user activates the DEBUG mode, all scripts should follow and log the debug entries.)The information is saved using AppDomain.GetData and SetData in a dictionary parameter. The dictionary isused to minimize the addition of named parameters to the AppDomain. The dictionary then includes all the internalparameters and their associated value. This way each script does not need to read the usersettings data which reducesio and saves time.

pyRevit uses environment variables extensively at its core and making changes to the core environment variables(starting with PYREVIT_) through scripts is strongly prohibited.

Example

>>> from pyrevit.coreutils import envvars>>> envvars.set_pyrevit_env_var('MY_SCRIPT_STATUS', True)>>> envvars.set_pyrevit_env_var('MY_SCRIPT_CONFIG', {'someconfig': True})

Then another script or same script when executed later within the same session can query the shared environmentvariable:

>>> envvars.get_pyrevit_env_vars('MY_SCRIPT_STATUS')True>>> envvars.get_pyrevit_env_vars('MY_SCRIPT_CONFIG'){'someconfig': True}

pyrevit.coreutils.envvars.get_pyrevit_env_var(param_name)Get value of a parameter shared between all scripts.

Parameters param_name (str) – name of environment variable

Returns any object stored as the environment variable value

Return type object

200 Chapter 17. pyrevit.coreutils

Page 205: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.coreutils.envvars.get_pyrevit_env_vars()Get the root dictionary, holding all environment variables.

pyrevit.coreutils.envvars.set_pyrevit_env_var(param_name, param_value)Set value of a parameter shared between all scripts.

Parameters

• param_name (str) – name of environment variable

• param_value (object) – any python object

17.2.1 Implementation

"""pyRevit managed environment variables framework.

pyRevit provides the environment variables framework to the pyRevit coreand all pyRevit tools so they can store arbitary data withing the running hostsession and share small data quickly between script runs.

Some settings needs to be set for the current session and might need to affectthe behaviour of all individual scripts inside the extensions.(e.g. If user activates the ``DEBUG`` mode, all scripts should follow and logthe debug entries.) The information is saved using ``AppDomain.GetData`` and``SetData`` in a dictionary parameter. The dictionary is used to minimize theaddition of named parameters to the AppDomain. The dictionary then includesall the internal parameters and their associated value. This way each scriptdoes not need to read the usersettings data which reduces io and saves time.

pyRevit uses environment variables extensively at its core and making changesto the core environment variables (starting with ``PYREVIT_``) throughscripts is strongly prohibited.

Example:>>> from pyrevit.coreutils import envvars>>> envvars.set_pyrevit_env_var('MY_SCRIPT_STATUS', True)>>> envvars.set_pyrevit_env_var('MY_SCRIPT_CONFIG', {'someconfig': True})

Then another script or same script when executed later within the samesession can query the shared environment variable:

>>> envvars.get_pyrevit_env_vars('MY_SCRIPT_STATUS')True>>> envvars.get_pyrevit_env_vars('MY_SCRIPT_CONFIG'){'someconfig': True}

"""

from pyrevit import PYREVIT_ADDON_NAMEfrom pyrevit.framework import AppDomain

# root env var dictionary key.# must be the same in this file and pyrevit/loader/basetypes/_config.cs# DomainStorageKeys.pyRevitEnvVarsDictKeyPYREVIT_ENV_VAR_DICT_NAME = 'pyRevitEnvVarsDict'PYREVIT_ENVVAR_PREFIX = PYREVIT_ADDON_NAME.upper()

(continues on next page)

17.2. pyrevit.coreutils.envvars 201

Page 206: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def get_pyrevit_env_vars():"""Get the root dictionary, holding all environment variables."""return AppDomain.CurrentDomain.GetData(PYREVIT_ENV_VAR_DICT_NAME)

def get_pyrevit_env_var(param_name):"""Get value of a parameter shared between all scripts.

Args:param_name (str): name of environment variable

Returns:object: any object stored as the environment variable value

"""# This function returns None if it can not find the parameter.# Thus value of None should not be used for params

data_dict = AppDomain.CurrentDomain.GetData(PYREVIT_ENV_VAR_DICT_NAME)

if data_dict:try:

return data_dict[param_name]except KeyError:

return Noneelse:

return None

def set_pyrevit_env_var(param_name, param_value):"""Set value of a parameter shared between all scripts.

Args:param_name (str): name of environment variableparam_value (object): any python object

"""# Get function returns None if it can not find the parameter.# Thus value of None should not be used for paramsdata_dict = AppDomain.CurrentDomain.GetData(PYREVIT_ENV_VAR_DICT_NAME)

if data_dict:data_dict[param_name] = param_value

else:data_dict = {param_name: param_value}

AppDomain.CurrentDomain.SetData(PYREVIT_ENV_VAR_DICT_NAME, data_dict)

17.3 pyrevit.coreutils.appdata

Utility functions for creating data files within pyRevit environment.

Most times, scripts need to save some data to shared between different scripts that work on a similar topic or betweenscript executions. This module provides the necessary and consistent mechanism for creating and maintaining suchfiles.

202 Chapter 17. pyrevit.coreutils

Page 207: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit.coreutils import appdata>>> appdata.list_data_files()

pyrevit.coreutils.appdata.cleanup_appdata_folder()Cleanup appdata folder of all temporary appdata files.

pyrevit.coreutils.appdata.garbage_data_file(file_path)Mark and remove the given appdata file.

Current implementation removes the file immediately.

Parameters file_path (str) – path to the target file

pyrevit.coreutils.appdata.get_data_file(file_id, file_ext, name_only=False)Get path to file that will not be cleaned up at Revit load.

e.g pyrevit_2016_eirannejad_file_id.file_ext

Parameters

• file_id (str) – Unique identifier for the file

• file_ext (str) – File extension

• name_only (bool) – If true, function returns file name only

Returns File name or full file path (depending on name_only)

Return type str

pyrevit.coreutils.appdata.get_instance_data_file(file_id, file_ext=’tmp’,name_only=False)

Get path to file that should be used by current instance only.

These data files will be cleaned up at Revit restart. e.g pyrevit_2016_eirannejad_2353_file_id.file_ext

Parameters

• file_id (str) – Unique identifier for the file

• file_ext (str) – File extension

• name_only (bool) – If true, function returns file name only

Returns File name or full file path (depending on name_only)

Return type str

pyrevit.coreutils.appdata.get_universal_data_file(file_id, file_ext, name_only=False)Get path to file that is shared between all host versions.

These data files are not cleaned up at Revit restart. e.g pyrevit_eirannejad_file_id.file_ext

Parameters

• file_id (str) – Unique identifier for the file

• file_ext (str) – File extension

• name_only (bool) – If true, function returns file name only

Returns File name or full file path (depending on name_only)

Return type str

17.3. pyrevit.coreutils.appdata 203

Page 208: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

pyrevit.coreutils.appdata.is_data_file_available(file_id, file_ext)Check if given file is available within appdata directory.

Parameters

• file_id (str) – data file id

• file_ext (str) – file extension

Returns file path if file is available

Return type str

pyrevit.coreutils.appdata.is_file_available(file_name, file_ext, universal=False)Check if given file is available within appdata directory.

Parameters

• file_name (str) – file name

• file_ext (str) – file extension

• universal (bool) – Check against universal data files

Returns file path if file is available

Return type str

pyrevit.coreutils.appdata.is_pyrevit_data_file(file_name)Check if given file is a pyRevit data file.

Parameters file_name (str) – file name

Returns True if file is a pyRevit data file

Return type bool

pyrevit.coreutils.appdata.list_data_files(file_ext, universal=False)List all data files with given extension.

Parameters

• file_ext (str) – file extension

• universal (bool) – Check against universal data files

Returns list of files

Return type list

pyrevit.coreutils.appdata.list_session_data_files(file_ext)List all data files associated with current session.

Parameters file_ext (str) – data files with this extension will be listed only.

Returns list of data files

Return type list

17.3.1 Implementation

"""Utility functions for creating data files within pyRevit environment.

Most times, scripts need to save some data to shared between different scriptsthat work on a similar topic or between script executions. This module provides

(continues on next page)

204 Chapter 17. pyrevit.coreutils

Page 209: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

the necessary and consistent mechanism for creating and maintaining such files.

Example:>>> from pyrevit.coreutils import appdata>>> appdata.list_data_files()

"""

import osimport os.path as opimport re

import pyrevitfrom pyrevit import EXEC_PARAMS, HOST_APPfrom pyrevit.coreutils import make_canonical_namefrom pyrevit.coreutils import loggerfrom pyrevit.labs import TargetApps

#pylint: disable=W0703,C0302mlogger = logger.get_logger(__name__) #pylint: disable=C0103

TEMP_FILE_EXT = 'tmp'

def _remove_app_file(file_path):try:

os.remove(file_path)except Exception as osremove_err:

mlogger.error('Error file cleanup on: %s | %s', file_path, osremove_err)

def _list_app_files(prefix, file_ext, universal=False):requested_files = []

if universal:appdata_folder = pyrevit.PYREVIT_APP_DIR

else:appdata_folder = pyrevit.PYREVIT_VERSION_APP_DIR

for appdata_file in os.listdir(appdata_folder):if appdata_file.startswith(prefix) and appdata_file.endswith(file_ext):

requested_files.append(op.join(appdata_folder, appdata_file))

return requested_files

def _get_app_file(file_id, file_ext,filename_only=False, stamped=False, universal=False):

appdata_folder = pyrevit.PYREVIT_VERSION_APP_DIRfile_prefix = pyrevit.PYREVIT_FILE_PREFIX

if stamped:file_prefix = pyrevit.PYREVIT_FILE_PREFIX_STAMPED

elif universal:appdata_folder = pyrevit.PYREVIT_APP_DIRfile_prefix = pyrevit.PYREVIT_FILE_PREFIX_UNIVERSAL

(continues on next page)

17.3. pyrevit.coreutils.appdata 205

Page 210: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

full_filename = '{}{}.{}'.format(file_prefix, file_id, file_ext)

if filename_only:return full_filename

else:return op.join(appdata_folder, full_filename)

def _match_file(file_name):match = re.match(pattern=pyrevit.PYREVIT_FILE_PREFIX_STAMPED_USER_REGEX,

string=file_name)if match:

return match.groupdict()

# e.g. pyRevit_2018_14422_match = re.match(pattern=pyrevit.PYREVIT_FILE_PREFIX_STAMPED_REGEX,

string=file_name)if match:

return match.groupdict()

# e.g. pyRevit_2018_eirannejad_match = re.match(pattern=pyrevit.PYREVIT_FILE_PREFIX_USER_REGEX,

string=file_name)if match:

return match.groupdict()

# e.g. pyRevit_2018_match = re.match(pattern=pyrevit.PYREVIT_FILE_PREFIX_REGEX,

string=file_name)if match:

return match.groupdict()

# e.g. pyRevit_eirannejad_match = re.match(pattern=pyrevit.PYREVIT_FILE_PREFIX_UNIVERSAL_USER_REGEX,

string=file_name)if match:

return match.groupdict()

# e.g. pyRevit_match = re.match(pattern=pyrevit.PYREVIT_FILE_PREFIX_UNIVERSAL_REGEX,

string=file_name)if match:

return match.groupdict()

return {}

def get_universal_data_file(file_id, file_ext, name_only=False):"""Get path to file that is shared between all host versions.

These data files are not cleaned up at Revit restart.e.g pyrevit_eirannejad_file_id.file_ext

Args:file_id (str): Unique identifier for the filefile_ext (str): File extension

(continues on next page)

206 Chapter 17. pyrevit.coreutils

Page 211: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

name_only (bool): If true, function returns file name only

Returns:str: File name or full file path (depending on name_only)

"""return _get_app_file(file_id, file_ext,

filename_only=name_only, universal=True)

def get_data_file(file_id, file_ext, name_only=False):"""Get path to file that will not be cleaned up at Revit load.

e.g pyrevit_2016_eirannejad_file_id.file_ext

Args:file_id (str): Unique identifier for the filefile_ext (str): File extensionname_only (bool): If true, function returns file name only

Returns:str: File name or full file path (depending on name_only)

"""return _get_app_file(file_id, file_ext, filename_only=name_only)

def get_instance_data_file(file_id, file_ext=TEMP_FILE_EXT, name_only=False):"""Get path to file that should be used by current instance only.

These data files will be cleaned up at Revit restart.e.g pyrevit_2016_eirannejad_2353_file_id.file_ext

Args:file_id (str): Unique identifier for the filefile_ext (str): File extensionname_only (bool): If true, function returns file name only

Returns:str: File name or full file path (depending on name_only)

"""return _get_app_file(file_id, file_ext,

filename_only=name_only, stamped=True)

def is_pyrevit_data_file(file_name):"""Check if given file is a pyRevit data file.

Args:file_name (str): file name

Returns:bool: True if file is a pyRevit data file

"""return pyrevit.PYREVIT_FILE_PREFIX in file_name

def is_file_available(file_name, file_ext, universal=False):"""Check if given file is available within appdata directory.

(continues on next page)

17.3. pyrevit.coreutils.appdata 207

Page 212: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Args:file_name (str): file namefile_ext (str): file extensionuniversal (bool): Check against universal data files

Returns:str: file path if file is available

"""if universal:

full_filename = op.join(pyrevit.PYREVIT_APP_DIR,make_canonical_name(file_name, file_ext))

else:full_filename = op.join(pyrevit.PYREVIT_VERSION_APP_DIR,

make_canonical_name(file_name, file_ext))if op.exists(full_filename):

return full_filenameelse:

return False

def is_data_file_available(file_id, file_ext):"""Check if given file is available within appdata directory.

Args:file_id (str): data file idfile_ext (str): file extension

Returns:str: file path if file is available

"""full_filename = _get_app_file(file_id, file_ext)if op.exists(full_filename):

return full_filenameelse:

return False

def list_data_files(file_ext, universal=False):"""List all data files with given extension.

Args:file_ext (str): file extensionuniversal (bool): Check against universal data files

Returns::obj:`list`: list of files

"""return _list_app_files(pyrevit.PYREVIT_FILE_PREFIX, file_ext, universal=universal)

def list_session_data_files(file_ext):"""List all data files associated with current session.

Args:file_ext (str): data files with this extension will be listed only.

(continues on next page)

208 Chapter 17. pyrevit.coreutils

Page 213: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Returns::obj:`list`: list of data files

"""return _list_app_files(pyrevit.PYREVIT_FILE_PREFIX_STAMPED, file_ext)

def garbage_data_file(file_path):"""Mark and remove the given appdata file.

Current implementation removes the file immediately.

Args:file_path (str): path to the target file

"""_remove_app_file(file_path)

def cleanup_appdata_folder():"""Cleanup appdata folder of all temporary appdata files."""if EXEC_PARAMS.first_load:

hostapp_pids = \[x.ProcessIdfor x in TargetApps.Revit.RevitController.ListRunningRevits()]

for appdata_file in os.listdir(pyrevit.PYREVIT_VERSION_APP_DIR):file_naming_dict = _match_file(appdata_file)if 'pid' in file_naming_dict:

try:pid = int(file_naming_dict['pid'])if pid not in hostapp_pids:

_remove_app_file(op.join(pyrevit.PYREVIT_VERSION_APP_DIR,

appdata_file))

except Exception:pass

17.4 pyrevit.coreutils.pyutils

Helper functions for python.

Example

>>> from pyrevit.coreutils import pyutils>>> pyutils.safe_cast('string', int, 0)

class pyrevit.coreutils.pyutils.DefaultOrderedDict(default_factory=None, *a, **kw)Ordered dictionary with default type.

This is similar to defaultdict and maintains the order of items added to it so in that regards it functions similarto OrderedDict.

17.4. pyrevit.coreutils.pyutils 209

Page 214: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> from pyrevit.coreutils import pyutils>>> od = pyutils.DefaultOrderedDict(list)>>> od['A'] = [1, 2, 3]>>> od['B'] = [4, 5, 6]>>> od['C'].extend([7, 8, 9])>>> for k, v in od.items():... print(k, v)('A', [1, 2, 3])('B', [4, 5, 6])('C', [7, 8, 9])

copy()Copy the dictionary.

pyrevit.coreutils.pyutils.compare_lists(x, y)Compare two lists.

See: https://stackoverflow.com/a/10872313/2350244

Parameters

• x (list) – first list

• y (list) – second list

pyrevit.coreutils.pyutils.isnumber(token)Verify if given string token is int or float.

Parameters token (str) – string value

Returns True of token is int or float

Return type bool

Example

>>> isnumber('12.3')True

pyrevit.coreutils.pyutils.pairwise(iterable, step=2)Iterate through items in pairs.

Parameters

• iterable (iterable) – any iterable object

• step (int) – number of steps to move when making pairs

Returns list of pairs

Return type iterable

Example

210 Chapter 17. pyrevit.coreutils

Page 215: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

>>> pairwise([1, 2, 3, 4, 5])[(1, 2), (3, 4)] # 5 can not be paired>>> pairwise([1, 2, 3, 4, 5, 6])[(1, 2), (3, 4), (5, 6)]>>> pairwise([1, 2, 3, 4, 5, 6], step=1)[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

pyrevit.coreutils.pyutils.safe_cast(val, to_type, default=None)Convert value to type gracefully.

This method basically calls to_type(value) and returns the default if exception occurs.

Parameters

• val (any) – value to be converted

• to_type (type) – target type

• default (any) – value to rerun on conversion exception

Example

>>> safe_cast('name', int, default=0)0

17.4.1 Implementation

"""Helper functions for python.

Example:>>> from pyrevit.coreutils import pyutils>>> pyutils.safe_cast('string', int, 0)

"""#pylint: disable=C0103import refrom collections import OrderedDict, Callable #pylint: disable=E0611

class DefaultOrderedDict(OrderedDict):"""Ordered dictionary with default type.

This is similar to defaultdict and maintains the order of items addedto it so in that regards it functions similar to OrderedDict.

Example:>>> from pyrevit.coreutils import pyutils>>> od = pyutils.DefaultOrderedDict(list)>>> od['A'] = [1, 2, 3]>>> od['B'] = [4, 5, 6]>>> od['C'].extend([7, 8, 9])>>> for k, v in od.items():... print(k, v)('A', [1, 2, 3])('B', [4, 5, 6])('C', [7, 8, 9])

(continues on next page)

17.4. pyrevit.coreutils.pyutils 211

Page 216: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""

# Source: http://stackoverflow.com/a/6190500/562769def __init__(self, default_factory=None, *a, **kw): #pylint: disable=W1113

if (default_factory is not None \and not isinstance(default_factory, Callable)):

raise TypeError('first argument must be callable')OrderedDict.__init__(self, *a, **kw)self.default_factory = default_factory

def __getitem__(self, key):try:

return OrderedDict.__getitem__(self, key)except KeyError:

return self.__missing__(key)

def __missing__(self, key):if self.default_factory is None:

raise KeyError(key)self[key] = value = self.default_factory()return value

def __reduce__(self):if self.default_factory is None:

args = tuple()else:

args = self.default_factory,return type(self), args, None, None, self.items()

def copy(self):"""Copy the dictionary."""return self.__copy__()

def __copy__(self):return type(self)(self.default_factory, self)

def __deepcopy__(self, memo):import copyreturn type(self)(self.default_factory,

copy.deepcopy(self.items()))

def __repr__(self, _repr_running=None):return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,

OrderedDict.__repr__(self))

def pairwise(iterable, step=2):"""Iterate through items in pairs.

Args:iterable (iterable): any iterable objectstep (int): number of steps to move when making pairs

Returns:iterable: list of pairs

(continues on next page)

212 Chapter 17. pyrevit.coreutils

Page 217: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Example:>>> pairwise([1, 2, 3, 4, 5])[(1, 2), (3, 4)] # 5 can not be paired>>> pairwise([1, 2, 3, 4, 5, 6])[(1, 2), (3, 4), (5, 6)]>>> pairwise([1, 2, 3, 4, 5, 6], step=1)[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

"""if step == 1:

from itertools import tee, izip #pylint: disable=E0611a, b = tee(iterable)next(b, None)return izip(a, b)

elif step == 2:a = iter(iterable)return zip(a, a)

def safe_cast(val, to_type, default=None):"""Convert value to type gracefully.

This method basically calls to_type(value) and returns the defaultif exception occurs.

Args:val (any): value to be convertedto_type (type): target typedefault (any): value to rerun on conversion exception

Example:>>> safe_cast('name', int, default=0)0

"""try:

return to_type(val)except (ValueError, TypeError):

return default

def isnumber(token):"""Verify if given string token is int or float.

Args:token (str): string value

Returns:bool: True of token is int or float

Example:>>> isnumber('12.3')True

"""if token:

return re.match("^[0-9.]+?$", token) is not Noneelse:

return False

(continues on next page)

17.4. pyrevit.coreutils.pyutils 213

Page 218: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def compare_lists(x, y):"""Compare two lists.

See: https://stackoverflow.com/a/10872313/2350244

Args:x (list): first listy (list): second list

"""return len(frozenset(x).difference(y)) == 0

17.5 pyrevit.coreutils.mathnet

MathNet importer module.

See https://www.mathdotnet.com for documentation.

Example

>>> from pyrevit.coreutils.mathnet import MathNet

17.5.1 Implementation

"""MathNet importer module.

See https://www.mathdotnet.com for documentation.

Example:>>> from pyrevit.coreutils.mathnet import MathNet

"""#pylint: disable=W0703,C0302,C0103from pyrevit import EXEC_PARAMSfrom pyrevit import frameworkfrom pyrevit.framework import clrfrom pyrevit.coreutils.logger import get_logger

mlogger = get_logger(__name__)

MATHNET_LIB = 'MathNet.Numerics'

if not EXEC_PARAMS.doc_mode:mathnet_dll = framework.get_dll_file(MATHNET_LIB)mlogger.debug('Loading dll: %s', mathnet_dll)try:

clr.AddReferenceToFileAndPath(mathnet_dll)import MathNet #pylint: disable=E0401,W0611

except Exception as load_err:mlogger.error('Can not load %s module. | %s', MATHNET_LIB, load_err)

214 Chapter 17. pyrevit.coreutils

Page 219: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

17.6 pyrevit.coreutils.moduleutils

Utility fuctions to support smart modules.

pyrevit.coreutils.moduleutils.copy_func(func, func_name, doc_string=None,arg_list=None)

Copy a function object to create a new function.

This is used inside smart modules that auto-generate functions based on context.

Parameters

• func (object) – python source function object

• func_name (str) – new function name

• doc_string (str) – new function docstring

• arg_list (list) – list of default values for function arguments

Returns new python function objects

Return type object

17.6.1 Implementation

"""Utility fuctions to support smart modules."""

import types

def copy_func(func, func_name, doc_string=None, arg_list=None):"""Copy a function object to create a new function.

This is used inside smart modules that auto-generate functions based oncontext.

Args:func (object): python source function objectfunc_name (str): new function namedoc_string (str): new function docstringarg_list (list): list of default values for function arguments

Returns:object: new python function objects

"""new_func = types.FunctionType(func.func_code, func.func_globals,

func_name, tuple(arg_list), func.func_closure)new_func.__doc__ = doc_stringreturn new_func

17.6. pyrevit.coreutils.moduleutils 215

Page 220: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

216 Chapter 17. pyrevit.coreutils

Page 221: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

CHAPTER 18

pyrevit.output

Provides access and control over the pyRevit output window.

18.1 pyrevit.output

Provide access to output window and its functionality.

This module provides access to the output window for the currently running pyRevit command. The proper way toaccess this wrapper object is through the get_output() of pyrevit.script module. This method, in returnuses the pyrevit.output module to get access to the output wrapper.

Example

>>> from pyrevit import script>>> output = script.get_output()

Here is the source of pyrevit.script.get_output(). As you can see this functions calls the pyrevit.output.get_output() to receive the output wrapper.

def get_output():"""Return object wrapping output window for current script.

Returns::obj:`pyrevit.output.PyRevitOutputWindow`: Output wrapper object

"""return output.get_output()

class pyrevit.output.PyRevitOutputWindowWrapper to interact with the output window.

add_style(style_code, attribs=None)Inject style tag into current html head of the output window.

217

Page 222: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Parameters

• style_code (str) – css styling code

• attribs (dict) – dictionary of attribute names and value

Example

>>> output = pyrevit.output.get_output()>>> output.add_style('body { color: blue; }')

close()Close the window.

close_others(all_open_outputs=False)Close all other windows that belong to the current command.

Parameters all_open_outputs (bool) – Close all any other windows if True

debug_modeSet debug mode on output window and stream.

This will cause the output window to print information about the buffer stream and other aspects of theoutput window mechanism.

freeze()Freeze output contetn update.

get_head_html()str: Return inner code of html head element.

get_height()int: Return current window height.

get_title()str: Return current window title.

get_width()int: Return current window width.

hide()Hide the window.

hide_logpanel()Hide output window logging panel.

hide_progress()Hide output window progress bar.

indeterminate_progress(state)Show or hide indeterminate progress bar.

inject_script(script_code, attribs=None, body=False)Inject script tag into current head (or body) of the output window.

Parameters

• script_code (str) – javascript code

• attribs (dict) – dictionary of attribute names and value

• body (bool, optional) – injects script into body instead of head

218 Chapter 18. pyrevit.output

Page 223: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> output = pyrevit.output.get_output()>>> output.inject_script('', # no script since it's a link

{'src': js_script_file_path})

inject_to_body(element_tag, element_contents, attribs=None)Inject html element to current html body of the output window.

Parameters

• element_tag (str) – html tag of the element e.g. ‘div’

• element_contents (str) – html code of the element contents

• attribs (dict) – dictionary of attribute names and value

Example

>>> output = pyrevit.output.get_output()>>> output.inject_to_body('script',

'', # no script since it's a link{'src': js_script_file_path})

inject_to_head(element_tag, element_contents, attribs=None)Inject html element to current html head of the output window.

Parameters

• element_tag (str) – html tag of the element e.g. ‘div’

• element_contents (str) – html code of the element contents

• attribs (dict) – dictionary of attribute names and value

Example

>>> output = pyrevit.output.get_output()>>> output.inject_to_head('script',

'', # no script since it's a link{'src': js_script_file_path})

insert_divider()Add horizontal rule to the output window.

static linkify(element_ids, title=None)Create clickable link for the provided element ids.

This method, creates the link but does not print it directly.

Parameters

• element_ids (list of ElementId) –

• element_ids – single or multiple ids

• title (str) – tile of the link. defaults to list of element ids

18.1. pyrevit.output 219

Page 224: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> output = pyrevit.output.get_output()>>> for idx, elid in enumerate(element_ids):>>> print('{}: {}'.format(idx+1, output.linkify(elid)))

lock_size()Lock window size.

log_error(message)Report ERROR message into output logging panel.

log_info(message)Report INFO message into output logging panel.

log_ok(message)Report OK message into output logging panel.

log_warning(message)Report WARNING message into output logging panel.

make_bar_chart()PyRevitOutputChart: Return bar chart object.

make_bubble_chart()PyRevitOutputChart: Return bubble chart object.

make_chart()PyRevitOutputChart: Return chart object.

make_doughnut_chart()PyRevitOutputChart: Return dougnut chart object.

make_line_chart()PyRevitOutputChart: Return line chart object.

make_pie_chart()PyRevitOutputChart: Return pie chart object.

make_polar_chart()PyRevitOutputChart: Return polar chart object.

make_radar_chart()PyRevitOutputChart: Return radar chart object.

make_stacked_chart()PyRevitOutputChart: Return stacked chart object.

next_page()Add hidden next page tag to the output window.

This is helpful to silently separate the output to multiple pages for better printing.

open_page(dest_file)Open html page in output window.

Parameters dest_file (str) – full path of the target html file

open_url(dest_url)Open url page in output window.

Parameters dest_url (str) – web url of the target page

220 Chapter 18. pyrevit.output

Page 225: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

output_idstr – Return id of the output window.

In current implementation, Id of output window is equal to the unique id of the pyRevit command itbelongs to. This means that all output windows belonging to the same pyRevit command, will haveidentical output_id values.

output_uniqueidstr – Return unique id of the output window.

In current implementation, unique id of output window is a GUID string generated when the output windowis opened. This id is unique to the instance of output window.

static print_code(code_str)Print code to the output window with special formatting.

Example

>>> output = pyrevit.output.get_output()>>> output.print_code('value = 12')

static print_html(html_str)Add the html code to the output window.

Example

>>> output = pyrevit.output.get_output()>>> output.print_html('<strong>Title</strong>')

static print_md(md_str)Process markdown code and print to output window.

Example

>>> output = pyrevit.output.get_output()>>> output.print_md('### Title')

print_table(table_data, columns=None, formats=None, title=”, last_line_style=”)Print provided data in a table in output window.

Parameters

• table_data (list of iterables) – 2D array of data

• title (str) – table title

• columns (list str) – list of column names

• formats (list str) – column data formats

• last_line_style (str) – css style of last row

18.1. pyrevit.output 221

Page 226: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

Example

>>> data = [... ['row1', 'data', 'data', 80 ],... ['row2', 'data', 'data', 45 ],... ]>>> output.print_table(... table_data=data,... title="Example Table",... columns=["Row Name", "Column 1", "Column 2", "Percentage"],... formats=['', '', '', '{}%'],... last_line_style='color:red;'... )

rendererReturn html renderer inside output window.

Returns System.Windows.Forms.WebBrowser (In current implementation)

reset_icon()Sets icon on the output window.

reset_progress()Reset output window progress bar to zero.

resize(width, height)Resize window to the new width and height.

save_contents(dest_file)Save html code of the window.

Parameters dest_file (str) – full path of the destination html file

self_destruct(seconds)Set self-destruct (close window) timer.

Parameters seconds (int) – number of seconds after which window is closed.

set_font(font_family, font_size)Set window font family to the new font family and size.

Parameters

• font_family (str) – font family name e.g. ‘Courier New’

• font_size (int) – font size e.g. 16

set_height(height)Set window height to the new height.

set_icon(iconpath)Sets icon on the output window.

set_title(new_title)Set window title to the new title.

set_width(width)Set window width to the new width.

show()Show the window.

222 Chapter 18. pyrevit.output

Page 227: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

show_logpanel()Show output window logging panel.

unfreeze()Unfreeze output contetn update.

unhide_progress()Unhide output window progress bar.

unlock_size()Unock window size.

update_progress(cur_value, max_value)Activate and update the output window progress bar.

Parameters

• cur_value (float) – current progress value e.g. 50

• max_value (float) – total value e.g. 100

Example

>>> output = pyrevit.output.get_output()>>> for i in range(100):>>> output.update_progress(i, 100)

windowPyRevitBaseClasses.ScriptOutput – Return output window object.

pyrevit.output.docclosing_eventhandler(sender, args)Close all output window on document closing.

pyrevit.output.get_default_stylesheet()Return default css stylesheet used by output window.

pyrevit.output.get_output()pyrevit.output.PyRevitOutputWindow : Return output window.

pyrevit.output.get_stylesheet()Return active css stylesheet used by output window.

pyrevit.output.reset_stylesheet()Reset active stylesheet to default.

pyrevit.output.set_stylesheet(stylesheet)Set active css stylesheet used by output window.

Parameters stylesheet (str) – full path to stylesheet file

pyrevit.output.setup_output_closer()Setup document closing event listener.

18.1.1 Implementation

"""Provide access to output window and its functionality.

This module provides access to the output window for the currently runningpyRevit command. The proper way to access this wrapper object is through

(continues on next page)

18.1. pyrevit.output 223

Page 228: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

the :func:`get_output` of :mod:`pyrevit.script` module. This method, in returnuses the `pyrevit.output` module to get access to the output wrapper.

Example:>>> from pyrevit import script>>> output = script.get_output()

Here is the source of :func:`pyrevit.script.get_output`. As you can see thisfunctions calls the :func:`pyrevit.output.get_output` to receive theoutput wrapper.

.. literalinclude:: ../../../pyrevitlib/pyrevit/script.py:pyobject: get_output

"""

from __future__ import print_functionimport os.path as opimport itertools

from pyrevit import HOST_APP, EXEC_PARAMSfrom pyrevit import frameworkfrom pyrevit import coreutilsfrom pyrevit.coreutils import loggerfrom pyrevit.coreutils import markdown, chartsfrom pyrevit.coreutils import envvarsfrom pyrevit.coreutils.loadertypes import EnvDictionaryKeysfrom pyrevit.coreutils.loadertypes import ScriptOutputManagerfrom pyrevit.output import linkmakerfrom pyrevit.userconfig import user_configfrom pyrevit import DB

#pylint: disable=W0703,C0302,C0103mlogger = logger.get_logger(__name__)

DEFAULT_STYLESHEET_NAME = 'outputstyles.css'

def docclosing_eventhandler(sender, args): #pylint: disable=W0613"""Close all output window on document closing."""ScriptOutputManager.CloseActiveOutputWindows()

def setup_output_closer():"""Setup document closing event listener."""HOST_APP.app.DocumentClosing += \

framework.EventHandler[DB.Events.DocumentClosingEventArgs](docclosing_eventhandler)

def set_stylesheet(stylesheet):"""Set active css stylesheet used by output window.

Args:stylesheet (str): full path to stylesheet file

(continues on next page)

224 Chapter 18. pyrevit.output

Page 229: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""envvars.set_pyrevit_env_var(EnvDictionaryKeys.outputStyleSheet,

stylesheet)

def get_stylesheet():"""Return active css stylesheet used by output window."""return envvars.get_pyrevit_env_var(EnvDictionaryKeys.outputStyleSheet)

def get_default_stylesheet():"""Return default css stylesheet used by output window."""return op.join(op.dirname(__file__), DEFAULT_STYLESHEET_NAME)

def reset_stylesheet():"""Reset active stylesheet to default."""envvars.set_pyrevit_env_var(EnvDictionaryKeys.outputStyleSheet,

get_default_stylesheet())

# setup output window stylesheetif not EXEC_PARAMS.doc_mode:

active_stylesheet = \user_config.core.get_option('outputstylesheet',

default_value=get_default_stylesheet())set_stylesheet(active_stylesheet)

class PyRevitOutputWindow(object):"""Wrapper to interact with the output window."""

@propertydef window(self):

"""``PyRevitBaseClasses.ScriptOutput``: Return output window object."""return EXEC_PARAMS.window_handle

@propertydef renderer(self):

"""Return html renderer inside output window.

Returns:``System.Windows.Forms.WebBrowser`` (In current implementation)

"""if self.window:

return self.window.renderer

@propertydef output_id(self):

"""str: Return id of the output window.

In current implementation, Id of output window is equal to theunique id of the pyRevit command it belongs to. This means that alloutput windows belonging to the same pyRevit command, will haveidentical output_id values."""if self.window:

(continues on next page)

18.1. pyrevit.output 225

Page 230: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

return self.window.OutputId

@propertydef output_uniqueid(self):

"""str: Return unique id of the output window.

In current implementation, unique id of output window is a GUID stringgenerated when the output window is opened. This id is unique to theinstance of output window."""if self.window:

return self.window.OutputUniqueId

@propertydef debug_mode(self):

"""Set debug mode on output window and stream.

This will cause the output window to print information about thebuffer stream and other aspects of the output window mechanism."""return EXEC_PARAMS.pyrevit_command.OutputStream.PrintDebugInfo

@debug_mode.setterdef debug_mode(self, value):

EXEC_PARAMS.pyrevit_command.OutputStream.PrintDebugInfo = value

def _get_head_element(self):return self.renderer.Document.GetElementsByTagName('head')[0]

def _get_body_element(self):return self.renderer.Document.GetElementsByTagName('body')[0]

def self_destruct(self, seconds):"""Set self-destruct (close window) timer.

Args:seconds (int): number of seconds after which window is closed.

"""if self.window:

self.window.SelfDestructTimer(seconds)

def inject_to_head(self, element_tag, element_contents, attribs=None):"""Inject html element to current html head of the output window.

Args:element_tag (str): html tag of the element e.g. 'div'element_contents (str): html code of the element contentsattribs (:obj:`dict`): dictionary of attribute names and value

Example:>>> output = pyrevit.output.get_output()>>> output.inject_to_head('script',

'', # no script since it's a link{'src': js_script_file_path})

"""html_element = self.renderer.Document.CreateElement(element_tag)if element_contents:

(continues on next page)

226 Chapter 18. pyrevit.output

Page 231: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

html_element.InnerHtml = element_contents

if attribs:for attribute, value in attribs.items():

html_element.SetAttribute(attribute, value)

# inject the script into headhead_el = self._get_head_element()head_el.AppendChild(html_element)

def inject_to_body(self, element_tag, element_contents, attribs=None):"""Inject html element to current html body of the output window.

Args:element_tag (str): html tag of the element e.g. 'div'element_contents (str): html code of the element contentsattribs (:obj:`dict`): dictionary of attribute names and value

Example:>>> output = pyrevit.output.get_output()>>> output.inject_to_body('script',

'', # no script since it's a link{'src': js_script_file_path})

"""html_element = self.renderer.Document.CreateElement(element_tag)if element_contents:

html_element.InnerHtml = element_contents

if attribs:for attribute, value in attribs.items():

html_element.SetAttribute(attribute, value)

# inject the script into bodybody_el = self._get_body_element()body_el.AppendChild(html_element)

def inject_script(self, script_code, attribs=None, body=False):"""Inject script tag into current head (or body) of the output window.

Args:script_code (str): javascript codeattribs (:obj:`dict`): dictionary of attribute names and valuebody (bool, optional): injects script into body instead of head

Example:>>> output = pyrevit.output.get_output()>>> output.inject_script('', # no script since it's a link

{'src': js_script_file_path})"""if body:

self.inject_to_body('script', script_code, attribs=attribs)else:

self.inject_to_head('script', script_code, attribs=attribs)

def add_style(self, style_code, attribs=None):"""Inject style tag into current html head of the output window.

(continues on next page)

18.1. pyrevit.output 227

Page 232: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

Args:style_code (str): css styling codeattribs (:obj:`dict`): dictionary of attribute names and value

Example:>>> output = pyrevit.output.get_output()>>> output.add_style('body { color: blue; }')

"""self.inject_to_head('style', style_code, attribs=attribs)

def get_head_html(self):"""str: Return inner code of html head element."""return self._get_head_element().InnerHtml

def set_title(self, new_title):"""Set window title to the new title."""if self.window:

self.window.Title = new_title

def set_width(self, width):"""Set window width to the new width."""if self.window:

self.window.Width = width

def set_height(self, height):"""Set window height to the new height."""if self.window:

self.window.Height = height

def set_font(self, font_family, font_size):"""Set window font family to the new font family and size.

Args:font_family (str): font family name e.g. 'Courier New'font_size (int): font size e.g. 16

"""self.renderer.Font = \

framework.Drawing.Font(font_family,font_size,framework.Drawing.FontStyle.Regular,framework.Drawing.GraphicsUnit.Point)

def resize(self, width, height):"""Resize window to the new width and height."""self.set_width(width)self.set_height(height)

def get_title(self):"""str: Return current window title."""if self.window:

return self.window.Text

def get_width(self):"""int: Return current window width."""if self.window:

return self.window.Width

(continues on next page)

228 Chapter 18. pyrevit.output

Page 233: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def get_height(self):"""int: Return current window height."""if self.window:

return self.window.Height

def close(self):"""Close the window."""if self.window:

self.window.Close()

def close_others(self, all_open_outputs=False):"""Close all other windows that belong to the current command.

Args:all_open_outputs (bool): Close all any other windows if True

"""if all_open_outputs:

ScriptOutputManager.CloseActiveOutputWindows(self.window)else:

ScriptOutputManager.CloseActiveOutputWindows(self.window,self.output_id)

def hide(self):"""Hide the window."""if self.window:

self.window.Hide()

def show(self):"""Show the window."""if self.window:

self.window.Show()

def lock_size(self):"""Lock window size."""if self.window:

self.window.LockSize()

def unlock_size(self):"""Unock window size."""if self.window:

self.window.UnlockSize()

def freeze(self):"""Freeze output contetn update."""if self.window:

self.window.Freeze()

def unfreeze(self):"""Unfreeze output contetn update."""if self.window:

self.window.Unfreeze()

def save_contents(self, dest_file):"""Save html code of the window.

Args:dest_file (str): full path of the destination html file

(continues on next page)

18.1. pyrevit.output 229

Page 234: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""if self.renderer:

html = \self.renderer.Document.Body.OuterHtml.encode('ascii', 'ignore')

doc_txt = self.renderer.DocumentTextfull_html = doc_txt.lower().replace('<body></body>', html)with open(dest_file, 'w') as output_file:

output_file.write(full_html)

def open_url(self, dest_url):"""Open url page in output window.

Args:dest_url (str): web url of the target page

"""if self.renderer:

self.renderer.Navigate(dest_url, False)

def open_page(self, dest_file):"""Open html page in output window.

Args:dest_file (str): full path of the target html file

"""self.show()self.open_url('file:///' + dest_file)

def update_progress(self, cur_value, max_value):"""Activate and update the output window progress bar.

Args:cur_value (float): current progress value e.g. 50max_value (float): total value e.g. 100

Example:>>> output = pyrevit.output.get_output()>>> for i in range(100):>>> output.update_progress(i, 100)

"""if self.window:

self.window.UpdateActivityBar(cur_value, max_value)

def reset_progress(self):"""Reset output window progress bar to zero."""if self.window:

self.window.UpdateActivityBar(0, 1)

def hide_progress(self):"""Hide output window progress bar."""if self.window:

self.window.SetActivityBarVisibility(False)

def unhide_progress(self):"""Unhide output window progress bar."""if self.window:

self.window.SetActivityBarVisibility(True)

(continues on next page)

230 Chapter 18. pyrevit.output

Page 235: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def indeterminate_progress(self, state):"""Show or hide indeterminate progress bar. """if self.window:

self.window.UpdateActivityBar(state)

def show_logpanel(self):"""Show output window logging panel."""if self.window:

self.window.SetActivityBarVisibility(True)

def hide_logpanel(self):"""Hide output window logging panel."""if self.window:

self.show_logpanel()self.window.SetActivityBarVisibility(False)

def log_ok(self, message):"""Report OK message into output logging panel."""if self.window:

self.show_logpanel()self.window.activityBar.ConsoleLogOK(message)

def log_info(self, message):"""Report INFO message into output logging panel."""if self.window:

self.show_logpanel()self.window.activityBar.ConsoleLogInfo(message)

def log_warning(self, message):"""Report WARNING message into output logging panel."""if self.window:

self.show_logpanel()self.window.activityBar.ConsoleLogWarning(message)

def log_error(self, message):"""Report ERROR message into output logging panel."""if self.window:

self.show_logpanel()self.window.activityBar.ConsoleLogError(message)

def set_icon(self, iconpath):"""Sets icon on the output window."""if self.window:

self.window.SetIcon(iconpath)

def reset_icon(self):"""Sets icon on the output window."""if self.window:

self.window.ResetIcon()

@staticmethoddef print_html(html_str):

"""Add the html code to the output window.

Example:>>> output = pyrevit.output.get_output()>>> output.print_html('<strong>Title</strong>')

(continues on next page)

18.1. pyrevit.output 231

Page 236: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""print(coreutils.prepare_html_str(html_str),

end="")

@staticmethoddef print_code(code_str):

"""Print code to the output window with special formatting.

Example:>>> output = pyrevit.output.get_output()>>> output.print_code('value = 12')

"""code_div = '<div class="code">{}</div>'print(

coreutils.prepare_html_str(code_div.format(

code_str.replace(' ', '&nbsp;'*4))

),end="")

@staticmethoddef print_md(md_str):

"""Process markdown code and print to output window.

Example:>>> output = pyrevit.output.get_output()>>> output.print_md('### Title')

"""tables_ext = 'pyrevit.coreutils.markdown.extensions.tables'markdown_html = markdown.markdown(md_str, extensions=[tables_ext])markdown_html = markdown_html.replace('\n', '').replace('\r', '')html_code = coreutils.prepare_html_str(markdown_html)print(html_code, end="")

def print_table(self, table_data, columns=None, formats=None,title='', last_line_style=''):

"""Print provided data in a table in output window.

Args:table_data (:obj:`list` of iterables): 2D array of datatitle (str): table titlecolumns (:obj:`list` str): list of column namesformats (:obj:`list` str): column data formatslast_line_style (str): css style of last row

Example:>>> data = [... ['row1', 'data', 'data', 80 ],... ['row2', 'data', 'data', 45 ],... ]>>> output.print_table(... table_data=data,... title="Example Table",... columns=["Row Name", "Column 1", "Column 2", "Percentage"],... formats=['', '', '', '{}%'],

(continues on next page)

232 Chapter 18. pyrevit.output

Page 237: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

... last_line_style='color:red;'

... )"""if not columns:

columns = []if not formats:

formats = []

if last_line_style:self.add_style('tr:last-child {{ {style} }}'

.format(style=last_line_style))

zipper = itertools.izip_longest #pylint: disable=E1101adjust_base_col = '|'adjust_extra_col = ':---|'base_col = '|'extra_col = '{data}|'

# find max column countmax_col = max([len(x) for x in table_data])

header = ''if columns:

header = base_colfor idx, col_name in zipper(range(max_col), columns, fillvalue=''):

→˓#pylint: disable=W0612header += extra_col.format(data=col_name)

header += '\n'

justifier = adjust_base_colfor idx in range(max_col):

justifier += adjust_extra_col

justifier += '\n'

rows = ''for entry in table_data:

row = base_colfor idx, attrib, attr_format \

in zipper(range(max_col), entry, formats, fillvalue=''):if attr_format:

value = attr_format.format(attrib)else:

value = attribrow += extra_col.format(data=value)

rows += row + '\n'

table = header + justifier + rowsself.print_md('### {title}'.format(title=title))self.print_md(table)

def insert_divider(self):"""Add horizontal rule to the output window."""self.print_md('-----')

def next_page(self):(continues on next page)

18.1. pyrevit.output 233

Page 238: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Add hidden next page tag to the output window.

This is helpful to silently separate the output to multiple pagesfor better printing."""self.print_html('<div class="nextpage"></div><div>&nbsp</div>')

@staticmethoddef linkify(element_ids, title=None):

"""Create clickable link for the provided element ids.

This method, creates the link but does not print it directly.

Args:element_ids (`ElementId`) orelement_ids (:obj:`list` of `ElementId`): single or multiple idstitle (str): tile of the link. defaults to list of element ids

Example:>>> output = pyrevit.output.get_output()>>> for idx, elid in enumerate(element_ids):>>> print('{}: {}'.format(idx+1, output.linkify(elid)))

"""return coreutils.prepare_html_str(

linkmaker.make_link(element_ids, contents=title))

def make_chart(self):""":obj:`PyRevitOutputChart`: Return chart object."""return charts.PyRevitOutputChart(self)

def make_line_chart(self):""":obj:`PyRevitOutputChart`: Return line chart object."""return charts.PyRevitOutputChart(self, chart_type=charts.LINE_CHART)

def make_stacked_chart(self):""":obj:`PyRevitOutputChart`: Return stacked chart object."""chart = charts.PyRevitOutputChart(self, chart_type=charts.LINE_CHART)chart.options.scales = {'yAxes': [{'stacked': True, }]}return chart

def make_bar_chart(self):""":obj:`PyRevitOutputChart`: Return bar chart object."""return charts.PyRevitOutputChart(self, chart_type=charts.BAR_CHART)

def make_radar_chart(self):""":obj:`PyRevitOutputChart`: Return radar chart object."""return charts.PyRevitOutputChart(self, chart_type=charts.RADAR_CHART)

def make_polar_chart(self):""":obj:`PyRevitOutputChart`: Return polar chart object."""return charts.PyRevitOutputChart(self, chart_type=charts.POLAR_CHART)

def make_pie_chart(self):""":obj:`PyRevitOutputChart`: Return pie chart object."""return charts.PyRevitOutputChart(self, chart_type=charts.PIE_CHART)

(continues on next page)

234 Chapter 18. pyrevit.output

Page 239: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

def make_doughnut_chart(self):""":obj:`PyRevitOutputChart`: Return dougnut chart object."""return charts.PyRevitOutputChart(self,

chart_type=charts.DOUGHNUT_CHART)

def make_bubble_chart(self):""":obj:`PyRevitOutputChart`: Return bubble chart object."""return charts.PyRevitOutputChart(self, chart_type=charts.BUBBLE_CHART)

def get_output():""":obj:`pyrevit.output.PyRevitOutputWindow` : Return output window."""return PyRevitOutputWindow()

18.2 pyrevit.output.linkmaker

Handle creation of output window helper links.

pyrevit.output.linkmaker.make_link(element_ids, contents=None)Create link for given element ids.

This link is a special format link with revit:// scheme that is handled by the output window to select the providedelement ids in current project. Scripts should not call this function directly. Creating clickable element links ishandled by the output wrapper object through the linkify() method.

Example

>>> output = pyrevit.output.get_output()>>> for idx, elid in enumerate(element_ids):>>> print('{}: {}'.format(idx+1, output.linkify(elid)))

18.2.1 Implementation

"""Handle creation of output window helper links."""

from pyrevit.compat import safe_strtypefrom pyrevit import DBfrom pyrevit.coreutils.logger import get_logger

#pylint: disable=W0703,C0302,C0103mlogger = get_logger(__name__)

PROTOCOL_NAME = 'revit://outputhelpers?'

DEFAULT_LINK = '<a title="Click to select or show element" ' \'class="elementlink" {}>{}</a>'

def make_link(element_ids, contents=None):(continues on next page)

18.2. pyrevit.output.linkmaker 235

Page 240: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

(continued from previous page)

"""Create link for given element ids.

This link is a special format link with revit:// scheme that is handledby the output window to select the provided element ids in current project.Scripts should not call this function directly. Creating clickable elementlinks is handled by the output wrapper object through the :func:`linkify`method.

Example:>>> output = pyrevit.output.get_output()>>> for idx, elid in enumerate(element_ids):>>> print('{}: {}'.format(idx+1, output.linkify(elid)))

"""elementquery = []if isinstance(element_ids, list):

strids = [safe_strtype(x.IntegerValue) for x in element_ids]elif isinstance(element_ids, DB.ElementId):

strids = [safe_strtype(element_ids.IntegerValue)]

for strid in strids:elementquery.append('element[]={}'.format(strid))

reviturl = '&'.join(elementquery)linkname = ', '.join(strids)

if len(reviturl) >= 2000:alertjs = 'alert(&quot;Url was too long and discarded!&quot;);'linkattrs = 'href="#" onClick="{}"'.format(alertjs)

else:linkattrs = 'href="{}{}{}"'.format(PROTOCOL_NAME,

'&command=select&',reviturl)

return DEFAULT_LINK.format(linkattrs, contents or linkname)

236 Chapter 18. pyrevit.output

Page 241: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

Python Module Index

ppyrevit, 61pyrevit.api, 75pyrevit.compat, 77pyrevit.coreutils, 163pyrevit.coreutils.appdata, 202pyrevit.coreutils.envvars, 200pyrevit.coreutils.mathnet, 214pyrevit.coreutils.moduleutils, 215pyrevit.coreutils.pyutils, 209pyrevit.forms, 79pyrevit.forms.utils, 94pyrevit.framework, 133pyrevit.output, 217pyrevit.output.linkmaker, 235pyrevit.script, 137pyrevit.userconfig, 153

237

Page 242: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

238 Python Module Index

Page 243: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

Index

Symbols_ExecutorParams (class in pyrevit), 63_HostAppPostableCommand (class in pyrevit), 61_HostApplication (class in pyrevit), 62_setup() (pyrevit.forms.CommandSwitchWindow

method), 80_setup() (pyrevit.forms.GetValueWindow method), 80_setup() (pyrevit.forms.ProgressBar method), 81_setup() (pyrevit.forms.SelectFromList method), 84_setup() (pyrevit.forms.TemplatePromptBar method), 85_setup() (pyrevit.forms.TemplateUserInputWindow

method), 85_setup() (pyrevit.forms.WarningBar method), 87

Aactiveview (pyrevit._HostApplication attribute), 62add_style() (pyrevit.output.PyRevitOutputWindow

method), 217alert() (in module pyrevit.forms), 87alert_ifnot() (in module pyrevit.forms), 88app (pyrevit._HostApplication attribute), 62available_servers (pyrevit._HostApplication attribute), 62

Bbitmap_from_file() (in module pyrevit.forms.utils), 94build (pyrevit._HostApplication attribute), 62button_select() (pyrevit.forms.SelectFromList method),

84

Ccalculate_dir_hash() (in module pyrevit.coreutils), 164can_access_url() (in module pyrevit.coreutils), 165check_all() (pyrevit.forms.SelectFromList method), 84check_familydoc() (in module pyrevit.forms), 88check_internet_connection() (in module pyre-

vit.coreutils), 165check_revittxt_encoding() (in module pyrevit.coreutils),

165

check_selected() (pyrevit.forms.SelectFromList method),84

check_selection() (in module pyrevit.forms), 89check_utf8bom_encoding() (in module pyrevit.coreutils),

165check_workshared() (in module pyrevit.forms), 89checkable (pyrevit.forms.TemplateListItem attribute), 85cleanup_appdata_folder() (in module pyre-

vit.coreutils.appdata), 203cleanup_filename() (in module pyrevit.coreutils), 165cleanup_string() (in module pyrevit.coreutils), 166clear_search() (pyrevit.forms.SelectFromList method), 84clicked_cancel() (pyrevit.forms.ProgressBar method), 81clipboard_copy() (in module pyrevit.script), 137close() (pyrevit.output.PyRevitOutputWindow method),

218close_others() (pyrevit.output.PyRevitOutputWindow

method), 218command_alt_path (pyrevit._ExecutorParams attribute),

63command_bundle (pyrevit._ExecutorParams attribute),

63command_data (pyrevit._ExecutorParams attribute), 63command_extension (pyrevit._ExecutorParams attribute),

63command_mode (pyrevit._ExecutorParams attribute), 63command_name (pyrevit._ExecutorParams attribute), 63command_path (pyrevit._ExecutorParams attribute), 63command_uniqueid (pyrevit._ExecutorParams attribute),

63CommandSwitchWindow (class in pyrevit.forms), 79compare_lists() (in module pyrevit.coreutils.pyutils), 210config_file (pyrevit.userconfig.PyRevitConfig attribute),

154copy() (pyrevit.coreutils.pyutils.DefaultOrderedDict

method), 210copy_func() (in module pyrevit.coreutils.moduleutils),

215correct_revittxt_encoding() (in module pyrevit.coreutils),

166

239

Page 244: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

create_ext_command_attrs() (in module pyre-vit.coreutils), 166

create_type() (in module pyrevit.coreutils), 166current_date() (in module pyrevit.coreutils), 167current_time() (in module pyrevit.coreutils), 167

Ddebug_mode (pyrevit.output.PyRevitOutputWindow at-

tribute), 218decrement_str() (in module pyrevit.coreutils), 167DefaultOrderedDict (class in pyrevit.coreutils.pyutils),

209disable_element() (pyrevit.forms.WPFWindow static

method), 86dletter_to_unc() (in module pyrevit.coreutils), 168doc (pyrevit._HostApplication attribute), 62doc_mode (pyrevit._ExecutorParams attribute), 63docclosing_eventhandler() (in module pyrevit.output),

223docs (pyrevit._HostApplication attribute), 62

Eenable_element() (pyrevit.forms.WPFWindow static

method), 86engine_mgr (pyrevit._ExecutorParams attribute), 63engine_ver (pyrevit._ExecutorParams attribute), 63executed_from_ui (pyrevit._ExecutorParams attribute),

63exit() (in module pyrevit.script), 137extract_guid() (in module pyrevit.coreutils), 168extract_param() (pyrevit.coreutils.ScriptFileParser

method), 164extract_range() (in module pyrevit.coreutils), 168

FFileWatcher (class in pyrevit.coreutils), 163filter_null_items() (in module pyrevit.coreutils), 168find_config_file() (in module pyrevit.userconfig), 155find_direct_match() (pyrevit.forms.SearchPrompt

method), 82find_loaded_asm() (in module pyrevit.coreutils), 168find_type_by_name() (in module pyrevit.coreutils), 169find_word_match() (pyrevit.forms.SearchPrompt

method), 82first_load (pyrevit._ExecutorParams attribute), 64forced_debug_mode (pyrevit._ExecutorParams attribute),

64format_hex_rgb() (in module pyrevit.coreutils), 169freeze() (pyrevit.output.PyRevitOutputWindow method),

218fully_remove_dir() (in module pyrevit.coreutils), 169fuzzy_search_ratio() (in module pyrevit.coreutils), 169

Ggarbage_data_file() (in module pyrevit.coreutils.appdata),

203get_all_buttons() (in module pyrevit.script), 137get_all_subclasses() (in module pyrevit.coreutils), 169get_alt_script_path() (in module pyrevit.script), 137get_bundle_file() (in module pyrevit.script), 137get_bundle_files() (in module pyrevit.script), 138get_bundle_name() (in module pyrevit.script), 138get_button() (in module pyrevit.script), 138get_canonical_parts() (in module pyrevit.coreutils), 169get_config() (in module pyrevit.script), 138get_config_version() (pyrevit.userconfig.PyRevitConfig

method), 154get_data_file() (in module pyrevit.coreutils.appdata), 203get_data_file() (in module pyrevit.script), 138get_default_stylesheet() (in module pyrevit.output), 223get_dll_file() (in module pyrevit.framework), 133get_docstring() (pyrevit.coreutils.ScriptFileParser

method), 164get_document_data_file() (in module pyrevit.script), 138get_enum_none() (in module pyrevit.coreutils), 169get_enum_value() (in module pyrevit.coreutils), 169get_enum_values() (in module pyrevit.coreutils), 169get_envvar() (in module pyrevit.script), 139get_ext_root_dirs() (pyrevit.userconfig.PyRevitConfig

method), 154get_extension_name() (in module pyrevit.script), 139get_file_name() (in module pyrevit.coreutils), 169get_head_html() (pyrevit.output.PyRevitOutputWindow

method), 218get_height() (pyrevit.output.PyRevitOutputWindow

method), 218get_info() (in module pyrevit.script), 139get_instance_data_file() (in module pyre-

vit.coreutils.appdata), 203get_instance_data_file() (in module pyrevit.script), 139get_logger() (in module pyrevit.script), 140get_mapped_drives_dict() (in module pyrevit.coreutils),

170get_output() (in module pyrevit.output), 223get_output() (in module pyrevit.script), 140get_postable_commands() (pyrevit._HostApplication

method), 62get_pyrevit_env_var() (in module pyre-

vit.coreutils.envvars), 200get_pyrevit_env_vars() (in module pyre-

vit.coreutils.envvars), 200get_pyrevit_version() (in module pyrevit.script), 140get_results() (in module pyrevit.script), 140get_revit_instance_count() (in module pyrevit.coreutils),

170get_script_path() (in module pyrevit.script), 140get_str_hash() (in module pyrevit.coreutils), 170

240 Index

Page 245: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

get_stylesheet() (in module pyrevit.output), 223get_sub_folders() (in module pyrevit.coreutils), 170get_thirdparty_ext_root_dirs() (pyre-

vit.userconfig.PyRevitConfig method), 154get_time() (pyrevit.coreutils.Timer method), 164get_title() (pyrevit.output.PyRevitOutputWindow

method), 218get_type() (in module pyrevit.framework), 133get_unique_id() (in module pyrevit.script), 140get_universal_data_file() (in module pyre-

vit.coreutils.appdata), 203get_universal_data_file() (in module pyrevit.script), 141get_width() (pyrevit.output.PyRevitOutputWindow

method), 218GetValueWindow (class in pyrevit.forms), 80

Hhandle_click() (pyrevit.forms.CommandSwitchWindow

method), 80handle_input_key() (pyre-

vit.forms.CommandSwitchWindow method),80

handle_input_key() (pyrevit.forms.WPFWindowmethod), 86

handle_kb_key() (pyrevit.forms.SearchPrompt method),82

has_changed (pyrevit.coreutils.FileWatcher attribute),163

has_nonprintable() (in module pyrevit.coreutils), 170hide() (pyrevit.output.PyRevitOutputWindow method),

218hide_element() (pyrevit.forms.WPFWindow static

method), 86hide_logpanel() (pyrevit.output.PyRevitOutputWindow

method), 218hide_progress() (pyrevit.output.PyRevitOutputWindow

method), 218

Iid (pyrevit._HostAppPostableCommand attribute), 61increment_str() (in module pyrevit.coreutils), 170indeterminate (pyrevit.forms.ProgressBar attribute), 81indeterminate_progress() (pyre-

vit.output.PyRevitOutputWindow method),218

inject_script() (pyrevit.output.PyRevitOutputWindowmethod), 218

inject_to_body() (pyrevit.output.PyRevitOutputWindowmethod), 219

inject_to_head() (pyrevit.output.PyRevitOutputWindowmethod), 219

insert_divider() (pyrevit.output.PyRevitOutputWindowmethod), 219

inspect_calling_scope_global_var() (in module pyre-vit.coreutils), 170

inspect_calling_scope_local_var() (in module pyre-vit.coreutils), 171

is_blank() (in module pyrevit.coreutils), 171is_box_visible_on_screens() (in module pyre-

vit.coreutils), 171is_checkbox() (pyrevit.forms.TemplateListItem class

method), 85is_data_file_available() (in module pyre-

vit.coreutils.appdata), 203is_exactly() (pyrevit._HostApplication method), 62is_file_available() (in module pyrevit.coreutils.appdata),

204is_newer_than() (pyrevit._HostApplication method), 62is_older_than() (pyrevit._HostApplication method), 62is_pyrevit_data_file() (in module pyre-

vit.coreutils.appdata), 204is_url_valid() (in module pyrevit.coreutils), 171isnumber() (in module pyrevit.coreutils.pyutils), 210

Jjoin_strings() (in module pyrevit.coreutils), 171journal_read() (in module pyrevit.script), 141journal_write() (in module pyrevit.script), 141

Kkey (pyrevit._HostAppPostableCommand attribute), 61

Llinkify() (pyrevit.output.PyRevitOutputWindow static

method), 219list_data_files() (in module pyrevit.coreutils.appdata),

204list_session_data_files() (in module pyre-

vit.coreutils.appdata), 204load_asm() (in module pyrevit.coreutils), 171load_asm_file() (in module pyrevit.coreutils), 171load_index() (in module pyrevit.script), 141lock_size() (pyrevit.output.PyRevitOutputWindow

method), 220log_error() (pyrevit.output.PyRevitOutputWindow

method), 220log_info() (pyrevit.output.PyRevitOutputWindow

method), 220log_ok() (pyrevit.output.PyRevitOutputWindow method),

220log_warning() (pyrevit.output.PyRevitOutputWindow

method), 220

Mmake_bar_chart() (pyrevit.output.PyRevitOutputWindow

method), 220

Index 241

Page 246: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

make_bubble_chart() (pyre-vit.output.PyRevitOutputWindow method),220

make_canonical_name() (in module pyrevit.coreutils),172

make_chart() (pyrevit.output.PyRevitOutputWindowmethod), 220

make_doughnut_chart() (pyre-vit.output.PyRevitOutputWindow method),220

make_line_chart() (pyre-vit.output.PyRevitOutputWindow method),220

make_link() (in module pyrevit.output.linkmaker), 235make_pie_chart() (pyrevit.output.PyRevitOutputWindow

method), 220make_polar_chart() (pyre-

vit.output.PyRevitOutputWindow method),220

make_radar_chart() (pyre-vit.output.PyRevitOutputWindow method),220

make_stacked_chart() (pyre-vit.output.PyRevitOutputWindow method),220

Nname (pyrevit._HostAppPostableCommand attribute), 61name (pyrevit.forms.RevisionOption attribute), 82name (pyrevit.forms.SheetOption attribute), 85name (pyrevit.forms.TemplateListItem attribute), 85name (pyrevit.forms.ViewOption attribute), 86new_uuid() (in module pyrevit.coreutils), 172next_page() (pyrevit.output.PyRevitOutputWindow

method), 220number (pyrevit.forms.SheetOption attribute), 85

Oopen_folder_in_explorer() (in module pyrevit.coreutils),

172open_page() (pyrevit.output.PyRevitOutputWindow

method), 220open_url() (in module pyrevit.script), 141open_url() (pyrevit.output.PyRevitOutputWindow

method), 220output_id (pyrevit.output.PyRevitOutputWindow at-

tribute), 220output_uniqueid (pyrevit.output.PyRevitOutputWindow

attribute), 221

Ppairwise() (in module pyrevit.coreutils.pyutils), 210pick_excel_file() (in module pyrevit.forms), 89pick_file() (in module pyrevit.forms), 89

pick_folder() (in module pyrevit.forms), 90prepare_html_str() (in module pyrevit.coreutils), 172print_code() (pyrevit.output.PyRevitOutputWindow static

method), 221print_html() (pyrevit.output.PyRevitOutputWindow static

method), 221print_md() (pyrevit.output.PyRevitOutputWindow static

method), 221print_table() (pyrevit.output.PyRevitOutputWindow

method), 221proc (pyrevit._HostApplication attribute), 62proc_id (pyrevit._HostApplication attribute), 62proc_name (pyrevit._HostApplication attribute), 62proc_path (pyrevit._HostApplication attribute), 62proc_screen (pyrevit._HostApplication attribute), 62proc_screen_scalefactor (pyrevit._HostApplication at-

tribute), 63proc_screen_workarea (pyrevit._HostApplication at-

tribute), 63process_option() (pyre-

vit.forms.CommandSwitchWindow method),80

ProgressBar (class in pyrevit.forms), 80pyrevit (module), 61pyrevit.api (module), 75pyrevit.compat (module), 77pyrevit.coreutils (module), 163pyrevit.coreutils.appdata (module), 202pyrevit.coreutils.envvars (module), 200pyrevit.coreutils.mathnet (module), 214pyrevit.coreutils.moduleutils (module), 215pyrevit.coreutils.pyutils (module), 209pyrevit.forms (module), 79pyrevit.forms.utils (module), 94pyrevit.framework (module), 133pyrevit.output (module), 217pyrevit.output.linkmaker (module), 235pyrevit.script (module), 137pyrevit.userconfig (module), 153pyrevit_command (pyrevit._ExecutorParams attribute),

64PyRevitConfig (class in pyrevit.userconfig), 154PyRevitException (class in pyrevit), 61PyRevitIOError (class in pyrevit), 61PyRevitOutputWindow (class in pyrevit.output), 217

Rrandom_alpha() (in module pyrevit.coreutils), 172random_color() (in module pyrevit.coreutils), 172random_hex_color() (in module pyrevit.coreutils), 172random_rgb_color() (in module pyrevit.coreutils), 172random_rgba_color() (in module pyrevit.coreutils), 173read_source_file() (in module pyrevit.coreutils), 173reformat_string() (in module pyrevit.coreutils), 173

242 Index

Page 247: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

renderer (pyrevit.output.PyRevitOutputWindow at-tribute), 222

reset() (pyrevit.forms.ProgressBar method), 81reset_config() (in module pyrevit.script), 141reset_icon() (pyrevit.output.PyRevitOutputWindow

method), 222reset_progress() (pyrevit.output.PyRevitOutputWindow

method), 222reset_stylesheet() (in module pyrevit.output), 223resize() (pyrevit.output.PyRevitOutputWindow method),

222restart() (pyrevit.coreutils.Timer method), 164result_dict (pyrevit._ExecutorParams attribute), 64reverse_dict() (in module pyrevit.coreutils), 173reverse_html() (in module pyrevit.coreutils), 174RevisionOption (class in pyrevit.forms), 82run_process() (in module pyrevit.coreutils), 174rvtobj (pyrevit._HostAppPostableCommand attribute), 61

Ssafe_cast() (in module pyrevit.coreutils.pyutils), 211SafeDict (class in pyrevit.coreutils), 163save_changes() (pyrevit.userconfig.PyRevitConfig

method), 154save_config() (in module pyrevit.script), 141save_contents() (pyrevit.output.PyRevitOutputWindow

method), 222save_excel_file() (in module pyrevit.forms), 90save_file() (in module pyrevit.forms), 90ScriptFileParser (class in pyrevit.coreutils), 164search_input (pyrevit.forms.SearchPrompt attribute), 82search_input_parts (pyrevit.forms.SearchPrompt at-

tribute), 82search_matches (pyrevit.forms.SearchPrompt attribute),

82search_term (pyrevit.forms.SearchPrompt attribute), 83search_term_args (pyrevit.forms.SearchPrompt attribute),

83search_term_main (pyrevit.forms.SearchPrompt at-

tribute), 83search_term_switches (pyrevit.forms.SearchPrompt at-

tribute), 83search_txt_changed() (pyre-

vit.forms.CommandSwitchWindow method),80

search_txt_changed() (pyrevit.forms.SearchPromptmethod), 83

search_txt_changed() (pyrevit.forms.SelectFromListmethod), 84

SearchPrompt (class in pyrevit.forms), 82select_image() (in module pyrevit.forms), 90select_open_docs() (in module pyrevit.forms), 91select_revisions() (in module pyrevit.forms), 91select_sheets() (in module pyrevit.forms), 92

select_swatch() (in module pyrevit.forms), 92select_titleblocks() (in module pyrevit.forms), 93select_views() (in module pyrevit.forms), 93SelectFromList (class in pyrevit.forms), 83self_destruct() (pyrevit.output.PyRevitOutputWindow

method), 222set_envvar() (in module pyrevit.script), 142set_font() (pyrevit.output.PyRevitOutputWindow

method), 222set_height() (pyrevit.output.PyRevitOutputWindow

method), 222set_icon() (pyrevit.output.PyRevitOutputWindow

method), 222set_image_source() (pyrevit.forms.WPFWindow

method), 86set_pyrevit_env_var() (in module pyre-

vit.coreutils.envvars), 201set_search_results() (pyrevit.forms.SearchPrompt

method), 83set_stylesheet() (in module pyrevit.output), 223set_thirdparty_ext_root_dirs() (pyre-

vit.userconfig.PyRevitConfig method), 154set_title() (pyrevit.output.PyRevitOutputWindow

method), 222set_width() (pyrevit.output.PyRevitOutputWindow

method), 222setup_icon() (pyrevit.forms.WPFWindow method), 87setup_output_closer() (in module pyrevit.output), 223SheetOption (class in pyrevit.forms), 85show() (pyrevit.forms.SearchPrompt class method), 83show() (pyrevit.forms.TemplateUserInputWindow class

method), 86show() (pyrevit.forms.WPFWindow method), 87show() (pyrevit.output.PyRevitOutputWindow method),

222show_dialog() (pyrevit.forms.WPFWindow method), 87show_element() (pyrevit.forms.WPFWindow static

method), 87show_entry_in_explorer() (in module pyrevit.coreutils),

174show_file_in_explorer() (in module pyrevit.script), 142show_logpanel() (pyrevit.output.PyRevitOutputWindow

method), 222subversion (pyrevit._HostApplication attribute), 63

TTemplateListItem (class in pyrevit.forms), 85TemplatePromptBar (class in pyrevit.forms), 85TemplateUserInputWindow (class in pyrevit.forms), 85Timer (class in pyrevit.coreutils), 164timestamp() (in module pyrevit.coreutils), 174title (pyrevit.forms.ProgressBar attribute), 81toast() (in module pyrevit.forms), 94toggle_all() (pyrevit.forms.SelectFromList method), 84

Index 243

Page 248: pyRevit Documentation - media.readthedocs.org · pyRevit Documentation, Release 4.5 1.1.2__doc__ Button Tooltip: Tooltips are displayed similar to the other buttons in Revit interface

pyRevit Documentation, Release 4.5

toggle_element() (pyrevit.forms.WPFWindow staticmethod), 87

toggle_icon() (in module pyrevit.script), 142touch() (in module pyrevit.coreutils), 174

Uuiapp (pyrevit._HostApplication attribute), 63uidoc (pyrevit._HostApplication attribute), 63unc_to_dletter() (in module pyrevit.coreutils), 175uncheck_all() (pyrevit.forms.SelectFromList method), 85uncheck_selected() (pyrevit.forms.SelectFromList

method), 85unfreeze() (pyrevit.output.PyRevitOutputWindow

method), 223unhide_progress() (pyre-

vit.output.PyRevitOutputWindow method),223

unlock_size() (pyrevit.output.PyRevitOutputWindowmethod), 223

unwrap() (pyrevit.forms.TemplateListItem method), 85update_progress() (pyrevit.forms.ProgressBar method),

81update_progress() (pyrevit.output.PyRevitOutputWindow

method), 223update_results_display() (pyrevit.forms.SearchPrompt

method), 83update_tstamp() (pyrevit.coreutils.FileWatcher method),

163update_window() (pyrevit.forms.TemplatePromptBar

method), 85username (pyrevit._HostApplication attribute), 63

Vverify_configs() (in module pyrevit.userconfig), 155verify_directory() (in module pyrevit.coreutils), 175version (pyrevit._HostApplication attribute), 63version_name (pyrevit._HostApplication attribute), 63ViewOption (class in pyrevit.forms), 86

Wwait_async() (pyrevit.forms.ProgressBar method), 81WarningBar (class in pyrevit.forms), 87window (pyrevit.output.PyRevitOutputWindow at-

tribute), 223window_handle (pyrevit._ExecutorParams attribute), 64WPFWindow (class in pyrevit.forms), 86

244 Index